+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
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 }
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
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);
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);
#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
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;
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);
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)
{
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);
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)
{
}
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);
}
}
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);