18 |
* and Andreas Schuldei <andreas@schuldei.org> |
* and Andreas Schuldei <andreas@schuldei.org> |
19 |
* |
* |
20 |
* Changes by Ian Jackson: added --retry (and associated rearrangements). |
* Changes by Ian Jackson: added --retry (and associated rearrangements). |
|
* |
|
21 |
* Modified for Gentoo rc-scripts by Donny Davies <woodchip@gentoo.org>: |
* Modified for Gentoo rc-scripts by Donny Davies <woodchip@gentoo.org>: |
22 |
* I removed the BSD/Hurd/OtherOS stuff, added #include <stddef.h> |
* I removed the BSD/Hurd/OtherOS stuff, added #include <stddef.h> |
23 |
* and stuck in a #define VERSION "1.9.18". Now it compiles without |
* and stuck in a #define VERSION "1.9.18". Now it compiles without |
27 |
* Fetched updates from Debian's dpkg-1.10.20, including fix for |
* Fetched updates from Debian's dpkg-1.10.20, including fix for |
28 |
* Gentoo bug 22686 (start-stop-daemon in baselayout doesn't allow |
* Gentoo bug 22686 (start-stop-daemon in baselayout doesn't allow |
29 |
* altered nicelevel). |
* altered nicelevel). |
30 |
|
* |
31 |
|
* |
32 |
|
* Changes by Quequero <quequero@bitchx.it>: |
33 |
|
* Added -e|--env for setting an environment variable before starting the |
34 |
|
* process. |
35 |
|
* Moved --make-pidfile after chrooting process (pid file will be wrote in |
36 |
|
* new root if -r option is used!). |
37 |
|
* Daemon binary will be stat()ed correctly if it's going to be chrooted |
38 |
|
* with -r|--chroot. |
39 |
|
* |
40 |
*/ |
*/ |
41 |
|
|
42 |
#define VERSION "1.10.20" |
#define VERSION "1.13.11" |
|
#include <stddef.h> |
|
43 |
|
|
44 |
#define NONRETURNPRINTFFORMAT(x, y) \ |
#define NONRETURNPRINTFFORMAT(x, y) \ |
45 |
__attribute__((noreturn, format(printf, x, y))) |
__attribute__((noreturn, format(printf, x, y))) |
60 |
# define OSFreeBSD |
# define OSFreeBSD |
61 |
#elif defined(__NetBSD__) |
#elif defined(__NetBSD__) |
62 |
# define OSNetBSD |
# define OSNetBSD |
63 |
|
#elif defined(__APPLE__) |
64 |
|
# define OSDarwin |
65 |
#else |
#else |
66 |
# error Unknown architecture - cannot build start-stop-daemon |
# error Unknown architecture - cannot build start-stop-daemon |
67 |
#endif |
#endif |
73 |
# include <ps.h> |
# include <ps.h> |
74 |
#endif |
#endif |
75 |
|
|
76 |
#if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD) |
#if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD) || defined(OSDarwin) |
77 |
#include <sys/param.h> |
#include <sys/param.h> |
78 |
#include <sys/user.h> |
#include <sys/user.h> |
79 |
#include <sys/proc.h> |
#include <sys/proc.h> |
80 |
#include <sys/stat.h> |
#include <sys/stat.h> |
81 |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
82 |
#include <sys/types.h> |
#include <sys/types.h> |
83 |
|
|
84 |
#include <err.h> |
#include <err.h> |
85 |
#include <kvm.h> |
#include <kvm.h> |
86 |
#include <limits.h> |
#include <limits.h> |
112 |
#include <assert.h> |
#include <assert.h> |
113 |
#include <ctype.h> |
#include <ctype.h> |
114 |
|
|
115 |
|
#include <stddef.h> |
116 |
|
|
117 |
#include "headers.h" |
#include "headers.h" |
118 |
|
|
119 |
#ifdef HURD_IHASH_H |
#ifdef HURD_IHASH_H |
132 |
static int user_id = -1; |
static int user_id = -1; |
133 |
static int runas_uid = -1; |
static int runas_uid = -1; |
134 |
static int runas_gid = -1; |
static int runas_gid = -1; |
135 |
|
static char *env = NULL; |
136 |
static const char *userspec = NULL; |
static const char *userspec = NULL; |
137 |
static char *changeuser = NULL; |
static char *changeuser = NULL; |
138 |
static const char *changegroup = NULL; |
static const char *changegroup = NULL; |
139 |
static char *changeroot = NULL; |
static char *changeroot = NULL; |
140 |
static const char *changedir = NULL; |
static const char *changedir = "/"; |
141 |
static const char *cmdname = NULL; |
static const char *cmdname = NULL; |
142 |
static char *execname = NULL; |
static char *execname = NULL; |
143 |
static char *startas = NULL; |
static char *startas = NULL; |
149 |
|
|
150 |
static struct stat exec_stat; |
static struct stat exec_stat; |
151 |
#if defined(OSHURD) |
#if defined(OSHURD) |
152 |
static struct proc_stat_list *procset; |
static struct proc_stat_list *procset = NULL; |
153 |
#endif |
#endif |
154 |
|
|
155 |
|
|
210 |
typedef long tvselector(const struct timeval*); |
typedef long tvselector(const struct timeval*); |
211 |
static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; } |
static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; } |
212 |
static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; } |
static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; } |
213 |
#define TVCALC_ELEM(result, expr, sec, adj) \ |
#define TVCALC_ELEM(result, expr, sec, adj) \ |
214 |
{ \ |
{ \ |
215 |
const long TVADJUST = adj; \ |
const long TVADJUST = adj; \ |
216 |
long (*const TVELEM)(const struct timeval*) = tvselector_##sec; \ |
long (*const TVELEM)(const struct timeval*) = tvselector_##sec; \ |
217 |
(result).tv_##sec = (expr); \ |
(result).tv_##sec = (expr); \ |
218 |
} |
} |
219 |
#define TVCALC(result,expr) \ |
#define TVCALC(result,expr) \ |
220 |
do { \ |
do { \ |
221 |
TVCALC_ELEM(result, expr, sec, (-1)); \ |
TVCALC_ELEM(result, expr, sec, (-1)); \ |
222 |
TVCALC_ELEM(result, expr, usec, (+1000000)); \ |
TVCALC_ELEM(result, expr, usec, (+1000000)); \ |
223 |
(result).tv_sec += (result).tv_usec / 1000000; \ |
(result).tv_sec += (result).tv_usec / 1000000; \ |
224 |
(result).tv_usec %= 1000000; \ |
(result).tv_usec %= 1000000; \ |
225 |
} while(0) |
} while(0) |
226 |
|
|
227 |
|
|
234 |
va_start(arglist, format); |
va_start(arglist, format); |
235 |
vfprintf(stderr, format, arglist); |
vfprintf(stderr, format, arglist); |
236 |
va_end(arglist); |
va_end(arglist); |
237 |
putc('\n', stderr); |
fprintf(stderr, " (%s)\n", strerror (errno)); |
238 |
exit(2); |
exit(2); |
239 |
} |
} |
240 |
|
|
311 |
" -b|--background force the process to detach\n" |
" -b|--background force the process to detach\n" |
312 |
" -m|--make-pidfile create the pidfile before starting\n" |
" -m|--make-pidfile create the pidfile before starting\n" |
313 |
" -R|--retry <schedule> check whether processes die, and retry\n" |
" -R|--retry <schedule> check whether processes die, and retry\n" |
314 |
|
" -e|--env <env-name> set an environment variable (PWD=\"/\")\n" |
315 |
|
" -r|--chroot <path> chroot process to given directory\n" |
316 |
" -t|--test test mode, don't do anything\n" |
" -t|--test test mode, don't do anything\n" |
317 |
" -o|--oknodo exit status 0 (not 1) if nothing done\n" |
" -o|--oknodo exit status 0 (not 1) if nothing done\n" |
318 |
" -q|--quiet be more quiet\n" |
" -q|--quiet be more quiet\n" |
476 |
parse_options(int argc, char * const *argv) |
parse_options(int argc, char * const *argv) |
477 |
{ |
{ |
478 |
static struct option longopts[] = { |
static struct option longopts[] = { |
479 |
{ "help", 0, NULL, 'H'}, |
{ "help", 0, NULL, 'H'}, |
480 |
{ "stop", 0, NULL, 'K'}, |
{ "stop", 0, NULL, 'K'}, |
481 |
{ "start", 0, NULL, 'S'}, |
{ "start", 0, NULL, 'S'}, |
482 |
{ "version", 0, NULL, 'V'}, |
{ "version", 0, NULL, 'V'}, |
483 |
{ "startas", 1, NULL, 'a'}, |
{ "startas", 1, NULL, 'a'}, |
484 |
{ "name", 1, NULL, 'n'}, |
{ "env", 1, NULL, 'e'}, |
485 |
{ "oknodo", 0, NULL, 'o'}, |
{ "name", 1, NULL, 'n'}, |
486 |
{ "pidfile", 1, NULL, 'p'}, |
{ "oknodo", 0, NULL, 'o'}, |
487 |
{ "quiet", 0, NULL, 'q'}, |
{ "pidfile", 1, NULL, 'p'}, |
488 |
{ "signal", 1, NULL, 's'}, |
{ "quiet", 0, NULL, 'q'}, |
489 |
{ "test", 0, NULL, 't'}, |
{ "signal", 1, NULL, 's'}, |
490 |
{ "user", 1, NULL, 'u'}, |
{ "test", 0, NULL, 't'}, |
491 |
{ "group", 1, NULL, 'g'}, |
{ "user", 1, NULL, 'u'}, |
492 |
{ "chroot", 1, NULL, 'r'}, |
{ "group", 1, NULL, 'g'}, |
493 |
{ "verbose", 0, NULL, 'v'}, |
{ "chroot", 1, NULL, 'r'}, |
494 |
{ "exec", 1, NULL, 'x'}, |
{ "verbose", 0, NULL, 'v'}, |
495 |
{ "chuid", 1, NULL, 'c'}, |
{ "exec", 1, NULL, 'x'}, |
496 |
{ "nicelevel", 1, NULL, 'N'}, |
{ "chuid", 1, NULL, 'c'}, |
497 |
|
{ "nicelevel", 1, NULL, 'N'}, |
498 |
{ "background", 0, NULL, 'b'}, |
{ "background", 0, NULL, 'b'}, |
499 |
{ "make-pidfile", 0, NULL, 'm'}, |
{ "make-pidfile", 0, NULL, 'm'}, |
500 |
{ "retry", 1, NULL, 'R'}, |
{ "retry", 1, NULL, 'R'}, |
501 |
{ "chdir", 1, NULL, 'd'}, |
{ "chdir", 1, NULL, 'd'}, |
502 |
{ NULL, 0, NULL, 0} |
{ NULL, 0, NULL, 0} |
503 |
}; |
}; |
504 |
int c; |
int c; |
505 |
|
|
506 |
for (;;) { |
for (;;) { |
507 |
c = getopt_long(argc, argv, "HKSV:a:n:op:qr:s:tu:vx:c:N:bmR:g:d:", |
c = getopt_long(argc, argv, "HKSVa:n:op:qr:e:s:tu:vx:c:N:bmR:g:d:", |
508 |
longopts, (int *) 0); |
longopts, (int *) 0); |
509 |
if (c == -1) |
if (c == -1) |
510 |
break; |
break; |
564 |
case 'r': /* --chroot /new/root */ |
case 'r': /* --chroot /new/root */ |
565 |
changeroot = optarg; |
changeroot = optarg; |
566 |
break; |
break; |
567 |
|
case 'e': /* --env <env-name> */ |
568 |
|
if (env) |
569 |
|
badusage("Only one --env option is supported, use /usr/bin/env if you need more"); |
570 |
|
env = optarg; |
571 |
|
break; |
572 |
case 'N': /* --nice */ |
case 'N': /* --nice */ |
573 |
nicelevel = atoi(optarg); |
nicelevel = atoi(optarg); |
574 |
break; |
break; |
673 |
|
|
674 |
|
|
675 |
#if defined(OSHURD) |
#if defined(OSHURD) |
676 |
|
static void |
677 |
|
init_procset(void) |
678 |
|
{ |
679 |
|
struct ps_context *context; |
680 |
|
error_t err; |
681 |
|
|
682 |
|
err = ps_context_create(getproc(), &context); |
683 |
|
if (err) |
684 |
|
error(1, err, "ps_context_create"); |
685 |
|
|
686 |
|
err = proc_stat_list_create(context, &procset); |
687 |
|
if (err) |
688 |
|
error(1, err, "proc_stat_list_create"); |
689 |
|
|
690 |
|
err = proc_stat_list_add_all(procset, 0, 0); |
691 |
|
if (err) |
692 |
|
error(1, err, "proc_stat_list_add_all"); |
693 |
|
} |
694 |
|
|
695 |
|
static struct proc_stat * |
696 |
|
get_proc_stat (pid_t pid, ps_flags_t flags) |
697 |
|
{ |
698 |
|
struct proc_stat *ps; |
699 |
|
ps_flags_t wanted_flags = PSTAT_PID | flags; |
700 |
|
|
701 |
|
if (!procset) |
702 |
|
init_procset(); |
703 |
|
|
704 |
|
ps = proc_stat_list_pid_proc_stat(procset, pid); |
705 |
|
if (!ps) |
706 |
|
return NULL; |
707 |
|
if (proc_stat_set_flags(ps, wanted_flags)) |
708 |
|
return NULL; |
709 |
|
if ((proc_stat_flags(ps) & wanted_flags) != wanted_flags) |
710 |
|
return NULL; |
711 |
|
|
712 |
|
return ps; |
713 |
|
} |
714 |
|
|
715 |
static int |
static int |
716 |
pid_is_user(pid_t pid, uid_t uid) |
pid_is_user(pid_t pid, uid_t uid) |
717 |
{ |
{ |
718 |
struct stat sb; |
struct proc_stat *ps; |
|
char buf[32]; |
|
|
struct proc_stat *pstat; |
|
719 |
|
|
720 |
sprintf(buf, "/proc/%d", pid); |
ps = get_proc_stat(pid, PSTAT_OWNER_UID); |
721 |
if (stat(buf, &sb) != 0) |
return ps && proc_stat_owner_uid(ps) == uid; |
|
return 0; |
|
|
return (sb.st_uid == uid); |
|
|
pstat = proc_stat_list_pid_proc_stat (procset, pid); |
|
|
if (pstat == NULL) |
|
|
fatal ("Error getting process information: NULL proc_stat struct"); |
|
|
proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID); |
|
|
return (pstat->owner_uid == uid); |
|
722 |
} |
} |
723 |
|
|
724 |
static int |
static int |
725 |
pid_is_cmd(pid_t pid, const char *name) |
pid_is_cmd(pid_t pid, const char *name) |
726 |
{ |
{ |
727 |
struct proc_stat *pstat; |
struct proc_stat *ps; |
728 |
pstat = proc_stat_list_pid_proc_stat (procset, pid); |
|
729 |
if (pstat == NULL) |
ps = get_proc_stat(pid, PSTAT_ARGS); |
730 |
fatal ("Error getting process information: NULL proc_stat struct"); |
return ps && !strcmp(proc_stat_args(ps), name); |
731 |
proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS); |
} |
732 |
return (!strcmp (name, pstat->args)); |
|
733 |
|
static int |
734 |
|
pid_is_running(pid_t pid) |
735 |
|
{ |
736 |
|
return get_proc_stat(pid, 0) != NULL; |
737 |
} |
} |
|
#endif /* OSHURD */ |
|
738 |
|
|
739 |
|
#else /* !OSHURD */ |
740 |
|
|
741 |
static int |
static int |
742 |
pid_is_running(pid_t pid) |
pid_is_running(pid_t pid) |
754 |
return 1; |
return 1; |
755 |
} |
} |
756 |
|
|
757 |
|
#endif /* OSHURD */ |
758 |
|
|
759 |
static void |
static void |
760 |
check(pid_t pid) |
check(pid_t pid) |
761 |
{ |
{ |
762 |
#if defined(OSLinux) || defined(OShpux) |
#if defined(OSLinux) || defined(OShpux) |
763 |
if (execname && !pid_is_exec(pid, &exec_stat)) |
if (execname && !pid_is_exec(pid, &exec_stat)) |
764 |
#elif defined(OSHURD) || defined(OSFreeBSD) || defined(OSNetBSD) |
return; |
765 |
/* I will try this to see if it works */ |
#elif defined(OSHURD) || defined(OSFreeBSD) || defined(OSNetBSD) || defined(OSDarwin) |
766 |
|
/* I will try this to see if it works */ |
767 |
if (execname && !pid_is_cmd(pid, execname)) |
if (execname && !pid_is_cmd(pid, execname)) |
|
#endif |
|
768 |
return; |
return; |
769 |
|
#endif |
770 |
if (userspec && !pid_is_user(pid, user_id)) |
if (userspec && !pid_is_user(pid, user_id)) |
771 |
return; |
return; |
772 |
if (cmdname && !pid_is_cmd(pid, cmdname)) |
if (cmdname && !pid_is_cmd(pid, cmdname)) |
823 |
|
|
824 |
|
|
825 |
#if defined(OSHURD) |
#if defined(OSHURD) |
826 |
error_t |
static int |
827 |
check_all(void *ptr) |
check_proc_stat (struct proc_stat *ps) |
828 |
{ |
{ |
829 |
struct proc_stat *pstat = ptr; |
check(ps->pid); |
|
|
|
|
check(pstat->pid); |
|
830 |
return 0; |
return 0; |
831 |
} |
} |
832 |
|
|
833 |
static void |
static void |
834 |
do_procinit(void) |
do_procinit(void) |
835 |
{ |
{ |
836 |
struct ps_context *context; |
if (!procset) |
837 |
error_t err; |
init_procset(); |
838 |
|
|
839 |
err = ps_context_create(getproc(), &context); |
proc_stat_list_for_each (procset, check_proc_stat); |
|
if (err) |
|
|
error(1, err, "ps_context_create"); |
|
|
|
|
|
err = proc_stat_list_create(context, &procset); |
|
|
if (err) |
|
|
error(1, err, "proc_stat_list_create"); |
|
|
|
|
|
err = proc_stat_list_add_all(procset, 0, 0); |
|
|
if (err) |
|
|
error(1, err, "proc_stat_list_add_all"); |
|
|
|
|
|
/* Check all pids */ |
|
|
ihash_iterate(context->procs, check_all); |
|
840 |
} |
} |
841 |
#endif /* OSHURD */ |
#endif /* OSHURD */ |
842 |
|
|
843 |
|
|
844 |
#if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD) |
#if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD) |
845 |
|
|
846 |
|
# if defined(OSNetBSD) |
847 |
|
# define _KINFO_PROC2 kinfo_proc2 |
848 |
|
# define _GET_KINFO_UID(kp) (kp->p_ruid) |
849 |
|
# define _GET_KINFO_COMM(kp) (kp->p_comm) |
850 |
|
# else |
851 |
|
# define _KINFO_PROC2 kinfo_proc |
852 |
|
# define _GET_KINFO_UID(kp) (kp->ki_ruid) |
853 |
|
# define _GET_KINFO_COMM(kp) (kp->ki_comm) |
854 |
|
# endif |
855 |
|
|
856 |
static int |
static int |
857 |
pid_is_cmd(pid_t pid, const char *name) |
pid_is_cmd(pid_t pid, const char *name) |
858 |
{ |
{ |
859 |
kvm_t *kd; |
kvm_t *kd; |
860 |
int nentries, argv_len=0; |
int nentries, argv_len=0; |
861 |
struct kinfo_proc *kp; |
struct kinfo_proc *kp; |
862 |
char errbuf[_POSIX2_LINE_MAX], buf[_POSIX2_LINE_MAX]; |
char errbuf[_POSIX2_LINE_MAX], buf[_POSIX2_LINE_MAX]; |
863 |
char **pid_argv_p; |
char **pid_argv_p; |
864 |
char *start_argv_0_p, *end_argv_0_p; |
char *start_argv_0_p, *end_argv_0_p; |
865 |
|
|
866 |
|
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); |
867 |
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); |
if (kd == 0) |
868 |
if (kd == 0) |
errx(1, "%s", errbuf); |
869 |
errx(1, "%s", errbuf); |
if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0) |
870 |
if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0) |
errx(1, "%s", kvm_geterr(kd)); |
|
errx(1, "%s", kvm_geterr(kd)); |
|
871 |
if ((pid_argv_p = kvm_getargv(kd, kp, argv_len)) == 0) |
if ((pid_argv_p = kvm_getargv(kd, kp, argv_len)) == 0) |
872 |
errx(1, "%s", kvm_geterr(kd)); |
errx(1, "%s", kvm_geterr(kd)); |
873 |
|
|
874 |
start_argv_0_p = *pid_argv_p; |
start_argv_0_p = *pid_argv_p; |
875 |
/* find and compare string */ |
/* find and compare string */ |
876 |
|
|
877 |
/* find end of argv[0] then copy and cut of str there. */ |
/* find end of argv[0] then copy and cut of str there. */ |
878 |
if ((end_argv_0_p = strchr(*pid_argv_p, ' ')) == 0 ) |
if ((end_argv_0_p = strchr(*pid_argv_p, ' ')) == 0 ) |
879 |
/* There seems to be no space, so we have the command |
/* There seems to be no space, so we have the command |
880 |
* allready in its desired form. */ |
* allready in its desired form. */ |
881 |
start_argv_0_p = *pid_argv_p; |
start_argv_0_p = *pid_argv_p; |
882 |
else { |
else { |
883 |
/* Tests indicate that this never happens, since |
/* Tests indicate that this never happens, since |
884 |
* kvm_getargv itselfe cuts of tailing stuff. This is |
* kvm_getargv itselfe cuts of tailing stuff. This is |
885 |
* not what the manpage says, however. */ |
* not what the manpage says, however. */ |
886 |
strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p)); |
strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p)); |
887 |
buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0'; |
buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0'; |
888 |
start_argv_0_p = buf; |
start_argv_0_p = buf; |
889 |
} |
} |
890 |
|
|
891 |
if (strlen(name) != strlen(start_argv_0_p)) |
if (strlen(name) != strlen(start_argv_0_p)) |
892 |
return 0; |
return 0; |
893 |
return (strcmp(name, start_argv_0_p) == 0) ? 1 : 0; |
return (strcmp(name, start_argv_0_p) == 0) ? 1 : 0; |
894 |
} |
} |
895 |
|
|
896 |
static int |
static int |
897 |
pid_is_user(pid_t pid, uid_t uid) |
pid_is_user(pid_t pid, uid_t uid) |
898 |
{ |
{ |
899 |
kvm_t *kd; |
kvm_t *kd; |
900 |
int nentries; /* Value not used */ |
int nentries; /* Value not used */ |
901 |
uid_t proc_uid; |
uid_t proc_uid; |
902 |
struct kinfo_proc *kp; |
struct _KINFO_PROC2 *kp; |
903 |
char errbuf[_POSIX2_LINE_MAX]; |
char errbuf[_POSIX2_LINE_MAX]; |
904 |
|
|
|
|
|
905 |
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); |
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); |
906 |
if (kd == 0) |
if (kd == 0) |
907 |
errx(1, "%s", errbuf); |
errx(1, "%s", errbuf); |
908 |
if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0) |
if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0) |
909 |
errx(1, "%s", kvm_geterr(kd)); |
errx(1, "%s", kvm_geterr(kd)); |
910 |
if (kp->ki_ruid ) |
if (_GET_KINFO_UID(kp)) |
911 |
kvm_read(kd, (u_long)&(kp->ki_ruid), |
kvm_read(kd, (u_long)&(_GET_KINFO_UID(kp)), |
912 |
&proc_uid, sizeof(uid_t)); |
&proc_uid, sizeof(uid_t)); |
913 |
else |
else |
914 |
return 0; |
return 0; |
920 |
{ |
{ |
921 |
kvm_t *kd; |
kvm_t *kd; |
922 |
int nentries; |
int nentries; |
923 |
struct kinfo_proc *kp; |
struct _KINFO_PROC2 *kp; |
924 |
char errbuf[_POSIX2_LINE_MAX], *pidexec; |
char errbuf[_POSIX2_LINE_MAX], *pidexec; |
925 |
|
|
926 |
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); |
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); |
928 |
errx(1, "%s", errbuf); |
errx(1, "%s", errbuf); |
929 |
if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0) |
if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0) |
930 |
errx(1, "%s", kvm_geterr(kd)); |
errx(1, "%s", kvm_geterr(kd)); |
931 |
pidexec = kp->ki_comm; |
pidexec = _GET_KINFO_COMM(kp); |
932 |
if (strlen(name) != strlen(pidexec)) |
if (strlen(name) != strlen(pidexec)) |
933 |
return 0; |
return 0; |
934 |
return (strcmp(name, pidexec) == 0) ? 1 : 0; |
return (strcmp(name, pidexec) == 0) ? 1 : 0; |
943 |
|
|
944 |
#endif /* OSOpenBSD */ |
#endif /* OSOpenBSD */ |
945 |
|
|
946 |
|
#if defined(OSDarwin) |
947 |
|
int |
948 |
|
pid_is_user(pid_t pid, uid_t uid) |
949 |
|
{ |
950 |
|
int mib[4]; |
951 |
|
size_t size; |
952 |
|
struct kinfo_proc ki; |
953 |
|
|
954 |
|
size = sizeof(ki); |
955 |
|
mib[0] = CTL_KERN; |
956 |
|
mib[1] = KERN_PROC; |
957 |
|
mib[2] = KERN_PROC_PID; |
958 |
|
mib[3] = pid; |
959 |
|
if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0) |
960 |
|
errx(1, "%s", "Failure calling sysctl"); |
961 |
|
return (uid == ki.kp_eproc.e_pcred.p_ruid); |
962 |
|
} |
963 |
|
|
964 |
|
static int |
965 |
|
pid_is_cmd(pid_t pid, const char *name) |
966 |
|
{ |
967 |
|
int mib[4]; |
968 |
|
size_t size; |
969 |
|
struct kinfo_proc ki; |
970 |
|
|
971 |
|
size = sizeof(ki); |
972 |
|
mib[0] = CTL_KERN; |
973 |
|
mib[1] = KERN_PROC; |
974 |
|
mib[2] = KERN_PROC_PID; |
975 |
|
mib[3] = pid; |
976 |
|
if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0) |
977 |
|
errx(1, "%s", "Failure calling sysctl"); |
978 |
|
return (!strncmp(name, ki.kp_proc.p_comm, MAXCOMLEN)); |
979 |
|
} |
980 |
|
|
981 |
|
static void |
982 |
|
do_procinit(void) |
983 |
|
{ |
984 |
|
int mib[3]; |
985 |
|
size_t size; |
986 |
|
int nprocs, ret, i; |
987 |
|
struct kinfo_proc *procs = NULL, *newprocs; |
988 |
|
|
989 |
|
mib[0] = CTL_KERN; |
990 |
|
mib[1] = KERN_PROC; |
991 |
|
mib[2] = KERN_PROC_ALL; |
992 |
|
ret = sysctl(mib, 3, NULL, &size, NULL, 0); |
993 |
|
/* Allocate enough memory for entire process table */ |
994 |
|
do { |
995 |
|
size += size / 10; |
996 |
|
newprocs = realloc(procs, size); |
997 |
|
if (newprocs == NULL) { |
998 |
|
if (procs) |
999 |
|
free(procs); |
1000 |
|
errx(1, "%s", "Could not reallocate memory"); |
1001 |
|
} |
1002 |
|
procs = newprocs; |
1003 |
|
ret = sysctl(mib, 3, procs, &size, NULL, 0); |
1004 |
|
} while (ret >= 0 && errno == ENOMEM); |
1005 |
|
|
1006 |
|
if (ret < 0) |
1007 |
|
errx(1, "%s", "Failure calling sysctl"); |
1008 |
|
|
1009 |
|
/* Verify size of proc structure */ |
1010 |
|
if (size % sizeof(struct kinfo_proc) != 0) |
1011 |
|
errx(1, "%s", "proc size mismatch, userland out of sync with kernel"); |
1012 |
|
nprocs = size / sizeof(struct kinfo_proc); |
1013 |
|
for (i = 0; i < nprocs; i++) { |
1014 |
|
check(procs[i].kp_proc.p_pid); |
1015 |
|
} |
1016 |
|
} |
1017 |
|
#endif /* OSDarwin */ |
1018 |
|
|
1019 |
#if defined(OShpux) |
#if defined(OShpux) |
1020 |
static int |
static int |
1056 |
int idx = 0; |
int idx = 0; |
1057 |
|
|
1058 |
while ((count = pstat_getproc(pst, sizeof(pst[0]), 10, idx)) > 0) { |
while ((count = pstat_getproc(pst, sizeof(pst[0]), 10, idx)) > 0) { |
1059 |
for (i = 0; i < count; i++) |
for (i = 0; i < count; i++) |
1060 |
check(pst[i].pst_pid); |
check(pst[i].pst_pid); |
1061 |
idx = pst[count - 1].pst_idx + 1; |
idx = pst[count - 1].pst_idx + 1; |
1062 |
} |
} |
1063 |
} |
} |
1064 |
#endif /* OShpux */ |
#endif /* OShpux */ |
1068 |
do_findprocs(void) |
do_findprocs(void) |
1069 |
{ |
{ |
1070 |
clear(&found); |
clear(&found); |
1071 |
|
|
1072 |
if (pidfile) |
if (pidfile) |
1073 |
do_pidfile(pidfile); |
do_pidfile(pidfile); |
1074 |
else |
else |
1081 |
{ |
{ |
1082 |
struct pid_list *p; |
struct pid_list *p; |
1083 |
|
|
1084 |
do_findprocs(); |
do_findprocs(); |
1085 |
|
|
1086 |
*n_killed = 0; |
*n_killed = 0; |
1087 |
*n_notkilled = 0; |
*n_notkilled = 0; |
1088 |
|
|
1089 |
if (!found) |
if (!found) |
1090 |
return; |
return; |
1091 |
|
|
1092 |
clear(&killed); |
clear(&killed); |
1093 |
|
|
1094 |
for (p = found; p; p = p->next) { |
for (p = found; p; p = p->next) { |
1095 |
if (testmode) { |
if (testmode) { |
1098 |
(*n_killed)++; |
(*n_killed)++; |
1099 |
} else if (kill(p->pid, signal_nr) == 0) { |
} else if (kill(p->pid, signal_nr) == 0) { |
1100 |
push(&killed, p->pid); |
push(&killed, p->pid); |
1101 |
(*n_killed)++; |
(*n_killed)++; |
1102 |
} else { |
} else { |
1103 |
printf("%s: warning: failed to kill %d: %s\n", |
printf("%s: warning: failed to kill %d: %s\n", |
1104 |
progname, p->pid, strerror(errno)); |
progname, p->pid, strerror(errno)); |
1105 |
(*n_notkilled)++; |
(*n_notkilled)++; |
1106 |
} |
} |
1107 |
} |
} |
1108 |
if (quietmode < 0 && killed) { |
if (quietmode < 0 && killed) { |
1109 |
printf("Stopped %s (pid", what_stop); |
printf("Stopped %s (pid", what_stop); |
1110 |
for (p = killed; p; p = p->next) |
for (p = killed; p; p = p->next) |
1111 |
printf(" %d", p->pid); |
printf(" %d", p->pid); |
1112 |
putchar(')'); |
putchar(')'); |
1113 |
if (retry_nr > 0) |
if (retry_nr > 0) |
1114 |
printf(", retry #%d", retry_nr); |
printf(", retry #%d", retry_nr); |
1115 |
printf(".\n"); |
printf(".\n"); |
1116 |
} |
} |
1117 |
} |
} |
1118 |
|
|
1228 |
|
|
1229 |
if (interval.tv_sec == 0 && |
if (interval.tv_sec == 0 && |
1230 |
interval.tv_usec <= MIN_POLL_INTERVAL) |
interval.tv_usec <= MIN_POLL_INTERVAL) |
1231 |
interval.tv_usec = MIN_POLL_INTERVAL; |
interval.tv_usec = MIN_POLL_INTERVAL; |
1232 |
|
|
1233 |
r = select(0,0,0,0,&interval); |
r = select(0,0,0,0,&interval); |
1234 |
if (r < 0 && errno != EINTR) |
if (r < 0 && errno != EINTR) |
1262 |
} |
} |
1263 |
|
|
1264 |
|
|
|
int main(int argc, char **argv) NONRETURNING; |
|
1265 |
int |
int |
1266 |
main(int argc, char **argv) |
main(int argc, char **argv) |
1267 |
{ |
{ |
1275 |
argc -= optind; |
argc -= optind; |
1276 |
argv += optind; |
argv += optind; |
1277 |
|
|
1278 |
if (execname && stat(execname, &exec_stat)) |
if (changeroot == NULL) { |
1279 |
fatal("stat %s: %s", execname, strerror(errno)); |
if (execname && stat(execname, &exec_stat)) |
1280 |
|
fatal("stat %s: %s", execname, strerror(errno)); |
1281 |
|
} else { |
1282 |
|
if (execname) { |
1283 |
|
char *tmp = NULL; |
1284 |
|
|
1285 |
|
tmp = malloc(strlen(changeroot) + strlen(execname) + 1); |
1286 |
|
strncpy(tmp, changeroot, strlen(changeroot)); |
1287 |
|
strncat(tmp, execname, strlen(execname)); |
1288 |
|
|
1289 |
|
if (stat(tmp, &exec_stat)) { |
1290 |
|
fatal("stat %s: %s", tmp, strerror(errno)); |
1291 |
|
free(tmp); |
1292 |
|
} else { |
1293 |
|
free(tmp); |
1294 |
|
} |
1295 |
|
} |
1296 |
|
} |
1297 |
|
|
1298 |
if (userspec && sscanf(userspec, "%d", &user_id) != 1) { |
if (userspec && sscanf(userspec, "%d", &user_id) != 1) { |
1299 |
struct passwd *pw; |
struct passwd *pw; |
1358 |
if (background) { /* ok, we need to detach this process */ |
if (background) { /* ok, we need to detach this process */ |
1359 |
int i; |
int i; |
1360 |
if (quietmode < 0) |
if (quietmode < 0) |
1361 |
printf("Detatching to start %s...", startas); |
printf("Detaching to start %s...", startas); |
1362 |
i = fork(); |
i = fork(); |
1363 |
if (i<0) { |
if (i<0) { |
1364 |
fatal("Unable to fork.\n"); |
fatal("Unable to fork.\n"); |
1381 |
fatal("Unable to alter nice level by %i: %s", nicelevel, |
fatal("Unable to alter nice level by %i: %s", nicelevel, |
1382 |
strerror(errno)); |
strerror(errno)); |
1383 |
} |
} |
|
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); |
|
|
} |
|
1384 |
if (changeroot != NULL) { |
if (changeroot != NULL) { |
1385 |
if (chdir(changeroot) < 0) |
if (chdir(changeroot) < 0) |
1386 |
fatal("Unable to chdir() to %s", changeroot); |
fatal("Unable to chdir() to %s", changeroot); |
1387 |
if (chroot(changeroot) < 0) |
if (chroot(changeroot) < 0) |
1388 |
fatal("Unable to chroot() to %s", changeroot); |
fatal("Unable to chroot() to %s", changeroot); |
1389 |
} |
} |
1390 |
if (changedir != NULL && chdir(changedir) < 0) |
if (chdir(changedir) < 0) |
1391 |
fatal("Unable to chdir() to %s", changedir); |
fatal("Unable to chdir() to %s", changedir); |
1392 |
|
if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */ |
1393 |
|
FILE *pidf = fopen(pidfile, "w"); |
1394 |
|
pid_t pidt = getpid(); |
1395 |
|
if (pidf == NULL) |
1396 |
|
fatal("Unable to open pidfile `%s' for writing: %s", pidfile, |
1397 |
|
strerror(errno)); |
1398 |
|
fprintf(pidf, "%d\n", pidt); |
1399 |
|
fclose(pidf); |
1400 |
|
} |
1401 |
if (changeuser != NULL) { |
if (changeuser != NULL) { |
1402 |
if (setgid(runas_gid)) |
if (setgid(runas_gid)) |
1403 |
fatal("Unable to set gid to %d", runas_gid); |
fatal("Unable to set gid to %d", runas_gid); |
1404 |
if (initgroups(changeuser, runas_gid)) |
if (initgroups(changeuser, runas_gid)) |
1405 |
fatal("Unable to set initgroups() with gid %d", runas_gid); |
fatal("Unable to set initgroups() with gid %d", runas_gid); |
1406 |
if (setuid(runas_uid)) |
if (setuid(runas_uid)) |
1407 |
fatal("Unable to set uid to %s", changeuser); |
fatal("Unable to set uid to %s", changeuser); |
1408 |
} |
} |
1409 |
|
if (env != NULL) { |
1410 |
|
if(putenv(env)) |
1411 |
|
fatal("Unable to set variable: %s", env); |
1412 |
|
} |
1413 |
if (background) { /* continue background setup */ |
if (background) { /* continue background setup */ |
1414 |
int i; |
int i; |
1415 |
#ifdef HAVE_TIOCNOTTY |
#ifdef HAVE_TIOCNOTTY |
1439 |
execv(startas, argv); |
execv(startas, argv); |
1440 |
fatal("Unable to start %s: %s", startas, strerror(errno)); |
fatal("Unable to start %s: %s", startas, strerror(errno)); |
1441 |
} |
} |
|
|
|