runit.c (8653B)
1 #include <sys/types.h> 2 #include <sys/reboot.h> 3 #include <sys/ioctl.h> 4 #include <sys/stat.h> 5 #include <signal.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <poll.h> 9 #include "runit.h" 10 #include "sig.h" 11 #include "strerr.h" 12 #include "error.h" 13 #include "coe.h" 14 #include "ndelay.h" 15 #include "wait.h" 16 #include <sys/wait.h> 17 #include "open.h" 18 19 /* #define DEBUG */ 20 21 #define INFO "- runit: " 22 #define WARNING "- runit: warning: " 23 #define FATAL "- runit: fatal: " 24 25 static const char * const stage[3] ={ 26 "/etc/runit/1", 27 "/etc/runit/2", 28 "/etc/runit/3" }; 29 30 static int selfpipe[2]; 31 static int sigc =0; 32 static int sigi =0; 33 34 static void sig_cont_handler( int s ) 35 { 36 sigc++; 37 write(selfpipe[1], "", 1); 38 } 39 static void sig_int_handler( int s ) 40 { 41 sigi++; 42 write(selfpipe[1], "", 1); 43 } 44 static void sig_child_handler( int s ) { write(selfpipe[1], "", 1); } 45 46 int main (int argc, const char * const *argv, char * const *envp) 47 { 48 const char * prog[2]; 49 int pid, pid2; 50 int wstat; 51 int st; 52 struct pollfd x; 53 char ch; 54 int ttyfd; 55 struct stat s; 56 57 if (getpid() != 1) strerr_die2x(111, FATAL, "must be run as process no 1."); 58 setsid(); 59 60 sig_block(sig_alarm); 61 sig_block(sig_child); 62 sig_catch(sig_child, sig_child_handler); 63 sig_block(sig_cont); 64 sig_catch(sig_cont, sig_cont_handler); 65 sig_block(sig_hangup); 66 sig_block(sig_int); 67 sig_catch(sig_int, sig_int_handler); 68 sig_block(sig_pipe); 69 sig_block(sig_term); 70 71 /* console */ 72 if ((ttyfd =open_write("/dev/console")) != -1) { 73 dup2(ttyfd, 0); dup2(ttyfd, 1); dup2(ttyfd, 2); 74 if (ttyfd > 2) close(ttyfd); 75 } 76 77 /* create selfpipe */ 78 while (pipe(selfpipe) == -1) { 79 strerr_warn2(FATAL, "unable to create selfpipe, pausing: ", &strerr_sys); 80 sleep(5); 81 } 82 coe(selfpipe[0]); 83 coe(selfpipe[1]); 84 ndelay_on(selfpipe[0]); 85 ndelay_on(selfpipe[1]); 86 87 #ifdef RB_DISABLE_CAD 88 /* activate ctrlaltdel handling, glibc, dietlibc */ 89 if (RB_DISABLE_CAD == 0) reboot(0); 90 #endif 91 92 strerr_warn3(INFO, VERSION, ": booting.", 0); 93 94 /* runit */ 95 for (st =0; st < 3; st++) { 96 /* if (st == 2) logwtmp("~", "reboot", ""); */ 97 while ((pid =fork()) == -1) { 98 strerr_warn4(FATAL, "unable to fork for \"", stage[st], "\" pausing: ", 99 &strerr_sys); 100 sleep(5); 101 } 102 if (!pid) { 103 /* child */ 104 prog[0] =stage[st]; 105 prog[1] =0; 106 107 /* stage 1 gets full control of console */ 108 if (st == 0) { 109 if ((ttyfd =open("/dev/console", O_RDWR)) != -1) { 110 #ifdef TIOCSCTTY 111 ioctl(ttyfd, TIOCSCTTY, (char *)0); 112 #endif 113 dup2(ttyfd, 0); 114 if (ttyfd > 2) close(ttyfd); 115 } 116 else 117 strerr_warn2(WARNING, "unable to open /dev/console: ", &strerr_sys); 118 } 119 else 120 setsid(); 121 122 sig_unblock(sig_alarm); 123 sig_unblock(sig_child); 124 sig_uncatch(sig_child); 125 sig_unblock(sig_cont); 126 sig_ignore(sig_cont); 127 sig_unblock(sig_hangup); 128 sig_unblock(sig_int); 129 sig_uncatch(sig_int); 130 sig_unblock(sig_pipe); 131 sig_unblock(sig_term); 132 133 strerr_warn3(INFO, "enter stage: ", stage[st], 0); 134 execve(*prog, (char const *const *)prog, envp); 135 strerr_die4sys(0, FATAL, "unable to start child: ", stage[st], ": "); 136 } 137 138 x.fd =selfpipe[0]; 139 x.events =POLLIN; 140 for (;;) { 141 int child; 142 143 sig_unblock(sig_child); 144 sig_unblock(sig_cont); 145 sig_unblock(sig_int); 146 poll(&x, 1, 14000); 147 sig_block(sig_cont); 148 sig_block(sig_child); 149 sig_block(sig_int); 150 151 while (read(selfpipe[0], &ch, 1) == 1) {} 152 while ((child =waitpid( -1, &wstat, WNOHANG )) > 0) 153 if (child == pid) break; 154 if (child == -1) { 155 strerr_warn2(WARNING, "waitpid, pausing: ", &strerr_sys); 156 sleep(5); 157 } 158 159 /* reget stderr */ 160 if ((ttyfd =open_write("/dev/console")) != -1) { 161 dup2(ttyfd, 2); 162 if (ttyfd > 2) close(ttyfd); 163 } 164 165 if (child == pid) { 166 if (wait_exitcode(wstat) != 0) { 167 if (wait_crashed(wstat)) 168 strerr_warn3(WARNING, "child crashed: ", stage[st], 0); 169 else 170 strerr_warn3(WARNING, "child failed: ", stage[st], 0); 171 if (st == 0) 172 /* this is stage 1 */ 173 if (wait_crashed(wstat) || (wait_exitcode(wstat) == 100)) { 174 strerr_warn3(INFO, "leave stage: ", stage[st], 0); 175 strerr_warn2(WARNING, "skipping stage 2...", 0); 176 st++; 177 break; 178 } 179 if (st == 1) 180 /* this is stage 2 */ 181 if (wait_crashed(wstat) || (wait_exitcode(wstat) == 111)) { 182 strerr_warn2(WARNING, "killing all processes in stage 2...", 0); 183 kill(-pid, 9); 184 sleep(5); 185 strerr_warn2(WARNING, "restarting.", 0); 186 st--; 187 break; 188 } 189 } 190 strerr_warn3(INFO, "leave stage: ", stage[st], 0); 191 break; 192 } 193 if (child != 0) { 194 /* collect terminated children */ 195 write(selfpipe[1], "", 1); 196 continue; 197 } 198 199 /* sig? */ 200 if (!sigc && !sigi) { 201 #ifdef DEBUG 202 strerr_warn2(WARNING, "poll: ", &strerr_sys); 203 #endif 204 continue; 205 } 206 if (st != 1) { 207 strerr_warn2(WARNING, "signals only work in stage 2.", 0); 208 sigc =sigi =0; 209 continue; 210 } 211 if (sigi && (stat(CTRLALTDEL, &s) != -1) && (s.st_mode & S_IXUSR)) { 212 strerr_warn2(INFO, "ctrl-alt-del request...", 0); 213 prog[0] =CTRLALTDEL; prog[1] =0; 214 while ((pid2 =fork()) == -1) { 215 strerr_warn4(FATAL, "unable to fork for \"", CTRLALTDEL, 216 "\" pausing: ", &strerr_sys); 217 sleep(5); 218 } 219 if (!pid2) { 220 /* child */ 221 strerr_warn3(INFO, "enter stage: ", prog[0], 0); 222 execve(*prog, (char const *const *) prog, envp); 223 strerr_die4sys(0, FATAL, "unable to start child: ", prog[0], ": "); 224 } 225 if (wait_pid(&wstat, pid2) == -1) 226 strerr_warn2(FATAL, "wait_pid: ", &strerr_sys); 227 if (wait_crashed(wstat)) 228 strerr_warn3(WARNING, "child crashed: ", CTRLALTDEL, 0); 229 strerr_warn3(INFO, "leave stage: ", prog[0], 0); 230 sigi =0; 231 sigc++; 232 } 233 if (sigc && (stat(STOPIT, &s) != -1) && (s.st_mode & S_IXUSR)) { 234 int i; 235 /* unlink(STOPIT); */ 236 chmod(STOPIT, 0); 237 238 /* kill stage 2 */ 239 #ifdef DEBUG 240 strerr_warn2(WARNING, "sending sigterm...", 0); 241 #endif 242 kill(pid, sig_term); 243 i =0; 244 while (i < 5) { 245 if ((child =waitpid( -1, &wstat, WNOHANG )) == pid) { 246 #ifdef DEBUG 247 strerr_warn2(WARNING, "stage 2 terminated.", 0); 248 #endif 249 pid =0; 250 break; 251 } 252 if (child) continue; 253 if (child == -1) 254 strerr_warn2(WARNING, "waitpid: ", &strerr_sys); 255 #ifdef DEBUG 256 strerr_warn2(WARNING, "waiting...", 0); 257 #endif 258 sleep(1); 259 i++; 260 } 261 if (pid) { 262 /* still there */ 263 strerr_warn2(WARNING, 264 "stage 2 not terminated, sending sigkill...", 0); 265 kill(pid, 9); 266 if (wait_pid(&wstat, pid) == -1) 267 strerr_warn2(WARNING, "wait_pid: ", &strerr_sys); 268 } 269 sigc =0; 270 strerr_warn3(INFO, "leave stage: ", stage[st], 0); 271 272 /* enter stage 3 */ 273 break; 274 } 275 sigc =sigi =0; 276 #ifdef DEBUG 277 strerr_warn2(WARNING, "no request.", 0); 278 #endif 279 } 280 } 281 282 /* reget stderr */ 283 if ((ttyfd =open_write("/dev/console")) != -1) { 284 dup2(ttyfd, 2); 285 if (ttyfd > 2) close(ttyfd); 286 } 287 288 #ifdef RB_AUTOBOOT 289 /* fallthrough stage 3 */ 290 strerr_warn2(INFO, "sending KILL signal to all processes...", 0); 291 kill(-1, SIGKILL); 292 293 pid =fork(); 294 switch (pid) { 295 case 0: 296 case -1: 297 if ((stat(REBOOT, &s) != -1) && (s.st_mode & S_IXUSR)) { 298 strerr_warn2(INFO, "system reboot.", 0); 299 sync(); 300 reboot(RB_AUTOBOOT); 301 } 302 else { 303 #ifdef RB_POWER_OFF 304 strerr_warn2(INFO, "power off...", 0); 305 sync(); 306 reboot(RB_POWER_OFF); 307 sleep(2); 308 #endif 309 #ifdef RB_HALT_SYSTEM 310 strerr_warn2(INFO, "system halt.", 0); 311 sync(); 312 reboot(RB_HALT_SYSTEM); 313 #else 314 #ifdef RB_HALT 315 strerr_warn2(INFO, "system halt.", 0); 316 sync(); 317 reboot(RB_HALT); 318 #else 319 strerr_warn2(INFO, "system reboot.", 0); 320 sync(); 321 reboot(RB_AUTOBOOT); 322 #endif 323 #endif 324 } 325 if (pid == 0) _exit(0); 326 break; 327 default: 328 sig_unblock(sig_child); 329 while (wait_pid(0, pid) == -1); 330 } 331 #endif 332 333 for (;;) sig_pause(); 334 /* not reached */ 335 strerr_die2x(0, INFO, "exit."); 336 return(0); 337 }