From 466ff3c456383456630ce9d67abae991566c158e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Apr 2009 01:08:37 +0200 Subject: Implemented lockfile stuff to prevent multiple running instances. Implemented daemonizing, use -f to run in foreground. Implemented logging to syslog (or to std{out,err} when running in foreground). Modified the udev rules file (removed --pidfile etc.). --- 85-usbmuxd.rules | 4 +- main.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 190 insertions(+), 27 deletions(-) diff --git a/85-usbmuxd.rules b/85-usbmuxd.rules index 90d49ea..69ddef8 100644 --- a/85-usbmuxd.rules +++ b/85-usbmuxd.rules @@ -30,8 +30,8 @@ ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep04", SYMLINK+="usbm ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", SYMLINK+="usbmux/out" # Start and stop 'usbmuxd' as required. -ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --background --make-pidfile --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" -ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --pidfile /var/run/usbmuxd.pid --exec /usr/local/sbin/usbmuxd" +ACTION=="add", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --start --oknodo --exec /usr/local/sbin/usbmuxd" +ACTION=="remove", SUBSYSTEM=="usb_endpoint", KERNEL=="usbdev*_ep85", RUN+="/sbin/start-stop-daemon --stop --signal 2 --exec /usr/local/sbin/usbmuxd" # skip LABEL="usbmuxd_rules_end" diff --git a/main.c b/main.c index 832ff7f..0af0735 100644 --- a/main.c +++ b/main.c @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -43,9 +47,12 @@ #define DEFAULT_CHILDREN_CAPACITY 10 #define DEBUG_LEVEL 0 +#define LOCKFILE "/var/run/usbmuxd.lock" + static int quit_flag = 0; static int fsock = -1; static int verbose = DEBUG_LEVEL; +static int foreground = 0; struct device_use_info { uint32_t device_id; @@ -764,7 +771,43 @@ leave: */ static int daemonize() { - // TODO still to be implemented, also logging is missing! + pid_t pid; + pid_t sid; + + // already a daemon + if (getppid() == 1) return 0; + + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + // exit parent process + exit(EXIT_SUCCESS); + } + + // At this point we are executing as the child process + + // Change the file mode mask + umask(0); + + // Create a new SID for the child process + sid = setsid(); + if (sid < 0) { + return -1; + } + + // Change the current working directory. + if ((chdir("/")) < 0) { + return -2; + } + + // Redirect standard files to /dev/null + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + return 0; } @@ -779,12 +822,85 @@ static void clean_exit(int sig) quit_flag = 1; } +static void logmsg(int prio, char *format, ...) +{ + va_list args; + va_start(args, format); + + if (!foreground) { + // daemon. log using syslog. + vsyslog(prio, format, args); + } else { + // running in foreground. log to stdout/stderr. + char msgbuf[256]; + FILE *lfp = stdout; + switch(prio) { + case LOG_EMERG: + case LOG_ALERT: + case LOG_CRIT: + case LOG_ERR: + case LOG_WARNING: + lfp = stderr; + break; + default: + lfp = stdout; + } + strcpy(msgbuf, "usbmuxd: "); + vsnprintf(msgbuf+9, 244, format, args); + strcat(msgbuf, "\n"); + fputs(msgbuf, lfp); + } + + va_end(args); +} + +static void usage() +{ + printf("usage: usbmuxd [options]\n"); + printf("\t-h|--help print this message.\n"); + printf("\t-v|--verbose be verbose\n"); + printf("\t-f|--foreground do not daemonize\n"); + printf("\n"); +} + +static void parse_opts(int argc, char **argv) +{ + static struct option longopts[] = { + { "help", 0, NULL, 'h' }, + { "foreground", 0, NULL, 'f' }, + { "verbose", 0, NULL, 'v' }, + { NULL, 0, NULL, 0} + }; + int c; + + while (1) { + c = getopt_long(argc, argv, "hfv", longopts, (int *) 0); + if (c == -1) { + break; + } + + switch (c) { + case 'h': + usage(); + exit(0); + case 'f': + foreground = 1; + break; + case 'v': + sock_stuff_set_verbose(++verbose); + break; + default: + usage(); + exit(2); + } + } +} + /** * main function. Initializes all stuff and then loops waiting in accept. */ int main(int argc, char **argv) { - int foreground = 1; struct sockaddr_un c_addr; socklen_t len = sizeof(struct sockaddr_un); struct client_data *cdata = NULL; @@ -793,20 +909,47 @@ int main(int argc, char **argv) int i; int result = 0; int cnt = 0; + FILE *lfd = NULL; + struct flock lock; - for (i = 1; i < argc; i++) { - if (argv[i] != NULL && (!strncmp("-v", argv[i], 2) || !strncmp("--verbose", argv[i], 10))) { - sock_stuff_set_verbose(++verbose); - } + parse_opts(argc, argv); + + argc -= optind; + argv += optind; + + if (!foreground) { + openlog("usbmuxd", LOG_PID, 0); } - if (verbose >= 2) fprintf(stderr, "usbmuxd: starting\n"); + if (verbose >= 2) logmsg(LOG_NOTICE, "starting"); - // TODO: Parameter checking. + // signal(SIGHUP, reload_conf); // none yet + signal(SIGINT, clean_exit); + signal(SIGQUIT, clean_exit); + signal(SIGTERM, clean_exit); + signal(SIGPIPE, SIG_IGN); + + // check for other running instance + lfd = fopen(LOCKFILE, "r"); + if (lfd) { + lock.l_type = 0; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + fcntl(fileno(lfd), F_GETLK, &lock); + fclose(lfd); + if (lock.l_type != F_UNLCK) { + logmsg(LOG_NOTICE, "another instance is already running. exiting."); + return -1; + } + } fsock = create_unix_socket(USBMUXD_SOCKET_FILE); if (fsock < 0) { - if (verbose >= 1) fprintf(stderr, "Could not create socket, exiting\n"); + logmsg(LOG_ERR, "Could not create socket, exiting"); + if (!foreground) { + closelog(); + } return -1; } @@ -814,26 +957,36 @@ int main(int argc, char **argv) if (!foreground) { if (daemonize() < 0) { + fprintf(stderr, "usbmuxd: FATAL: Could not daemonize!\n"); + syslog(LOG_ERR, "FATAL: Could not daemonize!"); + closelog(); exit(EXIT_FAILURE); } } - // signal(SIGHUP, reload_conf); // none yet - signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); - signal(SIGTERM, clean_exit); - signal(SIGPIPE, SIG_IGN); + // now open the lockfile and place the lock + lfd = fopen(LOCKFILE, "w"); + if (lfd) { + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + fcntl(fileno(lfd), F_SETLK, &lock); + } // Reserve space for 10 clients which should be enough. If not, the // buffer gets enlarged later. children = (struct client_data**)malloc(sizeof(struct client_data*) * children_capacity); if (!children) { - if (verbose >= 2) fprintf(stderr, "usbmuxd: Out of memory when allocating memory for child threads. Terminating.\n"); + logmsg(LOG_ERR, "Out of memory when allocating memory for child threads. Terminating."); + if (!foreground) { + closelog(); + } exit(EXIT_FAILURE); } memset(children, 0, sizeof(struct client_data*) * children_capacity); - if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for connection\n"); + if (verbose >= 2) logmsg(LOG_NOTICE, "waiting for connection"); while (!quit_flag) { // Check the file descriptor before accepting a connection. // If no connection attempt is made, just repeat... @@ -845,7 +998,7 @@ int main(int argc, char **argv) if (children[i]) { if (children[i]->dead != 0) { pthread_join(children[i]->thread, NULL); - if (verbose >= 3) fprintf(stderr, "usbmuxd: reclaimed client thread (fd=%d)\n", children[i]->socket); + if (verbose >= 3) logmsg(LOG_NOTICE, "reclaimed client thread (fd=%d)", children[i]->socket); free(children[i]); children[i] = NULL; cnt++; @@ -864,7 +1017,7 @@ int main(int argc, char **argv) } continue; } else { - if (verbose >= 3) fprintf(stderr, "usbmuxd: select error: %s\n", strerror(errno)); + if (verbose >= 3) logmsg(LOG_ERR, "usbmuxd: select error: %s", strerror(errno)); continue; } } @@ -873,7 +1026,7 @@ int main(int argc, char **argv) memset(cdata, 0, sizeof(struct client_data)); if (!cdata) { quit_flag = 1; - if (verbose >= 1) fprintf(stderr, "usbmuxd: Error: Out of memory! Terminating.\n"); + logmsg(LOG_ERR, "Error: Out of memory! Terminating."); break; } @@ -883,12 +1036,12 @@ int main(int argc, char **argv) if (errno == EINTR) { continue; } else { - if (verbose >= 3) fprintf(stderr, "usbmuxd: Error in accept: %s\n", strerror(errno)); + if (verbose >= 3) logmsg(LOG_ERR, "Error in accept: %s", strerror(errno)); continue; } } - if (verbose >= 1) fprintf(stderr, "usbmuxd: new client connected (fd=%d)\n", cdata->socket); + if (verbose >= 1) logmsg(LOG_NOTICE, "new client connected (fd=%d)", cdata->socket); // create client thread: if (pthread_create(&cdata->thread, NULL, usbmuxd_client_init_thread, cdata) == 0) { @@ -900,19 +1053,19 @@ int main(int argc, char **argv) children_capacity++; children = realloc(children, sizeof(struct client_data*) * children_capacity); if (!children) { - if (verbose >= 1) fprintf(stderr, "usbmuxd: Out of memory when enlarging child thread buffer\n"); + logmsg(LOG_ERR, "Out of memory when enlarging child thread buffer"); } } children[i] = cdata; } else { - if (verbose >= 3) fprintf(stderr, "usbmuxd: Failed to create client_init_thread.\n"); + logmsg(LOG_ERR, "Failed to create client_init_thread."); close(cdata->socket); free(cdata); cdata = NULL; } } - if (verbose >= 3) fprintf(stderr, "usbmuxd: terminating\n"); + if (verbose >= 3) logmsg(LOG_NOTICE, "terminating"); // preparing for shutdown: wait for child threads to terminate (if any) if (verbose >= 2) fprintf(stderr, "usbmuxd: waiting for child threads to terminate...\n"); @@ -934,7 +1087,17 @@ int main(int argc, char **argv) unlink(USBMUXD_SOCKET_FILE); - if (verbose >= 1) fprintf(stderr, "usbmuxd: terminated\n"); + // unlock lock file and close it. + if (lfd) { + lock.l_type = F_UNLCK; + fcntl(fileno(lfd), F_SETLK, lock); + fclose(lfd); + } + + if (verbose >= 1) logmsg(LOG_NOTICE, "usbmuxd: terminated"); + if (!foreground) { + closelog(); + } return 0; } -- cgit v1.1-32-gdbae