/[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 2586
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 if (gettimeofday (&now, NULL) != 0) {
399 eerror ("%s: gettimeofday: %s", progname, strerror (errno));
400 return (0);
401 }
429 if (timercmp (&now, &stopat, >)) 402 if (timercmp (&now, &stopat, >))
403 break;
404 }
430 break; 405 break;
431 }
432 break;
433 406
434 default: 407 default:
435 eerror ("%s: invalid schedule item `%d'", progname, item->type); 408 eerror ("%s: invalid schedule item `%d'", progname, item->type);
436 return (0); 409 return (0);
437 } 410 }
438 411
439 if (item) 412 if (item)
440 item = item->next; 413 item = item->next;
441 } 414 }
442 415
443 if (test || (tkilled > 0 && nrunning == 0)) 416 if (test || (tkilled > 0 && nrunning == 0))
444 return (nkilled); 417 return (nkilled);
445 418
446 if (! quiet) 419 if (! quiet) {
447 {
448 if (nrunning == 1) 420 if (nrunning == 1)
449 eerror ("%s: %d process refused to stop", progname, nrunning); 421 eerror ("%s: %d process refused to stop", progname, nrunning);
450 else 422 else
451 eerror ("%s: %d process(es) refused to stop", progname, nrunning); 423 eerror ("%s: %d process(es) refused to stop", progname, nrunning);
452 } 424 }
453 425
454 return (-nrunning); 426 return (-nrunning);
455} 427}
456 428
457static void handle_signal (int sig) 429static void handle_signal (int sig)
458{ 430{
459 int pid; 431 int pid;
460 int status; 432 int status;
461 int serrno = errno; 433 int serrno = errno;
462 char signame[10] = { '\0' }; 434 char signame[10] = { '\0' };
463 435
464 switch (sig) 436 switch (sig) {
465 {
466 case SIGINT: 437 case SIGINT:
467 if (! signame[0]) 438 if (! signame[0])
468 snprintf (signame, sizeof (signame), "SIGINT"); 439 snprintf (signame, sizeof (signame), "SIGINT");
469 case SIGTERM: 440 case SIGTERM:
470 if (! signame[0]) 441 if (! signame[0])
471 snprintf (signame, sizeof (signame), "SIGTERM"); 442 snprintf (signame, sizeof (signame), "SIGTERM");
472 case SIGQUIT: 443 case SIGQUIT:
473 if (! signame[0]) 444 if (! signame[0])
474 snprintf (signame, sizeof (signame), "SIGQUIT"); 445 snprintf (signame, sizeof (signame), "SIGQUIT");
475 eerrorx ("%s: caught %s, aborting", progname, signame); 446 eerrorx ("%s: caught %s, aborting", progname, signame);
476 447
477 case SIGCHLD: 448 case SIGCHLD:
478 while (1) 449 while (1) {
479 {
480 if ((pid = waitpid (-1, &status, WNOHANG)) < 0) 450 if ((pid = waitpid (-1, &status, WNOHANG)) < 0) {
481 {
482 if (errno != ECHILD) 451 if (errno != ECHILD)
483 eerror ("%s: waitpid: %s", progname, strerror (errno)); 452 eerror ("%s: waitpid: %s", progname, strerror (errno));
484 break; 453 break;
485 } 454 }
486 } 455 }
487 break; 456 break;
488 457
489 default: 458 default:
490 eerror ("%s: caught unknown signal %d", progname, sig); 459 eerror ("%s: caught unknown signal %d", progname, sig);
491 } 460 }
492 461
493 /* Restore errno */ 462 /* Restore errno */
494 errno = serrno; 463 errno = serrno;
495} 464}
496 465
497int main (int argc, char **argv) 466int main (int argc, char **argv)
498{ 467{
499 int devnull_fd = -1; 468 int devnull_fd = -1;
500 469
501#ifdef TIOCNOTTY 470#ifdef TIOCNOTTY
502 int tty_fd = -1; 471 int tty_fd = -1;
503#endif 472#endif
504#ifdef HAVE_PAM 473#ifdef HAVE_PAM
505 pam_handle_t *pamh = NULL; 474 pam_handle_t *pamh = NULL;
506 int pamr; 475 int pamr;
507#endif 476#endif
508 477
509 static struct option longopts[] = { 478 static struct option longopts[] = {
510 { "stop", 0, NULL, 'K'}, 479 { "stop", 0, NULL, 'K'},
511 { "nicelevel", 1, NULL, 'N'}, 480 { "nicelevel", 1, NULL, 'N'},
512 { "retry", 1, NULL, 'R'}, 481 { "retry", 1, NULL, 'R'},
513 { "start", 0, NULL, 'S'}, 482 { "start", 0, NULL, 'S'},
514 { "background", 0, NULL, 'b'}, 483 { "background", 0, NULL, 'b'},
515 { "chuid", 1, NULL, 'c'}, 484 { "chuid", 1, NULL, 'c'},
516 { "chdir", 1, NULL, 'd'}, 485 { "chdir", 1, NULL, 'd'},
517 { "group", 1, NULL, 'g'}, 486 { "group", 1, NULL, 'g'},
518 { "make-pidfile", 0, NULL, 'm'}, 487 { "make-pidfile", 0, NULL, 'm'},
519 { "name", 1, NULL, 'n'}, 488 { "name", 1, NULL, 'n'},
520 { "oknodo", 0, NULL, 'o'}, 489 { "oknodo", 0, NULL, 'o'},
521 { "pidfile", 1, NULL, 'p'}, 490 { "pidfile", 1, NULL, 'p'},
522 { "quiet", 0, NULL, 'q'}, 491 { "quiet", 0, NULL, 'q'},
523 { "signal", 1, NULL, 's'}, 492 { "signal", 1, NULL, 's'},
524 { "test", 0, NULL, 't'}, 493 { "test", 0, NULL, 't'},
525 { "user", 1, NULL, 'u'}, 494 { "user", 1, NULL, 'u'},
526 { "chroot", 1, NULL, 'r'}, 495 { "chroot", 1, NULL, 'r'},
527 { "verbose", 0, NULL, 'v'}, 496 { "verbose", 0, NULL, 'v'},
528 { "exec", 1, NULL, 'x'}, 497 { "exec", 1, NULL, 'x'},
529 { "stdout", 1, NULL, '1'}, 498 { "stdout", 1, NULL, '1'},
530 { "stderr", 1, NULL, '2'}, 499 { "stderr", 1, NULL, '2'},
531 { NULL, 0, NULL, 0} 500 { NULL, 0, NULL, 0}
532 }; 501 };
533 int c; 502 int c;
534 bool start = false; 503 bool start = false;
535 bool stop = false; 504 bool stop = false;
536 bool oknodo = false; 505 bool oknodo = false;
537 bool test = false; 506 bool test = false;
538 bool quiet = false; 507 bool quiet = false;
539 bool verbose = false; 508 bool verbose = false;
540 char *exec = NULL; 509 char *exec = NULL;
541 char *cmd = NULL; 510 char *cmd = NULL;
542 char *pidfile = NULL; 511 char *pidfile = NULL;
543 int sig = SIGTERM; 512 int sig = SIGTERM;
544 uid_t uid = 0; 513 uid_t uid = 0;
545 int nicelevel = 0; 514 int nicelevel = 0;
546 bool background = false; 515 bool background = false;
547 bool makepidfile = false; 516 bool makepidfile = false;
548 uid_t ch_uid = 0; 517 uid_t ch_uid = 0;
549 gid_t ch_gid = 0; 518 gid_t ch_gid = 0;
550 char *ch_root = NULL; 519 char *ch_root = NULL;
551 char *ch_dir = NULL; 520 char *ch_dir = NULL;
552 int tid = 0; 521 int tid = 0;
553 char *redirect_stderr = NULL; 522 char *redirect_stderr = NULL;
554 char *redirect_stdout = NULL; 523 char *redirect_stdout = NULL;
555 int stdout_fd; 524 int stdout_fd;
556 int stderr_fd; 525 int stderr_fd;
557 pid_t pid; 526 pid_t pid;
558 struct timeval tv; 527 struct timeval tv;
559 int i; 528 int i;
560 char *svcname = getenv ("SVCNAME"); 529 char *svcname = getenv ("SVCNAME");
561 char *env; 530 char *env;
562 531
563 progname = argv[0]; 532 progname = argv[0];
564 atexit (cleanup); 533 atexit (cleanup);
565 534
566 signal (SIGINT, handle_signal); 535 signal (SIGINT, handle_signal);
567 signal (SIGQUIT, handle_signal); 536 signal (SIGQUIT, handle_signal);
568 signal (SIGTERM, handle_signal); 537 signal (SIGTERM, handle_signal);
569 538
570 while ((c = getopt_long (argc, argv, 539 while ((c = getopt_long (argc, argv,
571 "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:", 540 "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:",
572 longopts, (int *) 0)) != -1) 541 longopts, (int *) 0)) != -1)
573 switch (c) 542 switch (c) {
574 {
575 case 'K': /* --stop */ 543 case 'K': /* --stop */
576 stop = true; 544 stop = true;
577 break; 545 break;
578 546
579 case 'N': /* --nice */ 547 case 'N': /* --nice */
580 if (sscanf (optarg, "%d", &nicelevel) != 1) 548 if (sscanf (optarg, "%d", &nicelevel) != 1)
581 eerrorx ("%s: invalid nice level `%s'", progname, optarg); 549 eerrorx ("%s: invalid nice level `%s'", progname, optarg);
582 break; 550 break;
583 551
584 case 'R': /* --retry <schedule>|<timeout> */ 552 case 'R': /* --retry <schedule>|<timeout> */
585 parse_schedule (optarg, sig); 553 parse_schedule (optarg, sig);
586 break; 554 break;
587 555
588 case 'S': /* --start */ 556 case 'S': /* --start */
589 start = true; 557 start = true;
590 break; 558 break;
591 559
592 case 'b': /* --background */ 560 case 'b': /* --background */
593 background = true; 561 background = true;
594 break; 562 break;
595 563
596 case 'c': /* --chuid <username>|<uid> */ 564 case 'c': /* --chuid <username>|<uid> */
597 /* we copy the string just in case we need the 565 {
598 * argument later. */
599 {
600 char *p = optarg; 566 char *p = optarg;
601 char *cu = strsep (&p, ":"); 567 char *cu = strsep (&p, ":");
568 struct passwd *pw = NULL;
569
602 changeuser = strdup (cu); 570 changeuser = strdup (cu);
603 if (sscanf (cu, "%d", &tid) != 1) 571 if (sscanf (cu, "%d", &tid) != 1)
604 { 572 pw = getpwnam (cu);
605 struct passwd *pw = getpwnam (cu); 573 else
574 pw = getpwuid (tid);
575
606 if (! pw) 576 if (! pw)
607 eerrorx ("%s: user `%s' not found", progname, cu); 577 eerrorx ("%s: user `%s' not found", progname, cu);
608 ch_uid = pw->pw_uid; 578 ch_uid = pw->pw_uid;
609 } 579 if (! ch_gid)
610 else 580 ch_gid = pw->pw_gid;
611 ch_uid = tid; 581
612 if (p) 582 if (p) {
613 { 583 struct group *gr = NULL;
614 char *cg = strsep (&p, ":"); 584 char *cg = strsep (&p, ":");
585
615 if (sscanf (cg, "%d", &tid) != 1) 586 if (sscanf (cg, "%d", &tid) != 1)
616 { 587 gr = getgrnam (cg);
617 struct group *gr = getgrnam (cg); 588 else
618 if (! gr) 589 gr = getgrgid (tid);
590
591 if (! gr)
619 eerrorx ("%s: group `%s' not found", progname, cg); 592 eerrorx ("%s: group `%s' not found", progname, cg);
593 ch_gid = gr->gr_gid;
594 }
595 }
596 break;
597
598 case 'd': /* --chdir /new/dir */
599 ch_dir = optarg;
600 break;
601
602 case 'g': /* --group <group>|<gid> */
603 {
604 struct group *gr = getgrnam (optarg);
605
606 if (sscanf (optarg, "%d", &tid) != 1)
607 gr = getgrnam (optarg);
608 else
609 gr = getgrgid (tid);
610
611 if (! gr)
612 eerrorx ("%s: group `%s' not found", progname, optarg);
620 ch_gid = gr->gr_gid; 613 ch_gid = gr->gr_gid;
614 }
615 break;
616
617 case 'm': /* --make-pidfile */
618 makepidfile = true;
619 break;
620
621 case 'n': /* --name <process-name> */
622 cmd = optarg;
623 break;
624
625 case 'o': /* --oknodo */
626 oknodo = true;
627 break;
628
629 case 'p': /* --pidfile <pid-file> */
630 pidfile = optarg;
631 break;
632
633 case 'q': /* --quiet */
634 quiet = true;
635 break;
636
637 case 's': /* --signal <signal> */
638 sig = parse_signal (optarg);
639 break;
640
641 case 't': /* --test */
642 test = true;
643 break;
644
645 case 'u': /* --user <username>|<uid> */
646 if (sscanf (optarg, "%d", &tid) != 1) {
647 struct passwd *pw = getpwnam (optarg);
648 if (! pw)
649 eerrorx ("%s: user `%s' not found", progname, optarg);
650 uid = pw->pw_uid;
651 } else
652 uid = tid;
653 break;
654
655 case 'r': /* --chroot /new/root */
656 ch_root = optarg;
657 break;
658
659 case 'v': /* --verbose */
660 verbose = true;
661 break;
662
663 case 'x': /* --exec <executable> */
664 exec = optarg;
665 break;
666
667 case '1': /* --stdout /path/to/stdout.lgfile */
668 redirect_stdout = optarg;
669 break;
670
671 case '2': /* --stderr /path/to/stderr.logfile */
672 redirect_stderr = optarg;
673 break;
674
675 default:
676 exit (EXIT_FAILURE);
621 } 677 }
678
679 /* Respect RC as well as how we are called */
680 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
681 quiet = true;
682
683 if (start == stop)
684 eerrorx ("%s: need one of --start or --stop", progname);
685
686 if (start && ! exec)
687 eerrorx ("%s: --start needs --exec", progname);
688
689 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
690 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
691
692 if (makepidfile && ! pidfile)
693 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
694
695 if (background && ! start)
696 eerrorx ("%s: --background is only relevant with --start", progname);
697
698 if ((redirect_stdout || redirect_stderr) && ! background)
699 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
700 progname);
701
702 argc -= optind;
703 argv += optind;
704
705 /* Validate that the binary rc_exists if we are starting */
706 if (exec && start) {
707 char *tmp;
708 if (ch_root)
709 tmp = rc_strcatpaths (ch_root, exec, (char *) NULL);
622 else 710 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; 711 tmp = exec;
742 if (! rc_is_file (tmp)) 712 if (! rc_is_file (tmp)) {
743 {
744 eerror ("%s: %s does not exist", progname, tmp); 713 eerror ("%s: %s does not exist", progname, tmp);
745 if (ch_root) 714 if (ch_root)
746 free (tmp); 715 free (tmp);
747 exit (EXIT_FAILURE); 716 exit (EXIT_FAILURE);
748 } 717 }
749 if (ch_root) 718 if (ch_root)
750 free (tmp); 719 free (tmp);
751 } 720 }
752 721
753 if (stop) 722 if (stop) {
754 { 723 int result;
755 int result;
756 724
757 if (! schedule) 725 if (! schedule) {
758 {
759 if (test || oknodo) 726 if (test || oknodo)
760 parse_schedule ("0", sig); 727 parse_schedule ("0", sig);
761 else 728 else
762 parse_schedule (NULL, sig); 729 parse_schedule (NULL, sig);
763 } 730 }
764 731
765 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); 732 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test);
766 if (test || oknodo) 733 if (test || oknodo)
767 return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); 734 return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
768 if (result < 1) 735 if (result < 1)
769 exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 736 exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
770 737
771 if (pidfile && rc_is_file (pidfile)) 738 if (pidfile && rc_is_file (pidfile))
772 unlink (pidfile); 739 unlink (pidfile);
773 740
774 if (svcname) 741 if (svcname)
775 rc_set_service_daemon (svcname, exec, cmd, pidfile, false); 742 rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
776 743
777 exit (EXIT_SUCCESS); 744 exit (EXIT_SUCCESS);
778 } 745 }
779 746
780 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) 747 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
781 eerrorx ("%s: %s is already running", progname, exec); 748 eerrorx ("%s: %s is already running", progname, exec);
782 749
783 if (test) 750 if (test) {
784 { 751 if (quiet)
785 if (quiet) 752 exit (EXIT_SUCCESS);
753
754 einfon ("Would start %s", exec);
755 while (argc-- > 0)
756 printf("%s ", *argv++);
757 printf ("\n");
758 eindent ();
759 if (ch_uid != 0)
760 einfo ("as user %d", ch_uid);
761 if (ch_gid != 0)
762 einfo ("as group %d", ch_gid);
763 if (ch_root)
764 einfo ("in root `%s'", ch_root);
765 if (ch_dir)
766 einfo ("in dir `%s'", ch_dir);
767 if (nicelevel != 0)
768 einfo ("with a priority of %d", nicelevel);
769 eoutdent ();
770 exit (EXIT_SUCCESS);
771 }
772
773 /* Ensure this is unset, so if the daemon does /etc/init.d/foo
774 Then we filter the environment accordingly */
775 unsetenv ("RC_SOFTLEVEL");
776
777 if (verbose) {
778 ebegin ("Detaching to start `%s'", exec);
779 eindent ();
780 }
781
782 if (background)
783 signal (SIGCHLD, handle_signal);
784
785 *--argv = exec;
786 if ((pid = fork ()) == -1)
787 eerrorx ("%s: fork: %s", progname, strerror (errno));
788
789 /* Child process - lets go! */
790 if (pid == 0) {
791 pid_t mypid = getpid ();
792
793#ifdef TIOCNOTTY
794 tty_fd = open("/dev/tty", O_RDWR);
795#endif
796
797 devnull_fd = open("/dev/null", O_RDWR);
798
799 if (nicelevel) {
800 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
801 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
802 strerror(errno));
803 }
804
805 if (ch_root && chroot (ch_root) < 0)
806 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
807
808 if (ch_dir && chdir (ch_dir) < 0)
809 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
810
811 if (makepidfile && pidfile) {
812 FILE *fp = fopen (pidfile, "w");
813 if (! fp)
814 eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror
815 (errno));
816 fprintf (fp, "%d\n", mypid);
817 fclose (fp);
818 }
819
820#ifdef HAVE_PAM
821 if (changeuser != NULL)
822 pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
823 else
824 pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
825
826 if (pamr == PAM_SUCCESS)
827 pamr = pam_authenticate (pamh, PAM_SILENT);
828 if (pamr == PAM_SUCCESS)
829 pamr = pam_acct_mgmt (pamh, PAM_SILENT);
830 if (pamr == PAM_SUCCESS)
831 pamr = pam_open_session (pamh, PAM_SILENT);
832 if (pamr != PAM_SUCCESS)
833 eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr));
834#endif
835
836 if (ch_gid && setgid (ch_gid))
837 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
838 if (changeuser && initgroups (changeuser, ch_gid))
839 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
840 if (ch_uid && setuid (ch_uid))
841 eerrorx ("%s: unable to set userid to %d", progname, ch_uid);
842 else {
843 struct passwd *passwd = getpwuid (ch_uid);
844 if (passwd) {
845 unsetenv ("HOME");
846 if (passwd->pw_dir)
847 setenv ("HOME", passwd->pw_dir, 1);
848 unsetenv ("USER");
849 if (passwd->pw_name)
850 setenv ("USER", passwd->pw_name, 1);
851 }
852 }
853
854 /* Close any fd's to the passwd database */
855 endpwent ();
856
857#ifdef TIOCNOTTY
858 ioctl(tty_fd, TIOCNOTTY, 0);
859 close(tty_fd);
860#endif
861
862 /* Clean the environment of any RC_ variables */
863 STRLIST_FOREACH (environ, env, i)
864 if (env && strncmp (env, "RC_", 3) != 0) {
865 /* For the path character, remove the rcscript bin dir from it */
866 if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
867 strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
868 {
869 char *path = env;
870 char *newpath;
871 int len;
872 path += strlen ("PATH=" RC_LIBDIR "bin:");
873 len = sizeof (char *) * strlen (path) + 6;
874 newpath = rc_xmalloc (len);
875 snprintf (newpath, len, "PATH=%s", path);
876 newenv = rc_strlist_add (newenv, newpath);
877 free (newpath);
878 } else
879 newenv = rc_strlist_add (newenv, env);
880 }
881
882 umask (022);
883
884 stdout_fd = devnull_fd;
885 stderr_fd = devnull_fd;
886 if (redirect_stdout) {
887 if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
888 S_IRUSR | S_IWUSR)) == -1)
889 eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
890 progname, redirect_stdout, strerror (errno));
891 }
892 if (redirect_stderr) {
893 if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
894 S_IRUSR | S_IWUSR)) == -1)
895 eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
896 progname, redirect_stderr, strerror (errno));
897 }
898
899 if (background) {
900 /* Hmmm, some daemons may need stdin? */
901 dup2 (devnull_fd, STDIN_FILENO);
902 dup2 (stdout_fd, STDOUT_FILENO);
903 dup2 (stderr_fd, STDERR_FILENO);
904 }
905
906 for (i = getdtablesize () - 1; i >= 3; --i)
907 close(i);
908
909 setsid ();
910
911 execve (exec, argv, newenv);
912#ifdef HAVE_PAM
913 if (pamr == PAM_SUCCESS)
914 pam_close_session (pamh, PAM_SILENT);
915#endif
916 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
917 }
918
919 /* Parent process */
920 if (! background) {
921 /* As we're not backgrounding the process, wait for our pid to return */
922 int status = 0;
923 int savepid = pid;
924
925 errno = 0;
926 do {
927 pid = waitpid (savepid, &status, 0);
928 if (pid < 1) {
929 eerror ("waitpid %d: %s", savepid, strerror (errno));
930 return (-1);
931 }
932 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
933
934 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
935 if (! quiet)
936 eerrorx ("%s: failed to started `%s'", progname, exec);
937 exit (EXIT_FAILURE);
938 }
939
940 pid = savepid;
941 }
942
943 /* Wait a little bit and check that process is still running
944 We do this as some badly written daemons fork and then barf */
945 if (START_WAIT > 0) {
946 struct timeval stopat;
947 struct timeval now;
948
949 if (gettimeofday (&stopat, NULL) != 0)
950 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
951
952 stopat.tv_usec += START_WAIT;
953 while (1) {
954 bool alive = false;
955
956 tv.tv_sec = 0;
957 tv.tv_usec = POLL_INTERVAL;
958 if (select (0, 0, 0, 0, &tv) < 0) {
959 /* Let our signal handler handle the interupt */
960 if (errno != EINTR)
961 eerrorx ("%s: select: %s", progname, strerror (errno));
962 }
963
964 if (gettimeofday (&now, NULL) != 0)
965 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
966
967 /* This is knarly.
968 If we backgrounded then we know the exact pid.
969 Otherwise if we have a pidfile then it *may* know the exact pid.
970 Failing that, we'll have to query processes.
971 We sleep first as some programs like ntp like to fork, and write
972 their pidfile a LONG time later. */
973 if (background) {
974 if (kill (pid, 0) == 0)
975 alive = true;
976 } else {
977 if (pidfile && rc_exists (pidfile)) {
978 if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0)
979 alive = true;
980 } else {
981 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0)
982 alive = true;
983 }
984 }
985
986 if (! alive)
987 eerrorx ("%s: %s died", progname, exec);
988
989 if (timercmp (&now, &stopat, >))
990 break;
991 }
992 }
993
994 if (svcname)
995 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
996
786 exit (EXIT_SUCCESS); 997 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} 998}

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

  ViewVC Help
Powered by ViewVC 1.1.20