/[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 2577
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 /* we copy the string just in case we need the
598 * argument later. */ 566 * argument later. */
599 { 567 {
600 char *p = optarg; 568 char *p = optarg;
601 char *cu = strsep (&p, ":"); 569 char *cu = strsep (&p, ":");
602 changeuser = strdup (cu); 570 changeuser = strdup (cu);
603 if (sscanf (cu, "%d", &tid) != 1) 571 if (sscanf (cu, "%d", &tid) != 1) {
604 {
605 struct passwd *pw = getpwnam (cu); 572 struct passwd *pw = getpwnam (cu);
606 if (! pw) 573 if (! pw)
607 eerrorx ("%s: user `%s' not found", progname, cu); 574 eerrorx ("%s: user `%s' not found", progname, cu);
608 ch_uid = pw->pw_uid; 575 ch_uid = pw->pw_uid;
609 } 576 } else
610 else 577 ch_uid = tid;
611 ch_uid = tid; 578 if (p) {
612 if (p)
613 {
614 char *cg = strsep (&p, ":"); 579 char *cg = strsep (&p, ":");
615 if (sscanf (cg, "%d", &tid) != 1) 580 if (sscanf (cg, "%d", &tid) != 1) {
616 {
617 struct group *gr = getgrnam (cg); 581 struct group *gr = getgrnam (cg);
618 if (! gr) 582 if (! gr)
619 eerrorx ("%s: group `%s' not found", progname, cg); 583 eerrorx ("%s: group `%s' not found", progname, cg);
584 ch_gid = gr->gr_gid;
585 } else
586 ch_gid = tid;
587 }
588 }
589 break;
590
591 case 'd': /* --chdir /new/dir */
592 ch_dir = optarg;
593 break;
594
595 case 'g': /* --group <group>|<gid> */
596 if (sscanf (optarg, "%d", &tid) != 1) {
597 struct group *gr = getgrnam (optarg);
598 if (! gr)
599 eerrorx ("%s: group `%s' not found", progname, optarg);
620 ch_gid = gr->gr_gid; 600 ch_gid = gr->gr_gid;
601 } else
602 ch_gid = tid;
603 break;
604
605 case 'm': /* --make-pidfile */
606 makepidfile = true;
607 break;
608
609 case 'n': /* --name <process-name> */
610 cmd = optarg;
611 break;
612
613 case 'o': /* --oknodo */
614 oknodo = true;
615 break;
616
617 case 'p': /* --pidfile <pid-file> */
618 pidfile = optarg;
619 break;
620
621 case 'q': /* --quiet */
622 quiet = true;
623 break;
624
625 case 's': /* --signal <signal> */
626 sig = parse_signal (optarg);
627 break;
628
629 case 't': /* --test */
630 test = true;
631 break;
632
633 case 'u': /* --user <username>|<uid> */
634 if (sscanf (optarg, "%d", &tid) != 1) {
635 struct passwd *pw = getpwnam (optarg);
636 if (! pw)
637 eerrorx ("%s: user `%s' not found", progname, optarg);
638 uid = pw->pw_uid;
639 } else
640 uid = tid;
641 break;
642
643 case 'r': /* --chroot /new/root */
644 ch_root = optarg;
645 break;
646
647 case 'v': /* --verbose */
648 verbose = true;
649 break;
650
651 case 'x': /* --exec <executable> */
652 exec = optarg;
653 break;
654
655 case '1': /* --stdout /path/to/stdout.lgfile */
656 redirect_stdout = optarg;
657 break;
658
659 case '2': /* --stderr /path/to/stderr.logfile */
660 redirect_stderr = optarg;
661 break;
662
663 default:
664 exit (EXIT_FAILURE);
621 } 665 }
666
667 /* Respect RC as well as how we are called */
668 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
669 quiet = true;
670
671 if (start == stop)
672 eerrorx ("%s: need one of --start or --stop", progname);
673
674 if (start && ! exec)
675 eerrorx ("%s: --start needs --exec", progname);
676
677 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
678 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
679
680 if (makepidfile && ! pidfile)
681 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
682
683 if (background && ! start)
684 eerrorx ("%s: --background is only relevant with --start", progname);
685
686 if ((redirect_stdout || redirect_stderr) && ! background)
687 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
688 progname);
689
690 argc -= optind;
691 argv += optind;
692
693 /* Validate that the binary rc_exists if we are starting */
694 if (exec && start) {
695 char *tmp;
696 if (ch_root)
697 tmp = rc_strcatpaths (ch_root, exec, (char *) NULL);
622 else 698 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; 699 tmp = exec;
742 if (! rc_is_file (tmp)) 700 if (! rc_is_file (tmp)) {
743 {
744 eerror ("%s: %s does not exist", progname, tmp); 701 eerror ("%s: %s does not exist", progname, tmp);
745 if (ch_root) 702 if (ch_root)
746 free (tmp); 703 free (tmp);
747 exit (EXIT_FAILURE); 704 exit (EXIT_FAILURE);
748 } 705 }
749 if (ch_root) 706 if (ch_root)
750 free (tmp); 707 free (tmp);
751 } 708 }
752 709
753 if (stop) 710 if (stop) {
754 { 711 int result;
755 int result;
756 712
757 if (! schedule) 713 if (! schedule) {
758 {
759 if (test || oknodo) 714 if (test || oknodo)
760 parse_schedule ("0", sig); 715 parse_schedule ("0", sig);
761 else 716 else
762 parse_schedule (NULL, sig); 717 parse_schedule (NULL, sig);
763 } 718 }
764 719
765 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); 720 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test);
766 if (test || oknodo) 721 if (test || oknodo)
767 return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); 722 return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
768 if (result < 1) 723 if (result < 1)
769 exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 724 exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
770 725
771 if (pidfile && rc_is_file (pidfile)) 726 if (pidfile && rc_is_file (pidfile))
772 unlink (pidfile); 727 unlink (pidfile);
773 728
774 if (svcname) 729 if (svcname)
775 rc_set_service_daemon (svcname, exec, cmd, pidfile, false); 730 rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
776 731
777 exit (EXIT_SUCCESS); 732 exit (EXIT_SUCCESS);
778 } 733 }
779 734
780 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) 735 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
781 eerrorx ("%s: %s is already running", progname, exec); 736 eerrorx ("%s: %s is already running", progname, exec);
782 737
783 if (test) 738 if (test) {
784 { 739 if (quiet)
785 if (quiet) 740 exit (EXIT_SUCCESS);
741
742 einfon ("Would start %s", exec);
743 while (argc-- > 0)
744 printf("%s ", *argv++);
745 printf ("\n");
746 eindent ();
747 if (ch_uid != 0)
748 einfo ("as user %d", ch_uid);
749 if (ch_gid != 0)
750 einfo ("as group %d", ch_gid);
751 if (ch_root)
752 einfo ("in root `%s'", ch_root);
753 if (ch_dir)
754 einfo ("in dir `%s'", ch_dir);
755 if (nicelevel != 0)
756 einfo ("with a priority of %d", nicelevel);
757 eoutdent ();
758 exit (EXIT_SUCCESS);
759 }
760
761 /* Ensure this is unset, so if the daemon does /etc/init.d/foo
762 Then we filter the environment accordingly */
763 unsetenv ("RC_SOFTLEVEL");
764
765 if (verbose) {
766 ebegin ("Detaching to start `%s'", exec);
767 eindent ();
768 }
769
770 if (background)
771 signal (SIGCHLD, handle_signal);
772
773 *--argv = exec;
774 if ((pid = fork ()) == -1)
775 eerrorx ("%s: fork: %s", progname, strerror (errno));
776
777 /* Child process - lets go! */
778 if (pid == 0) {
779 pid_t mypid = getpid ();
780
781#ifdef TIOCNOTTY
782 tty_fd = open("/dev/tty", O_RDWR);
783#endif
784
785 devnull_fd = open("/dev/null", O_RDWR);
786
787 if (nicelevel) {
788 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
789 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
790 strerror(errno));
791 }
792
793 if (ch_root && chroot (ch_root) < 0)
794 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
795
796 if (ch_dir && chdir (ch_dir) < 0)
797 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
798
799 if (makepidfile && pidfile) {
800 FILE *fp = fopen (pidfile, "w");
801 if (! fp)
802 eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror
803 (errno));
804 fprintf (fp, "%d\n", mypid);
805 fclose (fp);
806 }
807
808#ifdef HAVE_PAM
809 if (changeuser != NULL)
810 pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
811 else
812 pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
813
814 if (pamr == PAM_SUCCESS)
815 pamr = pam_authenticate (pamh, PAM_SILENT);
816 if (pamr == PAM_SUCCESS)
817 pamr = pam_acct_mgmt (pamh, PAM_SILENT);
818 if (pamr == PAM_SUCCESS)
819 pamr = pam_open_session (pamh, PAM_SILENT);
820 if (pamr != PAM_SUCCESS)
821 eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr));
822#endif
823
824 if ((ch_gid) && setgid(ch_gid))
825 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
826 if (changeuser && ch_gid)
827 if (initgroups (changeuser, ch_gid))
828 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
829 if (ch_uid && setuid (ch_uid))
830 eerrorx ("%s: unable to set userid to %d", progname, ch_uid);
831 else {
832 struct passwd *passwd = getpwuid (ch_uid);
833 if (passwd) {
834 unsetenv ("HOME");
835 if (passwd->pw_dir)
836 setenv ("HOME", passwd->pw_dir, 1);
837 unsetenv ("USER");
838 if (passwd->pw_name)
839 setenv ("USER", passwd->pw_name, 1);
840 }
841 }
842
843 /* Close any fd's to the passwd database */
844 endpwent ();
845
846#ifdef TIOCNOTTY
847 ioctl(tty_fd, TIOCNOTTY, 0);
848 close(tty_fd);
849#endif
850
851 /* Clean the environment of any RC_ variables */
852 STRLIST_FOREACH (environ, env, i)
853 if (env && strncmp (env, "RC_", 3) != 0) {
854 /* For the path character, remove the rcscript bin dir from it */
855 if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
856 strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
857 {
858 char *path = env;
859 char *newpath;
860 int len;
861 path += strlen ("PATH=" RC_LIBDIR "bin:");
862 len = sizeof (char *) * strlen (path) + 6;
863 newpath = rc_xmalloc (len);
864 snprintf (newpath, len, "PATH=%s", path);
865 newenv = rc_strlist_add (newenv, newpath);
866 free (newpath);
867 } else
868 newenv = rc_strlist_add (newenv, env);
869 }
870
871 umask (022);
872
873 stdout_fd = devnull_fd;
874 stderr_fd = devnull_fd;
875 if (redirect_stdout) {
876 if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
877 S_IRUSR | S_IWUSR)) == -1)
878 eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
879 progname, redirect_stdout, strerror (errno));
880 }
881 if (redirect_stderr) {
882 if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
883 S_IRUSR | S_IWUSR)) == -1)
884 eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
885 progname, redirect_stderr, strerror (errno));
886 }
887
888 if (background) {
889 /* Hmmm, some daemons may need stdin? */
890 dup2 (devnull_fd, STDIN_FILENO);
891 dup2 (stdout_fd, STDOUT_FILENO);
892 dup2 (stderr_fd, STDERR_FILENO);
893 }
894
895 for (i = getdtablesize () - 1; i >= 3; --i)
896 close(i);
897
898 setsid ();
899
900 execve (exec, argv, newenv);
901#ifdef HAVE_PAM
902 if (pamr == PAM_SUCCESS)
903 pam_close_session (pamh, PAM_SILENT);
904#endif
905 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
906 }
907
908 /* Parent process */
909 if (! background) {
910 /* As we're not backgrounding the process, wait for our pid to return */
911 int status = 0;
912 int savepid = pid;
913
914 errno = 0;
915 do {
916 pid = waitpid (savepid, &status, 0);
917 if (pid < 1) {
918 eerror ("waitpid %d: %s", savepid, strerror (errno));
919 return (-1);
920 }
921 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
922
923 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
924 if (! quiet)
925 eerrorx ("%s: failed to started `%s'", progname, exec);
926 exit (EXIT_FAILURE);
927 }
928
929 pid = savepid;
930 }
931
932 /* Wait a little bit and check that process is still running
933 We do this as some badly written daemons fork and then barf */
934 if (START_WAIT > 0) {
935 struct timeval stopat;
936 struct timeval now;
937
938 if (gettimeofday (&stopat, NULL) != 0)
939 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
940
941 stopat.tv_usec += START_WAIT;
942 while (1) {
943 bool alive = false;
944
945 tv.tv_sec = 0;
946 tv.tv_usec = POLL_INTERVAL;
947 if (select (0, 0, 0, 0, &tv) < 0) {
948 /* Let our signal handler handle the interupt */
949 if (errno != EINTR)
950 eerrorx ("%s: select: %s", progname, strerror (errno));
951 }
952
953 if (gettimeofday (&now, NULL) != 0)
954 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
955
956 /* This is knarly.
957 If we backgrounded then we know the exact pid.
958 Otherwise if we have a pidfile then it *may* know the exact pid.
959 Failing that, we'll have to query processes.
960 We sleep first as some programs like ntp like to fork, and write
961 their pidfile a LONG time later. */
962 if (background) {
963 if (kill (pid, 0) == 0)
964 alive = true;
965 } else {
966 if (pidfile && rc_exists (pidfile)) {
967 if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0)
968 alive = true;
969 } else {
970 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0)
971 alive = true;
972 }
973 }
974
975 if (! alive)
976 eerrorx ("%s: %s died", progname, exec);
977
978 if (timercmp (&now, &stopat, >))
979 break;
980 }
981 }
982
983 if (svcname)
984 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
985
786 exit (EXIT_SUCCESS); 986 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} 987}

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

  ViewVC Help
Powered by ViewVC 1.1.20