Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/runit/runsvdir.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/runit/runsvdir.c
r1765 r2725 26 26 */ 27 27 28 /* Busyboxed by Den is Vlasenko <vda.linux@googlemail.com> */28 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */ 29 29 /* TODO: depends on runit_lib.c - review and reduce/eliminate */ 30 30 … … 36 36 #define MAXSERVICES 1000 37 37 38 /* Should be not needed - all dirs are on same FS, right? */ 39 #define CHECK_DEVNO_TOO 0 40 38 41 struct service { 42 #if CHECK_DEVNO_TOO 39 43 dev_t dev; 44 #endif 40 45 ino_t ino; 41 46 pid_t pid; … … 43 48 }; 44 49 45 struct service *sv; 46 static char *svdir; 47 static int svnum; 48 static char *rplog; 49 static int rploglen; 50 static int logpipe[2]; 51 static struct pollfd pfd[1]; 52 static unsigned stamplog; 53 static smallint check = 1; 54 static smallint exitsoon; 55 static smallint set_pgrp; 50 struct globals { 51 struct service *sv; 52 char *svdir; 53 int svnum; 54 #if ENABLE_FEATURE_RUNSVDIR_LOG 55 char *rplog; 56 int rploglen; 57 struct fd_pair logpipe; 58 struct pollfd pfd[1]; 59 unsigned stamplog; 60 #endif 61 } FIX_ALIASING; 62 #define G (*(struct globals*)&bb_common_bufsiz1) 63 #define sv (G.sv ) 64 #define svdir (G.svdir ) 65 #define svnum (G.svnum ) 66 #define rplog (G.rplog ) 67 #define rploglen (G.rploglen ) 68 #define logpipe (G.logpipe ) 69 #define pfd (G.pfd ) 70 #define stamplog (G.stamplog ) 71 #define INIT_G() do { \ 72 } while (0) 56 73 57 74 static void fatal2_cannot(const char *m1, const char *m2) 58 75 { 59 bb_perror_msg_and_die("%s: fatal: can not %s%s", svdir, m1, m2);76 bb_perror_msg_and_die("%s: fatal: can't %s%s", svdir, m1, m2); 60 77 /* was exiting 100 */ 61 78 } … … 66 83 static void warn2_cannot(const char *m1, const char *m2) 67 84 { 68 warn3x("cannot ", m1, m2); 69 } 85 warn3x("can't ", m1, m2); 86 } 87 #if ENABLE_FEATURE_RUNSVDIR_LOG 70 88 static void warnx(const char *m1) 71 89 { 72 90 warn3x(m1, "", ""); 73 91 } 74 75 static void s_term(int sig_no) 76 { 77 exitsoon = 1; 78 } 79 static void s_hangup(int sig_no) 80 { 81 exitsoon = 2; 82 } 83 84 static void runsv(int no, const char *name) 92 #endif 93 94 /* inlining + vfork -> bigger code */ 95 static NOINLINE pid_t runsv(const char *name) 85 96 { 86 97 pid_t pid; 87 char *prog[3]; 88 89 prog[0] = (char*)"runsv"; 90 prog[1] = (char*)name; 91 prog[2] = NULL; 98 99 /* If we got signaled, stop spawning children at once! */ 100 if (bb_got_signal) 101 return 0; 92 102 93 103 pid = vfork(); 94 95 104 if (pid == -1) { 96 105 warn2_cannot("vfork", ""); 97 return ;106 return 0; 98 107 } 99 108 if (pid == 0) { 100 109 /* child */ 101 if ( set_pgrp)110 if (option_mask32 & 1) /* -P option? */ 102 111 setsid(); 103 signal(SIGHUP, SIG_DFL); 104 signal(SIGTERM, SIG_DFL); 105 execvp(prog[0], prog); 112 /* man execv: 113 * "Signals set to be caught by the calling process image 114 * shall be set to the default action in the new process image." 115 * Therefore, we do not need this: */ 116 #if 0 117 bb_signals(0 118 | (1 << SIGHUP) 119 | (1 << SIGTERM) 120 , SIG_DFL); 121 #endif 122 execlp("runsv", "runsv", name, (char *) NULL); 106 123 fatal2_cannot("start runsv ", name); 107 124 } 108 sv[no].pid = pid; 109 } 110 111 static void runsvdir(void) 125 return pid; 126 } 127 128 /* gcc 4.3.0 does better with NOINLINE */ 129 static NOINLINE int do_rescan(void) 112 130 { 113 131 DIR *dir; 114 direntry*d;132 struct dirent *d; 115 133 int i; 116 134 struct stat s; 135 int need_rescan = 0; 117 136 118 137 dir = opendir("."); 119 138 if (!dir) { 120 139 warn2_cannot("open directory ", svdir); 121 return ;140 return 1; /* need to rescan again soon */ 122 141 } 123 142 for (i = 0; i < svnum; i++) 124 143 sv[i].isgone = 1; 125 errno = 0; 126 while ((d = readdir(dir))) { 144 145 while (1) { 146 errno = 0; 147 d = readdir(dir); 148 if (!d) 149 break; 127 150 if (d->d_name[0] == '.') 128 151 continue; 129 152 if (stat(d->d_name, &s) == -1) { 130 153 warn2_cannot("stat ", d->d_name); 131 errno = 0;132 154 continue; 133 155 } 134 156 if (!S_ISDIR(s.st_mode)) 135 157 continue; 158 /* Do we have this service listed already? */ 136 159 for (i = 0; i < svnum; i++) { 137 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) { 138 sv[i].isgone = 0; 139 if (!sv[i].pid) 140 runsv(i, d->d_name); 141 break; 142 } 143 } 144 if (i == svnum) { 145 /* new service */ 160 if ((sv[i].ino == s.st_ino) 161 #if CHECK_DEVNO_TOO 162 && (sv[i].dev == s.st_dev) 163 #endif 164 ) { 165 if (sv[i].pid == 0) /* restart if it has died */ 166 goto run_ith_sv; 167 sv[i].isgone = 0; /* "we still see you" */ 168 goto next_dentry; 169 } 170 } 171 { /* Not found, make new service */ 146 172 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv)); 147 173 if (!svnew) { 148 warn 3x("cannot start runsv ", d->d_name,149 " too many services");174 warn2_cannot("start runsv ", d->d_name); 175 need_rescan = 1; 150 176 continue; 151 177 } 152 178 sv = svnew; 153 179 svnum++; 154 memset(&sv[i], 0, sizeof(sv[i])); 180 #if CHECK_DEVNO_TOO 181 sv[i].dev = s.st_dev; 182 #endif 155 183 sv[i].ino = s.st_ino; 156 sv[i].dev = s.st_dev; 157 /*sv[i].pid = 0;*/ 158 /*sv[i].isgone = 0;*/ 159 runsv(i, d->d_name); 160 check = 1; 161 } 162 } 163 if (errno) { 184 run_ith_sv: 185 sv[i].pid = runsv(d->d_name); 186 sv[i].isgone = 0; 187 } 188 next_dentry: ; 189 } 190 i = errno; 191 closedir(dir); 192 if (i) { /* readdir failed */ 164 193 warn2_cannot("read directory ", svdir); 165 closedir(dir); 166 check = 1; 167 return; 168 } 169 closedir(dir); 170 171 /* SIGTERM removed runsv's */ 194 return 1; /* need to rescan again soon */ 195 } 196 197 /* Send SIGTERM to runsv whose directories 198 * were no longer found (-> must have been removed) */ 172 199 for (i = 0; i < svnum; i++) { 173 200 if (!sv[i].isgone) … … 175 202 if (sv[i].pid) 176 203 kill(sv[i].pid, SIGTERM); 177 sv[i] = sv[--svnum]; 178 check = 1; 179 } 180 } 181 182 static int setup_log(void) 183 { 184 rploglen = strlen(rplog); 185 if (rploglen < 7) { 186 warnx("log must have at least seven characters"); 187 return 0; 188 } 189 if (pipe(logpipe)) { 190 warnx("cannot create pipe for log"); 191 return -1; 192 } 193 coe(logpipe[1]); 194 coe(logpipe[0]); 195 ndelay_on(logpipe[0]); 196 ndelay_on(logpipe[1]); 197 if (dup2(logpipe[1], 2) == -1) { 198 warnx("cannot set filedescriptor for log"); 199 return -1; 200 } 201 pfd[0].fd = logpipe[0]; 202 pfd[0].events = POLLIN; 203 stamplog = monotonic_sec(); 204 return 1; 205 } 206 207 int runsvdir_main(int argc, char **argv); 208 int runsvdir_main(int argc, char **argv) 204 svnum--; 205 sv[i] = sv[svnum]; 206 i--; /* so that we don't skip new sv[i] (bug was here!) */ 207 } 208 return need_rescan; 209 } 210 211 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 212 int runsvdir_main(int argc UNUSED_PARAM, char **argv) 209 213 { 210 214 struct stat s; … … 214 218 int wstat; 215 219 int curdir; 216 int pid;220 pid_t pid; 217 221 unsigned deadline; 218 222 unsigned now; 219 223 unsigned stampcheck; 220 char ch;221 224 int i; 222 223 argv++; 224 if (!*argv) 225 bb_show_usage(); 226 if (argv[0][0] == '-') { 227 switch (argv[0][1]) { 228 case 'P': set_pgrp = 1; 229 case '-': ++argv; 230 } 231 if (!*argv) 232 bb_show_usage(); 233 } 234 235 sig_catch(SIGTERM, s_term); 236 sig_catch(SIGHUP, s_hangup); 225 int need_rescan = 1; 226 char *opt_s_argv[3]; 227 228 INIT_G(); 229 230 opt_complementary = "-1"; 231 opt_s_argv[0] = NULL; 232 opt_s_argv[2] = NULL; 233 getopt32(argv, "Ps:", &opt_s_argv[0]); 234 argv += optind; 235 236 bb_signals(0 237 | (1 << SIGTERM) 238 | (1 << SIGHUP) 239 /* For busybox's init, SIGTERM == reboot, 240 * SIGUSR1 == halt 241 * SIGUSR2 == poweroff 242 * so we need to intercept SIGUSRn too. 243 * Note that we do not implement actual reboot 244 * (killall(TERM) + umount, etc), we just pause 245 * respawing and avoid exiting (-> making kernel oops). 246 * The user is responsible for the rest. */ 247 | (getpid() == 1 ? ((1 << SIGUSR1) | (1 << SIGUSR2)) : 0) 248 , record_signo); 237 249 svdir = *argv++; 238 if (argv && *argv) { 250 251 #if ENABLE_FEATURE_RUNSVDIR_LOG 252 /* setup log */ 253 if (*argv) { 239 254 rplog = *argv; 240 if (setup_log() != 1) { 241 rplog = 0; 242 warnx("log service disabled"); 243 } 244 } 245 curdir = open_read("."); 255 rploglen = strlen(rplog); 256 if (rploglen < 7) { 257 warnx("log must have at least seven characters"); 258 } else if (piped_pair(logpipe)) { 259 warnx("can't create pipe for log"); 260 } else { 261 close_on_exec_on(logpipe.rd); 262 close_on_exec_on(logpipe.wr); 263 ndelay_on(logpipe.rd); 264 ndelay_on(logpipe.wr); 265 if (dup2(logpipe.wr, 2) == -1) { 266 warnx("can't set filedescriptor for log"); 267 } else { 268 pfd[0].fd = logpipe.rd; 269 pfd[0].events = POLLIN; 270 stamplog = monotonic_sec(); 271 goto run; 272 } 273 } 274 rplog = NULL; 275 warnx("log service disabled"); 276 } 277 run: 278 #endif 279 curdir = open(".", O_RDONLY|O_NDELAY); 246 280 if (curdir == -1) 247 281 fatal2_cannot("open current directory", ""); 248 c oe(curdir);282 close_on_exec_on(curdir); 249 283 250 284 stampcheck = monotonic_sec(); … … 253 287 /* collect children */ 254 288 for (;;) { 255 pid = wait_ nohang(&wstat);289 pid = wait_any_nohang(&wstat); 256 290 if (pid <= 0) 257 291 break; 258 292 for (i = 0; i < svnum; i++) { 259 293 if (pid == sv[i].pid) { 260 /* runsv has gone*/294 /* runsv has died */ 261 295 sv[i].pid = 0; 262 check = 1; 263 break; 296 need_rescan = 1; 264 297 } 265 298 } … … 272 305 273 306 if (stat(svdir, &s) != -1) { 274 if ( check|| s.st_mtime != last_mtime307 if (need_rescan || s.st_mtime != last_mtime 275 308 || s.st_ino != last_ino || s.st_dev != last_dev 276 309 ) { … … 280 313 last_dev = s.st_dev; 281 314 last_ino = s.st_ino; 282 check = 0; 283 //if (now <= mtime) 284 // sleep(1); 285 runsvdir(); 315 /* if the svdir changed this very second, wait until the 316 * next second, because we won't be able to detect more 317 * changes within this second */ 318 while (time(NULL) == last_mtime) 319 usleep(100000); 320 need_rescan = do_rescan(); 286 321 while (fchdir(curdir) == -1) { 287 322 warn2_cannot("change directory, pausing", ""); 288 323 sleep(5); 289 324 } 290 } else 325 } else { 291 326 warn2_cannot("change directory to ", svdir); 327 } 292 328 } 293 } else 329 } else { 294 330 warn2_cannot("stat ", svdir); 295 } 296 331 } 332 } 333 334 #if ENABLE_FEATURE_RUNSVDIR_LOG 297 335 if (rplog) { 298 336 if ((int)(now - stamplog) >= 0) { 299 write(logpipe [1], ".", 1);337 write(logpipe.wr, ".", 1); 300 338 stamplog = now + 900; 301 339 } 302 340 } 303 304 341 pfd[0].revents = 0; 342 #endif 343 deadline = (need_rescan ? 1 : 5); 305 344 sig_block(SIGCHLD); 306 deadline = (check ? 1 : 5); 345 #if ENABLE_FEATURE_RUNSVDIR_LOG 307 346 if (rplog) 308 347 poll(pfd, 1, deadline*1000); 309 348 else 349 #endif 310 350 sleep(deadline); 311 351 sig_unblock(SIGCHLD); 312 352 353 #if ENABLE_FEATURE_RUNSVDIR_LOG 313 354 if (pfd[0].revents & POLLIN) { 314 while (read(logpipe[0], &ch, 1) > 0) { 315 if (ch) { 316 for (i = 6; i < rploglen; i++) 317 rplog[i-1] = rplog[i]; 318 rplog[rploglen-1] = ch; 319 } 320 } 321 } 322 323 switch (exitsoon) { 324 case 1: 325 _exit(0); 326 case 2: 355 char ch; 356 while (read(logpipe.rd, &ch, 1) > 0) { 357 if (ch < ' ') 358 ch = ' '; 359 for (i = 6; i < rploglen; i++) 360 rplog[i-1] = rplog[i]; 361 rplog[rploglen-1] = ch; 362 } 363 } 364 #endif 365 if (!bb_got_signal) 366 continue; 367 368 /* -s SCRIPT: useful if we are init. 369 * In this case typically script never returns, 370 * it halts/powers off/reboots the system. */ 371 if (opt_s_argv[0]) { 372 /* Single parameter: signal# */ 373 opt_s_argv[1] = utoa(bb_got_signal); 374 pid = spawn(opt_s_argv); 375 if (pid > 0) { 376 /* Remembering to wait for _any_ children, 377 * not just pid */ 378 while (wait(NULL) != pid) 379 continue; 380 } 381 } 382 383 if (bb_got_signal == SIGHUP) { 327 384 for (i = 0; i < svnum; i++) 328 385 if (sv[i].pid) 329 386 kill(sv[i].pid, SIGTERM); 330 _exit(111); 331 } 332 } 333 /* not reached */ 334 return 0; 335 } 387 } 388 /* SIGHUP or SIGTERM (or SIGUSRn if we are init) */ 389 /* Exit unless we are init */ 390 if (getpid() != 1) 391 return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS; 392 393 /* init continues to monitor services forever */ 394 bb_got_signal = 0; 395 } /* for (;;) */ 396 }
Note:
See TracChangeset
for help on using the changeset viewer.