/* * Emergency remote reboot switch, telnet to port, insert challenge and reboot * instantly, created for the use of remote embedded development nodes which * tend to run out of usefull interactive deamons due to swap, memory issues. * Causing great pain when trying to reboot. * * Rick van der Zwet * License: BSDLike - http://rickvanderzwet.nl/license */ /* Version: $Id$ */ /* XXX: Some signal handeling to nicely close connections on failure */ #include #include #include #include #include #include #include #include #include #define PORT_NUMBER 666 #define CHALLENGE "reboot" #define PIDFILE "/var/run/rebootd.pid" void error(const char * message) { perror(message); exit(EX_OSERR); } void init_reboot(const int dryrun) { if (dryrun == 1) { fprintf(stderr, "Reboot call detected\n"); return; } reboot(RB_AUTOBOOT); } void usage() { fprintf(stderr,"rebootd [-fn] [-c challenge] [-p pidfile] [-d port]\n \ Arguments: \n\ \tf = run in foreground [off] \n\ \tn = dry run, no actual reboot [off] \n\ \tpidfile = pid file to use [%s] \n\ \tport = tcp port to use [%i] \n\ \tchallenge = verification password [%s] \n",PIDFILE , PORT_NUMBER, CHALLENGE); exit(EX_USAGE); } int main (int argc, char * argv[]) { char * challenge = CHALLENGE; char * pidfile = PIDFILE; char buffer[256]; int port_number = PORT_NUMBER; int nodeamon_flag = 0; int dryrun_flag = 0; int sockfd, newsockfd, ch; pid_t pid; struct sockaddr_in serv_addr, cli_addr; while ((ch = getopt(argc, argv, "c:d:hfnp:")) != -1) { switch(ch) { case 'c': challenge = optarg; break; case 'd': port_number = atoi(optarg); if (port_number == 0) { usage(); } break; case 'f': nodeamon_flag = 1; break; case 'n': dryrun_flag = 1; break; case 'p': pidfile = optarg; break; case 'h': case '?': default: usage(); } } if (getuid() > 0) { fprintf(stderr,"Sorry, rebootd requires superuser power\n"); exit(EX_USAGE); } if (nodeamon_flag == 0) { pid = fork(); if (pid < 0) { exit(EX_OSERR); } else if (pid > 0) { FILE * pidhandle; pidhandle = fopen(pidfile, "w"); if (pidhandle) { fprintf(pidhandle, "%i", pid); fclose(pidhandle); } exit(EX_OK); } } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(PORT_NUMBER); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { error("ERROR on binding"); } listen(sockfd,5); while ( 1 ) { newsockfd = accept(sockfd, NULL, NULL); bzero(buffer,256); read(newsockfd,buffer,255); if (strncmp(buffer, "PING",4) == 0) { write(newsockfd,"ACK\n",4); } else if (strncmp(buffer, CHALLENGE, strlen(CHALLENGE)) == 0) { write(newsockfd,"OK - rebooting\n",15); init_reboot(dryrun_flag); } else { write(newsockfd,"ERROR - invalid command\n",25); } close(newsockfd); } return(EX_OK); }