diff --git a/commandline.c b/commandline.c index 0f0d8108..bc1c0a68 100644 --- a/commandline.c +++ b/commandline.c @@ -33,39 +33,34 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "rhizome.h" -static int servalNodeRunning(int *pid) +/** Return the PID of the currently running server process, return 0 if there is none. + */ +static int servalNodeRunning() { const char *instancepath = serval_instancepath(); struct stat st; - int r=stat(instancepath,&st); - if (r) - return setReason("Instance path '%s' non existant or not accessable: %s [errno=%d]" + if (stat(instancepath, &st) == -1) + return setReason( + "Instance path '%s' non existant or not accessable: %s [errno=%d]" " (Set SERVALINSTANCE_PATH to specify an alternate location)", instancepath, strerror(errno), errno ); - if ((st.st_mode&S_IFMT)!=S_IFDIR) + if ((st.st_mode & S_IFMT) != S_IFDIR) return setReason("Instance path '%s' is not a directory", instancepath); - - int running=0; char filename[1024]; - if (FORM_SERVAL_INSTANCE_PATH(filename, "serval.pid")) { - FILE *f=fopen(filename,"r"); - if (f) { - char line[1024]; - line[0]=0; fgets(line,1024,f); - *pid = strtoll(line,NULL,10); - running=*pid; - if (running) { - /* Check that process is really running. - Some systems don't have /proc (including mac), - so we need to find out some otherway.*/ - running=1; // assume pid means is running for now - } - fclose(f); - } + if (!FORM_SERVAL_INSTANCE_PATH(filename, "serval.pid")) + return -1; + FILE *f = NULL; + if ((f = fopen(filename, "r"))) { + char buf[20]; + fgets(buf, sizeof buf, f); + fclose(f); + int pid = atoi(buf); + if (pid > 0 && kill(pid, 0) != -1) + return pid; + unlink(filename); } - - return running; + return 0; } int cli_usage() { @@ -582,137 +577,122 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti int foregroundP= (argc >= 2 && !strcasecmp(argv[1], "foreground")); if (cli_arg(argc, argv, o, "instance path", &thisinstancepath, cli_absolute_path, NULL) == -1) return -1; - /* Create the instance directory if it does not yet exist */ if (create_serval_instance_dir() == -1) return -1; - + cli_puts("instancepath"); + cli_delim(":"); + cli_puts(serval_instancepath()); + cli_delim("\n"); /* Now that we know our instance path, we can ask for the default set of network interfaces that we will take interest in. */ - overlay_interface_args(confValueGet("interfaces","")); - if (strlen(confValueGet("interfaces",""))<1) { - WHY("Noone has told me which network interfaces to listen on; " - "you should probably put something in the interfaces setting."); + const char *interfaces = confValueGet("interfaces", ""); + if (!interfaces[0]) + WHY("No network interfaces configured (empty 'interfaces' config setting)"); + overlay_interface_args(interfaces); + int pid = servalNodeRunning(); + if (pid < 0) + return -1; + int ret = 1; + if (pid > 0) { + WHYF("Serval process already running (pid=%d)", pid); + } else { + /* Start the Serval process. + All server settings will be read by the server process from the + instance directory when it starts up. + We can just become the server process ourselves --- no need to fork. + */ + rhizome_datastore_path = serval_instancepath(); + rhizome_opendb(); + overlayMode = 1; + if ((pid = server(NULL, foregroundP)) <= 0) + return -1; + ret = 0; } - - int pid=-1; - int running = servalNodeRunning(&pid); - if (running<0) return -1; - if (running>0) - return WHYF("Serval process already running (pid=%d)", pid); - /* Start the Serval process. - All server settings will be read by the server process from the - instance directory when it starts up. - We can just become the server process ourselves --- no need to fork. - - */ - rhizome_datastore_path = serval_instancepath(); - rhizome_opendb(); - - overlayMode=1; - return server(NULL,foregroundP); + cli_puts("pid"); + cli_delim(":"); + cli_printf("%d", pid); + cli_delim("\n"); + return ret; } int app_server_stop(int argc, const char *const *argv, struct command_line_option *o) { if (cli_arg(argc, argv, o, "instance path", &thisinstancepath, cli_absolute_path, NULL) == -1) return -1; - - int tries=0; - - for(tries=0;tries<3;tries++) - { - int pid=-1; - int running = servalNodeRunning(&pid); - if (running>0) { - /* Is running, so we can try to kill it. - This is a little complicated by the fact that we catch most signals - so that unexpected aborts just restart. - What we can do is put some code in the signal handler that does abort - the process if a certain file exists, perhaps instance_path/doshutdown, - and removes the file. - */ - if (pid<0) { - WHY("Could not determine process id of Serval process. Stale instance perhaps?"); - return -1; + const char *instancepath = serval_instancepath(); + int pid = servalNodeRunning(); + if (pid < 0) + return -1; + cli_puts("instancepath"); + cli_delim(":"); + cli_puts(instancepath); + cli_delim("\n"); + if (pid) { + cli_puts("pid"); + cli_delim(":"); + cli_printf("%d", pid); + cli_delim("\n"); + int tries = 0; + while (1) { + if (tries >= 3) + return WHYF( + "Serval process for instance '%s' did not stop after %d SIGHUP signals", + instancepath, tries + ); + ++tries; + /* Create the stopfile, which causes the server process's signal handler to exit + instead of restarting. */ + char stopfile[1024]; + if (!FORM_SERVAL_INSTANCE_PATH(stopfile, "doshutdown")) + return -1; + FILE *f; + if ((f = fopen(stopfile, "w")) == NULL) + return WHYF("Could not create shutdown file '%s'", stopfile); + fclose(f); + if (kill(pid,SIGHUP) == -1) { + // ESRCH means process is gone, possibly we are racing with another stop, or servald just + // died unexpectedly. + if (errno == ESRCH) { + serverCleanUp(); + break; } - - char stopfile[1024]; - FILE *f; - if (!(FORM_SERVAL_INSTANCE_PATH(stopfile, "doshutdown") && (f = fopen(stopfile, "w")))) { - WHY("Could not create shutdown file"); - return -1; - } - fclose(f); - int result=kill(pid,SIGHUP); - if (!result) { - WHY("Stop request sent to Serval process."); - } else { - WHY("Could not send SIGHUP to Serval process."); - switch (errno) { - case EINVAL: WHY("This is embarassing, but the operating system says I don't know how to send a signal."); break; - case EPERM: WHY("I don't have permission to stop the Serval process. You could try using sudo, or run the stop command as the appropriate user."); break; - case ENOENT: - case ESRCH: WHY("The process id I have recorded doesn't seem to exist anymore. Did someone kill the process without telling me?"); - /* Clean up any lingering mess */ - servalShutdownCleanly(); - break; - default: - perror("This is reason given by the operating system"); - } - return -1; - } - - /* Allow a few seconds for the process to die, and keep an eye on things - while this is happening. */ - time_t timeout=time(0)+2; - while(timeout>time(0)) { - pid=-1; - int running = servalNodeRunning(&pid); - if (running<1) { - WHY("Serval process appears to have stopped."); - return 0; - } - } - } else { - return WHY("Serval process for that instance does not appear to be running."); + return WHYF("Error sending SIGHUP to Serval instance '%s' process pid=%d: %s [errno=%d]", + instancepath, pid, strerror(errno), errno + ); } + /* Allow a few seconds for the process to die, and keep an eye on things while this is + happening. */ + time_t timeout = time(NULL) + 2; + while (time(NULL) < timeout && servalNodeRunning() == pid) + usleep(200000); // 5 Hz } - - return WHY("Tried to stop servald without success"); + cli_puts("tries"); + cli_delim(":"); + cli_printf("%d", tries); + cli_delim("\n"); + } + return pid ? 0 : 1; } int app_server_status(int argc, const char *const *argv, struct command_line_option *o) { if (cli_arg(argc, argv, o, "instance path", &thisinstancepath, cli_absolute_path, NULL) == -1) return -1; - - /* Display configuration information */ - char filename[1024]; - FILE *f; - if (FORM_SERVAL_INSTANCE_PATH(filename, "serval.conf") && (f = fopen(filename, "r"))) { - char line[1024]; - line[0]=0; fgets(line,1024,f); - printf("\nServal Mesh configuration:\n"); - while(line[0]) { - printf(" %s",line); - line[0]=0; fgets(line,1024,f); - } - fclose(f); + int pid = servalNodeRunning(); + if (pid < 0) + return -1; + cli_puts("instancepath"); + cli_delim(":"); + cli_puts(serval_instancepath()); + cli_delim("\n"); + if (pid) { + cli_puts("pid"); + cli_delim(":"); + cli_printf("%d", pid); + cli_delim("\n"); } - - /* Display running status of daemon from serval.pid file */ - int pid=-1; - int running = servalNodeRunning(&pid); - if (running<0) return -1; - - printf("For Serval Mesh instance %s:\n", serval_instancepath()); - if (running) - printf(" Serval mesh process is running (pid=%d)\n",pid); - else - printf(" Serval Mesh process not running\n"); - - return 0; + return pid > 0 ? 0 : 1; } int app_mdp_ping(int argc, const char *const *argv, struct command_line_option *o) diff --git a/dna.c b/dna.c index fffa68f4..b39eb8ec 100644 --- a/dna.c +++ b/dna.c @@ -266,7 +266,7 @@ int form_serval_instance_path(char *buf, size_t bufsiz, const char *path) { if (snprintf(buf, bufsiz, "%s/%s", serval_instancepath(), path) < bufsiz) return 1; - fprintf(stderr, "Cannot form pathname \"%s/%s\" -- buffer too small (%lu bytes)", serval_instancepath(), path, (unsigned long)bufsiz); + setReason("Cannot form pathname \"%s/%s\" -- buffer too small (%lu bytes)", serval_instancepath(), path, (unsigned long)bufsiz); return 0; } @@ -290,9 +290,8 @@ int create_serval_instance_dir() { return 0; } -void servalShutdownCleanly() +void serverCleanUp() { - WHY("Shutting down as requested."); /* Try to remove shutdown and PID files and exit */ char filename[1024]; if (FORM_SERVAL_INSTANCE_PATH(filename, "doshutdown")) { @@ -308,26 +307,29 @@ void servalShutdownCleanly() } else { overlay_mdp_client_done(); } - exit(0); } void signal_handler( int signal ) { - if (signal==SIGQUIT) servalShutdownCleanly(); - - if (signal==SIGHUP||signal==SIGINT) { - /* Shut down. - The shutting down should be done from the main-line code rather than here, - so we first try to tell the mainline code to do so. If, however, this is - not the first time we have been asked to shut down, then we will do it here. */ - if (servalShutdown) { - /* We have been asked before, so shut down cleanly */ - servalShutdownCleanly(); - } else { - WHY("Asking Serval process to shutdown cleanly"); - servalShutdown=1; - } - return; + switch (signal) { + case SIGQUIT: + serverCleanUp(); + exit(0); + case SIGHUP: + case SIGINT: + /* Shut down. + The shutting down should be done from the main-line code rather than here, + so we first try to tell the mainline code to do so. If, however, this is + not the first time we have been asked to shut down, then we will do it here. */ + if (servalShutdown) { + /* We have been asked before, so shut down cleanly */ + serverCleanUp(); + exit(0); + } else { + WHY("Asking Serval process to shutdown cleanly"); + servalShutdown=1; + } + return; } /* oops - caught a bad signal -- exec() ourselves fresh */ @@ -477,7 +479,7 @@ void signal_handler( int signal ) { exit(-3); } -int setVerbosity(char *optarg) { +int setVerbosity(const char *optarg) { long long old_debug=debug; debug=strtoll(optarg,NULL,10); if (strstr(optarg,"interfaces")) debug|=DEBUG_OVERLAYINTERFACES; @@ -507,7 +509,7 @@ int setVerbosity(char *optarg) { if (strstr(optarg,"queues")) debug|=DEBUG_QUEUES; if (strstr(optarg,"broadcasts")) debug|=DEBUG_BROADCASTS; - if (old_debug==debug) { + if (old_debug==debug && optarg[0]) { fprintf(stderr,"WARNING: Option '%s' had no effect on existing debug/verbosity level.\n", optarg); } diff --git a/overlay.c b/overlay.c index c794bc9a..2bbb94da 100644 --- a/overlay.c +++ b/overlay.c @@ -121,7 +121,10 @@ int overlayServerMode() while(1) { - if (servalShutdown) servalShutdownCleanly(); + if (servalShutdown) { + serverCleanUp(); + exit(0); + } /* Work out how long we can wait before we need to tick */ long long ms=overlay_time_until_next_tick(); diff --git a/overlay_interface.c b/overlay_interface.c index 8b353474..f8a4406d 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -149,7 +149,7 @@ int overlay_interface_arg(char *arg) else { free(r); return WHY("Bad interface specification"); } } -int overlay_interface_args(char *arg) +int overlay_interface_args(const char *arg) { /* Parse series of comma-separated interface definitions from a single argument */ diff --git a/serval.h b/serval.h index 59776cf8..fce36256 100755 --- a/serval.h +++ b/serval.h @@ -381,7 +381,7 @@ extern int hexdigit[16]; extern int sock; -void servalShutdownCleanly(); +void serverCleanUp(); char *confValueGet(char *var,char *defaultValue); int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl, struct sockaddr *recvaddr,unsigned int *recvaddrlen); @@ -766,7 +766,7 @@ int overlay_rx_messages(); int overlay_check_ticks(); int overlay_add_selfannouncement(); int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b); -int overlay_interface_args(char *arg); +int overlay_interface_args(const char *arg); int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *nexthoplen, int *interface); int overlay_sendto(struct sockaddr_in *recipientaddr,unsigned char *bytes,int len); @@ -1233,7 +1233,7 @@ typedef struct overlay_mdp_frame { int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req); -int setVerbosity(char *optarg); +int setVerbosity(const char *optarg); /* Client-side MDP function */ extern int mdp_client_socket; diff --git a/server.c b/server.c index 88cb216b..7f7568ef 100644 --- a/server.c +++ b/server.c @@ -128,12 +128,12 @@ int server(char *backing_file,int foregroundMode) /* Record PID */ char filename[1024]; if (!FORM_SERVAL_INSTANCE_PATH(filename, "serval.pid")) - exit(-1); + return -1; FILE *f=fopen(filename,"w"); if (!f) { WHYF("Could not write to PID file %s", filename); perror("fopen"); - exit(-1); + return -1; } fprintf(f,"%d\n",getpid()); fclose(f); @@ -532,7 +532,10 @@ int simpleServerMode() int len; int r; - if (servalShutdown) servalShutdownCleanly(); + if (servalShutdown) { + serverCleanUp(); + exit(0); + } bzero((void *)&recvaddr,sizeof(recvaddr));