From 487cc3be34e100294ceab5dd90d7a13d169a29a5 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 13 Nov 2015 13:42:30 +0000 Subject: [PATCH] start-stop-daemon: added new port --- start-stop-daemon/.footprint | 7 + start-stop-daemon/.md5sum | 4 + start-stop-daemon/Pkgfile | 19 + start-stop-daemon/crux-patch.diff | 86 + start-stop-daemon/makefile | 12 + start-stop-daemon/start-stop-daemon.8 | 381 +++++ start-stop-daemon/start-stop-daemon.c | 2236 +++++++++++++++++++++++++ 7 files changed, 2745 insertions(+) create mode 100644 start-stop-daemon/.footprint create mode 100644 start-stop-daemon/.md5sum create mode 100644 start-stop-daemon/Pkgfile create mode 100644 start-stop-daemon/crux-patch.diff create mode 100644 start-stop-daemon/makefile create mode 100644 start-stop-daemon/start-stop-daemon.8 create mode 100644 start-stop-daemon/start-stop-daemon.c diff --git a/start-stop-daemon/.footprint b/start-stop-daemon/.footprint new file mode 100644 index 0000000..ad56180 --- /dev/null +++ b/start-stop-daemon/.footprint @@ -0,0 +1,7 @@ +drwxr-xr-x root/root sbin/ +-rwxr-xr-x root/root sbin/start-stop-daemon +drwxr-xr-x root/root usr/ +drwxr-xr-x root/root usr/share/ +drwxr-xr-x root/root usr/share/man/ +drwxr-xr-x root/root usr/share/man/man8/ +-rw-r--r-- root/root usr/share/man/man8/start-stop-daemon.8.gz diff --git a/start-stop-daemon/.md5sum b/start-stop-daemon/.md5sum new file mode 100644 index 0000000..76fcb21 --- /dev/null +++ b/start-stop-daemon/.md5sum @@ -0,0 +1,4 @@ +d69ea09c844389f3e4d0cda696d0d968 crux-patch.diff +707efd334e4ba1d5f65f366a3c03c794 makefile +c021c418059b2afcb2f501927239beca start-stop-daemon.8 +61ba9ca1003221e1af632714c1cfbd11 start-stop-daemon.c diff --git a/start-stop-daemon/Pkgfile b/start-stop-daemon/Pkgfile new file mode 100644 index 0000000..311d22d --- /dev/null +++ b/start-stop-daemon/Pkgfile @@ -0,0 +1,19 @@ +# Description: Control the creation and termination of system-level processes +# URL: http://man7.org/linux/man-pages/man8/start-stop-daemon.8.html +# Maintainer: CRUX System Team, core-ports at crux dot nu +# Arch Maintainer: CRUX-ARM System Team, devel at crux-arm dot nu + +name=start-stop-daemon +version=20150921 +release=1 +source=(start-stop-daemon.c start-stop-daemon.8 crux-patch.diff makefile) + +build () { + patch -p2 -i crux-patch.diff + + make CC="$CC" + + install -d $PKG/{sbin,usr/share/man/man8} + install -m 755 $name $PKG/sbin/ + install -m 644 $name.8 $PKG/usr/share/man/man8/ +} diff --git a/start-stop-daemon/crux-patch.diff b/start-stop-daemon/crux-patch.diff new file mode 100644 index 0000000..7c0498b --- /dev/null +++ b/start-stop-daemon/crux-patch.diff @@ -0,0 +1,86 @@ +diff --git a/start-stop-daemon/start-stop-daemon.8 b/start-stop-daemon/start-stop-daemon.8 +index deae6c6..28d2de8 100644 +--- a/start-stop-daemon/start-stop-daemon.8 ++++ b/start-stop-daemon/start-stop-daemon.8 +@@ -20,7 +20,7 @@ + .\" You should have received a copy of the GNU General Public License + .\" along with this program. If not, see . + . +-.TH start\-stop\-daemon 8 "2014-03-26" "Debian Project" "dpkg utilities" ++.TH start\-stop\-daemon 8 "2015-09-21" "CRUX 3.2" "core services" + .SH NAME + start\-stop\-daemon \- start and stop system daemon programs + . +diff --git a/start-stop-daemon/start-stop-daemon.c b/start-stop-daemon/start-stop-daemon.c +index c844f2e..67cd043 100644 +--- a/start-stop-daemon/start-stop-daemon.c ++++ b/start-stop-daemon/start-stop-daemon.c +@@ -20,10 +20,34 @@ + * Changes by Ian Jackson: added --retry (and associated rearrangements). + */ + ++#if 0 + #include + #include + + #include ++#else ++# define VERSION "20150921" ++# define CRUX "CRUX 3.2" ++ ++# define HAVE_SYS_PARAM_H ++# define HAVE_SYS_SYSCALL_H ++# define HAVE_SYS_SYSCTL_H ++# define HAVE_SYS_USER_H ++# define HAVE_STDDEF_H ++# define HAVE_ERROR_H ++# define HAVE_ERR_H ++ ++# define HAVE_CLOCK_MONOTONIC ++# define HAVE_GETDTABLESIZE ++# define HAVE_IOPRIO_SET ++# define HAVE_SETSID ++ ++# define DPKG_ATTR_NORET __attribute__((noreturn)) ++# define DPKG_ATTR_PRINTF(X) ++ ++# define _GNU_SOURCE ++# include ++#endif + + #if defined(linux) + # define OSLinux +@@ -142,6 +166,10 @@ + #define HAVE_IOPRIO_SET + #endif + ++#ifndef array_count ++# define array_count(x) (sizeof(x) / sizeof((x)[0])) ++#endif ++ + #define IOPRIO_CLASS_SHIFT 13 + #define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio)) + #define IO_SCHED_PRIO_MIN 0 +@@ -310,8 +338,7 @@ xstrndup(const char *str, size_t n) + static void + timespec_gettime(struct timespec *ts) + { +-#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && \ +- defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0 ++#ifdef HAVE_CLOCK_MONOTONIC + if (clock_gettime(CLOCK_MONOTONIC, ts) < 0) + fatal("clock_gettime failed"); + #else +@@ -615,9 +642,9 @@ usage(void) + static void + do_version(void) + { +- printf("start-stop-daemon %s for Debian\n\n", VERSION); +- +- printf("Written by Marek Michalkiewicz, public domain.\n"); ++ printf("start-stop-daemon " VERSION " for " CRUX "\n\n" ++ "Written by Marek Michalkiewicz, public domain.\n" ++ "Adjusted for " CRUX ".\n"); + } + + static void DPKG_ATTR_NORET diff --git a/start-stop-daemon/makefile b/start-stop-daemon/makefile new file mode 100644 index 0000000..976a01a --- /dev/null +++ b/start-stop-daemon/makefile @@ -0,0 +1,12 @@ +CC = cc +CFLAGS += -g -Wall +PROGRAM = start-stop-daemon +SOURCES = start-stop-daemon.c + +$(PROGRAM): $(SOURCES) + $(CC) $(CFLAGS) -o $(@) $(SOURCES) + + +all: $(PROGRAM) +clean: ; rm -f $(PROGRAM) +force: clean all diff --git a/start-stop-daemon/start-stop-daemon.8 b/start-stop-daemon/start-stop-daemon.8 new file mode 100644 index 0000000..deae6c6 --- /dev/null +++ b/start-stop-daemon/start-stop-daemon.8 @@ -0,0 +1,381 @@ +.\" dpkg manual page - start-stop-daemon(8) +.\" +.\" Copyright © 1999 Klee Dienes +.\" Copyright © 1999 Ben Collins +.\" Copyright © 2000-2001 Wichert Akkerman +.\" Copyright © 2002-2003 Adam Heath +.\" Copyright © 2004 Scott James Remnant +.\" Copyright © 2008-2015 Guillem Jover +.\" +.\" This is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program. If not, see . +. +.TH start\-stop\-daemon 8 "2014-03-26" "Debian Project" "dpkg utilities" +.SH NAME +start\-stop\-daemon \- start and stop system daemon programs +. +.SH SYNOPSIS +.B start\-stop\-daemon +.RI [ option "...] " command +. +.SH DESCRIPTION +.B start\-stop\-daemon +is used to control the creation and termination of system-level processes. +Using one of the matching options, \fBstart\-stop\-daemon\fP +can be configured to find existing instances of a running process. +.PP +Note: unless +.B \-\-pid +or +.B \-\-pidfile +are specified, +.B start\-stop\-daemon +behaves similar to +.BR killall (1). +.B start\-stop\-daemon +will scan the process table looking for any processes which +match the process name, parent pid, uid, and/or gid (if specified). Any +matching process will prevent +.BR \-\-start +from starting the daemon. All matching processes will be sent the TERM +signal (or the one specified via \fB\-\-signal\fP or \fB\-\-retry\fP) if +.BR \-\-stop +is specified. For daemons which have long-lived children +which need to live through a +.BR \-\-stop , +you must specify a pidfile. +. +.SH COMMANDS +.TP +.BR \-S ", " \-\-start " [" \-\- "] \fIarguments\fP" +Check for the existence of a specified process. +If such a process exists, +.B start\-stop\-daemon +does nothing, and exits with error status 1 (0 if +.BR \-\-oknodo +is specified). +If such a process does not exist, it starts an +instance, using either the executable specified by +.B \-\-exec +or, if specified, by +.BR \-\-startas . +Any arguments given after +.BR \-\- +on the command line are passed unmodified to the program being +started. +.TP +.BR \-K ", " \-\-stop +Checks for the existence of a specified process. +If such a process exists, +.B start\-stop\-daemon +sends it the signal specified by +.BR \-\-signal , +and exits with error status 0. +If such a process does not exist, +.B start\-stop\-daemon +exits with error status 1 +(0 if +.BR \-\-oknodo +is specified). If +.B \-\-retry +is specified, then +.B start\-stop\-daemon +will check that the process(es) have terminated. +.TP +.BR \-T ", " \-\-status +Check for the existence of a specified process, and returns an exit status +code, according to the LSB Init Script Actions (since version 1.16.1). +.TP +.BR \-H ", " \-\-help +Show usage information and exit. +.TP +.BR \-V ", " \-\-version +Show the program version and exit. +. +.SH OPTIONS +.SS Matching options +.TP +.BR \-\-pid " \fIpid\fP" +Check for a process with the specified \fIpid\fP (since version 1.17.6). +The \fIpid\fP must be a number greater than 0. +.TP +.BR \-\-ppid " \fIppid\fP" +Check for a process with the specified parent pid \fIppid\fP +(since version 1.17.7). +The \fIppid\fP must be a number greater than 0. +.TP +.BR \-p ", " \-\-pidfile " \fIpid-file\fP" +Check whether a process has created the file \fIpid-file\fP. Note: using this +matching option alone might cause unintended processes to be acted on, if the +old process terminated without being able to remove the \fIpid-file\fP. +.TP +.BR \-x ", " \-\-exec " \fIexecutable\fP" +Check for processes that are instances of this \fIexecutable\fP. The +\fIexecutable\fP argument should be an absolute pathname. Note: this might +not work as intended with interpreted scripts, as the executable will point +to the interpreter. Take into account processes running from inside a chroot +will also be matched, so other match restrictions might be needed. +.TP +.BR \-n ", " \-\-name " \fIprocess-name\fP" +Check for processes with the name \fIprocess-name\fP. The \fIprocess-name\fP +is usually the process filename, but it could have been changed by the +process itself. Note: on most systems this information is retrieved from +the process comm name from the kernel, which tends to have a relatively +short length limit (assuming more than 15 characters is non-portable). +.TP +.BR \-u ", " \-\-user " \fIusername\fP|\fIuid\fP +Check for processes owned by the user specified by \fIusername\fP or +\fIuid\fP. Note: using this matching option alone will cause all processes +matching the user to be acted on. +. +.SS Generic options +.TP +.BR \-g ", " \-\-group " \fIgroup\fP|\fIgid\fP" +Change to \fIgroup\fP or \fIgid\fP when starting the process. +.TP +.BR \-s ", " \-\-signal " \fIsignal\fP" +With +.BR \-\-stop , +specifies the signal to send to processes being stopped (default TERM). +.TP +.BR \-R ", " \-\-retry " \fItimeout\fP|\fIschedule\fP" +With +.BR \-\-stop , +specifies that +.B start\-stop\-daemon +is to check whether the process(es) +do finish. It will check repeatedly whether any matching processes +are running, until none are. If the processes do not exit it will +then take further action as determined by the schedule. + +If +.I timeout +is specified instead of +.IR schedule , +then the schedule +.IB signal / timeout /KILL/ timeout +is used, where +.I signal +is the signal specified with +.BR \-\-signal . + +.I schedule +is a list of at least two items separated by slashes +.RB ( / ); +each item may be +.BI \- signal-number +or [\fB\-\fP]\fIsignal-name\fP, +which means to send that signal, +or +.IR timeout , +which means to wait that many seconds for processes to +exit, +or +.BR forever , +which means to repeat the rest of the schedule forever if +necessary. + +If the end of the schedule is reached and +.BR forever +is not specified, then +.B start\-stop\-daemon +exits with error status 2. +If a schedule is specified, then any signal specified +with +.B \-\-signal +is ignored. +.TP +.BR \-a ", " \-\-startas " \fIpathname\fP" +With +.BR \-\-start , +start the process specified by +.IR pathname . +If not specified, defaults to the argument given to +.BR \-\-exec . +.TP +.BR \-t ", " \-\-test +Print actions that would be taken and set appropriate return value, +but take no action. +.TP +.BR \-o ", " \-\-oknodo +Return exit status 0 instead of 1 if no actions are (would be) taken. +.TP +.BR \-q ", " \-\-quiet +Do not print informational messages; only display error messages. +.TP +.BR \-c ", " \-\-chuid " \fIusername\fR|\fIuid\fP[\fB:\fP\fIgroup\fR|\fIgid\fP]" +Change to this username/uid before starting the process. You can also +specify a group by appending a +.BR : , +then the group or gid in the same way +as you would for the \fBchown\fP(1) command (\fIuser\fP\fB:\fP\fIgroup\fP). +If a user is specified without a group, the primary GID for that user is used. +When using this option +you must realize that the primary and supplemental groups are set as well, +even if the +.B \-\-group +option is not specified. The +.B \-\-group +option is only for +groups that the user isn't normally a member of (like adding per process +group membership for generic users like +.BR nobody ). +.TP +.BR \-r ", " \-\-chroot " \fIroot\fP" +Chdir and chroot to +.I root +before starting the process. Please note that the pidfile is also written +after the chroot. +.TP +.BR \-d ", " \-\-chdir " \fIpath\fP" +Chdir to +.I path +before starting the process. This is done after the chroot if the +\fB\-r\fP|\fB\-\-chroot\fP option is set. When not specified, +.B start\-stop\-daemon +will chdir to the root directory before starting the process. +.TP +.BR \-b ", " \-\-background +Typically used with programs that don't detach on their own. This option +will force +.B start\-stop\-daemon +to fork before starting the process, and force it into the background. +.B Warning: start\-stop\-daemon +cannot check the exit status if the process fails to execute for +.B any +reason. This is a last resort, and is only meant for programs that either +make no sense forking on their own, or where it's not feasible to add the +code for them to do this themselves. +.TP +.BR \-C ", " \-\-no\-close +Do not close any file descriptor when forcing the daemon into the background +(since version 1.16.5). +Used for debugging purposes to see the process output, or to redirect file +descriptors to log the process output. +Only relevant when using \fB\-\-background\fP. +.TP +.BR \-N ", " \-\-nicelevel " \fIint\fP" +This alters the priority of the process before starting it. +.TP +.BR \-P ", " \-\-procsched " \fIpolicy\fP\fB:\fP\fIpriority\fP" +This alters the process scheduler policy and priority of the process before +starting it (since version 1.15.0). +The priority can be optionally specified by appending a \fB:\fP +followed by the value. The default \fIpriority\fP is 0. The currently +supported policy values are \fBother\fP, \fBfifo\fP and \fBrr\fP. +.TP +.BR \-I ", " \-\-iosched " \fIclass\fP\fB:\fP\fIpriority\fP" +This alters the IO scheduler class and priority of the process before starting +it (since version 1.15.0). +The priority can be optionally specified by appending a \fB:\fP followed +by the value. The default \fIpriority\fP is 4, unless \fIclass\fP is \fBidle\fP, +then \fIpriority\fP will always be 7. The currently supported values for +\fIclass\fP are \fBidle\fP, \fBbest-effort\fP and \fBreal-time\fP. +.TP +.BR \-k ", " \-\-umask " \fImask\fP" +This sets the umask of the process before starting it (since version 1.13.22). +.TP +.BR \-m ", " \-\-make\-pidfile +Used when starting a program that does not create its own pid file. This +option will make +.B start\-stop\-daemon +create the file referenced with +.B \-\-pidfile +and place the pid into it just before executing the process. Note, the +file will only be removed when stopping the program if +\fB\-\-remove\-pidfile\fP is used. +.B Note: +This feature may not work in all cases. Most notably when the program +being executed forks from its main process. Because of this, it is usually +only useful when combined with the +.B \-\-background +option. +.TP +.B \-\-remove\-pidfile +Used when stopping a program that does not remove its own pid file +(since version 1.17.19). +This option will make +.B start\-stop\-daemon +remove the file referenced with +.B \-\-pidfile +after terminating the process. +.TP +.BR \-v ", " \-\-verbose +Print verbose informational messages. +. +.SH EXIT STATUS +.TP +.B 0 +The requested action was performed. If +.B \-\-oknodo +was specified, it's also possible that nothing had to be done. +This can happen when +.B \-\-start +was specified and a matching process was already running, or when +.B \-\-stop +was specified and there were no matching processes. +.TP +.B 1 +If +.B \-\-oknodo +was not specified and nothing was done. +.TP +.B 2 +If +.B \-\-stop +and +.B \-\-retry +were specified, but the end of the schedule was reached and the processes were +still running. +.TP +.B 3 +Any other error. +.PP +When using the \fB\-\-status\fP command, the following status codes are +returned: +.TP +.B 0 +Program is running. +.TP +.B 1 +Program is not running and the pid file exists. +.TP +.B 3 +Program is not running. +.TP +.B 4 +Unable to determine program status. +. +.SH EXAMPLE +Start the \fBfood\fP daemon, unless one is already running (a process named +food, running as user food, with pid in food.pid): +.IP +.nf +start\-stop\-daemon \-\-start \-\-oknodo \-\-user food \-\-name food \\ + \-\-pidfile /run/food.pid \-\-startas /usr/sbin/food \\ + \-\-chuid food \-\- \-\-daemon +.fi +.PP +Send \fBSIGTERM\fP to \fBfood\fP and wait up to 5 seconds for it to stop: +.IP +.nf +start\-stop\-daemon \-\-stop \-\-oknodo \-\-user food \-\-name food \\ + \-\-pidfile /run/food.pid \-\-retry 5 +.fi +.PP +Demonstration of a custom schedule for stopping \fBfood\fP: +.IP +.nf +start\-stop\-daemon \-\-stop \-\-oknodo \-\-user food \-\-name food \\ + \-\-pidfile /run/food.pid \-\-retry=TERM/30/KILL/5 +.fi diff --git a/start-stop-daemon/start-stop-daemon.c b/start-stop-daemon/start-stop-daemon.c new file mode 100644 index 0000000..c844f2e --- /dev/null +++ b/start-stop-daemon/start-stop-daemon.c @@ -0,0 +1,2236 @@ +/* + * 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). + */ + +#include +#include + +#include + +#if defined(linux) +# define OSLinux +#elif defined(__GNU__) +# define OSHurd +#elif defined(__sun) +# define OSsunos +#elif defined(OPENBSD) || defined(__OpenBSD__) +# define OSOpenBSD +#elif defined(hpux) +# define OShpux +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# define OSFreeBSD +#elif defined(__NetBSD__) +# define OSNetBSD +#elif defined(__DragonFly__) +# define OSDragonFlyBSD +#else +# error Unknown architecture - cannot build start-stop-daemon +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_SYSCALL_H +#include +#endif +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif +#ifdef HAVE_SYS_PROC_H +#include +#endif +#ifdef HAVE_SYS_USER_H +#include +#endif +#ifdef HAVE_SYS_PSTAT_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDDEF_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_ERROR_H +#include +#endif +#ifdef HAVE_ERR_H +#include +#endif + +#if defined(OSHurd) +#include +#include +#endif + +#ifdef HAVE_KVM_H +#include +#if defined(OSFreeBSD) +#define KVM_MEMFILE "/dev/null" +#else +#define KVM_MEMFILE NULL +#endif +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING +#include +#else +#define SCHED_OTHER -1 +#define SCHED_FIFO -1 +#define SCHED_RR -1 +#endif + +#if defined(OSLinux) +/* This comes from TASK_COMM_LEN defined in Linux' include/linux/sched.h. */ +#define PROCESS_NAME_SIZE 15 +#elif defined(OSsunos) +#define PROCESS_NAME_SIZE 15 +#elif defined(OSDarwin) +#define PROCESS_NAME_SIZE 16 +#elif defined(OSNetBSD) +#define PROCESS_NAME_SIZE 16 +#elif defined(OSOpenBSD) +#define PROCESS_NAME_SIZE 16 +#elif defined(OSFreeBSD) +#define PROCESS_NAME_SIZE 19 +#elif defined(OSDragonFlyBSD) +/* On DragonFlyBSD MAXCOMLEN expands to 16. */ +#define PROCESS_NAME_SIZE MAXCOMLEN +#endif + +#if defined(SYS_ioprio_set) && defined(linux) +#define HAVE_IOPRIO_SET +#endif + +#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 + +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, +}; + +/* Time conversion constants. */ +enum { + NANOSEC_IN_SEC = 1000000000L, + NANOSEC_IN_MILLISEC = 1000000L, + NANOSEC_IN_MICROSEC = 1000L, +}; + +/* The minimum polling interval, 20ms. */ +static const long MIN_POLL_INTERVAL = 20 * NANOSEC_IN_MILLISEC; + +static enum action_code action; +static bool testmode = false; +static int quietmode = 0; +static int exitnodo = 1; +static bool background = false; +static bool close_io = true; +static bool mpidfile = false; +static bool rpidfile = false; +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 pid_t match_pid = -1; +static pid_t match_ppid = -1; +static const char *pidfile = NULL; +static char what_stop[1024]; +static const char *progname = ""; +static int nicelevel = 0; +static int umask_value = -1; + +static struct stat exec_stat; +#if defined(OSHurd) +static struct proc_stat_list *procset = NULL; +#endif + +/* 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 * +xstrndup(const char *str, size_t n) +{ + char *new_str; + + new_str = strndup(str, n); + if (new_str) + return new_str; + fatal("strndup(%s, %zu) failed", str, n); +} + +static void +timespec_gettime(struct timespec *ts) +{ +#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && \ + defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0 + if (clock_gettime(CLOCK_MONOTONIC, ts) < 0) + fatal("clock_gettime failed"); +#else + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday failed"); + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * NANOSEC_IN_MICROSEC; +#endif +} + +#define timespec_cmp(a, b, OP) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_nsec OP (b)->tv_nsec) : \ + ((a)->tv_sec OP (b)->tv_sec)) + +static void +timespec_sub(struct timespec *a, struct timespec *b, struct timespec *res) +{ + res->tv_sec = a->tv_sec - b->tv_sec; + res->tv_nsec = a->tv_nsec - b->tv_nsec; + if (res->tv_nsec < 0) { + res->tv_sec--; + res->tv_nsec += NANOSEC_IN_SEC; + } +} + +static void +timespec_mul(struct timespec *a, int b) +{ + long nsec = a->tv_nsec * b; + + a->tv_sec *= b; + a->tv_sec += nsec / NANOSEC_IN_SEC; + a->tv_nsec = nsec % NANOSEC_IN_SEC; +} + +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) +{ +#ifdef HAVE_GETDTABLESIZE + return getdtablesize(); +#else + return sysconf(_SC_OPEN_MAX); +#endif +} + +#ifndef HAVE_SETSID +static void +detach_controlling_tty(void) +{ +#ifdef HAVE_TIOCNOTTY + int tty_fd; + + tty_fd = open("/dev/tty", O_RDWR); + + /* The current process does not have a controlling tty. */ + if (tty_fd < 0) + return; + + if (ioctl(tty_fd, TIOCNOTTY, 0) != 0) + fatal("unable to detach controlling tty"); + + close(tty_fd); +#endif +} + +static pid_t +setsid(void) +{ + if (setpgid(0, 0) < 0) + return -1: + + detach_controlling_tty(); + + return 0; +} +#endif + +static void +wait_for_child(pid_t pid) +{ + pid_t child; + int status; + + do { + child = waitpid(pid, &status, 0); + } while (child == -1 && errno == EINTR); + + if (child != pid) + fatal("error waiting for child"); + + if (WIFEXITED(status)) { + int err = WEXITSTATUS(status); + + if (err != 0) + fatal("child returned error exit status %d", err); + } else if (WIFSIGNALED(status)) { + int signo = WTERMSIG(status); + + fatal("child was killed by signal %d", signo); + } else { + fatal("unexpected status %d waiting for child", status); + } +} + +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 +remove_pidfile(const char *filename) +{ + if (unlink(filename) < 0 && errno != ENOENT) + fatal("cannot remove pidfile '%s'", filename); +} + +static void +daemonize(void) +{ + pid_t pid; + sigset_t mask; + sigset_t oldmask; + + if (quietmode < 0) + printf("Detaching to start %s...", startas); + + /* Block SIGCHLD to allow waiting for the child process while it is + * performing actions, such as creating a pidfile. */ + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1) + fatal("cannot block SIGCHLD"); + + pid = fork(); + if (pid < 0) + fatal("unable to do first fork"); + else if (pid) { /* First Parent. */ + /* Wait for the second parent to exit, so that if we need to + * perform any actions there, like creating a pidfile, we do + * not suffer from race conditions on return. */ + wait_for_child(pid); + + _exit(0); + } + + /* Create a new session. */ + if (setsid() < 0) + fatal("cannot set session ID"); + + pid = fork(); + if (pid < 0) + fatal("unable to do second fork"); + else if (pid) { /* Second parent. */ + /* Set a default umask for dumb programs, which might get + * overridden by the --umask option later on, so that we get + * a defined umask when creating the pidfille. */ + umask(022); + + if (mpidfile && pidfile != NULL) + /* User wants _us_ to make the pidfile. */ + write_pidfile(pidfile, pid); + + _exit(0); + } + + if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) + fatal("cannot restore signal mask"); + + if (quietmode < 0) + printf("done.\n"); +} + +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 [