diff --git a/talimatname/genel/start-stop-daemon/makefile b/talimatname/genel/start-stop-daemon/makefile new file mode 100644 index 000000000..976a01ab3 --- /dev/null +++ b/talimatname/genel/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/talimatname/genel/start-stop-daemon/ornek_servis b/talimatname/genel/start-stop-daemon/ornek_servis new file mode 100644 index 000000000..dad1ea465 --- /dev/null +++ b/talimatname/genel/start-stop-daemon/ornek_servis @@ -0,0 +1,48 @@ +#!/bin/sh + +# Derived from https://gist.github.com/sodik82/4f4aafdb52e84102b75d + +set -e +. /lib/lsb/init-functions + +# Must be a valid filename +NAME=foo +PIDFILE=/run/$NAME.pid + +# Full path to executable +DAEMON=/usr/local/bin/bar + +# Options +DAEMON_OPTS="--baz=quux" + +# User to run the command as +USER=www + + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + +case "$1" in + start) + echo -n "Starting daemon: "$NAME + start-stop-daemon --start --quiet -b -m --pidfile $PIDFILE --chdir $WORK_DIR --chuid $USER --exec $DAEMON -- $DAEMON_OPTS + echo "." + ;; + stop) + echo -n "Stopping daemon: "$NAME + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE + echo "." + ;; + restart) + echo -n "Restarting daemon: "$NAME + start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PIDFILE + start-stop-daemon --start --quiet -b -m --pidfile $PIDFILE --chdir $WORK_DIR --chuid $USER --exec $DAEMON -- $DAEMON_OPTS + echo "." + ;; + status) + status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? + ;; + + *) + echo "Usage: "$1" {start|stop|restart}" + exit 1 +esac diff --git a/talimatname/genel/start-stop-daemon/start-stop-daemon.8 b/talimatname/genel/start-stop-daemon/start-stop-daemon.8 new file mode 100644 index 000000000..deae6c6b0 --- /dev/null +++ b/talimatname/genel/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/talimatname/genel/start-stop-daemon/start-stop-daemon.c b/talimatname/genel/start-stop-daemon/start-stop-daemon.c new file mode 100644 index 000000000..a749008bc --- /dev/null +++ b/talimatname/genel/start-stop-daemon/start-stop-daemon.c @@ -0,0 +1,1059 @@ +/* + * 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 aswell. + * + * Port to OpenBSD by Sontri Tomo Huynh + * and Andreas Schuldei + * + * Changes by Ian Jackson: added --retry (and associated rearrangements). + * + * Modified for Gentoo rc-scripts by Donny Davies : + * I removed the BSD/Hurd/OtherOS stuff, added #include + * and stuck in a #define VERSION "1.9.18". Now it compiles without + * the whole automake/config.h dance. + */ + +#ifdef HAVE_LXC +#define _GNU_SOURCE +#include +#endif /* HAVE_LXC */ + +#include +#define VERSION "1.9.18" + +#define MIN_POLL_INTERVAL 20000 /*us*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int testmode = 0; +static int quietmode = 0; +static int exitnodo = 1; +static int start = 0; +static int stop = 0; +static int background = 0; +static int mpidfile = 0; +static int signal_nr = 15; +static const char *signal_str = NULL; +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 *cmdname = NULL; +static char *execname = NULL; +static char *startas = NULL; +static const char *pidfile = NULL; +static char what_stop[1024]; +static const char *schedule_str = NULL; +static const char *progname = ""; +static int nicelevel = 0; + +static struct stat exec_stat; + +struct pid_list { + struct pid_list *next; + pid_t pid; +}; + +static struct pid_list *found = NULL; +static struct pid_list *killed = NULL; + +struct schedule_item { + enum { sched_timeout, sched_signal, sched_goto, sched_forever } type; + int value; /* seconds, signal no., or index into array */ + /* sched_forever is only seen within parse_schedule and callees */ +}; + +static int schedule_length; +static struct schedule_item *schedule = NULL; + +LIST_HEAD(namespace_head, namespace); + +struct namespace { + LIST_ENTRY(namespace) list; + char *path; + int nstype; +}; + +static struct namespace_head namespace_head; + +static void *xmalloc(int size); +static void push(struct pid_list **list, pid_t pid); +static void do_help(void); +static void parse_options(int argc, char * const *argv); +static int pid_is_user(pid_t pid, uid_t uid); +static int pid_is_cmd(pid_t pid, const char *name); +static void check(pid_t pid); +static void do_pidfile(const char *name); +static void do_stop(int signal_nr, int quietmode, + int *n_killed, int *n_notkilled, int retry_nr); +static int pid_is_exec(pid_t pid, const struct stat *esb); + +#ifdef __GNUC__ +static void fatal(const char *format, ...) + __attribute__((noreturn, format(printf, 1, 2))); +static void badusage(const char *msg) + __attribute__((noreturn)); +#else +static void fatal(const char *format, ...); +static void badusage(const char *msg); +#endif + +/* This next part serves only to construct the TVCALC macro, which + * is used for doing arithmetic on struct timeval's. It works like this: + * TVCALC(result, expression); + * where result is a struct timeval (and must be an lvalue) and + * expression is the single expression for both components. In this + * expression you can use the special values TVELEM, which when fed a + * const struct timeval* gives you the relevant component, and + * TVADJUST. TVADJUST is necessary when subtracting timevals, to make + * it easier to renormalise. Whenver you subtract timeval elements, + * you must make sure that TVADJUST is added to the result of the + * subtraction (before any resulting multiplication or what have you). + * TVELEM must be linear in TVADJUST. + */ +typedef long tvselector(const struct timeval*); +static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; } +static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; } +#define TVCALC_ELEM(result, expr, sec, adj) \ +{ \ + const long TVADJUST = adj; \ + long (*const TVELEM)(const struct timeval*) = tvselector_##sec; \ + (result).tv_##sec = (expr); \ +} +#define TVCALC(result,expr) \ +do { \ + TVCALC_ELEM(result, expr, sec, (-1)); \ + TVCALC_ELEM(result, expr, usec, (+1000000)); \ + (result).tv_sec += (result).tv_usec / 1000000; \ + (result).tv_usec %= 1000000; \ +} while(0) + + +static void +fatal(const char *format, ...) +{ + va_list arglist; + + fprintf(stderr, "%s: ", progname); + va_start(arglist, format); + vfprintf(stderr, format, arglist); + va_end(arglist); + putc('\n', stderr); + exit(2); +} + + +static void * +xmalloc(int size) +{ + void *ptr; + + ptr = malloc(size); + if (ptr) + return ptr; + fatal("malloc(%d) failed", size); +} + +static void +xgettimeofday(struct timeval *tv) +{ + if (gettimeofday(tv,0) != 0) + fatal("gettimeofday failed: %s", strerror(errno)); +} + +static void +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 +clear(struct pid_list **list) +{ + struct pid_list *here, *next; + + for (here = *list; here != NULL; here = next) { + next = here->next; + free(here); + } + + *list = NULL; +} + +static char * +next_dirname(const char *s) +{ + char *cur; + + cur = (char *)s; + + if (*cur != '\0') { + for (; *cur != '/'; ++cur) + if (*cur == '\0') + return cur; + + for (; *cur == '/'; ++cur) + ; + } + + return cur; +} + +static void +add_namespace(const char *path) +{ + int nstype; + char *nsdirname, *nsname, *cur; + struct namespace *namespace; + + cur = (char *)path; + nsdirname = nsname = ""; + + while ((cur = next_dirname(cur))[0] != '\0') { + nsdirname = nsname; + nsname = cur; + } + + if (!memcmp(nsdirname, "ipcns/", strlen("ipcns/"))) + nstype = CLONE_NEWIPC; + else if (!memcmp(nsdirname, "netns/", strlen("netns/"))) + nstype = CLONE_NEWNET; + else if (!memcmp(nsdirname, "utcns/", strlen("utcns/"))) + nstype = CLONE_NEWUTS; + else + badusage("invalid namepspace path"); + + namespace = xmalloc(sizeof(*namespace)); + namespace->path = (char *)path; + namespace->nstype = nstype; + LIST_INSERT_HEAD(&namespace_head, namespace, list); +} + +#ifdef HAVE_LXC +static void +set_namespaces() +{ + struct namespace *namespace; + int fd; + + LIST_FOREACH(namespace, &namespace_head, list) { + if ((fd = open(namespace->path, O_RDONLY)) == -1) + fatal("open namespace %s: %s", namespace->path, strerror(errno)); + if (setns(fd, namespace->nstype) == -1) + fatal("setns %s: %s", namespace->path, strerror(errno)); + } +} +#else +static void +set_namespaces() +{ + if (!LIST_EMPTY(&namespace_head)) + fatal("LCX namespaces not supported"); +} +#endif + +static void +do_help(void) +{ + printf( +"start-stop-daemon " VERSION " for Milis linux - small and fast C version written by\n" +"Marek Michalkiewicz , public domain.\n" +"Milis Linux milisarge@gmail.com .\n" +"\n" +"Usage:\n" +" start-stop-daemon -S|--start options ... -- arguments ...\n" +" start-stop-daemon -K|--stop options ...\n" +" start-stop-daemon -H|--help\n" +" start-stop-daemon -V|--version\n" +"\n" +"Options (at least one of --exec|--pidfile|--user is required):\n" +" -x|--exec program to start/check if it is running\n" +" -p|--pidfile pid file to check\n" +" -c|--chuid \n" +" change to this user/group before starting process\n" +" -u|--user | stop processes owned by this user\n" +" -n|--name stop processes with this name\n" +" -s|--signal signal to send (default TERM)\n" +" -a|--startas program to start (default is )\n" +" -N|--nicelevel add incr to the process's nice level\n" +" -b|--background force the process to detach\n" +" -m|--make-pidfile create the pidfile before starting\n" +" -R|--retry check whether processes die, and retry\n" +" -t|--test test mode, don't do anything\n" +" -o|--oknodo exit status 0 (not 1) if nothing done\n" +" -q|--quiet be more quiet\n" +" -v|--verbose be more verbose\n" +"Retry is |//... where is one of\n" +" -|[-] send that signal\n" +" wait that many seconds\n" +" forever repeat remainder forever\n" +"or may be just , meaning //KILL/\n" +"\n" +"Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo)\n" +" 3 = trouble 2 = with --retry, processes wouldn't die\n"); +} + + +static void +badusage(const char *msg) +{ + if (msg) + fprintf(stderr, "%s: %s\n", progname, msg); + fprintf(stderr, "Try `%s --help' for more information.\n", progname); + exit(3); +} + +struct sigpair { + const char *name; + int signal; +}; + +const struct sigpair siglist[] = { + { "ABRT", SIGABRT }, + { "ALRM", SIGALRM }, + { "FPE", SIGFPE }, + { "HUP", SIGHUP }, + { "ILL", SIGILL }, + { "INT", SIGINT }, + { "KILL", SIGKILL }, + { "PIPE", SIGPIPE }, + { "QUIT", SIGQUIT }, + { "SEGV", SIGSEGV }, + { "TERM", SIGTERM }, + { "USR1", SIGUSR1 }, + { "USR2", SIGUSR2 }, + { "CHLD", SIGCHLD }, + { "CONT", SIGCONT }, + { "STOP", SIGSTOP }, + { "TSTP", SIGTSTP }, + { "TTIN", SIGTTIN }, + { "TTOU", SIGTTOU } +}; + +static int parse_integer (const char *string, int *value_r) { + unsigned long ul; + char *ep; + + if (!string[0]) + return -1; + + ul= strtoul(string,&ep,10); + if (ul > INT_MAX || *ep != '\0') + return -1; + + *value_r= ul; + return 0; +} + +static int parse_signal (const char *signal_str, int *signal_nr) +{ + unsigned int i; + + if (parse_integer(signal_str, signal_nr) == 0) + return 0; + + for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) { + if (strcmp (signal_str, siglist[i].name) == 0) { + *signal_nr = siglist[i].signal; + return 0; + } + } + return -1; +} + +static void +parse_schedule_item(const char *string, struct schedule_item *item) { + const char *after_hyph; + + if (!strcmp(string,"forever")) { + item->type = sched_forever; + } else if (isdigit(string[0])) { + item->type = sched_timeout; + if (parse_integer(string, &item->value) != 0) + badusage("invalid timeout value in schedule"); + } else if ((after_hyph = string + (string[0] == '-')) && + parse_signal(after_hyph, &item->value) == 0) { + item->type = sched_signal; + } else { + badusage("invalid schedule item (must be [-], " + "-, or `forever'"); + } +} + +static void +parse_schedule(const char *schedule_str) { + char item_buf[20]; + const char *slash; + int count, repeatat; + ptrdiff_t str_len; + + count = 0; + for (slash = schedule_str; *slash; slash++) + if (*slash == '/') + count++; + + schedule_length = (count == 0) ? 4 : count+1; + schedule = xmalloc(sizeof(*schedule) * schedule_length); + + if (count == 0) { + schedule[0].type = sched_signal; + schedule[0].value = signal_nr; + parse_schedule_item(schedule_str, &schedule[1]); + if (schedule[1].type != sched_timeout) { + badusage ("--retry takes timeout, or schedule list" + " of at least two items"); + } + schedule[2].type = sched_signal; + schedule[2].value = SIGKILL; + schedule[3]= schedule[1]; + } else { + count = 0; + repeatat = -1; + while (schedule_str != NULL) { + slash = strchr(schedule_str,'/'); + str_len = slash ? slash - schedule_str : strlen(schedule_str); + if (str_len >= (ptrdiff_t)sizeof(item_buf)) + badusage("invalid schedule item: far too long" + " (you must delimit items with slashes)"); + memcpy(item_buf, schedule_str, str_len); + item_buf[str_len] = 0; + schedule_str = slash ? slash+1 : NULL; + + parse_schedule_item(item_buf, &schedule[count]); + if (schedule[count].type == sched_forever) { + if (repeatat >= 0) + badusage("invalid schedule: `forever'" + " appears more than once"); + repeatat = count; + continue; + } + count++; + } + if (repeatat >= 0) { + schedule[count].type = sched_goto; + schedule[count].value = repeatat; + count++; + } + assert(count == schedule_length); + } +} + +static void +parse_options(int argc, char * const *argv) +{ + static struct option longopts[] = { + { "help", 0, NULL, 'H'}, + { "stop", 0, NULL, 'K'}, + { "start", 0, NULL, 'S'}, + { "version", 0, NULL, 'V'}, + { "startas", 1, NULL, 'a'}, + { "name", 1, NULL, 'n'}, + { "oknodo", 0, NULL, 'o'}, + { "pidfile", 1, NULL, 'p'}, + { "quiet", 0, NULL, 'q'}, + { "signal", 1, NULL, 's'}, + { "test", 0, NULL, 't'}, + { "user", 1, NULL, 'u'}, + { "chroot", 1, NULL, 'r'}, + { "namespace", 1, NULL, 'd'}, + { "verbose", 0, NULL, 'v'}, + { "exec", 1, NULL, 'x'}, + { "chuid", 1, NULL, 'c'}, + { "nicelevel", 1, NULL, 'N'}, + { "background", 0, NULL, 'b'}, + { "make-pidfile", 0, NULL, 'm'}, + { "retry", 1, NULL, 'R'}, + { NULL, 0, NULL, 0} + }; + int c; + + for (;;) { + c = getopt_long(argc, argv, "HKSVa:n:op:qr:d:s:tu:vx:c:N:bmR:", + longopts, (int *) 0); + if (c == -1) + break; + switch (c) { + case 'H': /* --help */ + do_help(); + exit(0); + case 'K': /* --stop */ + stop = 1; + break; + case 'S': /* --start */ + start = 1; + break; + case 'V': /* --version */ + printf("start-stop-daemon " VERSION "\n"); + exit(0); + case 'a': /* --startas */ + startas = optarg; + break; + case 'n': /* --name */ + cmdname = optarg; + break; + case 'o': /* --oknodo */ + exitnodo = 0; + break; + case 'p': /* --pidfile */ + pidfile = optarg; + break; + case 'q': /* --quiet */ + quietmode = 1; + break; + case 's': /* --signal */ + signal_str = optarg; + break; + case 't': /* --test */ + testmode = 1; + break; + case 'u': /* --user | */ + userspec = optarg; + break; + case 'v': /* --verbose */ + quietmode = -1; + break; + case 'x': /* --exec */ + execname = optarg; + break; + case 'c': /* --chuid | */ + /* we copy the string just in case we need the + * argument later. */ + changeuser = strdup(optarg); + changeuser = strtok(changeuser, ":"); + changegroup = strtok(NULL, ":"); + break; + case 'r': /* --chroot /new/root */ + changeroot = optarg; + break; + case 'd': /* --namespace /.../||/name */ + add_namespace(optarg); + break; + case 'N': /* --nice */ + nicelevel = atoi(optarg); + break; + case 'b': /* --background */ + background = 1; + break; + case 'm': /* --make-pidfile */ + mpidfile = 1; + break; + case 'R': /* --retry | */ + schedule_str = optarg; + break; + default: + badusage(NULL); /* message printed by getopt */ + } + } + + if (signal_str != NULL) { + if (parse_signal (signal_str, &signal_nr) != 0) + badusage("signal value must be numeric or name" + " of signal (KILL, INTR, ...)"); + } + + if (schedule_str != NULL) { + parse_schedule(schedule_str); + } + + if (start == stop) + badusage("need one of --start or --stop"); + + if (!execname && !pidfile && !userspec && !cmdname) + badusage("need at least one of --exec, --pidfile, --user or --name"); + + if (!startas) + startas = execname; + + if (start && !startas) + badusage("--start needs --exec or --startas"); + + if (mpidfile && pidfile == NULL) + badusage("--make-pidfile is only relevant with --pidfile"); + + if (background && !start) + badusage("--background is only relevant with --start"); + +} + +static int +pid_is_exec(pid_t pid, const struct stat *esb) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d/exe", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino); +} + + +static int +pid_is_user(pid_t pid, uid_t uid) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_uid == uid); +} + + +static int +pid_is_cmd(pid_t pid, const char *name) +{ + char buf[32]; + FILE *f; + int c; + + sprintf(buf, "/proc/%d/stat", pid); + f = fopen(buf, "r"); + if (!f) + return 0; + while ((c = getc(f)) != EOF && c != '(') + ; + if (c != '(') { + fclose(f); + return 0; + } + /* this hopefully handles command names containing ')' */ + while ((c = getc(f)) != EOF && c == *name) + name++; + fclose(f); + return (c == ')' && *name == '\0'); +} + + +static void +check(pid_t pid) +{ + if (execname && !pid_is_exec(pid, &exec_stat)) + return; + if (userspec && !pid_is_user(pid, user_id)) + return; + if (cmdname && !pid_is_cmd(pid, cmdname)) + return; + push(&found, pid); +} + +static void +do_pidfile(const char *name) +{ + FILE *f; + pid_t pid; + + f = fopen(name, "r"); + if (f) { + if (fscanf(f, "%d", &pid) == 1) + check(pid); + fclose(f); + } else if (errno != ENOENT) + fatal("open pidfile %s: %s", name, strerror(errno)); + +} + +/* WTA: this needs to be an autoconf check for /proc/pid existance. + */ +static void +do_procinit(void) +{ + DIR *procdir; + struct dirent *entry; + int foundany; + pid_t pid; + + procdir = opendir("/proc"); + if (!procdir) + fatal("opendir /proc: %s", strerror(errno)); + + foundany = 0; + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &pid) != 1) + continue; + foundany++; + check(pid); + } + closedir(procdir); + if (!foundany) + fatal("nothing in /proc - not mounted?"); +} + +static void +do_findprocs(void) +{ + clear(&found); + + if (pidfile) + do_pidfile(pidfile); + else + do_procinit(); +} + +/* return 1 on failure */ +static void +do_stop(int signal_nr, int quietmode, int *n_killed, int *n_notkilled, int retry_nr) +{ + struct pid_list *p; + + do_findprocs(); + + *n_killed = 0; + *n_notkilled = 0; + + if (!found) + return; + + clear(&killed); + + for (p = found; p; p = p->next) { + if (testmode) + printf("Would send signal %d to %d.\n", + signal_nr, p->pid); + else if (kill(p->pid, signal_nr) == 0) { + push(&killed, p->pid); + (*n_killed)++; + } else { + printf("%s: warning: failed to kill %d: %s\n", + progname, p->pid, strerror(errno)); + (*n_notkilled)++; + } + } + if (quietmode < 0 && killed) { + printf("Stopped %s (pid", what_stop); + for (p = killed; p; p = p->next) + printf(" %d", p->pid); + putchar(')'); + if (retry_nr > 0) + printf(", retry #%d", retry_nr); + printf(".\n"); + } +} + + +static void +set_what_stop(const char *str) +{ + strncpy(what_stop, str, sizeof(what_stop)); + what_stop[sizeof(what_stop)-1] = '\0'; +} + +static int +run_stop_schedule(void) +{ + int r, position, n_killed, n_notkilled, value, ratio, anykilled, retry_nr; + struct timeval stopat, before, after, interval, maxinterval; + + if (testmode) { + if (schedule != NULL) { + printf("Ignoring --retry in test mode\n"); + schedule = NULL; + } + } + + if (cmdname) + set_what_stop(cmdname); + else if (execname) + set_what_stop(execname); + else if (pidfile) + sprintf(what_stop, "process in pidfile `%.200s'", pidfile); + else if (userspec) + sprintf(what_stop, "process(es) owned by `%.200s'", userspec); + else + fatal("internal error, please report"); + + anykilled = 0; + retry_nr = 0; + + if (schedule == NULL) { + do_stop(signal_nr, quietmode, &n_killed, &n_notkilled, 0); + if (n_notkilled > 0 && quietmode <= 0) + printf("%d pids were not killed\n", n_notkilled); + if (n_killed) + anykilled = 1; + goto x_finished; + } + + for (position = 0; position < schedule_length; ) { + value= schedule[position].value; + n_notkilled = 0; + + switch (schedule[position].type) { + + case sched_goto: + position = value; + continue; + + case sched_signal: + do_stop(value, quietmode, &n_killed, &n_notkilled, retry_nr++); + if (!n_killed) + goto x_finished; + else + anykilled = 1; + goto next_item; + + case sched_timeout: + /* We want to keep polling for the processes, to see if they've exited, + * or until the timeout expires. + * + * This is a somewhat complicated algorithm to try to ensure that we + * notice reasonably quickly when all the processes have exited, but + * don't spend too much CPU time polling. In particular, on a fast + * machine with quick-exiting daemons we don't want to delay system + * shutdown too much, whereas on a slow one, or where processes are + * taking some time to exit, we want to increase the polling + * interval. + * + * The algorithm is as follows: we measure the elapsed time it takes + * to do one poll(), and wait a multiple of this time for the next + * poll. However, if that would put us past the end of the timeout + * period we wait only as long as the timeout period, but in any case + * we always wait at least MIN_POLL_INTERVAL (20ms). The multiple + * (`ratio') starts out as 2, and increases by 1 for each poll to a + * maximum of 10; so we use up to between 30% and 10% of the + * machine's resources (assuming a few reasonable things about system + * performance). + */ + xgettimeofday(&stopat); + stopat.tv_sec += value; + ratio = 1; + for (;;) { + xgettimeofday(&before); + if (timercmp(&before,&stopat,>)) + goto next_item; + + do_stop(0, 1, &n_killed, &n_notkilled, 0); + if (!n_killed) + goto x_finished; + + xgettimeofday(&after); + + if (!timercmp(&after,&stopat,<)) + goto next_item; + + if (ratio < 10) + ratio++; + + TVCALC(interval, ratio * (TVELEM(&after) - TVELEM(&before) + TVADJUST)); + TVCALC(maxinterval, TVELEM(&stopat) - TVELEM(&after) + TVADJUST); + + if (timercmp(&interval,&maxinterval,>)) + interval = maxinterval; + + if (interval.tv_sec == 0 && + interval.tv_usec <= MIN_POLL_INTERVAL) + interval.tv_usec = MIN_POLL_INTERVAL; + + r = select(0,0,0,0,&interval); + if (r < 0 && errno != EINTR) + fatal("select() failed for pause: %s", + strerror(errno)); + } + + default: + assert(!"schedule[].type value must be valid"); + + } + + next_item: + position++; + } + + if (quietmode <= 0) + printf("Program %s, %d process(es), refused to die.\n", + what_stop, n_killed); + + return 2; + +x_finished: + if (!anykilled) { + if (quietmode <= 0) + printf("No %s found running; none killed.\n", what_stop); + return exitnodo; + } else { + return 0; + } +} + +/* +int main(int argc, char **argv) NONRETURNING; +*/ + +int +main(int argc, char **argv) +{ + progname = argv[0]; + + LIST_INIT(&namespace_head); + + parse_options(argc, argv); + argc -= optind; + argv += optind; + + if (execname && stat(execname, &exec_stat)) + fatal("stat %s: %s", execname, strerror(errno)); + + if (userspec && sscanf(userspec, "%d", &user_id) != 1) { + struct passwd *pw; + + pw = getpwnam(userspec); + if (!pw) + fatal("user `%s' not found\n", userspec); + + user_id = pw->pw_uid; + } + + if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) { + struct group *gr = getgrnam(changegroup); + if (!gr) + fatal("group `%s' not found\n", changegroup); + runas_gid = gr->gr_gid; + } + if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) { + struct passwd *pw = getpwnam(changeuser); + if (!pw) + fatal("user `%s' not found\n", changeuser); + runas_uid = pw->pw_uid; + if (changegroup == NULL) { /* pass the default group of this user */ + changegroup = ""; /* just empty */ + runas_gid = pw->pw_gid; + } + } + + if (stop) { + int i = run_stop_schedule(); + exit(i); + } + + do_findprocs(); + + if (found) { + if (quietmode <= 0) + printf("%s already running.\n", execname); + exit(exitnodo); + } + if (testmode) { + printf("Would start %s ", startas); + while (argc-- > 0) + printf("%s ", *argv++); + if (changeuser != NULL) { + printf(" (as user %s[%d]", changeuser, runas_uid); + if (changegroup != NULL) + printf(", and group %s[%d])", changegroup, runas_gid); + else + printf(")"); + } + if (changeroot != NULL) + printf(" in directory %s", changeroot); + if (nicelevel) + printf(", and add %i to the priority", nicelevel); + printf(".\n"); + exit(0); + } + if (quietmode < 0) + printf("Starting %s...\n", startas); + *--argv = startas; + if (changeroot != NULL) { + if (chdir(changeroot) < 0) + fatal("Unable to chdir() to %s", changeroot); + if (chroot(changeroot) < 0) + fatal("Unable to chroot() to %s", changeroot); + } + if (changeuser != NULL) { + if (setgid(runas_gid)) + fatal("Unable to set gid to %d", runas_gid); + if (initgroups(changeuser, runas_gid)) + fatal("Unable to set initgroups() with gid %d", runas_gid); + if (setuid(runas_uid)) + fatal("Unable to set uid to %s", changeuser); + } + + if (background) { /* ok, we need to detach this process */ + int i, fd; + if (quietmode < 0) + printf("Detatching to start %s...", startas); + i = fork(); + if (i<0) { + fatal("Unable to fork.\n"); + } + if (i) { /* parent */ + if (quietmode < 0) + printf("done.\n"); + exit(0); + } + /* child continues here */ + /* now close all extra fds */ + for (i=getdtablesize()-1; i>=0; --i) close(i); + /* change tty */ + fd = open("/dev/tty", O_RDWR); + ioctl(fd, TIOCNOTTY, 0); + close(fd); + chdir("/"); + umask(022); /* set a default for dumb programs */ + setpgid(0,0); /* set the process group */ + fd=open("/dev/null", O_RDWR); /* stdin */ + dup(fd); /* stdout */ + dup(fd); /* stderr */ + } + if (nicelevel) { + errno = 0; + if (nice(nicelevel) < 0 && errno) + fatal("Unable to alter nice level by %i: %s", nicelevel, + strerror(errno)); + } + if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */ + FILE *pidf = fopen(pidfile, "w"); + pid_t pidt = getpid(); + if (pidf == NULL) + fatal("Unable to open pidfile `%s' for writing: %s", pidfile, + strerror(errno)); + fprintf(pidf, "%d\n", pidt); + fclose(pidf); + } + set_namespaces(); + execv(startas, argv); + fatal("Unable to start %s: %s", startas, strerror(errno)); +} diff --git a/talimatname/genel/start-stop-daemon/talimat b/talimatname/genel/start-stop-daemon/talimat new file mode 100644 index 000000000..c840d9488 --- /dev/null +++ b/talimatname/genel/start-stop-daemon/talimat @@ -0,0 +1,16 @@ +# Description: sistem servislerinin kontrol programı +# URL: http://man7.org/linux/man-pages/man8/start-stop-daemon.8.html +# Packager: milisarge +# Depends on: + +name=start-stop-daemon +version=1.0 +release=1 +source=(start-stop-daemon.c start-stop-daemon.8 ornek_servis makefile) + +build () { + make + install -d $PKG/{sbin,usr/share/man/man8} + install -m 755 $name $PKG/sbin/ + install -m 644 $name.8 $PKG/usr/share/man/man8/ +}