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

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

  ViewVC Help
Powered by ViewVC 1.1.20