/[baselayout]/trunk/src/start-stop-daemon.c
Gentoo

Diff of /trunk/src/start-stop-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 2563 Revision 2708
28#include <signal.h> 28#include <signal.h>
29#include <stddef.h> 29#include <stddef.h>
30#include <stdio.h> 30#include <stdio.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#include <string.h> 32#include <string.h>
33#include <time.h>
33#include <unistd.h> 34#include <unistd.h>
34 35
35#ifdef HAVE_PAM 36#ifdef HAVE_PAM
36#include <security/pam_appl.h> 37#include <security/pam_appl.h>
37 38
44#include "rc-misc.h" 45#include "rc-misc.h"
45#include "strlist.h" 46#include "strlist.h"
46 47
47typedef struct schedulelist 48typedef struct schedulelist
48{ 49{
49 enum 50 enum
50 { 51 {
51 schedule_timeout, 52 schedule_timeout,
52 schedule_signal, 53 schedule_signal,
53 schedule_goto, 54 schedule_goto,
54 schedule_forever 55 schedule_forever
55 } type; 56 } type;
56 int value; 57 int value;
57 struct schedulelist *gotolist; 58 struct schedulelist *gotolist;
58 struct schedulelist *next; 59 struct schedulelist *next;
59} schedulelist_t; 60} schedulelist_t;
60static schedulelist_t *schedule; 61static schedulelist_t *schedule;
61 62
62static char *progname; 63static char *progname;
63static char *changeuser; 64static char *changeuser;
65 66
66extern char **environ; 67extern char **environ;
67 68
68static void free_schedulelist (schedulelist_t **list) 69static void free_schedulelist (schedulelist_t **list)
69{ 70{
70 schedulelist_t *here; 71 schedulelist_t *here;
71 schedulelist_t *next; 72 schedulelist_t *next;
72 73
73 for (here = *list; here; here = next) 74 for (here = *list; here; here = next) {
74 {
75 next = here->next; 75 next = here->next;
76 free (here); 76 free (here);
77 } 77 }
78 78
79 *list = NULL; 79 *list = NULL;
80} 80}
81 81
82static void cleanup (void) 82static void cleanup (void)
83{ 83{
84 if (changeuser) 84 if (changeuser)
85 free (changeuser); 85 free (changeuser);
86 86
87 if (schedule) 87 if (schedule)
88 free_schedulelist (&schedule); 88 free_schedulelist (&schedule);
89 89
90 if (newenv) 90 if (newenv)
91 rc_strlist_free (newenv); 91 rc_strlist_free (newenv);
92} 92}
93 93
94static int get_time(struct timeval *tp)
95{
96 struct timespec ts;
97
98 if (clock_gettime (CLOCK_MONOTONIC, &ts) == -1) {
99 eerror ("clock_gettime: %s", strerror (errno));
100 return (-1);
101 }
102
103 tp->tv_sec = ts.tv_sec;
104 tp->tv_usec = ts.tv_nsec / 1000;
105 return (0);
106}
107
94static int parse_signal (const char *sig) 108static int parse_signal (const char *sig)
95{ 109{
96 typedef struct signalpair 110 typedef struct signalpair
97 { 111 {
98 const char *name; 112 const char *name;
99 int signal; 113 int signal;
100 } signalpair_t; 114 } signalpair_t;
101 115
102 static const signalpair_t signallist[] = { 116 static const signalpair_t signallist[] = {
103 { "ABRT", SIGABRT }, 117 { "ABRT", SIGABRT },
104 { "ALRM", SIGALRM }, 118 { "ALRM", SIGALRM },
105 { "FPE", SIGFPE }, 119 { "FPE", SIGFPE },
106 { "HUP", SIGHUP }, 120 { "HUP", SIGHUP },
107 { "ILL", SIGILL }, 121 { "ILL", SIGILL },
108 { "INT", SIGINT }, 122 { "INT", SIGINT },
109 { "KILL", SIGKILL }, 123 { "KILL", SIGKILL },
110 { "PIPE", SIGPIPE }, 124 { "PIPE", SIGPIPE },
111 { "QUIT", SIGQUIT }, 125 { "QUIT", SIGQUIT },
112 { "SEGV", SIGSEGV }, 126 { "SEGV", SIGSEGV },
113 { "TERM", SIGTERM }, 127 { "TERM", SIGTERM },
114 { "USR1", SIGUSR1 }, 128 { "USR1", SIGUSR1 },
115 { "USR2", SIGUSR2 }, 129 { "USR2", SIGUSR2 },
116 { "CHLD", SIGCHLD }, 130 { "CHLD", SIGCHLD },
117 { "CONT", SIGCONT }, 131 { "CONT", SIGCONT },
118 { "STOP", SIGSTOP }, 132 { "STOP", SIGSTOP },
119 { "TSTP", SIGTSTP }, 133 { "TSTP", SIGTSTP },
120 { "TTIN", SIGTTIN }, 134 { "TTIN", SIGTTIN },
121 { "TTOU", SIGTTOU } 135 { "TTOU", SIGTTOU }
122 }; 136 };
123 137
124 unsigned int i = 0; 138 unsigned int i = 0;
125 char *s; 139 char *s;
126 140
127 if (! sig || strlen (sig) == 0) 141 if (! sig || strlen (sig) == 0)
128 return (-1); 142 return (-1);
129 143
130 if (sscanf (sig, "%u", &i) == 1) 144 if (sscanf (sig, "%u", &i) == 1) {
131 {
132 if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0])) 145 if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0]))
133 return (i); 146 return (i);
134 eerrorx ("%s: `%s' is not a valid signal", progname, sig); 147 eerrorx ("%s: `%s' is not a valid signal", progname, sig);
135 } 148 }
136 149
137 if (strncmp (sig, "SIG", 3) == 0) 150 if (strncmp (sig, "SIG", 3) == 0)
138 s = (char *) sig + 3; 151 s = (char *) sig + 3;
139 else 152 else
140 s = NULL; 153 s = NULL;
141 154
142 for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++) 155 for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++)
143 if (strcmp (sig, signallist[i].name) == 0 || 156 if (strcmp (sig, signallist[i].name) == 0 ||
144 (s && strcmp (s, signallist[i].name) == 0)) 157 (s && strcmp (s, signallist[i].name) == 0))
145 return (signallist[i].signal); 158 return (signallist[i].signal);
146 159
147 eerrorx ("%s: `%s' is not a valid signal", progname, sig); 160 eerrorx ("%s: `%s' is not a valid signal", progname, sig);
148} 161}
149 162
150static void parse_schedule_item (schedulelist_t *item, const char *string) 163static void parse_schedule_item (schedulelist_t *item, const char *string)
151{ 164{
152 const char *after_hyph; 165 const char *after_hyph;
153 int sig; 166 int sig;
154 167
155 if (strcmp (string,"forever") == 0) 168 if (strcmp (string,"forever") == 0)
156 item->type = schedule_forever; 169 item->type = schedule_forever;
157 else if (isdigit (string[0])) 170 else if (isdigit (string[0])) {
158 {
159 item->type = schedule_timeout; 171 item->type = schedule_timeout;
160 errno = 0; 172 errno = 0;
161 if (sscanf (string, "%d", &item->value) != 1) 173 if (sscanf (string, "%d", &item->value) != 1)
162 eerrorx ("%s: invalid timeout value in schedule `%s'", progname, 174 eerrorx ("%s: invalid timeout value in schedule `%s'", progname,
163 string); 175 string);
164 }
165 else if ((after_hyph = string + (string[0] == '-')) && 176 } else if ((after_hyph = string + (string[0] == '-')) &&
166 ((sig = parse_signal (after_hyph)) != -1)) 177 ((sig = parse_signal (after_hyph)) != -1))
167 { 178 {
168 item->type = schedule_signal; 179 item->type = schedule_signal;
169 item->value = (int) sig; 180 item->value = (int) sig;
170 } 181 }
171 else 182 else
172 eerrorx ("%s: invalid schedule item `%s'", progname, string); 183 eerrorx ("%s: invalid schedule item `%s'", progname, string);
173} 184}
174 185
175static void parse_schedule (const char *string, int default_signal) 186static void parse_schedule (const char *string, int default_signal)
176{ 187{
177 char buffer[20]; 188 char buffer[20];
178 const char *slash; 189 const char *slash;
179 int count = 0; 190 int count = 0;
180 schedulelist_t *repeatat = NULL; 191 schedulelist_t *repeatat = NULL;
181 ptrdiff_t len; 192 ptrdiff_t len;
182 schedulelist_t *next; 193 schedulelist_t *next;
183 194
184 if (string) 195 if (string)
185 for (slash = string; *slash; slash++) 196 for (slash = string; *slash; slash++)
186 if (*slash == '/') 197 if (*slash == '/')
187 count++; 198 count++;
188 199
189 if (schedule) 200 if (schedule)
190 free_schedulelist (&schedule); 201 free_schedulelist (&schedule);
191 202
192 schedule = rc_xmalloc (sizeof (schedulelist_t)); 203 schedule = rc_xmalloc (sizeof (schedulelist_t));
193 schedule->gotolist = NULL; 204 schedule->gotolist = NULL;
194 205
195 if (count == 0) 206 if (count == 0) {
196 {
197 schedule->type = schedule_signal; 207 schedule->type = schedule_signal;
198 schedule->value = default_signal; 208 schedule->value = default_signal;
199 schedule->next = rc_xmalloc (sizeof (schedulelist_t)); 209 schedule->next = rc_xmalloc (sizeof (schedulelist_t));
200 next = schedule->next; 210 next = schedule->next;
201 next->type = schedule_timeout; 211 next->type = schedule_timeout;
202 next->gotolist = NULL; 212 next->gotolist = NULL;
203 if (string) 213 if (string) {
204 {
205 if (sscanf (string, "%d", &next->value) != 1) 214 if (sscanf (string, "%d", &next->value) != 1)
206 eerrorx ("%s: invalid timeout value in schedule", progname); 215 eerrorx ("%s: invalid timeout value in schedule", progname);
207 } 216 }
208 else 217 else
209 next->value = 5; 218 next->value = 5;
210 next->next = NULL; 219 next->next = NULL;
211 220
212 return; 221 return;
213 } 222 }
214 223
215 next = schedule; 224 next = schedule;
216 while (string != NULL) 225 while (string != NULL) {
217 {
218 if ((slash = strchr (string, '/'))) 226 if ((slash = strchr (string, '/')))
219 len = slash - string; 227 len = slash - string;
220 else 228 else
221 len = strlen (string); 229 len = strlen (string);
222 230
223 if (len >= (ptrdiff_t) sizeof (buffer)) 231 if (len >= (ptrdiff_t) sizeof (buffer))
224 eerrorx ("%s: invalid schedule item, far too long", progname); 232 eerrorx ("%s: invalid schedule item, far too long", progname);
225 233
226 memcpy (buffer, string, len); 234 memcpy (buffer, string, len);
227 buffer[len] = 0; 235 buffer[len] = 0;
228 string = slash ? slash + 1 : NULL; 236 string = slash ? slash + 1 : NULL;
229 237
230 parse_schedule_item (next, buffer); 238 parse_schedule_item (next, buffer);
231 if (next->type == schedule_forever) 239 if (next->type == schedule_forever) {
232 {
233 if (repeatat) 240 if (repeatat)
234 eerrorx ("%s: invalid schedule, `forever' appears more than once", 241 eerrorx ("%s: invalid schedule, `forever' appears more than once",
235 progname); 242 progname);
236 243
237 repeatat = next; 244 repeatat = next;
238 continue; 245 continue;
239 } 246 }
240 247
241 if (string) 248 if (string) {
242 { 249 next->next = rc_xmalloc (sizeof (schedulelist_t));
250 next = next->next;
251 next->gotolist = NULL;
252 }
253 }
254
255 if (repeatat) {
243 next->next = rc_xmalloc (sizeof (schedulelist_t)); 256 next->next = rc_xmalloc (sizeof (schedulelist_t));
244 next = next->next; 257 next = next->next;
245 next->gotolist = NULL;
246 }
247 }
248
249 if (repeatat)
250 {
251 next->next = rc_xmalloc (sizeof (schedulelist_t));
252 next = next->next;
253 next->type = schedule_goto; 258 next->type = schedule_goto;
254 next->value = 0; 259 next->value = 0;
255 next->gotolist = repeatat; 260 next->gotolist = repeatat;
256 } 261 }
257 262
258 next->next = NULL; 263 next->next = NULL;
259 return; 264 return;
260} 265}
261 266
262static pid_t get_pid (const char *pidfile, bool quiet) 267static pid_t get_pid (const char *pidfile, bool quiet)
263{ 268{
264 FILE *fp; 269 FILE *fp;
265 pid_t pid; 270 pid_t pid;
266 271
267 if (! pidfile) 272 if (! pidfile)
268 return (-1); 273 return (-1);
269 274
270 if ((fp = fopen (pidfile, "r")) == NULL) 275 if ((fp = fopen (pidfile, "r")) == NULL) {
271 {
272 if (! quiet) 276 if (! quiet)
273 eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno)); 277 eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno));
274 return (-1); 278 return (-1);
275 } 279 }
276 280
277 if (fscanf (fp, "%d", &pid) != 1) 281 if (fscanf (fp, "%d", &pid) != 1) {
278 {
279 if (! quiet) 282 if (! quiet)
280 eerror ("%s: no pid found in `%s'", progname, pidfile); 283 eerror ("%s: no pid found in `%s'", progname, pidfile);
281 fclose (fp); 284 fclose (fp);
282 return (-1); 285 return (-1);
283 } 286 }
284 fclose (fp); 287 fclose (fp);
285 288
286 return (pid); 289 return (pid);
287} 290}
288 291
289/* return number of processed killed, -1 on error */ 292/* return number of processed killed, -1 on error */
290static int do_stop (const char *exec, const char *cmd, 293static int do_stop (const char *exec, const char *cmd,
291 const char *pidfile, uid_t uid,int sig, 294 const char *pidfile, uid_t uid,int sig,
292 bool quiet, bool verbose, bool test) 295 bool quiet, bool verbose, bool test)
293{ 296{
294 pid_t *pids; 297 pid_t *pids;
295 bool killed; 298 bool killed;
296 int nkilled = 0; 299 int nkilled = 0;
297 pid_t pid = 0; 300 pid_t pid = 0;
298 int i; 301 int i;
299 302
300 if (pidfile) 303 if (pidfile)
301 if ((pid = get_pid (pidfile, quiet)) == -1) 304 if ((pid = get_pid (pidfile, quiet)) == -1)
302 return (quiet ? 0 : -1); 305 return (quiet ? 0 : -1);
303 306
304 if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL) 307 if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL)
305 return (0); 308 return (0);
306 309
307 for (i = 0; pids[i]; i++) 310 for (i = 0; pids[i]; i++) {
308 { 311 if (test) {
309 if (test)
310 {
311 if (! quiet) 312 if (! quiet)
312 einfo ("Would send signal %d to PID %d", sig, pids[i]); 313 einfo ("Would send signal %d to PID %d", sig, pids[i]);
313 nkilled++; 314 nkilled++;
314 continue; 315 continue;
315 } 316 }
316 317
317 if (verbose) 318 if (verbose)
318 ebegin ("Sending signal %d to PID %d", sig, pids[i]); 319 ebegin ("Sending signal %d to PID %d", sig, pids[i]);
319 errno = 0; 320 errno = 0;
320 killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false); 321 killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false);
321 if (! killed) 322 if (! killed) {
322 {
323 if (! quiet) 323 if (! quiet)
324 eerror ("%s: failed to send signal %d to PID %d: %s", 324 eerror ("%s: failed to send signal %d to PID %d: %s",
325 progname, sig, pids[i], strerror (errno)); 325 progname, sig, pids[i], strerror (errno));
326 if (verbose) 326 if (verbose)
327 eend (1, NULL); 327 eend (1, NULL);
328 nkilled = -1; 328 nkilled = -1;
329 } 329 } else {
330 else
331 {
332 if (verbose) 330 if (verbose)
333 eend (0, NULL); 331 eend (0, NULL);
334 if (nkilled != -1) 332 if (nkilled != -1)
335 nkilled++; 333 nkilled++;
336 } 334 }
337 } 335 }
338 336
339 free (pids); 337 free (pids);
340 return (nkilled); 338 return (nkilled);
341} 339}
342 340
343static int run_stop_schedule (const char *exec, const char *cmd, 341static int run_stop_schedule (const char *exec, const char *cmd,
344 const char *pidfile, uid_t uid, 342 const char *pidfile, uid_t uid,
345 bool quiet, bool verbose, bool test) 343 bool quiet, bool verbose, bool test)
346{ 344{
347 schedulelist_t *item = schedule; 345 schedulelist_t *item = schedule;
348 int nkilled = 0; 346 int nkilled = 0;
349 int tkilled = 0; 347 int tkilled = 0;
350 int nrunning = 0; 348 int nrunning = 0;
351 struct timeval tv; 349 struct timeval tv;
352 struct timeval now; 350 struct timeval now;
353 struct timeval stopat; 351 struct timeval stopat;
354 352
355 if (verbose) 353 if (verbose) {
356 {
357 if (pidfile) 354 if (pidfile)
358 einfo ("Will stop PID in pidfile `%s'", pidfile); 355 einfo ("Will stop PID in pidfile `%s'", pidfile);
359 if (uid) 356 if (uid)
360 einfo ("Will stop processes owned by UID %d", uid); 357 einfo ("Will stop processes owned by UID %d", uid);
361 if (exec) 358 if (exec)
362 einfo ("Will stop processes of `%s'", exec); 359 einfo ("Will stop processes of `%s'", exec);
363 if (cmd) 360 if (cmd)
364 einfo ("Will stop processes called `%s'", cmd); 361 einfo ("Will stop processes called `%s'", cmd);
365 } 362 }
366 363
367 while (item) 364 while (item) {
368 {
369 switch (item->type) 365 switch (item->type) {
370 {
371 case schedule_goto: 366 case schedule_goto:
372 item = item->gotolist; 367 item = item->gotolist;
373 continue; 368 continue;
374 369
375 case schedule_signal: 370 case schedule_signal:
376 nrunning = 0; 371 nrunning = 0;
377 nkilled = do_stop (exec, cmd, pidfile, uid, item->value, 372 nkilled = do_stop (exec, cmd, pidfile, uid, item->value,
378 quiet, verbose, test); 373 quiet, verbose, test);
379 if (nkilled == 0) 374 if (nkilled == 0) {
380 {
381 if (tkilled == 0) 375 if (tkilled == 0) {
382 {
383 if (! quiet) 376 if (! quiet)
384 eerror ("%s: no matching processes found", progname); 377 eerror ("%s: no matching processes found", progname);
385 } 378 }
386 return (tkilled); 379 return (tkilled);
387 } 380 }
388 else if (nkilled == -1) 381 else if (nkilled == -1)
389 return (0); 382 return (0);
390 383
391 tkilled += nkilled; 384 tkilled += nkilled;
392 break; 385 break;
393 case schedule_timeout: 386 case schedule_timeout:
394 if (item->value < 1) 387 if (item->value < 1) {
395 { 388 item = NULL;
396 item = NULL; 389 break;
397 break; 390 }
398 }
399 391
400 if (gettimeofday (&stopat, NULL) != 0) 392 if (get_time (&stopat) != 0)
401 { 393 return (0);
402 eerror ("%s: gettimeofday: %s", progname, strerror (errno));
403 return (0);
404 }
405 394
406 stopat.tv_sec += item->value; 395 stopat.tv_sec += item->value;
407 while (1) 396 while (1) {
408 {
409 if ((nrunning = do_stop (exec, cmd, pidfile, 397 if ((nrunning = do_stop (exec, cmd, pidfile,
410 uid, 0, true, false, true)) == 0) 398 uid, 0, true, false, true)) == 0)
411 return (true); 399 return (true);
412 400
413 tv.tv_sec = 0; 401 tv.tv_sec = 0;
414 tv.tv_usec = POLL_INTERVAL; 402 tv.tv_usec = POLL_INTERVAL;
415 if (select (0, 0, 0, 0, &tv) < 0) 403 if (select (0, 0, 0, 0, &tv) < 0) {
416 {
417 if (errno == EINTR) 404 if (errno == EINTR)
418 eerror ("%s: caught an interupt", progname); 405 eerror ("%s: caught an interupt", progname);
419 else 406 else {
420 eerror ("%s: select: %s", progname, strerror (errno)); 407 eerror ("%s: select: %s", progname, strerror (errno));
408 return (0);
409 }
410 }
411
412 if (get_time (&now) != 0)
421 return (0); 413 return (0);
422 }
423
424 if (gettimeofday (&now, NULL) != 0)
425 {
426 eerror ("%s: gettimeofday: %s", progname, strerror (errno));
427 return (0);
428 }
429 if (timercmp (&now, &stopat, >)) 414 if (timercmp (&now, &stopat, >))
415 break;
416 }
430 break; 417 break;
431 }
432 break;
433 418
434 default: 419 default:
435 eerror ("%s: invalid schedule item `%d'", progname, item->type); 420 eerror ("%s: invalid schedule item `%d'", progname, item->type);
436 return (0); 421 return (0);
437 } 422 }
438 423
439 if (item) 424 if (item)
440 item = item->next; 425 item = item->next;
441 } 426 }
442 427
443 if (test || (tkilled > 0 && nrunning == 0)) 428 if (test || (tkilled > 0 && nrunning == 0))
444 return (nkilled); 429 return (nkilled);
445 430
446 if (! quiet) 431 if (! quiet) {
447 {
448 if (nrunning == 1) 432 if (nrunning == 1)
449 eerror ("%s: %d process refused to stop", progname, nrunning); 433 eerror ("%s: %d process refused to stop", progname, nrunning);
450 else 434 else
451 eerror ("%s: %d process(es) refused to stop", progname, nrunning); 435 eerror ("%s: %d process(es) refused to stop", progname, nrunning);
452 } 436 }
453 437
454 return (-nrunning); 438 return (-nrunning);
455} 439}
456 440
457static void handle_signal (int sig) 441static void handle_signal (int sig)
458{ 442{
459 int pid; 443 int pid;
460 int status; 444 int status;
461 int serrno = errno; 445 int serrno = errno;
462 char signame[10] = { '\0' }; 446 char signame[10] = { '\0' };
463 447
464 switch (sig) 448 switch (sig) {
465 {
466 case SIGINT: 449 case SIGINT:
467 if (! signame[0]) 450 if (! signame[0])
468 snprintf (signame, sizeof (signame), "SIGINT"); 451 snprintf (signame, sizeof (signame), "SIGINT");
469 case SIGTERM: 452 case SIGTERM:
470 if (! signame[0]) 453 if (! signame[0])
471 snprintf (signame, sizeof (signame), "SIGTERM"); 454 snprintf (signame, sizeof (signame), "SIGTERM");
472 case SIGQUIT: 455 case SIGQUIT:
473 if (! signame[0]) 456 if (! signame[0])
474 snprintf (signame, sizeof (signame), "SIGQUIT"); 457 snprintf (signame, sizeof (signame), "SIGQUIT");
475 eerrorx ("%s: caught %s, aborting", progname, signame); 458 eerrorx ("%s: caught %s, aborting", progname, signame);
476 459
477 case SIGCHLD: 460 case SIGCHLD:
478 while (1) 461 while (1) {
479 {
480 if ((pid = waitpid (-1, &status, WNOHANG)) < 0) 462 if ((pid = waitpid (-1, &status, WNOHANG)) < 0) {
481 {
482 if (errno != ECHILD) 463 if (errno != ECHILD)
483 eerror ("%s: waitpid: %s", progname, strerror (errno)); 464 eerror ("%s: waitpid: %s", progname, strerror (errno));
484 break; 465 break;
485 } 466 }
486 } 467 }
487 break; 468 break;
488 469
489 default: 470 default:
490 eerror ("%s: caught unknown signal %d", progname, sig); 471 eerror ("%s: caught unknown signal %d", progname, sig);
491 } 472 }
492 473
493 /* Restore errno */ 474 /* Restore errno */
494 errno = serrno; 475 errno = serrno;
495} 476}
496 477
497int main (int argc, char **argv) 478int main (int argc, char **argv)
498{ 479{
499 int devnull_fd = -1; 480 int devnull_fd = -1;
500 481
501#ifdef TIOCNOTTY 482#ifdef TIOCNOTTY
502 int tty_fd = -1; 483 int tty_fd = -1;
503#endif 484#endif
504#ifdef HAVE_PAM 485#ifdef HAVE_PAM
505 pam_handle_t *pamh = NULL; 486 pam_handle_t *pamh = NULL;
506 int pamr; 487 int pamr;
507#endif 488#endif
508 489
509 static struct option longopts[] = { 490 static struct option longopts[] = {
510 { "stop", 0, NULL, 'K'}, 491 { "stop", 0, NULL, 'K'},
511 { "nicelevel", 1, NULL, 'N'}, 492 { "nicelevel", 1, NULL, 'N'},
512 { "retry", 1, NULL, 'R'}, 493 { "retry", 1, NULL, 'R'},
513 { "start", 0, NULL, 'S'}, 494 { "start", 0, NULL, 'S'},
495 { "startas", 1, NULL, 'a'},
514 { "background", 0, NULL, 'b'}, 496 { "background", 0, NULL, 'b'},
515 { "chuid", 1, NULL, 'c'}, 497 { "chuid", 1, NULL, 'c'},
516 { "chdir", 1, NULL, 'd'}, 498 { "chdir", 1, NULL, 'd'},
517 { "group", 1, NULL, 'g'}, 499 { "group", 1, NULL, 'g'},
518 { "make-pidfile", 0, NULL, 'm'}, 500 { "make-pidfile", 0, NULL, 'm'},
519 { "name", 1, NULL, 'n'}, 501 { "name", 1, NULL, 'n'},
520 { "oknodo", 0, NULL, 'o'}, 502 { "oknodo", 0, NULL, 'o'},
521 { "pidfile", 1, NULL, 'p'}, 503 { "pidfile", 1, NULL, 'p'},
522 { "quiet", 0, NULL, 'q'}, 504 { "quiet", 0, NULL, 'q'},
523 { "signal", 1, NULL, 's'}, 505 { "signal", 1, NULL, 's'},
524 { "test", 0, NULL, 't'}, 506 { "test", 0, NULL, 't'},
525 { "user", 1, NULL, 'u'}, 507 { "user", 1, NULL, 'u'},
526 { "chroot", 1, NULL, 'r'}, 508 { "chroot", 1, NULL, 'r'},
527 { "verbose", 0, NULL, 'v'}, 509 { "verbose", 0, NULL, 'v'},
528 { "exec", 1, NULL, 'x'}, 510 { "exec", 1, NULL, 'x'},
529 { "stdout", 1, NULL, '1'}, 511 { "stdout", 1, NULL, '1'},
530 { "stderr", 1, NULL, '2'}, 512 { "stderr", 1, NULL, '2'},
531 { NULL, 0, NULL, 0} 513 { NULL, 0, NULL, 0}
532 }; 514 };
533 int c; 515 int opt;
534 bool start = false; 516 bool start = false;
535 bool stop = false; 517 bool stop = false;
536 bool oknodo = false; 518 bool oknodo = false;
537 bool test = false; 519 bool test = false;
538 bool quiet = false; 520 bool quiet = false;
539 bool verbose = false; 521 bool verbose = false;
540 char *exec = NULL; 522 char *exec = NULL;
541 char *cmd = NULL; 523 char *cmd = NULL;
542 char *pidfile = NULL; 524 char *pidfile = NULL;
543 int sig = SIGTERM; 525 int sig = SIGTERM;
544 uid_t uid = 0; 526 uid_t uid = 0;
545 int nicelevel = 0; 527 int nicelevel = 0;
546 bool background = false; 528 bool background = false;
547 bool makepidfile = false; 529 bool makepidfile = false;
548 uid_t ch_uid = 0; 530 uid_t ch_uid = 0;
549 gid_t ch_gid = 0; 531 gid_t ch_gid = 0;
550 char *ch_root = NULL; 532 char *ch_root = NULL;
551 char *ch_dir = NULL; 533 char *ch_dir = NULL;
552 int tid = 0; 534 int tid = 0;
553 char *redirect_stderr = NULL; 535 char *redirect_stderr = NULL;
554 char *redirect_stdout = NULL; 536 char *redirect_stdout = NULL;
555 int stdout_fd; 537 int stdout_fd;
556 int stderr_fd; 538 int stderr_fd;
557 pid_t pid; 539 pid_t pid;
558 struct timeval tv; 540 struct timeval tv;
559 int i; 541 int i;
560 char *svcname = getenv ("SVCNAME"); 542 char *svcname = getenv ("SVCNAME");
561 char *env; 543 char *env;
562 544
563 progname = argv[0]; 545 progname = argv[0];
564 atexit (cleanup); 546 atexit (cleanup);
565 547
566 signal (SIGINT, handle_signal); 548 signal (SIGINT, handle_signal);
567 signal (SIGQUIT, handle_signal); 549 signal (SIGQUIT, handle_signal);
568 signal (SIGTERM, handle_signal); 550 signal (SIGTERM, handle_signal);
569 551
552 if ((env = getenv ("SSD_NICELEVEL")))
553 if (sscanf (env, "%d", &nicelevel) != 1)
554 eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", progname, env);
555
570 while ((c = getopt_long (argc, argv, 556 while ((opt = getopt_long (argc, argv,
571 "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:", 557 "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:",
572 longopts, (int *) 0)) != -1) 558 longopts, (int *) 0)) != -1)
573 switch (c) 559 switch (opt) {
574 {
575 case 'K': /* --stop */ 560 case 'K': /* --stop */
576 stop = true; 561 stop = true;
577 break; 562 break;
578 563
579 case 'N': /* --nice */ 564 case 'N': /* --nice */
580 if (sscanf (optarg, "%d", &nicelevel) != 1) 565 if (sscanf (optarg, "%d", &nicelevel) != 1)
581 eerrorx ("%s: invalid nice level `%s'", progname, optarg); 566 eerrorx ("%s: invalid nice level `%s'", progname, optarg);
582 break; 567 break;
583 568
584 case 'R': /* --retry <schedule>|<timeout> */ 569 case 'R': /* --retry <schedule>|<timeout> */
585 parse_schedule (optarg, sig); 570 parse_schedule (optarg, sig);
586 break; 571 break;
587 572
588 case 'S': /* --start */ 573 case 'S': /* --start */
589 start = true; 574 start = true;
590 break; 575 break;
591 576
592 case 'b': /* --background */ 577 case 'b': /* --background */
593 background = true; 578 background = true;
594 break; 579 break;
595 580
596 case 'c': /* --chuid <username>|<uid> */ 581 case 'c': /* --chuid <username>|<uid> */
597 /* we copy the string just in case we need the 582 {
598 * argument later. */
599 {
600 char *p = optarg; 583 char *p = optarg;
601 char *cu = strsep (&p, ":"); 584 char *cu = strsep (&p, ":");
585 struct passwd *pw = NULL;
586
602 changeuser = strdup (cu); 587 changeuser = rc_xstrdup (cu);
603 if (sscanf (cu, "%d", &tid) != 1) 588 if (sscanf (cu, "%d", &tid) != 1)
604 { 589 pw = getpwnam (cu);
605 struct passwd *pw = getpwnam (cu); 590 else
591 pw = getpwuid (tid);
592
606 if (! pw) 593 if (! pw)
607 eerrorx ("%s: user `%s' not found", progname, cu); 594 eerrorx ("%s: user `%s' not found", progname, cu);
608 ch_uid = pw->pw_uid; 595 ch_uid = pw->pw_uid;
609 } 596 if (! ch_gid)
610 else 597 ch_gid = pw->pw_gid;
611 ch_uid = tid; 598
612 if (p) 599 if (p) {
613 { 600 struct group *gr = NULL;
614 char *cg = strsep (&p, ":"); 601 char *cg = strsep (&p, ":");
602
615 if (sscanf (cg, "%d", &tid) != 1) 603 if (sscanf (cg, "%d", &tid) != 1)
616 { 604 gr = getgrnam (cg);
617 struct group *gr = getgrnam (cg); 605 else
618 if (! gr) 606 gr = getgrgid (tid);
607
608 if (! gr)
619 eerrorx ("%s: group `%s' not found", progname, cg); 609 eerrorx ("%s: group `%s' not found", progname, cg);
610 ch_gid = gr->gr_gid;
611 }
612 }
613 break;
614
615 case 'd': /* --chdir /new/dir */
616 ch_dir = optarg;
617 break;
618
619 case 'g': /* --group <group>|<gid> */
620 {
621 struct group *gr = getgrnam (optarg);
622
623 if (sscanf (optarg, "%d", &tid) != 1)
624 gr = getgrnam (optarg);
625 else
626 gr = getgrgid (tid);
627
628 if (! gr)
629 eerrorx ("%s: group `%s' not found", progname, optarg);
620 ch_gid = gr->gr_gid; 630 ch_gid = gr->gr_gid;
631 }
632 break;
633
634 case 'm': /* --make-pidfile */
635 makepidfile = true;
636 break;
637
638 case 'n': /* --name <process-name> */
639 cmd = optarg;
640 break;
641
642 case 'o': /* --oknodo */
643 oknodo = true;
644 break;
645
646 case 'p': /* --pidfile <pid-file> */
647 pidfile = optarg;
648 break;
649
650 case 'q': /* --quiet */
651 quiet = true;
652 break;
653
654 case 's': /* --signal <signal> */
655 sig = parse_signal (optarg);
656 break;
657
658 case 't': /* --test */
659 test = true;
660 break;
661
662 case 'u': /* --user <username>|<uid> */
663 if (sscanf (optarg, "%d", &tid) != 1) {
664 struct passwd *pw = getpwnam (optarg);
665 if (! pw)
666 eerrorx ("%s: user `%s' not found", progname, optarg);
667 uid = pw->pw_uid;
668 } else
669 uid = tid;
670 break;
671
672 case 'r': /* --chroot /new/root */
673 ch_root = optarg;
674 break;
675
676 case 'v': /* --verbose */
677 verbose = true;
678 break;
679
680 case 'a':
681 case 'x': /* --exec <executable> */
682 exec = optarg;
683 break;
684
685 case '1': /* --stdout /path/to/stdout.lgfile */
686 redirect_stdout = optarg;
687 break;
688
689 case '2': /* --stderr /path/to/stderr.logfile */
690 redirect_stderr = optarg;
691 break;
692
693 default:
694 exit (EXIT_FAILURE);
621 } 695 }
696
697 /* Respect RC as well as how we are called */
698 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
699 quiet = true;
700
701 /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq
702 * instead of forcing --stop --oknodo as well */
703 if (! start && ! stop)
704 if (sig != SIGINT &&
705 sig != SIGTERM &&
706 sig != SIGQUIT &&
707 sig != SIGKILL)
708 {
709 oknodo = true;
710 stop = true;
711 }
712
713 if (start == stop)
714 eerrorx ("%s: need one of --start or --stop", progname);
715
716 if (start && ! exec)
717 eerrorx ("%s: --start needs --exec", progname);
718
719 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
720 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
721
722 if (makepidfile && ! pidfile)
723 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
724
725 if (background && ! start)
726 eerrorx ("%s: --background is only relevant with --start", progname);
727
728 if ((redirect_stdout || redirect_stderr) && ! background)
729 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
730 progname);
731
732 argc -= optind;
733 argv += optind;
734
735 /* Validate that the binary rc_exists if we are starting */
736 if (exec && start) {
737 char *tmp;
738 if (ch_root)
739 tmp = rc_strcatpaths (ch_root, exec, (char *) NULL);
622 else 740 else
623 ch_gid = tid;
624 }
625 }
626 break;
627
628 case 'd': /* --chdir /new/dir */
629 ch_dir = optarg;
630 break;
631
632 case 'g': /* --group <group>|<gid> */
633 if (sscanf (optarg, "%d", &tid) != 1)
634 {
635 struct group *gr = getgrnam (optarg);
636 if (! gr)
637 eerrorx ("%s: group `%s' not found", progname, optarg);
638 ch_gid = gr->gr_gid;
639 }
640 else
641 ch_gid = tid;
642 break;
643
644 case 'm': /* --make-pidfile */
645 makepidfile = true;
646 break;
647
648 case 'n': /* --name <process-name> */
649 cmd = optarg;
650 break;
651
652 case 'o': /* --oknodo */
653 oknodo = true;
654 break;
655
656 case 'p': /* --pidfile <pid-file> */
657 pidfile = optarg;
658 break;
659
660 case 'q': /* --quiet */
661 quiet = true;
662 break;
663
664 case 's': /* --signal <signal> */
665 sig = parse_signal (optarg);
666 break;
667
668 case 't': /* --test */
669 test = true;
670 break;
671
672 case 'u': /* --user <username>|<uid> */
673 if (sscanf (optarg, "%d", &tid) != 1)
674 {
675 struct passwd *pw = getpwnam (optarg);
676 if (! pw)
677 eerrorx ("%s: user `%s' not found", progname, optarg);
678 uid = pw->pw_uid;
679 }
680 else
681 uid = tid;
682 break;
683
684 case 'r': /* --chroot /new/root */
685 ch_root = optarg;
686 break;
687
688 case 'v': /* --verbose */
689 verbose = true;
690 break;
691
692 case 'x': /* --exec <executable> */
693 exec = optarg;
694 break;
695
696 case '1': /* --stdout /path/to/stdout.lgfile */
697 redirect_stdout = optarg;
698 break;
699
700 case '2': /* --stderr /path/to/stderr.logfile */
701 redirect_stderr = optarg;
702 break;
703
704 default:
705 exit (EXIT_FAILURE);
706 }
707
708 /* Respect RC as well as how we are called */
709 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
710 quiet = true;
711
712 if (start == stop)
713 eerrorx ("%s: need one of --start or --stop", progname);
714
715 if (start && ! exec)
716 eerrorx ("%s: --start needs --exec", progname);
717
718 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
719 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
720
721 if (makepidfile && ! pidfile)
722 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
723
724 if (background && ! start)
725 eerrorx ("%s: --background is only relevant with --start", progname);
726
727 if ((redirect_stdout || redirect_stderr) && ! background)
728 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
729 progname);
730
731 argc -= optind;
732 argv += optind;
733
734 /* Validate that the binary rc_exists if we are starting */
735 if (exec && start)
736 {
737 char *tmp;
738 if (ch_root)
739 tmp = rc_strcatpaths (ch_root, exec, (char *) NULL);
740 else
741 tmp = exec; 741 tmp = exec;
742 if (! rc_is_file (tmp)) 742 if (! rc_is_file (tmp)) {
743 {
744 eerror ("%s: %s does not exist", progname, tmp); 743 eerror ("%s: %s does not exist", progname, tmp);
745 if (ch_root) 744 if (ch_root)
746 free (tmp); 745 free (tmp);
747 exit (EXIT_FAILURE); 746 exit (EXIT_FAILURE);
748 } 747 }
749 if (ch_root) 748 if (ch_root)
750 free (tmp); 749 free (tmp);
751 } 750 }
752 751
753 if (stop) 752 if (stop) {
754 { 753 int result;
755 int result;
756 754
757 if (! schedule) 755 if (! schedule) {
758 {
759 if (test || oknodo) 756 if (test || oknodo)
760 parse_schedule ("0", sig); 757 parse_schedule ("0", sig);
761 else 758 else
762 parse_schedule (NULL, sig); 759 parse_schedule (NULL, sig);
763 } 760 }
764 761
765 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); 762 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test);
766 if (test || oknodo) 763 if (test || oknodo)
767 return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); 764 return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
768 if (result < 1) 765 if (result < 1)
769 exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 766 exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
770 767
771 if (pidfile && rc_is_file (pidfile)) 768 if (pidfile && rc_is_file (pidfile))
772 unlink (pidfile); 769 unlink (pidfile);
773 770
774 if (svcname) 771 if (svcname)
775 rc_set_service_daemon (svcname, exec, cmd, pidfile, false); 772 rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
776 773
777 exit (EXIT_SUCCESS); 774 exit (EXIT_SUCCESS);
778 } 775 }
779 776
780 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) 777 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
781 eerrorx ("%s: %s is already running", progname, exec); 778 eerrorx ("%s: %s is already running", progname, exec);
782 779
783 if (test) 780 if (test) {
784 { 781 if (quiet)
785 if (quiet) 782 exit (EXIT_SUCCESS);
783
784 einfon ("Would start %s", exec);
785 while (argc-- > 0)
786 printf("%s ", *argv++);
787 printf ("\n");
788 eindent ();
789 if (ch_uid != 0)
790 einfo ("as user %d", ch_uid);
791 if (ch_gid != 0)
792 einfo ("as group %d", ch_gid);
793 if (ch_root)
794 einfo ("in root `%s'", ch_root);
795 if (ch_dir)
796 einfo ("in dir `%s'", ch_dir);
797 if (nicelevel != 0)
798 einfo ("with a priority of %d", nicelevel);
799 eoutdent ();
800 exit (EXIT_SUCCESS);
801 }
802
803 /* Ensure this is unset, so if the daemon does /etc/init.d/foo
804 Then we filter the environment accordingly */
805 unsetenv ("RC_SOFTLEVEL");
806
807 if (verbose) {
808 ebegin ("Detaching to start `%s'", exec);
809 eindent ();
810 }
811
812 if (background)
813 signal (SIGCHLD, handle_signal);
814
815 *--argv = exec;
816 if ((pid = fork ()) == -1)
817 eerrorx ("%s: fork: %s", progname, strerror (errno));
818
819 /* Child process - lets go! */
820 if (pid == 0) {
821 pid_t mypid = getpid ();
822
823#ifdef TIOCNOTTY
824 tty_fd = open("/dev/tty", O_RDWR);
825#endif
826
827 devnull_fd = open("/dev/null", O_RDWR);
828
829 if (nicelevel) {
830 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
831 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
832 strerror(errno));
833 }
834
835 if (ch_root && chroot (ch_root) < 0)
836 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
837
838 if (ch_dir && chdir (ch_dir) < 0)
839 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
840
841 if (makepidfile && pidfile) {
842 FILE *fp = fopen (pidfile, "w");
843 if (! fp)
844 eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror
845 (errno));
846 fprintf (fp, "%d\n", mypid);
847 fclose (fp);
848 }
849
850#ifdef HAVE_PAM
851 if (changeuser != NULL)
852 pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
853 else
854 pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
855
856 if (pamr == PAM_SUCCESS)
857 pamr = pam_authenticate (pamh, PAM_SILENT);
858 if (pamr == PAM_SUCCESS)
859 pamr = pam_acct_mgmt (pamh, PAM_SILENT);
860 if (pamr == PAM_SUCCESS)
861 pamr = pam_open_session (pamh, PAM_SILENT);
862 if (pamr != PAM_SUCCESS)
863 eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr));
864#endif
865
866 if (ch_gid && setgid (ch_gid))
867 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
868 if (changeuser && initgroups (changeuser, ch_gid))
869 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
870 if (ch_uid && setuid (ch_uid))
871 eerrorx ("%s: unable to set userid to %d", progname, ch_uid);
872 else {
873 struct passwd *passwd = getpwuid (ch_uid);
874 if (passwd) {
875 unsetenv ("HOME");
876 if (passwd->pw_dir)
877 setenv ("HOME", passwd->pw_dir, 1);
878 unsetenv ("USER");
879 if (passwd->pw_name)
880 setenv ("USER", passwd->pw_name, 1);
881 }
882 }
883
884 /* Close any fd's to the passwd database */
885 endpwent ();
886
887#ifdef TIOCNOTTY
888 ioctl(tty_fd, TIOCNOTTY, 0);
889 close(tty_fd);
890#endif
891
892 /* Clean the environment of any RC_ variables */
893 STRLIST_FOREACH (environ, env, i)
894 if (env && strncmp (env, "RC_", 3) != 0) {
895 /* For the path character, remove the rcscript bin dir from it */
896 if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
897 strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
898 {
899 char *path = env;
900 char *newpath;
901 int len;
902 path += strlen ("PATH=" RC_LIBDIR "bin:");
903 len = sizeof (char *) * strlen (path) + 6;
904 newpath = rc_xmalloc (len);
905 snprintf (newpath, len, "PATH=%s", path);
906 newenv = rc_strlist_add (newenv, newpath);
907 free (newpath);
908 } else
909 newenv = rc_strlist_add (newenv, env);
910 }
911
912 umask (022);
913
914 stdout_fd = devnull_fd;
915 stderr_fd = devnull_fd;
916 if (redirect_stdout) {
917 if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
918 S_IRUSR | S_IWUSR)) == -1)
919 eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
920 progname, redirect_stdout, strerror (errno));
921 }
922 if (redirect_stderr) {
923 if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
924 S_IRUSR | S_IWUSR)) == -1)
925 eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
926 progname, redirect_stderr, strerror (errno));
927 }
928
929 if (background) {
930 /* Hmmm, some daemons may need stdin? */
931 dup2 (devnull_fd, STDIN_FILENO);
932 dup2 (stdout_fd, STDOUT_FILENO);
933 dup2 (stderr_fd, STDERR_FILENO);
934 }
935
936 for (i = getdtablesize () - 1; i >= 3; --i)
937 close(i);
938
939 setsid ();
940
941 execve (exec, argv, newenv);
942#ifdef HAVE_PAM
943 if (pamr == PAM_SUCCESS)
944 pam_close_session (pamh, PAM_SILENT);
945#endif
946 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
947 }
948
949 /* Parent process */
950 if (! background) {
951 /* As we're not backgrounding the process, wait for our pid to return */
952 int status = 0;
953 int savepid = pid;
954
955 errno = 0;
956 do {
957 pid = waitpid (savepid, &status, 0);
958 if (pid < 1) {
959 eerror ("waitpid %d: %s", savepid, strerror (errno));
960 return (-1);
961 }
962 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
963
964 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
965 if (! quiet)
966 eerrorx ("%s: failed to started `%s'", progname, exec);
967 exit (EXIT_FAILURE);
968 }
969
970 pid = savepid;
971 }
972
973 /* Wait a little bit and check that process is still running
974 We do this as some badly written daemons fork and then barf */
975 if (START_WAIT > 0) {
976 struct timeval stopat;
977 struct timeval now;
978 bool retestpid = false;
979
980 if (get_time (&stopat) != 0)
981 exit (EXIT_FAILURE);
982
983 stopat.tv_usec += START_WAIT;
984 while (1) {
985 bool alive = false;
986
987 tv.tv_sec = 0;
988 tv.tv_usec = POLL_INTERVAL;
989 if (select (0, 0, 0, 0, &tv) < 0) {
990 /* Let our signal handler handle the interupt */
991 if (errno != EINTR)
992 eerrorx ("%s: select: %s", progname, strerror (errno));
993 }
994
995 /* This is knarly.
996 If we backgrounded then we know the exact pid.
997 Otherwise if we have a pidfile then it *may* know the exact pid.
998 Failing that, we'll have to query processes.
999 We sleep first as some programs like ntp like to fork, and write
1000 their pidfile a LONG time later. */
1001 if (background) {
1002 if (kill (pid, 0) == 0)
1003 alive = true;
1004 } else {
1005 if (pidfile) {
1006 /* The pidfile may not have been written yet - give it some time */
1007 if (get_pid (pidfile, true) == -1) {
1008 alive = true;
1009 retestpid = true;
1010 } else {
1011 printf ("%d\n", get_pid (pidfile, true));
1012 retestpid = false;
1013 if (do_stop (NULL, NULL, pidfile, uid, 0,
1014 true, false, true) > 0)
1015 alive = true;
1016 }
1017 } else {
1018 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true)
1019 > 0)
1020 alive = true;
1021 }
1022 }
1023
1024 if (! alive)
1025 eerrorx ("%s: %s died", progname, exec);
1026
1027 if (get_time (&now) != 0)
1028 exit (EXIT_FAILURE);
1029 if (timercmp (&now, &stopat, >))
1030 break;
1031 }
1032
1033 if (retestpid) {
1034 if (do_stop (NULL, NULL, pidfile, uid, 0, true,
1035 false, true) < 1)
1036 eerrorx ("%s: %s died", progname, exec);
1037 }
1038 }
1039
1040 if (svcname)
1041 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
1042
786 exit (EXIT_SUCCESS); 1043 exit (EXIT_SUCCESS);
787
788 einfon ("Would start %s", exec);
789 while (argc-- > 0)
790 printf("%s ", *argv++);
791 printf ("\n");
792 eindent ();
793 if (ch_uid != 0)
794 einfo ("as user %d", ch_uid);
795 if (ch_gid != 0)
796 einfo ("as group %d", ch_gid);
797 if (ch_root)
798 einfo ("in root `%s'", ch_root);
799 if (ch_dir)
800 einfo ("in dir `%s'", ch_dir);
801 if (nicelevel != 0)
802 einfo ("with a priority of %d", nicelevel);
803 eoutdent ();
804 exit (EXIT_SUCCESS);
805 }
806
807 /* Ensure this is unset, so if the daemon does /etc/init.d/foo
808 Then we filter the environment accordingly */
809 unsetenv ("RC_SOFTLEVEL");
810
811 if (verbose)
812 {
813 ebegin ("Detaching to start `%s'", exec);
814 eindent ();
815 }
816
817 if (background)
818 signal (SIGCHLD, handle_signal);
819
820 *--argv = exec;
821 if ((pid = fork ()) == -1)
822 eerrorx ("%s: fork: %s", progname, strerror (errno));
823
824 /* Child process - lets go! */
825 if (pid == 0)
826 {
827 pid_t mypid = getpid ();
828
829#ifdef TIOCNOTTY
830 tty_fd = open("/dev/tty", O_RDWR);
831#endif
832
833 devnull_fd = open("/dev/null", O_RDWR);
834
835 if (nicelevel)
836 {
837 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
838 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
839 strerror(errno));
840 }
841
842 if (ch_root && chroot (ch_root) < 0)
843 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
844
845 if (ch_dir && chdir (ch_dir) < 0)
846 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
847
848 if (makepidfile && pidfile)
849 {
850 FILE *fp = fopen (pidfile, "w");
851 if (! fp)
852 eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror
853 (errno));
854 fprintf (fp, "%d\n", mypid);
855 fclose (fp);
856 }
857
858#ifdef HAVE_PAM
859 if (changeuser != NULL)
860 pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
861 else
862 pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
863
864 if (pamr == PAM_SUCCESS)
865 pamr = pam_authenticate (pamh, PAM_SILENT);
866 if (pamr == PAM_SUCCESS)
867 pamr = pam_acct_mgmt (pamh, PAM_SILENT);
868 if (pamr == PAM_SUCCESS)
869 pamr = pam_open_session (pamh, PAM_SILENT);
870 if (pamr != PAM_SUCCESS)
871 eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr));
872#endif
873
874 if ((ch_gid) && setgid(ch_gid))
875 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
876 if (changeuser && ch_gid)
877 if (initgroups (changeuser, ch_gid))
878 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
879 if (ch_uid && setuid (ch_uid))
880 eerrorx ("%s: unable to set userid to %d", progname, ch_uid);
881 else
882 {
883 struct passwd *passwd = getpwuid (ch_uid);
884 if (passwd)
885 {
886 unsetenv ("HOME");
887 if (passwd->pw_dir)
888 setenv ("HOME", passwd->pw_dir, 1);
889 unsetenv ("USER");
890 if (passwd->pw_name)
891 setenv ("USER", passwd->pw_name, 1);
892 }
893 }
894
895 /* Close any fd's to the passwd database */
896 endpwent ();
897
898#ifdef TIOCNOTTY
899 ioctl(tty_fd, TIOCNOTTY, 0);
900 close(tty_fd);
901#endif
902
903 /* Clean the environment of any RC_ variables */
904 STRLIST_FOREACH (environ, env, i)
905 if (env && strncmp (env, "RC_", 3) != 0)
906 {
907 /* For the path character, remove the rcscript bin dir from it */
908 if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
909 strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
910 {
911 char *path = env;
912 char *newpath;
913 int len;
914 path += strlen ("PATH=" RC_LIBDIR "bin:");
915 len = sizeof (char *) * strlen (path) + 6;
916 newpath = rc_xmalloc (len);
917 snprintf (newpath, len, "PATH=%s", path);
918 newenv = rc_strlist_add (newenv, newpath);
919 free (newpath);
920 }
921 else
922 newenv = rc_strlist_add (newenv, env);
923 }
924
925 umask (022);
926
927 stdout_fd = devnull_fd;
928 stderr_fd = devnull_fd;
929 if (redirect_stdout)
930 {
931 if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
932 S_IRUSR | S_IWUSR)) == -1)
933 eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
934 progname, redirect_stdout, strerror (errno));
935 }
936 if (redirect_stderr)
937 {
938 if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
939 S_IRUSR | S_IWUSR)) == -1)
940 eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
941 progname, redirect_stderr, strerror (errno));
942 }
943
944 dup2 (devnull_fd, STDIN_FILENO);
945 if (background)
946 {
947 dup2 (stdout_fd, STDOUT_FILENO);
948 dup2 (stderr_fd, STDERR_FILENO);
949 }
950
951 for (i = getdtablesize () - 1; i >= 3; --i)
952 close(i);
953
954 setsid ();
955
956 execve (exec, argv, newenv);
957#ifdef HAVE_PAM
958 if (pamr == PAM_SUCCESS)
959 pam_close_session (pamh, PAM_SILENT);
960#endif
961 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
962 }
963
964 /* Parent process */
965 if (! background)
966 {
967 /* As we're not backgrounding the process, wait for our pid to return */
968 int status = 0;
969 int savepid = pid;
970
971 errno = 0;
972 do
973 {
974 pid = waitpid (savepid, &status, 0);
975 if (pid < 1)
976 {
977 eerror ("waitpid %d: %s", savepid, strerror (errno));
978 return (-1);
979 }
980 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
981
982 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0)
983 {
984 if (! quiet)
985 eerrorx ("%s: failed to started `%s'", progname, exec);
986 exit (EXIT_FAILURE);
987 }
988
989 pid = savepid;
990 }
991
992 /* Wait a little bit and check that process is still running
993 We do this as some badly written daemons fork and then barf */
994 if (START_WAIT > 0)
995 {
996 struct timeval stopat;
997 struct timeval now;
998
999 if (gettimeofday (&stopat, NULL) != 0)
1000 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
1001
1002 stopat.tv_usec += START_WAIT;
1003 while (1)
1004 {
1005 bool alive = false;
1006
1007 tv.tv_sec = 0;
1008 tv.tv_usec = POLL_INTERVAL;
1009 if (select (0, 0, 0, 0, &tv) < 0)
1010 {
1011 /* Let our signal handler handle the interupt */
1012 if (errno != EINTR)
1013 eerrorx ("%s: select: %s", progname, strerror (errno));
1014 }
1015
1016 if (gettimeofday (&now, NULL) != 0)
1017 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
1018
1019 /* This is knarly.
1020 If we backgrounded then we know the exact pid.
1021 Otherwise if we have a pidfile then it *may* know the exact pid.
1022 Failing that, we'll have to query processes.
1023 We sleep first as some programs like ntp like to fork, and write
1024 their pidfile a LONG time later. */
1025 if (background)
1026 {
1027 if (kill (pid, 0) == 0)
1028 alive = true;
1029 }
1030 else
1031 {
1032 if (pidfile && rc_exists (pidfile))
1033 {
1034 if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0)
1035 alive = true;
1036 }
1037 else
1038 {
1039 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0)
1040 alive = true;
1041 }
1042 }
1043
1044 if (! alive)
1045 eerrorx ("%s: %s died", progname, exec);
1046
1047 if (timercmp (&now, &stopat, >))
1048 break;
1049 }
1050 }
1051
1052 if (svcname)
1053 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
1054
1055 exit (EXIT_SUCCESS);
1056} 1044}

Legend:
Removed from v.2563  
changed lines
  Added in v.2708

  ViewVC Help
Powered by ViewVC 1.1.20