2005-12-08 Carl Worth <cworth@cworth.org>
authorCarl Worth <carl@theworths.org>
Thu, 8 Dec 2005 23:42:28 +0000 (23:42 +0000)
committerCarl Worth <carl@theworths.org>
Thu, 8 Dec 2005 23:42:28 +0000 (23:42 +0000)
        * src/ttt-args.h:
        * src/ttt-args.c: (ttt_args_help), (ttt_args_parse): Add
        -d,--detach and --pid-file=FILE options for running the server as
        a daemon.

        * src/ttt-server.c: (ttt_server_statistics),
        (ttt_server_verify_username), (_detach_and_write_child_pid_to),
        (main): Add support for detaching and writing out the child PID to
        a file.

        * src/x.h:
        * src/x.c: (xfopen), (xdup2): Two new x-functions.

ChangeLog
src/ttt-args.c
src/ttt-args.h
src/ttt-server.c
src/x.c
src/x.h

index bc97e1b9547315de96a37b79a29ea1f58c475d64..640a333683480e7bdc9171566aeb2c61e2e08bc2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2005-12-08  Carl Worth  <cworth@cworth.org>
+
+       * src/ttt-args.h:
+       * src/ttt-args.c: (ttt_args_help), (ttt_args_parse): Add
+       -d,--detach and --pid-file=FILE options for running the server as
+       a daemon.
+       
+       * src/ttt-server.c: (ttt_server_statistics),
+       (ttt_server_verify_username), (_detach_and_write_child_pid_to),
+       (main): Add support for detaching and writing out the child PID to
+       a file.
+
+       * src/x.h:
+       * src/x.c: (xfopen), (xdup2): Two new x-functions.
+
+2005-12-08  Carl Worth  <cworth@cworth.org>
+
+       * src/ttt-args.c: (ttt_args_help), (ttt_args_parse):
+       * src/ttt-args.h:
+       * src/ttt-server.c: (ttt_server_statistics),
+       (ttt_server_verify_username), (_detach_and_write_child_pid_to),
+       (main):
+       * src/x.c: (xfopen), (xdup2):
+       * src/x.h:
+
 2005-12-08  Bryan Worth  <bryan@theworths.org>
         * src/ttt-curses-client.c: Multiple improvements!
         Username taken from USER environment variable and stored as
index 54cc0dbbd823ac5c9ddebe464e99ceec63500985..f367716c6b70e8e28326d1223c3d1e914424a54e 100644 (file)
@@ -48,16 +48,19 @@ static char TTT_ARGS_PROGRAM_ARGDOC[] = "";
 
 enum {
     TTT_ARGS_VAL_LOG_FILE = 256,
+    TTT_ARGS_VAL_PID_FILE,
     TTT_ARGS_VAL_HELP,
-    TTT_ARGS_VAL_VERSION
+    TTT_ARGS_VAL_VERSION,
 };
 
-static char ttt_args_optstring[] = "h:p:";
+static char ttt_args_optstring[] = "dh:p:";
 static struct option ttt_args_options[] = {
     /* name,           has_arg,        flag,   val */
     {"host",           1,              0,      'h'},
     {"port",           1,              0,      'p'},
+    {"detach",         0,              0,      'd'},
     {"log-file",       1,              0,      TTT_ARGS_VAL_LOG_FILE},
+    {"pid-file",       1,              0,      TTT_ARGS_VAL_PID_FILE},
     {"help",           0,              0,      TTT_ARGS_VAL_HELP},
     {"version",                0,              0,      TTT_ARGS_VAL_VERSION},
     { 0 }
@@ -71,14 +74,20 @@ ttt_args_help (const char *argv0)
     puts ("");
     printf ("Options that are common to both client and server:\n");
     puts ("");
-    printf ("  -h HOST, --host=HOST\tHost to connect/bind to\n");
-    printf ("  -p PORT, --port=PORT\tPort to connect/bind to\n");
+    printf ("  -h HOST, --host=HOST\tHost to connect/bind to [%s]\n",
+           TTT_ARGS_HOST_DEFAULT);
+    printf ("  -p PORT, --port=PORT\tPort to connect/bind to [%s]\n",
+           TTT_ARGS_PORT_DEFAULT);
     printf ("           --help\tGive this help list\n");
     printf ("           --version\tPrint program version\n");
     puts ("");
     printf ("Options that are specific to the server:\n");
     puts ("");
-    printf ("           --log-file=FILE\tFile to use for logging\n");
+    printf ("           --log-file=FILE\tFile to use for logging [stderr]\n");
+    printf ("       -d, --detach\tDetach and daemonize\n");
+    printf ("           --pid-file=FILE\tFile in which to save PID (if -d given)\n"
+           "                          \t[%s]\n",
+           TTT_ARGS_PID_FILE_DEFAULT);
 }
 
 #if 0
@@ -101,6 +110,8 @@ ttt_args_parse(ttt_args_t *args, int argc, char *argv[])
     args->host = TTT_ARGS_HOST_DEFAULT;
     args->port = TTT_ARGS_PORT_DEFAULT;
     args->log_file = TTT_ARGS_LOG_FILE_DEFAULT;
+    args->detach = FALSE;
+    args->pid_file = TTT_ARGS_PID_FILE_DEFAULT;
 
     while (1) {
        c = getopt_long (argc, argv, ttt_args_optstring, ttt_args_options, NULL);
@@ -117,6 +128,12 @@ ttt_args_parse(ttt_args_t *args, int argc, char *argv[])
        case TTT_ARGS_VAL_LOG_FILE:
            args->log_file = optarg;
            break;
+       case 'd':
+           args->detach = TRUE;
+           break;
+       case TTT_ARGS_VAL_PID_FILE:
+           args->pid_file = optarg;
+           break;
        case TTT_ARGS_VAL_VERSION:
            printf ("%s\n", VERSION);
            exit (0);
index 7c18acde62878beb244004a16eedbcf9b390d1aa..5a1b3cfe67f822657e51b054b71749989a58cd8e 100644 (file)
 #ifndef TTT_ARGS_H
 #define TTT_ARGS_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "ttt.h"
 
 #define TTT_ARGS_HOST_DEFAULT "localhost"
 #define TTT_ARGS_PORT_DEFAULT "5334"
 /* NULL means to just log to stderr. */
 #define TTT_ARGS_LOG_FILE_DEFAULT NULL
+#define TTT_ARGS_PID_FILE_DEFAULT "/var/run/ttt-server.pid"
 
 typedef struct ttt_args
 {
     char *host;
     char *port;
     char *log_file;
+    ttt_bool_t detach;
+    char *pid_file;
 } ttt_args_t;
 
 int
index c94d3d23a44c5fc3d624b6d87bd30ddd7c9fa0b4..34159b547ddb0b0946ef97d5a655646259223c07 100644 (file)
@@ -162,7 +162,7 @@ ttt_error_t
 ttt_server_statistics (ttt_server_t *server, const char *username, char **response)
 {
     ttt_bool_t usernamefound = FALSE;
-    char *client_username;
+    const char *client_username;
     int client_num_wins;
     int i;
 
@@ -193,7 +193,7 @@ ttt_error_t
 ttt_server_verify_username (ttt_server_t *server, const char *username)
 {
     ttt_bool_t usernamefound = FALSE;
-    char *client_username;
+    const char *client_username;
     int i;
 
     pthread_mutex_lock (&server->mutex);
@@ -248,6 +248,35 @@ _ttt_server_accept (void *closure, int client_socket)
     ttt_client_new (server, client_socket);
 }
 
+static void
+_detach_and_write_child_pid_to (const char *filename)
+{
+    pid_t pid;
+
+    /* Use the Unix double-fork trick to detach completely. See
+     * setsid(2) for some details as to why two forks are
+     * needed. */
+    pid = xfork ();
+    if (pid) {
+       /* First parent just exits */
+       exit (0);
+    }
+    
+    chdir ("/");
+    setsid ();
+    
+    pid = xfork ();
+    if (pid) {
+       /* Second parent exits after writing pid */
+       FILE *file = xfopen (filename, "w");
+       fprintf (file, "%d\n", pid);
+       fclose (file);
+       exit (0);
+    }
+    
+    /* Final, detached child returns. */
+}
+
 int 
 main (int argc, char **argv)
 {
@@ -257,12 +286,34 @@ main (int argc, char **argv)
 
     ttt_args_parse (&args, argc, argv);
 
-    if (args.log_file)
-       xfreopen (args.log_file, "a", stderr);
+    if (args.log_file || args.detach) {
+       FILE *log_file;
+       /* In the detach case, we force redirection to a log file. */
+       if (args.log_file == NULL)
+           args.log_file = "/var/log/ttt-server.log";
+       log_file = fopen (args.log_file, "a");
+       if (log_file == NULL) {
+           printf ("Warning: Failed to open log file %s: %s.\n",
+                   args.log_file, strerror (errno));
+           printf ("Logging will be disabled.\n");
+           xdup2 (1, 2);
+       } else {
+           xdup2 (fileno (log_file), 2);
+       }
+    }
+
+    if (args.detach)
+       _detach_and_write_child_pid_to (args.pid_file);
 
     socket = ttt_socket_create_server (args.host, args.port);
 
-    printf (WELCOME_MESSAGE, args.host, args.port, args.host, args.port);
+    if (args.detach)
+       printf ("Server started listening on %s:%s\n", args.host, args.port);
+    else
+       printf (WELCOME_MESSAGE, args.host, args.port, args.host, args.port);
+
+    fclose (stdout);
+    fclose (stdin);
 
     ttt_server_init (&server, args.host, args.port);
 
diff --git a/src/x.c b/src/x.c
index a95fedfbc5e8a142606698cf4ab629368e1e2e8d..c35f4c88955f3147271d86c1c3113140aeafb496 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -117,6 +117,22 @@ xrealloc (void *ptr, size_t size)
     return ret;
 }
 
+FILE *
+xfopen (const char *path, const char *mode)
+{
+    FILE *ret;
+
+    ret = fopen (path, mode);
+
+    if (ret == NULL) {
+       fprintf (stderr, "Error: fopen of %s failed: %s. Aborting.\n",
+                path, strerror (errno));
+       exit (1);
+    }
+
+    return ret;
+}
+
 FILE *
 xfdopen (int filedes, const char *mode)
 {
@@ -134,14 +150,14 @@ xfdopen (int filedes, const char *mode)
 }
 
 void
-xfreopen (const char *path, const char *mode, FILE *stream)
+xdup2 (int oldfd, int newfd)
 {
-    FILE *ret;
+    int ret;
 
-    ret = freopen (path, mode, stream);
-    if (ret == NULL) {
-       fprintf (stderr, "Error: freopen of %s failed: %s. Aborting.\n",
-                path, strerror (errno));
+    ret = dup2 (oldfd, newfd);
+    if (ret == -1) {
+       printf ("Error: dup2 failed: %s. Aborting.\n",
+               strerror (errno));
        exit (1);
     }
 }
diff --git a/src/x.h b/src/x.h
index 3b7f208d324e10b2582040779c36d78f443b72d4..64a18a22c2492d5727379258efb059d4e1d3b2e2 100644 (file)
--- a/src/x.h
+++ b/src/x.h
@@ -45,11 +45,14 @@ xcalloc (size_t nmemb, size_t size);
 void *
 xrealloc (void *ptr, size_t size);
 
+FILE *
+xfopen (const char *path, const char *mode);
+
 FILE *
 xfdopen (int filedes, const char *mode);
 
 void
-xfreopen (const char *path, const char *mode, FILE *stream);
+xdup2 (int oldfd, int newfd);
 
 char *
 xstrdup (const char *s);