init.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This module implements the init utility, which serves as the first user
  7. process on most Unix-like operating systems.
  8. Author:
  9. Evan Green 18-Mar-2015
  10. Environment:
  11. POSIX
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/lib/types.h>
  17. #include <alloca.h>
  18. #include <assert.h>
  19. #include <ctype.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <getopt.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <syslog.h>
  26. #include <sys/ioctl.h>
  27. #include <sys/wait.h>
  28. #include <termios.h>
  29. #include <unistd.h>
  30. #include <utmpx.h>
  31. #include "swlib.h"
  32. #include "login/lutil.h"
  33. //
  34. // --------------------------------------------------------------------- Macros
  35. //
  36. //
  37. // This macro converts the given character into its control code.
  38. //
  39. #define INIT_CONTROL(_Character) ((_Character) ^ 0x40)
  40. //
  41. // ---------------------------------------------------------------- Definitions
  42. //
  43. #define INIT_VERSION_MAJOR 1
  44. #define INIT_VERSION_MINOR 0
  45. #define INIT_USAGE \
  46. "usage: init [options] [runlevel]\n" \
  47. "The init utility performs system initialization steps. The runlevel be \n"\
  48. "1-6, a-c (for on-demand runlevels), q to re-examine inittab, s to \n" \
  49. "switch to single user mode, or u to re-execute. Options are:\n" \
  50. " -d, --debug -- Debug mode, prints more things.\n" \
  51. " -s, -S, --single -- Single-user mode. Examines /etc/inittab and runs \n"\
  52. " bootup rc scripts, then runs a single user shell.\n" \
  53. " -b, --emergency -- Boot directly into a single user shell without\n" \
  54. " running any other startup scripts.\n" \
  55. " --help -- Displays this help text and exits.\n" \
  56. " --version -- Displays the application version and exits.\n"
  57. #define INIT_OPTIONS_STRING "bdsS:hV"
  58. #define INIT_DEFAULT_TERMINAL_TYPE "xterm"
  59. #define INIT_INITTAB_PATH "/etc/inittab"
  60. #define INIT_DEFAULT_CONSOLE "/dev/console"
  61. #define INIT_INIT_SCRIPT "/etc/init.d/rcS"
  62. //
  63. // Define the time between sending SIGTERM and SIGKILL when reloading inittab
  64. // or switching runlevels.
  65. //
  66. #define INIT_KILL_DELAY 5
  67. //
  68. // Define application options.
  69. //
  70. //
  71. // Set this option to to boot into a single user shell, non-emergency.
  72. //
  73. #define INIT_OPTION_SINGLE_USER 0x00000001
  74. //
  75. // Set this option to boot into a single user shell, emergency mode.
  76. //
  77. #define INIT_OPTION_EMERGENCY 0x00000002
  78. //
  79. // Set this option to enable debug mode.
  80. //
  81. #define INIT_OPTION_DEBUG 0x00000004
  82. //
  83. // Define init log destinations.
  84. //
  85. #define INIT_LOG_SYSLOG 0x00000001
  86. #define INIT_LOG_CONSOLE 0x00000002
  87. #define INIT_LOG_DEBUG 0x00000004
  88. //
  89. // Define the init runlevel masks.
  90. //
  91. #define INIT_RUNLEVEL_0 0x00000001
  92. #define INIT_RUNLEVEL_1 0x00000002
  93. #define INIT_RUNLEVEL_2 0x00000004
  94. #define INIT_RUNLEVEL_3 0x00000008
  95. #define INIT_RUNLEVEL_4 0x00000010
  96. #define INIT_RUNLEVEL_5 0x00000020
  97. #define INIT_RUNLEVEL_6 0x00000040
  98. #define INIT_RUNLEVEL_7 0x00000080
  99. #define INIT_RUNLEVEL_8 0x00000100
  100. #define INIT_RUNLEVEL_9 0x00000200
  101. #define INIT_RUNLEVEL_A 0x00000400
  102. #define INIT_RUNLEVEL_B 0x00000800
  103. #define INIT_RUNLEVEL_C 0x00001000
  104. #define INIT_RUNLEVEL_S 0x00002000
  105. #define INIT_RUNLEVEL_MASK 0x00003FFF
  106. #define INIT_RUNLEVEL_NAMES "0123456789ABCS"
  107. //
  108. // ------------------------------------------------------ Data Type Definitions
  109. //
  110. typedef enum _INIT_ACTION_TYPE {
  111. InitActionInvalid,
  112. InitActionNone,
  113. InitActionSysinit,
  114. InitActionBoot,
  115. InitActionBootWait,
  116. InitActionWait,
  117. InitActionOnce,
  118. InitActionRespawn,
  119. InitActionCtrlAltDel,
  120. InitActionShutdown,
  121. InitActionRestart,
  122. InitActionOnDemand,
  123. InitActionInitDefault,
  124. InitActionCount
  125. } INIT_ACTION_TYPE, *PINIT_ACTION_TYPE;
  126. typedef enum _INIT_REBOOT_PHASE {
  127. InitNotRebooting,
  128. InitRebootRunningActions,
  129. InitRebootTerm,
  130. InitRebootKill,
  131. InitRebootComplete
  132. } INIT_REBOOT_PHASE, *PINIT_REBOOT_PHASE;
  133. /*++
  134. Structure Description:
  135. This structure stores information about an init action.
  136. Members:
  137. ListEntry - Stores pointers to the next and previous init actions.
  138. ProcessId - Stores the process ID if the action is currently running.
  139. Id - Stores the ID of the command.
  140. RunLevels - Stores the bitmask of runlevels this action applies to.
  141. Type - Stores the action flavor.
  142. Command - Stores the command to execute.
  143. --*/
  144. typedef struct _INIT_ACTION {
  145. LIST_ENTRY ListEntry;
  146. pid_t ProcessId;
  147. CHAR Id[5];
  148. ULONG RunLevels;
  149. INIT_ACTION_TYPE Type;
  150. PSTR Command;
  151. } INIT_ACTION, *PINIT_ACTION;
  152. /*++
  153. Structure Description:
  154. This structure stores information about an init application instance.
  155. Members:
  156. SyslogOpen - Stores a boolean indicating whether the system log has been
  157. opened yet or not.
  158. Options - Stores the application options. See INIT_OPTION_* definitions.
  159. ActionList - Stores the head of the list of init actions.
  160. DefaultRunLevel - Stores the default runlevel (mask) to go to. Only one
  161. bit should be set here.
  162. CurrentRunLevel - Stores the current runlevel (mask). Only one bit should
  163. be set here.
  164. PreviousRunLevel - Stores the previous runlevel (mask). Only one bit should
  165. be set.
  166. RebootPhase - Stores the phase of system reboot init is currently working
  167. towards.
  168. RebootSignal - Stores the signal that initiated the reboot action, which
  169. also dictates the type.
  170. --*/
  171. typedef struct _INIT_CONTEXT {
  172. BOOL SyslogOpen;
  173. ULONG Options;
  174. LIST_ENTRY ActionList;
  175. ULONG DefaultRunLevel;
  176. ULONG CurrentRunLevel;
  177. ULONG PreviousRunLevel;
  178. INIT_REBOOT_PHASE RebootPhase;
  179. ULONG RebootSignal;
  180. } INIT_CONTEXT, *PINIT_CONTEXT;
  181. //
  182. // ----------------------------------------------- Internal Function Prototypes
  183. //
  184. VOID
  185. InitInitializeConsole (
  186. PINIT_CONTEXT Context
  187. );
  188. VOID
  189. InitConfigureTerminal (
  190. VOID
  191. );
  192. BOOL
  193. InitCheckSignals (
  194. PINIT_CONTEXT Context
  195. );
  196. VOID
  197. InitReloadInittab (
  198. PINIT_CONTEXT Context
  199. );
  200. VOID
  201. InitReexec (
  202. PINIT_CONTEXT Context
  203. );
  204. VOID
  205. InitRunResetSystem (
  206. PINIT_CONTEXT Context,
  207. INT Signal
  208. );
  209. VOID
  210. InitShutdownAndKillProcesses (
  211. PINIT_CONTEXT Context
  212. );
  213. VOID
  214. InitReboot (
  215. PINIT_CONTEXT Context,
  216. SWISS_REBOOT_TYPE RebootType
  217. );
  218. VOID
  219. InitParseInittab (
  220. PINIT_CONTEXT Context
  221. );
  222. VOID
  223. InitCreateAction (
  224. PINIT_CONTEXT Context,
  225. PSTR Id,
  226. ULONG RunLevels,
  227. INIT_ACTION_TYPE ActionType,
  228. PSTR Command
  229. );
  230. VOID
  231. InitRunActions (
  232. PINIT_CONTEXT Context,
  233. INIT_ACTION_TYPE ActionType,
  234. ULONG RunLevelMask
  235. );
  236. pid_t
  237. InitRunAction (
  238. PINIT_CONTEXT Context,
  239. PINIT_ACTION Action
  240. );
  241. VOID
  242. InitExec (
  243. PINIT_CONTEXT Context,
  244. PSTR Command
  245. );
  246. VOID
  247. InitWaitForProcess (
  248. PINIT_CONTEXT Context,
  249. pid_t ProcessId
  250. );
  251. PINIT_ACTION
  252. InitMarkProcessTerminated (
  253. PINIT_CONTEXT Context,
  254. pid_t ProcessId,
  255. int Status
  256. );
  257. VOID
  258. InitResetSignalHandlers (
  259. VOID
  260. );
  261. VOID
  262. InitLog (
  263. PINIT_CONTEXT Context,
  264. ULONG Destination,
  265. PSTR Format,
  266. ...
  267. );
  268. void
  269. InitSignalHandler (
  270. int Signal
  271. );
  272. //
  273. // -------------------------------------------------------------------- Globals
  274. //
  275. extern char **environ;
  276. struct option InitLongOptions[] = {
  277. {"debug", no_argument, 0, 'd'},
  278. {"single", no_argument, 0, 's'},
  279. {"emergency", no_argument, 0, 'b'},
  280. {"help", no_argument, 0, 'H'},
  281. {"version", no_argument, 0, 'V'},
  282. {NULL, 0, 0, 0},
  283. };
  284. const PSTR InitActionTypeNames[InitActionCount] = {
  285. "INVALID",
  286. "off",
  287. "sysinit",
  288. "boot",
  289. "bootwait",
  290. "wait",
  291. "once",
  292. "respawn",
  293. "ctrlaltdel",
  294. "shutdown",
  295. "restart",
  296. "ondemand",
  297. "initdefault"
  298. };
  299. PUINTN InitSignalCounts = NULL;
  300. //
  301. // ------------------------------------------------------------------ Functions
  302. //
  303. INT
  304. InitMain (
  305. INT ArgumentCount,
  306. CHAR **Arguments
  307. )
  308. /*++
  309. Routine Description:
  310. This routine is the main entry point for the init utility.
  311. Arguments:
  312. ArgumentCount - Supplies the number of command line arguments the program
  313. was invoked with.
  314. Arguments - Supplies a tokenized array of command line arguments.
  315. Return Value:
  316. Returns an integer exit code. 0 for success, nonzero otherwise.
  317. --*/
  318. {
  319. PINIT_ACTION Action;
  320. ULONG ArgumentIndex;
  321. CHAR Character;
  322. INIT_CONTEXT Context;
  323. PLIST_ENTRY CurrentEntry;
  324. UINTN Index;
  325. int NoHang;
  326. INT Option;
  327. ULONG Options;
  328. pid_t ProcessId;
  329. PSTR RunLevelString;
  330. struct sigaction SignalAction;
  331. UINTN SignalCounts[NSIG];
  332. int Status;
  333. Options = 0;
  334. RunLevelString = NULL;
  335. memset(&Context, 0, sizeof(INIT_CONTEXT));
  336. INITIALIZE_LIST_HEAD(&(Context.ActionList));
  337. memset(SignalCounts, 0, sizeof(SignalCounts));
  338. InitSignalCounts = SignalCounts;
  339. //
  340. // Process the control arguments.
  341. //
  342. while (TRUE) {
  343. Option = getopt_long(ArgumentCount,
  344. Arguments,
  345. INIT_OPTIONS_STRING,
  346. InitLongOptions,
  347. NULL);
  348. if (Option == -1) {
  349. break;
  350. }
  351. if ((Option == '?') || (Option == ':')) {
  352. Status = 1;
  353. goto MainEnd;
  354. }
  355. switch (Option) {
  356. case 'b':
  357. Options |= INIT_OPTION_EMERGENCY;
  358. break;
  359. case 'd':
  360. Options |= INIT_OPTION_DEBUG;
  361. break;
  362. case 'S':
  363. case 's':
  364. Options |= INIT_OPTION_SINGLE_USER;
  365. break;
  366. case 'V':
  367. SwPrintVersion(INIT_VERSION_MAJOR, INIT_VERSION_MINOR);
  368. return 1;
  369. case 'h':
  370. printf(INIT_USAGE);
  371. return 1;
  372. default:
  373. assert(FALSE);
  374. Status = 1;
  375. goto MainEnd;
  376. }
  377. }
  378. ArgumentIndex = optind;
  379. if (ArgumentIndex > ArgumentCount) {
  380. ArgumentIndex = ArgumentCount;
  381. }
  382. if (ArgumentIndex < ArgumentCount) {
  383. RunLevelString = Arguments[ArgumentIndex];
  384. ArgumentIndex += 1;
  385. }
  386. Context.Options = Options;
  387. InitInitializeConsole(&Context);
  388. InitConfigureTerminal();
  389. Status = chdir("/");
  390. if (Status != 0) {
  391. Status = errno;
  392. goto MainEnd;
  393. }
  394. setsid();
  395. //
  396. // Set some default environment variables.
  397. //
  398. setenv("HOME", "/", 0);
  399. setenv("PATH", SUPERUSER_DEFAULT_PATH, 0);
  400. setenv("SHELL", USER_FALLBACK_SHELL, 0);
  401. if (RunLevelString != NULL) {
  402. setenv("RUNLEVEL", RunLevelString, 1);
  403. }
  404. InitLog(&Context,
  405. INIT_LOG_SYSLOG | INIT_LOG_DEBUG,
  406. "Minoca init v%d.%d.%d",
  407. INIT_VERSION_MAJOR,
  408. INIT_VERSION_MINOR,
  409. SwGetSerialVersion());
  410. Status = 0;
  411. //
  412. // In emergency mode, just specify a shell to drop into.
  413. //
  414. if ((Options & INIT_OPTION_EMERGENCY) != 0) {
  415. InitCreateAction(&Context,
  416. "0",
  417. INIT_RUNLEVEL_MASK,
  418. InitActionRespawn,
  419. USER_FALLBACK_SHELL);
  420. } else {
  421. InitParseInittab(&Context);
  422. }
  423. //
  424. // In single-user mode, shoot for S.
  425. //
  426. if ((Options & INIT_OPTION_SINGLE_USER) != 0) {
  427. Context.DefaultRunLevel = INIT_RUNLEVEL_S;
  428. //
  429. // Shoot for whatever runlevel is on the command line.
  430. //
  431. } else if (RunLevelString != NULL) {
  432. if (strlen(RunLevelString) != 1) {
  433. InitLog(&Context,
  434. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  435. "Invalid runlevel argument: %s",
  436. RunLevelString);
  437. } else {
  438. Index = 0;
  439. Character = toupper(*RunLevelString);
  440. while (INIT_RUNLEVEL_NAMES[Index] != '\0') {
  441. if (INIT_RUNLEVEL_NAMES[Index] == Character) {
  442. Context.DefaultRunLevel = 1 << Index;
  443. break;
  444. }
  445. }
  446. if (INIT_RUNLEVEL_NAMES[Index] == '\0') {
  447. InitLog(&Context,
  448. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  449. "Invalid runlevel argument: %s",
  450. RunLevelString);
  451. }
  452. }
  453. }
  454. Context.CurrentRunLevel = Context.DefaultRunLevel;
  455. Context.PreviousRunLevel = Context.CurrentRunLevel;
  456. //
  457. // Set up the signal handlers.
  458. //
  459. memset(&SignalAction, 0, sizeof(SignalAction));
  460. sigfillset(&(SignalAction.sa_mask));
  461. SignalAction.sa_handler = SIG_IGN;
  462. sigaction(SIGTSTP, &SignalAction, NULL);
  463. SignalAction.sa_handler = InitSignalHandler;
  464. sigaction(SIGINT, &SignalAction, NULL);
  465. sigaction(SIGQUIT, &SignalAction, NULL);
  466. sigaction(SIGUSR1, &SignalAction, NULL);
  467. sigaction(SIGUSR2, &SignalAction, NULL);
  468. sigaction(SIGTERM, &SignalAction, NULL);
  469. sigaction(SIGHUP, &SignalAction, NULL);
  470. sigaction(SIGALRM, &SignalAction, NULL);
  471. //
  472. // Perform the actions.
  473. //
  474. InitRunActions(&Context, InitActionSysinit, 0);
  475. InitCheckSignals(&Context);
  476. InitRunActions(&Context, InitActionBoot, 0);
  477. InitCheckSignals(&Context);
  478. InitRunActions(&Context, InitActionBootWait, 0);
  479. InitCheckSignals(&Context);
  480. InitRunActions(&Context, InitActionWait, Context.CurrentRunLevel);
  481. InitCheckSignals(&Context);
  482. InitRunActions(&Context, InitActionOnce, Context.CurrentRunLevel);
  483. //
  484. // Now loop forever.
  485. //
  486. while (TRUE) {
  487. NoHang = 0;
  488. if (InitCheckSignals(&Context) != FALSE) {
  489. NoHang = WNOHANG;
  490. }
  491. //
  492. // Respawn processes unless a reboot is in progress.
  493. //
  494. if (Context.RebootPhase == InitNotRebooting) {
  495. InitRunActions(&Context,
  496. InitActionRespawn,
  497. Context.CurrentRunLevel);
  498. }
  499. if (InitCheckSignals(&Context) != FALSE) {
  500. NoHang = WNOHANG;
  501. }
  502. if (Context.RebootPhase == InitNotRebooting) {
  503. sleep(1);
  504. }
  505. if (InitCheckSignals(&Context) != FALSE) {
  506. NoHang = WNOHANG;
  507. }
  508. //
  509. // Loop getting all dead processes. There is a race in here where if a
  510. // new signal were to come in now but no child processes were ready,
  511. // the wait would just block, leaving a signal delivered but not dealt
  512. // with. That signal will be dealt with once the next child dies.
  513. //
  514. while (TRUE) {
  515. ProcessId = waitpid(-1, &Status, NoHang);
  516. if (ProcessId <= 0) {
  517. //
  518. // If there are no more children left and a reboot is requested,
  519. // go do it now.
  520. //
  521. if ((Context.RebootPhase > InitRebootRunningActions) &&
  522. (errno == ECHILD) && (NoHang == 0)) {
  523. Context.RebootPhase = InitRebootComplete;
  524. InitRunResetSystem(&Context, 0);
  525. }
  526. break;
  527. }
  528. InitMarkProcessTerminated(&Context, ProcessId, Status);
  529. NoHang = WNOHANG;
  530. }
  531. }
  532. Status = 0;
  533. MainEnd:
  534. InitResetSignalHandlers();
  535. CurrentEntry = Context.ActionList.Next;
  536. while (CurrentEntry != &(Context.ActionList)) {
  537. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  538. CurrentEntry = CurrentEntry->Next;
  539. free(Action);
  540. }
  541. return Status;
  542. }
  543. //
  544. // --------------------------------------------------------- Internal Functions
  545. //
  546. VOID
  547. InitInitializeConsole (
  548. PINIT_CONTEXT Context
  549. )
  550. /*++
  551. Routine Description:
  552. This routine initializes the console.
  553. Arguments:
  554. Context - Supplies a pointer to the application context.
  555. Return Value:
  556. None.
  557. --*/
  558. {
  559. PSTR Console;
  560. int Descriptor;
  561. PSTR TermVariable;
  562. Console = getenv("CONSOLE");
  563. if (Console == NULL) {
  564. Console = getenv("console");
  565. }
  566. //
  567. // Set it to a default.
  568. //
  569. if (Console == NULL) {
  570. Console = INIT_DEFAULT_CONSOLE;
  571. setenv("CONSOLE", Console, 1);
  572. }
  573. if (Console != NULL) {
  574. Descriptor = open(Console, O_RDWR | O_NONBLOCK | O_NOCTTY);
  575. if (Descriptor >= 0) {
  576. dup2(Descriptor, STDIN_FILENO);
  577. dup2(Descriptor, STDOUT_FILENO);
  578. dup2(Descriptor, STDERR_FILENO);
  579. if (Descriptor > STDERR_FILENO) {
  580. close(Descriptor);
  581. }
  582. }
  583. InitLog(Context, INIT_LOG_SYSLOG, "CONSOLE=%s", Console);
  584. }
  585. TermVariable = getenv("TERM");
  586. if (TermVariable == NULL) {
  587. setenv("TERM", INIT_DEFAULT_TERMINAL_TYPE, 1);
  588. }
  589. return;
  590. }
  591. VOID
  592. InitConfigureTerminal (
  593. VOID
  594. )
  595. /*++
  596. Routine Description:
  597. This routine sets some sane defaults for the terminal.
  598. Arguments:
  599. None.
  600. Return Value:
  601. None.
  602. --*/
  603. {
  604. struct termios Settings;
  605. if (tcgetattr(STDIN_FILENO, &Settings) != 0) {
  606. return;
  607. }
  608. Settings.c_cc[VINTR] = INIT_CONTROL('C');
  609. Settings.c_cc[VQUIT] = INIT_CONTROL('\\');
  610. Settings.c_cc[VERASE] = INIT_CONTROL('?');
  611. Settings.c_cc[VKILL] = INIT_CONTROL('U');
  612. Settings.c_cc[VEOF] = INIT_CONTROL('D');
  613. Settings.c_cc[VSTART] = INIT_CONTROL('Q');
  614. Settings.c_cc[VSTOP] = INIT_CONTROL('S');
  615. Settings.c_cc[VSUSP] = INIT_CONTROL('Z');
  616. //
  617. // Save the character size, stop bits, and parity configuration. Add in
  618. // receiver enable, hangup on close, and the local flag.
  619. //
  620. Settings.c_cflag &= CSIZE | CSTOPB | PARENB | PARODD;
  621. Settings.c_cflag |= CREAD | HUPCL | CLOCAL;
  622. Settings.c_iflag = ICRNL | IXON | IXOFF;
  623. Settings.c_oflag = OPOST | ONLCR;
  624. Settings.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOKE | ECHOCTL | IEXTEN;
  625. tcsetattr(STDIN_FILENO, TCSANOW, &Settings);
  626. return;
  627. }
  628. BOOL
  629. InitCheckSignals (
  630. PINIT_CONTEXT Context
  631. )
  632. /*++
  633. Routine Description:
  634. This routine checks for any signals that might have occurred recently.
  635. Arguments:
  636. Context - Supplies a pointer to the application context.
  637. Return Value:
  638. TRUE if a signal was processed.
  639. FALSE if no signals were processed.
  640. --*/
  641. {
  642. INT Signal;
  643. BOOL SignalsSeen;
  644. SignalsSeen = FALSE;
  645. while (TRUE) {
  646. //
  647. // Exit quickly if no signals occurred.
  648. //
  649. if (InitSignalCounts[0] == 0) {
  650. break;
  651. }
  652. //
  653. // Clear the "signals seen" boolean before checking.
  654. //
  655. InitSignalCounts[0] = 0;
  656. for (Signal = 1; Signal < NSIG; Signal += 1) {
  657. if (InitSignalCounts[Signal] != 0) {
  658. SignalsSeen = TRUE;
  659. InitSignalCounts[Signal] = 0;
  660. if (Signal == SIGINT) {
  661. InitRunActions(Context, InitActionCtrlAltDel, 0);
  662. } else if (Signal == SIGQUIT) {
  663. InitReexec(Context);
  664. } else if (Signal == SIGHUP) {
  665. InitReloadInittab(Context);
  666. } else if (Signal == SIGALRM) {
  667. if (Context->RebootPhase == InitRebootTerm) {
  668. Context->RebootPhase = InitRebootKill;
  669. InitRunResetSystem(Context, Signal);
  670. } else if (Context->RebootPhase == InitRebootKill) {
  671. Context->RebootPhase = InitRebootComplete;
  672. InitRunResetSystem(Context, Signal);
  673. }
  674. //
  675. // Other signals initiate a reboot.
  676. //
  677. } else {
  678. if (Context->RebootPhase == InitNotRebooting) {
  679. InitRunResetSystem(Context, Signal);
  680. }
  681. }
  682. }
  683. }
  684. }
  685. return SignalsSeen;
  686. }
  687. VOID
  688. InitReloadInittab (
  689. PINIT_CONTEXT Context
  690. )
  691. /*++
  692. Routine Description:
  693. This routine attempts to reload the inittab file, and reconcile the
  694. processes.
  695. Arguments:
  696. Context - Supplies a pointer to the application context.
  697. Return Value:
  698. None.
  699. --*/
  700. {
  701. PINIT_ACTION Action;
  702. pid_t Child;
  703. PLIST_ENTRY CurrentEntry;
  704. InitLog(Context,
  705. INIT_LOG_SYSLOG | INIT_LOG_DEBUG,
  706. "Reloading inittab");
  707. //
  708. // Clear out all the action types to know which entries don't show up
  709. // in the new file.
  710. //
  711. CurrentEntry = Context->ActionList.Next;
  712. while (CurrentEntry != &(Context->ActionList)) {
  713. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  714. Action->Type = InitActionInvalid;
  715. CurrentEntry = CurrentEntry->Next;
  716. }
  717. Context->PreviousRunLevel = Context->CurrentRunLevel;
  718. InitParseInittab(Context);
  719. //
  720. // Remove any leftover entries.
  721. //
  722. CurrentEntry = Context->ActionList.Next;
  723. while (CurrentEntry != &(Context->ActionList)) {
  724. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  725. CurrentEntry = CurrentEntry->Next;
  726. //
  727. // Kill a running entry that's either 1) not in the new inittab or
  728. // 2) Got a runlevel and it's not the current runlevel.
  729. //
  730. if ((Action->ProcessId > 0) &&
  731. ((Action->Type == InitActionInvalid) ||
  732. ((Action->RunLevels != 0) &&
  733. ((Action->RunLevels & Context->CurrentRunLevel) == 0)))) {
  734. InitLog(Context,
  735. INIT_LOG_DEBUG,
  736. "Killing: %d: %s",
  737. Action->ProcessId,
  738. Action->Command);
  739. kill(Action->ProcessId, SIGTERM);
  740. }
  741. }
  742. //
  743. // Fork, wait a bit, and then send kill to all these processes.
  744. //
  745. Child = fork();
  746. if (Child == 0) {
  747. sleep(INIT_KILL_DELAY);
  748. CurrentEntry = Context->ActionList.Next;
  749. while (CurrentEntry != &(Context->ActionList)) {
  750. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  751. if ((Action->ProcessId > 0) &&
  752. ((Action->Type == InitActionInvalid) ||
  753. ((Action->RunLevels != 0) &&
  754. ((Action->RunLevels & Context->CurrentRunLevel) == 0)))) {
  755. kill(Action->ProcessId, SIGKILL);
  756. }
  757. CurrentEntry = CurrentEntry->Next;
  758. }
  759. _exit(0);
  760. }
  761. //
  762. // Remove the unused entries. Also take the opportunity to free sysinit and
  763. // boot entries, which are never used again.
  764. //
  765. CurrentEntry = Context->ActionList.Next;
  766. while (CurrentEntry != &(Context->ActionList)) {
  767. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  768. CurrentEntry = CurrentEntry->Next;
  769. if ((Action->Type == InitActionInvalid) ||
  770. (Action->Type == InitActionSysinit) ||
  771. (Action->Type == InitActionBoot) ||
  772. (Action->Type == InitActionBootWait)) {
  773. LIST_REMOVE(&(Action->ListEntry));
  774. free(Action);
  775. }
  776. }
  777. return;
  778. }
  779. VOID
  780. InitReexec (
  781. PINIT_CONTEXT Context
  782. )
  783. /*++
  784. Routine Description:
  785. This routine attempts to run the restart action, execing init into that
  786. action.
  787. Arguments:
  788. Context - Supplies a pointer to the application context.
  789. Return Value:
  790. None. Does not return on success.
  791. --*/
  792. {
  793. PINIT_ACTION Action;
  794. PLIST_ENTRY CurrentEntry;
  795. CurrentEntry = Context->ActionList.Next;
  796. while (CurrentEntry != &(Context->ActionList)) {
  797. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  798. if (Action->Type == InitActionRestart) {
  799. break;
  800. }
  801. CurrentEntry = CurrentEntry->Next;
  802. }
  803. if (CurrentEntry == &(Context->ActionList)) {
  804. InitLog(Context, INIT_LOG_SYSLOG, "No restart action found");
  805. return;
  806. }
  807. InitResetSignalHandlers();
  808. InitShutdownAndKillProcesses(Context);
  809. InitLog(Context,
  810. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  811. "Re-exec init: %s",
  812. Action->Command);
  813. InitExec(Context, Action->Command);
  814. InitReboot(Context, RebootTypeHalt);
  815. return;
  816. }
  817. VOID
  818. InitRunResetSystem (
  819. PINIT_CONTEXT Context,
  820. INT Signal
  821. )
  822. /*++
  823. Routine Description:
  824. This routine runs the tasks associated with resetting the system, and then
  825. resets the system.
  826. Arguments:
  827. Context - Supplies a pointer to the application context.
  828. Signal - Supplies the signal, which dictates the type of actions and
  829. power state to enter.
  830. Return Value:
  831. None.
  832. --*/
  833. {
  834. PSTR Message;
  835. SWISS_REBOOT_TYPE RebootType;
  836. switch (Context->RebootPhase) {
  837. case InitNotRebooting:
  838. Context->RebootPhase = InitRebootRunningActions;
  839. Context->RebootSignal = Signal;
  840. InitResetSignalHandlers();
  841. case InitRebootRunningActions:
  842. InitShutdownAndKillProcesses(Context);
  843. Context->RebootPhase = InitRebootTerm;
  844. //
  845. // Fall through.
  846. //
  847. case InitRebootTerm:
  848. case InitRebootKill:
  849. InitShutdownAndKillProcesses(Context);
  850. alarm(10);
  851. break;
  852. case InitRebootComplete:
  853. Signal = Context->RebootSignal;
  854. Message = "halt";
  855. RebootType = RebootTypeHalt;
  856. if (Signal == SIGTERM) {
  857. Message = "reboot";
  858. RebootType = RebootTypeWarm;
  859. } else if (Signal == SIGUSR2) {
  860. Message = "poweroff";
  861. }
  862. InitLog(Context,
  863. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  864. "Requesting system %s.",
  865. Message);
  866. InitReboot(Context, RebootType);
  867. break;
  868. default:
  869. assert(FALSE);
  870. break;
  871. }
  872. return;
  873. }
  874. VOID
  875. InitShutdownAndKillProcesses (
  876. PINIT_CONTEXT Context
  877. )
  878. /*++
  879. Routine Description:
  880. This routine runs the shutdown action and attempts to kill all processes.
  881. Arguments:
  882. Context - Supplies a pointer to the application context.
  883. Return Value:
  884. None.
  885. --*/
  886. {
  887. if (Context->RebootPhase == InitNotRebooting) {
  888. InitRunActions(Context, InitActionShutdown, 0);
  889. InitLog(Context,
  890. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  891. "The system is going down.");
  892. kill(-1, SIGTERM);
  893. sleep(1);
  894. kill(-1, SIGKILL);
  895. sync();
  896. } else if (Context->RebootPhase == InitRebootRunningActions) {
  897. InitRunActions(Context, InitActionShutdown, 0);
  898. InitLog(Context,
  899. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  900. "The system is going down.");
  901. } else if (Context->RebootPhase == InitRebootTerm) {
  902. kill(-1, SIGTERM);
  903. InitLog(Context,
  904. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  905. "Sent SIG%s to all processes.",
  906. "TERM");
  907. } else if (Context->RebootPhase == InitRebootKill) {
  908. kill(-1, SIGKILL);
  909. InitLog(Context,
  910. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  911. "Sent SIG%s to all processes.",
  912. "KILL");
  913. }
  914. return;
  915. }
  916. VOID
  917. InitReboot (
  918. PINIT_CONTEXT Context,
  919. SWISS_REBOOT_TYPE RebootType
  920. )
  921. /*++
  922. Routine Description:
  923. This routine actually resets the system.
  924. Arguments:
  925. Context - Supplies a pointer to the application context.
  926. RebootType - Supplies the type of reboot to perform.
  927. Return Value:
  928. None.
  929. --*/
  930. {
  931. pid_t Child;
  932. sleep(1);
  933. //
  934. // Do this in a child process since some reboot implementations exit,
  935. // which some OSes might have a problem with for pid 1.
  936. //
  937. Child = fork();
  938. if (Child == 0) {
  939. SwResetSystem(RebootType);
  940. _exit(0);
  941. }
  942. _exit(0);
  943. return;
  944. }
  945. VOID
  946. InitParseInittab (
  947. PINIT_CONTEXT Context
  948. )
  949. /*++
  950. Routine Description:
  951. This routine parses the inittab file.
  952. Arguments:
  953. Context - Supplies a pointer to the application context.
  954. Return Value:
  955. None.
  956. --*/
  957. {
  958. INIT_ACTION_TYPE ActionType;
  959. CHAR Character;
  960. PSTR Colon;
  961. PSTR Fields[4];
  962. FILE *File;
  963. UINTN Index;
  964. char *Line;
  965. size_t LineBufferSize;
  966. ssize_t LineSize;
  967. ULONG RunLevelMask;
  968. INT Status;
  969. PSTR String;
  970. Line = NULL;
  971. LineBufferSize = 0;
  972. File = fopen(INIT_INITTAB_PATH, "r");
  973. if (File == NULL) {
  974. Status = errno;
  975. //
  976. // If there is no inittab, create a basic one.
  977. //
  978. if (Status == ENOENT) {
  979. InitCreateAction(Context,
  980. "1",
  981. INIT_RUNLEVEL_1,
  982. InitActionSysinit,
  983. INIT_INIT_SCRIPT);
  984. InitCreateAction(Context,
  985. "2",
  986. INIT_RUNLEVEL_1,
  987. InitActionOnce,
  988. USER_FALLBACK_SHELL);
  989. InitCreateAction(Context,
  990. "3",
  991. INIT_RUNLEVEL_1,
  992. InitActionInitDefault,
  993. NULL);
  994. InitCreateAction(Context,
  995. "4",
  996. 0,
  997. InitActionCtrlAltDel,
  998. "reboot");
  999. InitCreateAction(Context,
  1000. "5",
  1001. 0,
  1002. InitActionShutdown,
  1003. "reboot -h");
  1004. InitCreateAction(Context,
  1005. "6",
  1006. 0,
  1007. InitActionRestart,
  1008. "init");
  1009. Status = 0;
  1010. }
  1011. goto ParseInittabEnd;
  1012. }
  1013. //
  1014. // Loop parsing entries in the following form:
  1015. // id:runlevels:action:command...
  1016. //
  1017. while (TRUE) {
  1018. LineSize = getline(&Line, &LineBufferSize, File);
  1019. if (LineSize < 0) {
  1020. break;
  1021. }
  1022. while ((LineSize != 0) && (isspace(Line[LineSize - 1]))) {
  1023. LineSize -= 1;
  1024. }
  1025. String = Line;
  1026. String[LineSize] = '\0';
  1027. //
  1028. // Get past whitespace.
  1029. //
  1030. while (isspace(*String)) {
  1031. String += 1;
  1032. }
  1033. //
  1034. // Skip any commented lines.
  1035. //
  1036. if ((*String == '\0') || (*String == '#')) {
  1037. continue;
  1038. }
  1039. //
  1040. // Parse out the first three fields that have colons after them.
  1041. //
  1042. for (Index = 0; Index < 3; Index += 1) {
  1043. Fields[Index] = String;
  1044. Colon = strchr(String, ':');
  1045. if (Colon == NULL) {
  1046. InitLog(Context,
  1047. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1048. "Ignoring: %s",
  1049. Line);
  1050. break;
  1051. }
  1052. *Colon = '\0';
  1053. String = Colon + 1;
  1054. }
  1055. if (Index != 3) {
  1056. continue;
  1057. }
  1058. //
  1059. // The last field gets the rest of the line.
  1060. //
  1061. Fields[Index] = String;
  1062. //
  1063. // Figure out the action type, the third field.
  1064. //
  1065. for (Index = 0; Index < InitActionCount; Index += 1) {
  1066. if (strcmp(Fields[2], InitActionTypeNames[Index]) == 0) {
  1067. ActionType = Index;
  1068. break;
  1069. }
  1070. }
  1071. if (Index == InitActionCount) {
  1072. InitLog(Context,
  1073. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1074. "Unknown action type: %s",
  1075. Fields[2]);
  1076. continue;
  1077. }
  1078. //
  1079. // Figure out the runlevel mask.
  1080. //
  1081. RunLevelMask = 0;
  1082. String = Fields[1];
  1083. while (*String != '\0') {
  1084. Index = 0;
  1085. Character = toupper(*String);
  1086. while (INIT_RUNLEVEL_NAMES[Index] != '\0') {
  1087. if (Character == INIT_RUNLEVEL_NAMES[Index]) {
  1088. RunLevelMask |= 1 << Index;
  1089. break;
  1090. }
  1091. Index += 1;
  1092. }
  1093. if (INIT_RUNLEVEL_NAMES[Index] == '\0') {
  1094. InitLog(Context,
  1095. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1096. "Ignoring unknown runlevel %c",
  1097. Character);
  1098. }
  1099. String += 1;
  1100. }
  1101. InitCreateAction(Context,
  1102. Fields[0],
  1103. RunLevelMask,
  1104. ActionType,
  1105. Fields[3]);
  1106. }
  1107. Status = 0;
  1108. ParseInittabEnd:
  1109. if (File != NULL) {
  1110. fclose(File);
  1111. }
  1112. if (Line != NULL) {
  1113. free(Line);
  1114. }
  1115. if (Status != 0) {
  1116. InitLog(Context,
  1117. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1118. "Failed to parse inittab, adding default entry: %s",
  1119. strerror(Status));
  1120. InitCreateAction(Context,
  1121. "0",
  1122. INIT_RUNLEVEL_MASK,
  1123. InitActionRespawn,
  1124. USER_FALLBACK_SHELL);
  1125. }
  1126. return;
  1127. }
  1128. VOID
  1129. InitCreateAction (
  1130. PINIT_CONTEXT Context,
  1131. PSTR Id,
  1132. ULONG RunLevels,
  1133. INIT_ACTION_TYPE ActionType,
  1134. PSTR Command
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. This routine creates and adds a new init action to the application context.
  1139. Arguments:
  1140. Context - Supplies a pointer to the application context.
  1141. Id - Supplies up to 4 characters of ID information.
  1142. RunLevels - Supplies the mask of runlevels this action is active for.
  1143. ActionType - Supplies the type of action.
  1144. Command - Supplies a pointer to the command to run.
  1145. Return Value:
  1146. None.
  1147. --*/
  1148. {
  1149. PINIT_ACTION Action;
  1150. size_t AllocationSize;
  1151. PLIST_ENTRY CurrentEntry;
  1152. if (Id == NULL) {
  1153. Id = "";
  1154. }
  1155. //
  1156. // If this is an "init default" action, just save the default run-level
  1157. // but don't bother creating a full action.
  1158. //
  1159. if (ActionType == InitActionInitDefault) {
  1160. Context->DefaultRunLevel = RunLevels;
  1161. return;
  1162. }
  1163. //
  1164. // Search for an action that exists already. Use this to avoid losing
  1165. // running actions.
  1166. //
  1167. CurrentEntry = Context->ActionList.Next;
  1168. while (CurrentEntry != &(Context->ActionList)) {
  1169. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  1170. if ((strcmp(Id, Action->Id) == 0) &&
  1171. (strcmp(Command, Action->Command) == 0)) {
  1172. LIST_REMOVE(&(Action->ListEntry));
  1173. break;
  1174. }
  1175. CurrentEntry = CurrentEntry->Next;
  1176. }
  1177. //
  1178. // Allocate a new entry if one was not found.
  1179. //
  1180. if (CurrentEntry == &(Context->ActionList)) {
  1181. AllocationSize = sizeof(INIT_ACTION) + strlen(Command) + 1;
  1182. Action = malloc(AllocationSize);
  1183. if (Action == NULL) {
  1184. return;
  1185. }
  1186. memset(Action, 0, AllocationSize);
  1187. Action->Command = (PSTR)(Action + 1);
  1188. }
  1189. strncpy(Action->Id, Id, sizeof(Action->Id) - 1);
  1190. strcpy(Action->Command, Command);
  1191. Action->Type = ActionType;
  1192. Action->RunLevels = RunLevels;
  1193. INSERT_BEFORE(&(Action->ListEntry), &(Context->ActionList));
  1194. InitLog(Context,
  1195. INIT_LOG_DEBUG,
  1196. "New Action: %s:%x:%s:%s",
  1197. Action->Id,
  1198. Action->RunLevels,
  1199. InitActionTypeNames[Action->Type],
  1200. Action->Command);
  1201. return;
  1202. }
  1203. VOID
  1204. InitRunActions (
  1205. PINIT_CONTEXT Context,
  1206. INIT_ACTION_TYPE ActionType,
  1207. ULONG RunLevelMask
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. This routine runs all actions with a given action type that have a bit set
  1212. in the given runlevel mask.
  1213. Arguments:
  1214. Context - Supplies a pointer to the application context.
  1215. ActionType - Supplies the action type to filter.
  1216. RunLevelMask - Supplies the run-level mask to filter.
  1217. Return Value:
  1218. None.
  1219. --*/
  1220. {
  1221. PINIT_ACTION Action;
  1222. PLIST_ENTRY CurrentEntry;
  1223. CurrentEntry = Context->ActionList.Next;
  1224. while (CurrentEntry != &(Context->ActionList)) {
  1225. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  1226. CurrentEntry = CurrentEntry->Next;
  1227. if (Action->Type != ActionType) {
  1228. continue;
  1229. }
  1230. if ((RunLevelMask != 0) && ((Action->RunLevels & RunLevelMask) == 0)) {
  1231. continue;
  1232. }
  1233. //
  1234. // For respawn actions, only run them if they're not already running.
  1235. //
  1236. if (ActionType == InitActionRespawn) {
  1237. if (Action->ProcessId <= 0) {
  1238. Action->ProcessId = InitRunAction(Context, Action);
  1239. }
  1240. } else {
  1241. Action->ProcessId = InitRunAction(Context, Action);
  1242. if ((ActionType == InitActionSysinit) ||
  1243. (ActionType == InitActionWait) ||
  1244. (ActionType == InitActionOnce) ||
  1245. (ActionType == InitActionCtrlAltDel) ||
  1246. (ActionType == InitActionShutdown)) {
  1247. InitWaitForProcess(Context, Action->ProcessId);
  1248. }
  1249. }
  1250. }
  1251. return;
  1252. }
  1253. pid_t
  1254. InitRunAction (
  1255. PINIT_CONTEXT Context,
  1256. PINIT_ACTION Action
  1257. )
  1258. /*++
  1259. Routine Description:
  1260. This routine fires up the given action.
  1261. Arguments:
  1262. Context - Supplies a pointer to the application context.
  1263. Action - Supplies a pointer to the action to run.
  1264. Return Value:
  1265. Returns the process ID of the newly running process.
  1266. --*/
  1267. {
  1268. int Flags;
  1269. pid_t ProcessId;
  1270. ProcessId = fork();
  1271. if (ProcessId < 0) {
  1272. InitLog(Context,
  1273. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  1274. "Failed to fork: %s",
  1275. strerror(errno));
  1276. return 0;
  1277. }
  1278. //
  1279. // If this is the parent, just walk right back out with the new process ID
  1280. // in hand.
  1281. //
  1282. if (ProcessId > 0) {
  1283. return ProcessId;
  1284. }
  1285. //
  1286. // Put signals back to their standard configuration.
  1287. //
  1288. InitResetSignalHandlers();
  1289. //
  1290. // Create a new session and process group.
  1291. //
  1292. setsid();
  1293. //
  1294. // For certain types of entries, force the console to be the controlling
  1295. // terminal.
  1296. //
  1297. if ((Action->Type == InitActionSysinit) ||
  1298. (Action->Type == InitActionBootWait) ||
  1299. (Action->Type == InitActionWait)) {
  1300. ioctl(STDIN_FILENO, TIOCSCTTY, 1);
  1301. Flags = fcntl(STDIN_FILENO, F_GETFL);
  1302. if (Flags != -1) {
  1303. Flags &= ~O_NONBLOCK;
  1304. fcntl(STDIN_FILENO, F_SETFL, Flags);
  1305. }
  1306. }
  1307. InitLog(Context,
  1308. INIT_LOG_SYSLOG,
  1309. "Starting ID %s, PID %d: %s",
  1310. Action->Id,
  1311. getpid(),
  1312. Action->Command);
  1313. InitExec(Context, Action->Command);
  1314. _exit(-1);
  1315. }
  1316. VOID
  1317. InitExec (
  1318. PINIT_CONTEXT Context,
  1319. PSTR Command
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. This routine executes the given command.
  1324. Arguments:
  1325. Context - Supplies a pointer to the application context.
  1326. Command - Supplies a pointer to the command to execute.
  1327. Return Value:
  1328. None.
  1329. --*/
  1330. {
  1331. PSTR *Array;
  1332. UINTN ArrayCount;
  1333. UINTN CommandLength;
  1334. BOOL HasDash;
  1335. UINTN Index;
  1336. BOOL WasBlank;
  1337. HasDash = FALSE;
  1338. if (Command[0] == '-') {
  1339. HasDash = TRUE;
  1340. Command += 1;
  1341. }
  1342. CommandLength = strlen(Command);
  1343. //
  1344. // If there is anything weird in the command, let the shell navigate it.
  1345. // The login shell define has a leading dash in front of it.
  1346. //
  1347. if (strpbrk(Command, "~`!$^&*()=\\|[]{};'\"<>?") != NULL) {
  1348. Array = alloca(sizeof(PSTR) * 5);
  1349. if (HasDash != FALSE) {
  1350. Array[0] = USER_DEFAULT_LOGIN_SHELL;
  1351. } else {
  1352. Array[0] = USER_DEFAULT_LOGIN_SHELL + 1;
  1353. }
  1354. Array[1] = "-c";
  1355. Array[2] = alloca(CommandLength + 6);
  1356. snprintf(Array[2], CommandLength + 6, "exec %s", Command);
  1357. Array[3] = NULL;
  1358. Command = USER_DEFAULT_LOGIN_SHELL + 1;
  1359. } else {
  1360. ArrayCount = (CommandLength / 2) + 2;
  1361. Array = alloca(sizeof(PSTR) * ArrayCount);
  1362. Index = 0;
  1363. WasBlank = TRUE;
  1364. while (*Command != '\0') {
  1365. //
  1366. // The previous character was blank. If this one is too, keep
  1367. // going, otherwise mark a new argument.
  1368. //
  1369. if (WasBlank != FALSE) {
  1370. if (!isblank(*Command)) {
  1371. Array[Index] = Command;
  1372. Index += 1;
  1373. WasBlank = FALSE;
  1374. }
  1375. //
  1376. // The previous character was not blank. If it becomes blank,
  1377. // null out this blank character to delimit the previous argument.
  1378. //
  1379. } else {
  1380. if (isblank(*Command)) {
  1381. WasBlank = TRUE;
  1382. *Command = '\0';
  1383. }
  1384. }
  1385. Command += 1;
  1386. }
  1387. Array[Index] = NULL;
  1388. assert(Index < ArrayCount);
  1389. }
  1390. //
  1391. // If there's a dash, then this is an interactive session. Attempt to set
  1392. // the controlling terminal if it's not already set. Don't be forceful
  1393. // though.
  1394. //
  1395. if (HasDash != FALSE) {
  1396. ioctl(STDIN_FILENO, TIOCSCTTY, 0);
  1397. }
  1398. execve(Array[0], Array, environ);
  1399. InitLog(Context,
  1400. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1401. "Failed to exec %s: %s",
  1402. Array[0],
  1403. strerror(errno));
  1404. return;
  1405. }
  1406. VOID
  1407. InitWaitForProcess (
  1408. PINIT_CONTEXT Context,
  1409. pid_t ProcessId
  1410. )
  1411. /*++
  1412. Routine Description:
  1413. This routine waits for a specific process to complete.
  1414. Arguments:
  1415. Context - Supplies a pointer to the application context.
  1416. ProcessId - Supplies the process ID to wait for.
  1417. Return Value:
  1418. None.
  1419. --*/
  1420. {
  1421. pid_t DeadProcess;
  1422. int Status;
  1423. if (ProcessId <= 0) {
  1424. return;
  1425. }
  1426. while (TRUE) {
  1427. DeadProcess = wait(&Status);
  1428. InitMarkProcessTerminated(Context, DeadProcess, Status);
  1429. if (DeadProcess == ProcessId) {
  1430. break;
  1431. }
  1432. }
  1433. return;
  1434. }
  1435. PINIT_ACTION
  1436. InitMarkProcessTerminated (
  1437. PINIT_CONTEXT Context,
  1438. pid_t ProcessId,
  1439. int Status
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This routine cleans up after a dead process.
  1444. Arguments:
  1445. Context - Supplies a pointer to the application context.
  1446. ProcessId - Supplies the process ID that ended.
  1447. Status - Supplies the exit status of the process.
  1448. Return Value:
  1449. Returns a pointer to the action associated with the process ID if it's
  1450. one of init's processes.
  1451. NULL if the process is not a tracked process.
  1452. --*/
  1453. {
  1454. PINIT_ACTION Action;
  1455. PLIST_ENTRY CurrentEntry;
  1456. PINIT_ACTION FoundAction;
  1457. FoundAction = NULL;
  1458. if (ProcessId > 0) {
  1459. SwUpdateUtmp(ProcessId, DEAD_PROCESS, NULL, NULL, NULL);
  1460. CurrentEntry = Context->ActionList.Next;
  1461. while (CurrentEntry != &(Context->ActionList)) {
  1462. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  1463. CurrentEntry = CurrentEntry->Next;
  1464. if (Action->ProcessId == ProcessId) {
  1465. Action->ProcessId = 0;
  1466. FoundAction = Action;
  1467. break;
  1468. }
  1469. }
  1470. }
  1471. if ((FoundAction != NULL) && (Action->Type == InitActionRespawn)) {
  1472. InitLog(Context,
  1473. INIT_LOG_DEBUG | INIT_LOG_SYSLOG,
  1474. "Process '%s' (pid %d) exited with status %d. Scheduling for "
  1475. "restart",
  1476. FoundAction->Command,
  1477. ProcessId,
  1478. Status);
  1479. } else {
  1480. InitLog(Context,
  1481. INIT_LOG_DEBUG,
  1482. "Process id %d exited with status %d.",
  1483. ProcessId,
  1484. Status);
  1485. }
  1486. return FoundAction;
  1487. }
  1488. VOID
  1489. InitResetSignalHandlers (
  1490. VOID
  1491. )
  1492. /*++
  1493. Routine Description:
  1494. This routine resets signal handlers back to their default values.
  1495. Arguments:
  1496. None.
  1497. Return Value:
  1498. None.
  1499. --*/
  1500. {
  1501. struct sigaction SignalAction;
  1502. memset(&SignalAction, 0, sizeof(SignalAction));
  1503. sigemptyset(&(SignalAction.sa_mask));
  1504. SignalAction.sa_handler = SIG_DFL;
  1505. sigaction(SIGTSTP, &SignalAction, NULL);
  1506. sigaction(SIGINT, &SignalAction, NULL);
  1507. sigaction(SIGQUIT, &SignalAction, NULL);
  1508. sigaction(SIGUSR1, &SignalAction, NULL);
  1509. sigaction(SIGUSR2, &SignalAction, NULL);
  1510. sigaction(SIGTERM, &SignalAction, NULL);
  1511. sigaction(SIGHUP, &SignalAction, NULL);
  1512. sigprocmask(SIG_SETMASK, &(SignalAction.sa_mask), NULL);
  1513. return;
  1514. }
  1515. VOID
  1516. InitLog (
  1517. PINIT_CONTEXT Context,
  1518. ULONG Destination,
  1519. PSTR Format,
  1520. ...
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. This routine prints a message to the system log, console, or both.
  1525. Arguments:
  1526. Context - Supplies a pointer to the application context.
  1527. Destination - Supplies the bitfield of destinations the message should be
  1528. printed to. See INIT_LOG_* definitions.
  1529. Format - Supplies the printf-style format of the message.
  1530. ... - Supplies the additional arguments dictated by the format.
  1531. Return Value:
  1532. None.
  1533. --*/
  1534. {
  1535. va_list ArgumentList;
  1536. if ((Destination & INIT_LOG_DEBUG) != 0) {
  1537. if ((Context->Options & INIT_OPTION_DEBUG) != 0) {
  1538. Destination |= INIT_LOG_SYSLOG | INIT_LOG_CONSOLE;
  1539. }
  1540. }
  1541. if ((Destination & INIT_LOG_SYSLOG) != 0) {
  1542. if (Context->SyslogOpen == FALSE) {
  1543. openlog("init", 0, LOG_DAEMON);
  1544. Context->SyslogOpen = TRUE;
  1545. }
  1546. va_start(ArgumentList, Format);
  1547. vsyslog(LOG_INFO, Format, ArgumentList);
  1548. va_end(ArgumentList);
  1549. }
  1550. if ((Destination & INIT_LOG_CONSOLE) != 0) {
  1551. va_start(ArgumentList, Format);
  1552. vfprintf(stderr, Format, ArgumentList);
  1553. va_end(ArgumentList);
  1554. fprintf(stderr, "\n");
  1555. }
  1556. return;
  1557. }
  1558. void
  1559. InitSignalHandler (
  1560. int Signal
  1561. )
  1562. /*++
  1563. Routine Description:
  1564. This routine is called when a signal fires. It simply records that the
  1565. signal occurred.
  1566. Arguments:
  1567. Signal - Supplies the signal that fired.
  1568. Return Value:
  1569. None.
  1570. --*/
  1571. {
  1572. assert(Signal < NSIG);
  1573. //
  1574. // Mark that a signal was seen in slot 0, and then increment the count for
  1575. // the particular signal.
  1576. //
  1577. InitSignalCounts[0] = 1;
  1578. InitSignalCounts[Signal] += 1;
  1579. return;
  1580. }