"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
" [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
" [--base-path=path] [--user-path | --user-path=path]\n"
-" [--reuseaddr] [directory...]";
+" [--reuseaddr] [--detach] [--pid-file=file] [directory...]";
/* List of acceptable pathname prefixes */
-static char **ok_paths = NULL;
-static int strict_paths = 0;
+static char **ok_paths;
+static int strict_paths;
/* If this is set, git-daemon-export-ok is not required */
-static int export_all_trees = 0;
+static int export_all_trees;
/* Take all paths relative to this one if non-NULL */
-static char *base_path = NULL;
+static char *base_path;
/* If defined, ~user notation is allowed and the string is inserted
* after ~user/. E.g. a request to git://host/~alice/frotz would
* go to /home/alice/pub_git/frotz with --user-path=pub_git.
*/
-static char *user_path = NULL;
+static const char *user_path;
/* Timeout, and initial timeout */
-static unsigned int timeout = 0;
-static unsigned int init_timeout = 0;
+static unsigned int timeout;
+static unsigned int init_timeout;
static void logreport(int priority, const char *err, va_list params)
{
va_end(params);
}
+static void NORETURN daemon_die(const char *err, va_list params)
+{
+ logreport(LOG_ERR, err, params);
+ exit(1);
+}
+
static int avoid_alias(char *p)
{
int sl, ndot;
static int max_connections = 25;
/* These are updated by the signal handler */
-static volatile unsigned int children_reaped = 0;
+static volatile unsigned int children_reaped;
static pid_t dead_child[MAX_CHILDREN];
/* These are updated by the main loop */
-static unsigned int children_spawned = 0;
-static unsigned int children_deleted = 0;
+static unsigned int children_spawned;
+static unsigned int children_deleted;
static struct child {
pid_t pid;
children_reaped = reaped + 1;
/* XXX: Custom logging, since we don't wanna getpid() */
if (verbose) {
- char *dead = "";
+ const char *dead = "";
if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
dead = " (with error)";
if (log_syslog)
}
}
+/* if any standard file descriptor is missing open it to /dev/null */
+static void sanitize_stdfds(void)
+{
+ int fd = open("/dev/null", O_RDWR, 0);
+ while (fd != -1 && fd < 2)
+ fd = dup(fd);
+ if (fd == -1)
+ die("open /dev/null or dup failed: %s", strerror(errno));
+ if (fd > 2)
+ close(fd);
+}
+
+static void daemonize(void)
+{
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ die("fork failed: %s", strerror(errno));
+ default:
+ exit(0);
+ }
+ if (setsid() == -1)
+ die("setsid failed: %s", strerror(errno));
+ close(0);
+ close(1);
+ close(2);
+ sanitize_stdfds();
+}
+
+static void store_pid(const char *path)
+{
+ FILE *f = fopen(path, "w");
+ if (!f)
+ die("cannot open pid file %s: %s", path, strerror(errno));
+ fprintf(f, "%d\n", getpid());
+ fclose(f);
+}
+
static int serve(int port)
{
int socknum, *socklist;
{
int port = DEFAULT_GIT_PORT;
int inetd_mode = 0;
+ const char *pid_file = NULL;
+ int detach = 0;
int i;
/* Without this we cannot rely on waitpid() to tell
user_path = arg + 12;
continue;
}
+ if (!strncmp(arg, "--pid-file=", 11)) {
+ pid_file = arg + 11;
+ continue;
+ }
+ if (!strcmp(arg, "--detach")) {
+ detach = 1;
+ log_syslog = 1;
+ continue;
+ }
if (!strcmp(arg, "--")) {
ok_paths = &argv[i+1];
break;
usage(daemon_usage);
}
- if (log_syslog)
+ if (log_syslog) {
openlog("git-daemon", 0, LOG_DAEMON);
-
- if (strict_paths && (!ok_paths || !*ok_paths)) {
- if (!inetd_mode)
- die("git-daemon: option --strict-paths requires a whitelist");
-
- logerror("option --strict-paths requires a whitelist");
- exit (1);
+ set_die_routine(daemon_die);
}
+ if (strict_paths && (!ok_paths || !*ok_paths))
+ die("option --strict-paths requires a whitelist");
+
if (inetd_mode) {
struct sockaddr_storage ss;
struct sockaddr *peer = (struct sockaddr *)&ss;
return execute(peer);
}
+ if (detach)
+ daemonize();
+ else
+ sanitize_stdfds();
+
+ if (pid_file)
+ store_pid(pid_file);
+
return serve(port);
}