/[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 2576 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 { 225 if (repeatat)
233 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 {
243 next->next = rc_xmalloc (sizeof (schedulelist_t)); 234 next->next = rc_xmalloc (sizeof (schedulelist_t));
244 next = next->next; 235 next = next->next;
245 next->gotolist = NULL; 236 next->gotolist = NULL;
246 } 237 }
247 } 238 }
248 239
249 if (repeatat) 240 if (repeatat) {
250 {
251 next->next = rc_xmalloc (sizeof (schedulelist_t)); 241 next->next = rc_xmalloc (sizeof (schedulelist_t));
252 next = next->next; 242 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) 297 if (! quiet)
310 {
311 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 { 308 if (! quiet)
323 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 315 if (verbose)
331 { 316 eend (0, NULL);
332 if (verbose) 317 if (nkilled != -1)
333 eend (0, NULL); 318 nkilled++;
334 if (nkilled != -1) 319 }
335 nkilled++; 320 }
336 }
337 }
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 { 360 if (tkilled == 0) {
381 if (tkilled == 0) 361 if (! quiet)
382 {
383 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)); 378 eerror ("%s: gettimeofday: %s", progname, strerror (errno));
403 return (0); 379 return (0);
404 } 380 }
405 381
406 stopat.tv_sec += item->value; 382 stopat.tv_sec += item->value;
407 while (1) 383 while (1) {
408 {
409 if ((nrunning = do_stop (exec, cmd, pidfile, 384 if ((nrunning = do_stop (exec, cmd, pidfile,
410 uid, 0, true, false, true)) == 0) 385 uid, 0, true, false, true)) == 0)
411 return (true); 386 return (true);
412 387
413 tv.tv_sec = 0; 388 tv.tv_sec = 0;
414 tv.tv_usec = POLL_INTERVAL; 389 tv.tv_usec = POLL_INTERVAL;
415 if (select (0, 0, 0, 0, &tv) < 0) 390 if (select (0, 0, 0, 0, &tv) < 0) {
416 { 391 if (errno == EINTR)
417 if (errno == EINTR)
418 eerror ("%s: caught an interupt", progname); 392 eerror ("%s: caught an interupt", progname);
419 else 393 else
420 eerror ("%s: select: %s", progname, strerror (errno)); 394 eerror ("%s: select: %s", progname, strerror (errno));
421 return (0); 395 return (0);
422 } 396 }
423 397
424 if (gettimeofday (&now, NULL) != 0) 398 if (gettimeofday (&now, NULL) != 0) {
425 {
426 eerror ("%s: gettimeofday: %s", progname, strerror (errno)); 399 eerror ("%s: gettimeofday: %s", progname, strerror (errno));
427 return (0); 400 return (0);
428 } 401 }
429 if (timercmp (&now, &stopat, >)) 402 if (timercmp (&now, &stopat, >))
430 break; 403 break;
431 } 404 }
432 break; 405 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 { 451 if (errno != ECHILD)
482 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) 579 char *cg = strsep (&p, ":");
613 { 580 if (sscanf (cg, "%d", &tid) != 1) {
614 char *cg = strsep (&p, ":"); 581 struct group *gr = getgrnam (cg);
615 if (sscanf (cg, "%d", &tid) != 1) 582 if (! gr)
616 {
617 struct group *gr = getgrnam (cg);
618 if (! gr)
619 eerrorx ("%s: group `%s' not found", progname, cg); 583 eerrorx ("%s: group `%s' not found", progname, cg);
620 ch_gid = gr->gr_gid; 584 ch_gid = gr->gr_gid;
621 } 585 } else
622 else 586 ch_gid = tid;
623 ch_gid = tid; 587 }
624 } 588 }
625 } 589 break;
626 break;
627 590
628 case 'd': /* --chdir /new/dir */ 591 case 'd': /* --chdir /new/dir */
629 ch_dir = optarg; 592 ch_dir = optarg;
630 break; 593 break;
631 594
632 case 'g': /* --group <group>|<gid> */ 595 case 'g': /* --group <group>|<gid> */
633 if (sscanf (optarg, "%d", &tid) != 1) 596 if (sscanf (optarg, "%d", &tid) != 1) {
634 {
635 struct group *gr = getgrnam (optarg); 597 struct group *gr = getgrnam (optarg);
636 if (! gr) 598 if (! gr)
637 eerrorx ("%s: group `%s' not found", progname, optarg); 599 eerrorx ("%s: group `%s' not found", progname, optarg);
638 ch_gid = gr->gr_gid; 600 ch_gid = gr->gr_gid;
639 } 601 } else
640 else 602 ch_gid = tid;
641 ch_gid = tid; 603 break;
642 break;
643 604
644 case 'm': /* --make-pidfile */ 605 case 'm': /* --make-pidfile */
645 makepidfile = true; 606 makepidfile = true;
646 break; 607 break;
647 608
648 case 'n': /* --name <process-name> */ 609 case 'n': /* --name <process-name> */
649 cmd = optarg; 610 cmd = optarg;
650 break; 611 break;
651 612
652 case 'o': /* --oknodo */ 613 case 'o': /* --oknodo */
653 oknodo = true; 614 oknodo = true;
654 break; 615 break;
655 616
656 case 'p': /* --pidfile <pid-file> */ 617 case 'p': /* --pidfile <pid-file> */
657 pidfile = optarg; 618 pidfile = optarg;
658 break; 619 break;
659 620
660 case 'q': /* --quiet */ 621 case 'q': /* --quiet */
661 quiet = true; 622 quiet = true;
662 break; 623 break;
663 624
664 case 's': /* --signal <signal> */ 625 case 's': /* --signal <signal> */
665 sig = parse_signal (optarg); 626 sig = parse_signal (optarg);
666 break; 627 break;
667 628
668 case 't': /* --test */ 629 case 't': /* --test */
669 test = true; 630 test = true;
670 break; 631 break;
671 632
672 case 'u': /* --user <username>|<uid> */ 633 case 'u': /* --user <username>|<uid> */
673 if (sscanf (optarg, "%d", &tid) != 1) 634 if (sscanf (optarg, "%d", &tid) != 1) {
674 {
675 struct passwd *pw = getpwnam (optarg); 635 struct passwd *pw = getpwnam (optarg);
676 if (! pw) 636 if (! pw)
677 eerrorx ("%s: user `%s' not found", progname, optarg); 637 eerrorx ("%s: user `%s' not found", progname, optarg);
678 uid = pw->pw_uid; 638 uid = pw->pw_uid;
679 } 639 } else
680 else 640 uid = tid;
681 uid = tid; 641 break;
682 break;
683 642
684 case 'r': /* --chroot /new/root */ 643 case 'r': /* --chroot /new/root */
685 ch_root = optarg; 644 ch_root = optarg;
686 break; 645 break;
687 646
688 case 'v': /* --verbose */ 647 case 'v': /* --verbose */
689 verbose = true; 648 verbose = true;
690 break; 649 break;
691 650
692 case 'x': /* --exec <executable> */ 651 case 'x': /* --exec <executable> */
693 exec = optarg; 652 exec = optarg;
694 break; 653 break;
695 654
696 case '1': /* --stdout /path/to/stdout.lgfile */ 655 case '1': /* --stdout /path/to/stdout.lgfile */
697 redirect_stdout = optarg; 656 redirect_stdout = optarg;
698 break; 657 break;
699 658
700 case '2': /* --stderr /path/to/stderr.logfile */ 659 case '2': /* --stderr /path/to/stderr.logfile */
701 redirect_stderr = optarg; 660 redirect_stderr = optarg;
702 break; 661 break;
703 662
704 default: 663 default:
705 exit (EXIT_FAILURE); 664 exit (EXIT_FAILURE);
706 } 665 }
707 666
708 /* Respect RC as well as how we are called */ 667 /* Respect RC as well as how we are called */
709 if (rc_is_env ("RC_QUIET", "yes") && ! verbose) 668 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
710 quiet = true; 669 quiet = true;
711 670
712 if (start == stop) 671 if (start == stop)
713 eerrorx ("%s: need one of --start or --stop", progname); 672 eerrorx ("%s: need one of --start or --stop", progname);
714 673
715 if (start && ! exec) 674 if (start && ! exec)
716 eerrorx ("%s: --start needs --exec", progname); 675 eerrorx ("%s: --start needs --exec", progname);
717 676
718 if (stop && ! exec && ! pidfile && ! cmd && ! uid) 677 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
719 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname); 678 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
720 679
721 if (makepidfile && ! pidfile) 680 if (makepidfile && ! pidfile)
722 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname); 681 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
723 682
724 if (background && ! start) 683 if (background && ! start)
725 eerrorx ("%s: --background is only relevant with --start", progname); 684 eerrorx ("%s: --background is only relevant with --start", progname);
726 685
727 if ((redirect_stdout || redirect_stderr) && ! background) 686 if ((redirect_stdout || redirect_stderr) && ! background)
728 eerrorx ("%s: --stdout and --stderr are only relevant with --background", 687 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
729 progname); 688 progname);
730 689
731 argc -= optind; 690 argc -= optind;
732 argv += optind; 691 argv += optind;
733 692
734 /* Validate that the binary rc_exists if we are starting */ 693 /* Validate that the binary rc_exists if we are starting */
735 if (exec && start) 694 if (exec && start) {
736 { 695 char *tmp;
737 char *tmp;
738 if (ch_root) 696 if (ch_root)
739 tmp = rc_strcatpaths (ch_root, exec, (char *) NULL); 697 tmp = rc_strcatpaths (ch_root, exec, (char *) NULL);
740 else 698 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 { 714 if (test || oknodo)
759 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)
786 exit (EXIT_SUCCESS); 740 exit (EXIT_SUCCESS);
787 741
788 einfon ("Would start %s", exec); 742 einfon ("Would start %s", exec);
789 while (argc-- > 0) 743 while (argc-- > 0)
790 printf("%s ", *argv++); 744 printf("%s ", *argv++);
791 printf ("\n"); 745 printf ("\n");
792 eindent (); 746 eindent ();
793 if (ch_uid != 0) 747 if (ch_uid != 0)
794 einfo ("as user %d", ch_uid); 748 einfo ("as user %d", ch_uid);
795 if (ch_gid != 0) 749 if (ch_gid != 0)
796 einfo ("as group %d", ch_gid); 750 einfo ("as group %d", ch_gid);
797 if (ch_root) 751 if (ch_root)
798 einfo ("in root `%s'", ch_root); 752 einfo ("in root `%s'", ch_root);
799 if (ch_dir) 753 if (ch_dir)
800 einfo ("in dir `%s'", ch_dir); 754 einfo ("in dir `%s'", ch_dir);
801 if (nicelevel != 0) 755 if (nicelevel != 0)
802 einfo ("with a priority of %d", nicelevel); 756 einfo ("with a priority of %d", nicelevel);
803 eoutdent (); 757 eoutdent ();
804 exit (EXIT_SUCCESS); 758 exit (EXIT_SUCCESS);
805 } 759 }
806 760
807 /* Ensure this is unset, so if the daemon does /etc/init.d/foo 761 /* Ensure this is unset, so if the daemon does /etc/init.d/foo
808 Then we filter the environment accordingly */ 762 Then we filter the environment accordingly */
809 unsetenv ("RC_SOFTLEVEL"); 763 unsetenv ("RC_SOFTLEVEL");
810 764
811 if (verbose) 765 if (verbose) {
812 {
813 ebegin ("Detaching to start `%s'", exec); 766 ebegin ("Detaching to start `%s'", exec);
814 eindent (); 767 eindent ();
815 } 768 }
816 769
817 if (background) 770 if (background)
818 signal (SIGCHLD, handle_signal); 771 signal (SIGCHLD, handle_signal);
819 772
820 *--argv = exec; 773 *--argv = exec;
821 if ((pid = fork ()) == -1) 774 if ((pid = fork ()) == -1)
822 eerrorx ("%s: fork: %s", progname, strerror (errno)); 775 eerrorx ("%s: fork: %s", progname, strerror (errno));
823 776
824 /* Child process - lets go! */ 777 /* Child process - lets go! */
825 if (pid == 0) 778 if (pid == 0) {
826 {
827 pid_t mypid = getpid (); 779 pid_t mypid = getpid ();
828 780
829#ifdef TIOCNOTTY 781#ifdef TIOCNOTTY
830 tty_fd = open("/dev/tty", O_RDWR); 782 tty_fd = open("/dev/tty", O_RDWR);
831#endif 783#endif
832 784
833 devnull_fd = open("/dev/null", O_RDWR); 785 devnull_fd = open("/dev/null", O_RDWR);
834 786
835 if (nicelevel) 787 if (nicelevel) {
836 {
837 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1) 788 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
838 eerrorx ("%s: setpritory %d: %s", progname, nicelevel, 789 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
839 strerror(errno)); 790 strerror(errno));
840 } 791 }
841 792
842 if (ch_root && chroot (ch_root) < 0) 793 if (ch_root && chroot (ch_root) < 0)
843 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno)); 794 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
844 795
845 if (ch_dir && chdir (ch_dir) < 0) 796 if (ch_dir && chdir (ch_dir) < 0)
846 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno)); 797 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
847 798
848 if (makepidfile && pidfile) 799 if (makepidfile && pidfile) {
849 {
850 FILE *fp = fopen (pidfile, "w"); 800 FILE *fp = fopen (pidfile, "w");
851 if (! fp) 801 if (! fp)
852 eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror 802 eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror
853 (errno)); 803 (errno));
854 fprintf (fp, "%d\n", mypid); 804 fprintf (fp, "%d\n", mypid);
855 fclose (fp); 805 fclose (fp);
856 } 806 }
857 807
858#ifdef HAVE_PAM 808#ifdef HAVE_PAM
859 if (changeuser != NULL) 809 if (changeuser != NULL)
860 pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh); 810 pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
861 else 811 else
862 pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh); 812 pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
863 813
864 if (pamr == PAM_SUCCESS) 814 if (pamr == PAM_SUCCESS)
865 pamr = pam_authenticate (pamh, PAM_SILENT); 815 pamr = pam_authenticate (pamh, PAM_SILENT);
866 if (pamr == PAM_SUCCESS) 816 if (pamr == PAM_SUCCESS)
867 pamr = pam_acct_mgmt (pamh, PAM_SILENT); 817 pamr = pam_acct_mgmt (pamh, PAM_SILENT);
868 if (pamr == PAM_SUCCESS) 818 if (pamr == PAM_SUCCESS)
869 pamr = pam_open_session (pamh, PAM_SILENT); 819 pamr = pam_open_session (pamh, PAM_SILENT);
870 if (pamr != PAM_SUCCESS) 820 if (pamr != PAM_SUCCESS)
871 eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr)); 821 eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr));
872#endif 822#endif
873 823
874 if ((ch_gid) && setgid(ch_gid)) 824 if ((ch_gid) && setgid(ch_gid))
875 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid); 825 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
876 if (changeuser && ch_gid) 826 if (changeuser && ch_gid)
877 if (initgroups (changeuser, ch_gid)) 827 if (initgroups (changeuser, ch_gid))
878 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid); 828 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
879 if (ch_uid && setuid (ch_uid)) 829 if (ch_uid && setuid (ch_uid))
880 eerrorx ("%s: unable to set userid to %d", progname, ch_uid); 830 eerrorx ("%s: unable to set userid to %d", progname, ch_uid);
881 else 831 else {
882 {
883 struct passwd *passwd = getpwuid (ch_uid); 832 struct passwd *passwd = getpwuid (ch_uid);
884 if (passwd) 833 if (passwd) {
885 { 834 unsetenv ("HOME");
886 unsetenv ("HOME"); 835 if (passwd->pw_dir)
887 if (passwd->pw_dir)
888 setenv ("HOME", passwd->pw_dir, 1); 836 setenv ("HOME", passwd->pw_dir, 1);
889 unsetenv ("USER"); 837 unsetenv ("USER");
890 if (passwd->pw_name) 838 if (passwd->pw_name)
891 setenv ("USER", passwd->pw_name, 1); 839 setenv ("USER", passwd->pw_name, 1);
892 } 840 }
893 } 841 }
894 842
895 /* Close any fd's to the passwd database */ 843 /* Close any fd's to the passwd database */
896 endpwent (); 844 endpwent ();
897 845
898#ifdef TIOCNOTTY 846#ifdef TIOCNOTTY
899 ioctl(tty_fd, TIOCNOTTY, 0); 847 ioctl(tty_fd, TIOCNOTTY, 0);
900 close(tty_fd); 848 close(tty_fd);
901#endif 849#endif
902 850
903 /* Clean the environment of any RC_ variables */ 851 /* Clean the environment of any RC_ variables */
904 STRLIST_FOREACH (environ, env, i) 852 STRLIST_FOREACH (environ, env, i)
905 if (env && strncmp (env, "RC_", 3) != 0) 853 if (env && strncmp (env, "RC_", 3) != 0) {
906 {
907 /* For the path character, remove the rcscript bin dir from it */ 854 /* For the path character, remove the rcscript bin dir from it */
908 if (strncmp (env, "PATH=" RC_LIBDIR "bin:", 855 if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
909 strlen ("PATH=" RC_LIBDIR "bin:")) == 0) 856 strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
910 { 857 {
911 char *path = env; 858 char *path = env;
912 char *newpath; 859 char *newpath;
913 int len; 860 int len;
914 path += strlen ("PATH=" RC_LIBDIR "bin:"); 861 path += strlen ("PATH=" RC_LIBDIR "bin:");
915 len = sizeof (char *) * strlen (path) + 6; 862 len = sizeof (char *) * strlen (path) + 6;
916 newpath = rc_xmalloc (len); 863 newpath = rc_xmalloc (len);
917 snprintf (newpath, len, "PATH=%s", path); 864 snprintf (newpath, len, "PATH=%s", path);
918 newenv = rc_strlist_add (newenv, newpath); 865 newenv = rc_strlist_add (newenv, newpath);
919 free (newpath); 866 free (newpath);
920 } 867 } else
921 else
922 newenv = rc_strlist_add (newenv, env); 868 newenv = rc_strlist_add (newenv, env);
923 } 869 }
924 870
925 umask (022); 871 umask (022);
926 872
927 stdout_fd = devnull_fd; 873 stdout_fd = devnull_fd;
928 stderr_fd = devnull_fd; 874 stderr_fd = devnull_fd;
929 if (redirect_stdout) 875 if (redirect_stdout) {
930 {
931 if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, 876 if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
932 S_IRUSR | S_IWUSR)) == -1) 877 S_IRUSR | S_IWUSR)) == -1)
933 eerrorx ("%s: unable to open the logfile for stdout `%s': %s", 878 eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
934 progname, redirect_stdout, strerror (errno)); 879 progname, redirect_stdout, strerror (errno));
935 } 880 }
936 if (redirect_stderr) 881 if (redirect_stderr) {
937 {
938 if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, 882 if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
939 S_IRUSR | S_IWUSR)) == -1) 883 S_IRUSR | S_IWUSR)) == -1)
940 eerrorx ("%s: unable to open the logfile for stderr `%s': %s", 884 eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
941 progname, redirect_stderr, strerror (errno)); 885 progname, redirect_stderr, strerror (errno));
942 } 886 }
943 887
888 if (background) {
889 /* Hmmm, some daemons may need stdin? */
944 dup2 (devnull_fd, STDIN_FILENO); 890 dup2 (devnull_fd, STDIN_FILENO);
945 if (background)
946 {
947 dup2 (stdout_fd, STDOUT_FILENO); 891 dup2 (stdout_fd, STDOUT_FILENO);
948 dup2 (stderr_fd, STDERR_FILENO); 892 dup2 (stderr_fd, STDERR_FILENO);
949 } 893 }
950 894
951 for (i = getdtablesize () - 1; i >= 3; --i) 895 for (i = getdtablesize () - 1; i >= 3; --i)
952 close(i); 896 close(i);
953 897
954 setsid (); 898 setsid ();
955 899
956 execve (exec, argv, newenv); 900 execve (exec, argv, newenv);
957#ifdef HAVE_PAM 901#ifdef HAVE_PAM
958 if (pamr == PAM_SUCCESS) 902 if (pamr == PAM_SUCCESS)
959 pam_close_session (pamh, PAM_SILENT); 903 pam_close_session (pamh, PAM_SILENT);
960#endif 904#endif
961 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno)); 905 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
962 } 906 }
963 907
964 /* Parent process */ 908 /* Parent process */
965 if (! background) 909 if (! background) {
966 {
967 /* As we're not backgrounding the process, wait for our pid to return */ 910 /* As we're not backgrounding the process, wait for our pid to return */
968 int status = 0; 911 int status = 0;
969 int savepid = pid; 912 int savepid = pid;
970 913
971 errno = 0; 914 errno = 0;
972 do 915 do {
973 {
974 pid = waitpid (savepid, &status, 0); 916 pid = waitpid (savepid, &status, 0);
975 if (pid < 1) 917 if (pid < 1) {
976 {
977 eerror ("waitpid %d: %s", savepid, strerror (errno)); 918 eerror ("waitpid %d: %s", savepid, strerror (errno));
978 return (-1); 919 return (-1);
979 } 920 }
980 } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); 921 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
981 922
982 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) 923 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
983 { 924 if (! quiet)
984 if (! quiet)
985 eerrorx ("%s: failed to started `%s'", progname, exec); 925 eerrorx ("%s: failed to started `%s'", progname, exec);
986 exit (EXIT_FAILURE); 926 exit (EXIT_FAILURE);
987 } 927 }
988 928
989 pid = savepid; 929 pid = savepid;
990 } 930 }
991 931
992 /* Wait a little bit and check that process is still running 932 /* Wait a little bit and check that process is still running
993 We do this as some badly written daemons fork and then barf */ 933 We do this as some badly written daemons fork and then barf */
994 if (START_WAIT > 0) 934 if (START_WAIT > 0) {
995 {
996 struct timeval stopat; 935 struct timeval stopat;
997 struct timeval now; 936 struct timeval now;
998 937
999 if (gettimeofday (&stopat, NULL) != 0) 938 if (gettimeofday (&stopat, NULL) != 0)
1000 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); 939 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
1001 940
1002 stopat.tv_usec += START_WAIT; 941 stopat.tv_usec += START_WAIT;
1003 while (1) 942 while (1) {
1004 { 943 bool alive = false;
1005 bool alive = false;
1006 944
1007 tv.tv_sec = 0; 945 tv.tv_sec = 0;
1008 tv.tv_usec = POLL_INTERVAL; 946 tv.tv_usec = POLL_INTERVAL;
1009 if (select (0, 0, 0, 0, &tv) < 0) 947 if (select (0, 0, 0, 0, &tv) < 0) {
1010 {
1011 /* Let our signal handler handle the interupt */ 948 /* Let our signal handler handle the interupt */
1012 if (errno != EINTR) 949 if (errno != EINTR)
1013 eerrorx ("%s: select: %s", progname, strerror (errno)); 950 eerrorx ("%s: select: %s", progname, strerror (errno));
1014 } 951 }
1015 952
1016 if (gettimeofday (&now, NULL) != 0) 953 if (gettimeofday (&now, NULL) != 0)
1017 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); 954 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
1018 955
1019 /* This is knarly. 956 /* This is knarly.
1020 If we backgrounded then we know the exact pid. 957 If we backgrounded then we know the exact pid.
1021 Otherwise if we have a pidfile then it *may* know the exact pid. 958 Otherwise if we have a pidfile then it *may* know the exact pid.
1022 Failing that, we'll have to query processes. 959 Failing that, we'll have to query processes.
1023 We sleep first as some programs like ntp like to fork, and write 960 We sleep first as some programs like ntp like to fork, and write
1024 their pidfile a LONG time later. */ 961 their pidfile a LONG time later. */
1025 if (background) 962 if (background) {
1026 { 963 if (kill (pid, 0) == 0)
1027 if (kill (pid, 0) == 0) 964 alive = true;
1028 alive = true; 965 } else {
1029 }
1030 else
1031 {
1032 if (pidfile && rc_exists (pidfile)) 966 if (pidfile && rc_exists (pidfile)) {
1033 {
1034 if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0) 967 if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0)
1035 alive = true; 968 alive = true;
1036 } 969 } else {
1037 else
1038 {
1039 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0) 970 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0)
1040 alive = true; 971 alive = true;
1041 } 972 }
1042 } 973 }
1043 974
1044 if (! alive) 975 if (! alive)
1045 eerrorx ("%s: %s died", progname, exec); 976 eerrorx ("%s: %s died", progname, exec);
1046 977
1047 if (timercmp (&now, &stopat, >)) 978 if (timercmp (&now, &stopat, >))
1048 break; 979 break;
1049 } 980 }
1050 } 981 }
1051 982
1052 if (svcname) 983 if (svcname)
1053 rc_set_service_daemon (svcname, exec, cmd, pidfile, true); 984 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
1054 985
1055 exit (EXIT_SUCCESS); 986 exit (EXIT_SUCCESS);
1056} 987}

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

  ViewVC Help
Powered by ViewVC 1.1.20