/* * A rewrite of the original Debian's start-stop-daemon Perl script * in C (faster - it is executed many times during system startup). * * Written by Marek Michalkiewicz , * public domain. Based conceptually on start-stop-daemon.pl, by Ian * Jackson . May be used and distributed * freely for any purpose. Changes by Christian Schwarz * , to make output conform to the Debian * Console Message Standard, also placed in public domain. Minor * changes by Klee Dienes , also placed in the Public * Domain. * * Changes by Ben Collins , added --chuid, --background * and --make-pidfile options, placed in public domain as well. * * Port to OpenBSD by Sontri Tomo Huynh * and Andreas Schuldei * * Changes by Ian Jackson: added --retry (and associated rearrangements). */ /* * MODIFIED TO NOT DEPEND ON EXTERNAL HEADERS! * By Christian Illy * Used dpkg source package from https://packages.debian.org/stable/dpkg * Version 1.16.14 */ // from config.h, generated by configure: #define VERSION "1.16.14_01" //***************************************** // Stuff from dpkg/macros.h #define DPKG_ATTR_NORET #define DPKG_ATTR_PRINTF(n) /** * @def array_count * * Returns the amount of items in an array. */ #ifndef array_count #define array_count(a) (sizeof(a) / sizeof((a)[0])) #endif // End of stuff from dpkg/macros.h //***************************************** //***************************************** // Required on some systems to get O_NOFOLLOW: #define _POSIX_C_SOURCE 200809L #define _GNU_SOURCE //***************************************** #define OSLinux #define MIN_POLL_INTERVAL 20000 /* µs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _POSIX_PRIORITY_SCHEDULING #include #else #define SCHED_OTHER -1 #define SCHED_FIFO -1 #define SCHED_RR -1 #endif /* This comes from TASK_COMM_LEN defined in Linux' include/linux/sched.h. */ #define PROCESS_NAME_SIZE 15 #if defined(SYS_ioprio_set) #define HAVE_IOPRIO_SET #endif enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, }; enum { IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE, }; enum action_code { action_none, action_start, action_stop, action_status, }; static enum action_code action; static int testmode = 0; static int quietmode = 0; static int exitnodo = 1; static int background = 0; static int close_io = 1; static int mpidfile = 0; static int signal_nr = SIGTERM; static int user_id = -1; static int runas_uid = -1; static int runas_gid = -1; static const char *userspec = NULL; static char *changeuser = NULL; static const char *changegroup = NULL; static char *changeroot = NULL; static const char *changedir = "/"; static const char *cmdname = NULL; static char *execname = NULL; static char *startas = NULL; static const char *pidfile = NULL; static char what_stop[1024]; static const char *progname = ""; static int nicelevel = 0; static int umask_value = -1; #define IOPRIO_CLASS_SHIFT 13 #define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio)) #define IO_SCHED_PRIO_MIN 0 #define IO_SCHED_PRIO_MAX 7 static struct stat exec_stat; /* LSB Init Script process status exit codes. */ enum status_code { status_ok = 0, status_dead_pidfile = 1, status_dead_lockfile = 2, status_dead = 3, status_unknown = 4, }; struct pid_list { struct pid_list *next; pid_t pid; }; static struct pid_list *found = NULL; static struct pid_list *killed = NULL; /* Resource scheduling policy. */ struct res_schedule { const char *policy_name; int policy; int priority; }; struct schedule_item { enum { sched_timeout, sched_signal, sched_goto, /* Only seen within parse_schedule and callees. */ sched_forever, } type; /* Seconds, signal no., or index into array. */ int value; }; static struct res_schedule *proc_sched = NULL; static struct res_schedule *io_sched = NULL; static int schedule_length; static struct schedule_item *schedule = NULL; static void DPKG_ATTR_PRINTF(1) warning(const char *format, ...) { va_list arglist; fprintf(stderr, "%s: warning: ", progname); va_start(arglist, format); vfprintf(stderr, format, arglist); va_end(arglist); } static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(1) fatal(const char *format, ...) { va_list arglist; int errno_fatal = errno; fprintf(stderr, "%s: ", progname); va_start(arglist, format); vfprintf(stderr, format, arglist); va_end(arglist); if (errno_fatal) fprintf(stderr, " (%s)\n", strerror(errno_fatal)); else fprintf(stderr, "\n"); if (action == action_status) exit(status_unknown); else exit(2); } static void * xmalloc(int size) { void *ptr; ptr = malloc(size); if (ptr) return ptr; fatal("malloc(%d) failed", size); } static char * xstrdup(const char *str) { char *new_str; new_str = strdup(str); if (new_str) return new_str; fatal("strdup(%s) failed", str); } static void xgettimeofday(struct timeval *tv) { if (gettimeofday(tv, NULL) != 0) fatal("gettimeofday failed"); } static void tmul(struct timeval *a, int b) { a->tv_sec *= b; a->tv_usec *= b; a->tv_sec = a->tv_sec + a->tv_usec / 1000000; a->tv_usec %= 1000000; } static char * newpath(const char *dirname, const char *filename) { char *path; size_t path_len; path_len = strlen(dirname) + 1 + strlen(filename) + 1; path = xmalloc(path_len); snprintf(path, path_len, "%s/%s", dirname, filename); return path; } static long get_open_fd_max(void) { return getdtablesize(); } static void daemonize(void) { pid_t pid; if (quietmode < 0) printf("Detaching to start %s...", startas); pid = fork(); if (pid < 0) fatal("unable to do first fork"); else if (pid) /* Parent. */ _exit(0); /* Create a new session. */ setsid(); pid = fork(); if (pid < 0) fatal("unable to do second fork"); else if (pid) /* Parent. */ _exit(0); if (quietmode < 0) printf("done.\n"); } static void write_pidfile(const char *filename, pid_t pid) { FILE *fp; int fd; fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666); if (fd < 0) fp = NULL; else fp = fdopen(fd, "w"); if (fp == NULL) fatal("unable to open pidfile '%s' for writing", filename); fprintf(fp, "%d\n", pid); if (fclose(fp)) fatal("unable to close pidfile '%s'", filename); } static void pid_list_push(struct pid_list **list, pid_t pid) { struct pid_list *p; p = xmalloc(sizeof(*p)); p->next = *list; p->pid = pid; *list = p; } static void pid_list_free(struct pid_list **list) { struct pid_list *here, *next; for (here = *list; here != NULL; here = next) { next = here->next; free(here); } *list = NULL; } static void usage(void) { printf( "Usage: start-stop-daemon [