staging: usbip: add "-P" / "--pid" option to save usbipd process id
[linux-2.6-block.git] / drivers / staging / usbip / userspace / src / usbipd.c
index 3e913b861dc2f980d82838c9877d0db1cc23d54e..f31b8b4246a36f5423629cdef0cd8afe60e8872f 100644 (file)
 
 #define MAIN_LOOP_TIMEOUT 10
 
+#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
+
 static const char usbip_version_string[] = PACKAGE_STRING;
 
 static const char usbipd_help_string[] =
-       "usage: usbipd [options]                        \n"
-       "       -D, --daemon                            \n"
-       "               Run as a daemon process.        \n"
-       "                                               \n"
-       "       -d, --debug                             \n"
-       "               Print debugging information.    \n"
-       "                                               \n"
-       "       -h, --help                              \n"
-       "               Print this help.                \n"
-       "                                               \n"
-       "       -v, --version                           \n"
-       "               Show version.                   \n";
+       "usage: usbipd [options]\n"
+       "       -D, --daemon\n"
+       "               Run as a daemon process.\n"
+       "\n"
+       "       -d, --debug\n"
+       "               Print debugging information.\n"
+       "\n"
+       "       -PFILE, --pid FILE\n"
+       "               Write process id to FILE.\n"
+       "               If no FILE specified, use " DEFAULT_PID_FILE "\n"
+       "\n"
+       "       -h, --help\n"
+       "               Print this help.\n"
+       "\n"
+       "       -v, --version\n"
+       "               Show version.\n";
 
 static void usbipd_help(void)
 {
@@ -286,13 +292,13 @@ static int do_accept(int listenfd)
 
        memset(&ss, 0, sizeof(ss));
 
-       connfd = accept(listenfd, (struct sockaddr *) &ss, &len);
+       connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
        if (connfd < 0) {
                err("failed to accept connection");
                return -1;
        }
 
-       rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host),
+       rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
                         port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
        if (rc)
                err("getnameinfo: %s", gai_strerror(rc));
@@ -328,56 +334,69 @@ int process_request(int listenfd)
        return 0;
 }
 
-static void log_addrinfo(struct addrinfo *ai)
+static void addrinfo_to_text(struct addrinfo *ai, char buf[],
+                            const size_t buf_size)
 {
        char hbuf[NI_MAXHOST];
        char sbuf[NI_MAXSERV];
        int rc;
 
+       buf[0] = '\0';
+
        rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
                         sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
        if (rc)
                err("getnameinfo: %s", gai_strerror(rc));
 
-       info("listening on %s:%s", hbuf, sbuf);
+       snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
 }
 
 static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])
 {
        struct addrinfo *ai;
        int ret, nsockfd = 0;
+       const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
+       char ai_buf[ai_buf_size];
 
        for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) {
-               sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype,
-                                            ai->ai_protocol);
-               if (sockfdlist[nsockfd] < 0)
+               int sock;
+               addrinfo_to_text(ai, ai_buf, ai_buf_size);
+               dbg("opening %s", ai_buf);
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0) {
+                       err("socket: %s: %d (%s)",
+                           ai_buf, errno, strerror(errno));
                        continue;
+               }
 
-               usbip_net_set_reuseaddr(sockfdlist[nsockfd]);
-               usbip_net_set_nodelay(sockfdlist[nsockfd]);
+               usbip_net_set_reuseaddr(sock);
+               usbip_net_set_nodelay(sock);
 
-               if (sockfdlist[nsockfd] >= FD_SETSIZE) {
-                       close(sockfdlist[nsockfd]);
-                       sockfdlist[nsockfd] = -1;
+               if (sock >= FD_SETSIZE) {
+                       err("FD_SETSIZE: %s: sock=%d, max=%d",
+                           ai_buf, sock, FD_SETSIZE);
+                       close(sock);
                        continue;
                }
 
-               ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen);
+               ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
                if (ret < 0) {
-                       close(sockfdlist[nsockfd]);
-                       sockfdlist[nsockfd] = -1;
+                       err("bind: %s: %d (%s)",
+                           ai_buf, errno, strerror(errno));
+                       close(sock);
                        continue;
                }
 
-               ret = listen(sockfdlist[nsockfd], SOMAXCONN);
+               ret = listen(sock, SOMAXCONN);
                if (ret < 0) {
-                       close(sockfdlist[nsockfd]);
-                       sockfdlist[nsockfd] = -1;
+                       err("listen: %s: %d (%s)",
+                           ai_buf, errno, strerror(errno));
+                       close(sock);
                        continue;
                }
 
-               log_addrinfo(ai);
-               nsockfd++;
+               info("listening on %s", ai_buf);
+               sockfdlist[nsockfd++] = sock;
        }
 
        if (nsockfd == 0)
@@ -426,6 +445,31 @@ static void set_signal(void)
        sigaction(SIGCLD, &act, NULL);
 }
 
+static const char *pid_file;
+
+static void write_pid_file()
+{
+       if (pid_file) {
+               dbg("creating pid file %s", pid_file);
+               FILE *fp = fopen(pid_file, "w");
+               if (!fp) {
+                       err("pid_file: %s: %d (%s)",
+                           pid_file, errno, strerror(errno));
+                       return;
+               }
+               fprintf(fp, "%d\n", getpid());
+               fclose(fp);
+       }
+}
+
+static void remove_pid_file()
+{
+       if (pid_file) {
+               dbg("removing pid file %s", pid_file);
+               unlink(pid_file);
+       }
+}
+
 static int do_standalone_mode(int daemonize)
 {
        struct addrinfo *ai_head;
@@ -452,6 +496,7 @@ static int do_standalone_mode(int daemonize)
                usbip_use_syslog = 1;
        }
        set_signal();
+       write_pid_file();
 
        ai_head = do_getaddrinfo(NULL, PF_UNSPEC);
        if (!ai_head) {
@@ -496,8 +541,9 @@ static int do_standalone_mode(int daemonize)
                                        process_request(sockfdlist[i]);
                                }
                        }
-               } else
+               } else {
                        dbg("heartbeat timeout on ppoll()");
+               }
        }
 
        info("shutting down " PROGNAME);
@@ -513,6 +559,7 @@ int main(int argc, char *argv[])
        static const struct option longopts[] = {
                { "daemon",  no_argument, NULL, 'D' },
                { "debug",   no_argument, NULL, 'd' },
+               { "pid",     optional_argument, NULL, 'P' },
                { "help",    no_argument, NULL, 'h' },
                { "version", no_argument, NULL, 'v' },
                { NULL,      0,           NULL,  0  }
@@ -526,6 +573,7 @@ int main(int argc, char *argv[])
 
        int daemonize = 0;
        int opt, rc = -1;
+       pid_file = NULL;
 
        usbip_use_stderr = 1;
        usbip_use_syslog = 0;
@@ -535,7 +583,7 @@ int main(int argc, char *argv[])
 
        cmd = cmd_standalone_mode;
        for (;;) {
-               opt = getopt_long(argc, argv, "Ddhv", longopts, NULL);
+               opt = getopt_long(argc, argv, "DdP::hv", longopts, NULL);
 
                if (opt == -1)
                        break;
@@ -550,6 +598,9 @@ int main(int argc, char *argv[])
                case 'h':
                        cmd = cmd_help;
                        break;
+               case 'P':
+                       pid_file = optarg ? optarg : DEFAULT_PID_FILE;
+                       break;
                case 'v':
                        cmd = cmd_version;
                        break;
@@ -563,6 +614,7 @@ int main(int argc, char *argv[])
        switch (cmd) {
        case cmd_standalone_mode:
                rc = do_standalone_mode(daemonize);
+               remove_pid_file();
                break;
        case cmd_version:
                printf(PROGNAME " (%s)\n", usbip_version_string);