1
0

init.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128
  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. InitSignalCounts = NULL;
  542. return Status;
  543. }
  544. //
  545. // --------------------------------------------------------- Internal Functions
  546. //
  547. VOID
  548. InitInitializeConsole (
  549. PINIT_CONTEXT Context
  550. )
  551. /*++
  552. Routine Description:
  553. This routine initializes the console.
  554. Arguments:
  555. Context - Supplies a pointer to the application context.
  556. Return Value:
  557. None.
  558. --*/
  559. {
  560. PSTR Console;
  561. int Descriptor;
  562. PSTR TermVariable;
  563. Console = getenv("CONSOLE");
  564. if (Console == NULL) {
  565. Console = getenv("console");
  566. }
  567. //
  568. // Set it to a default.
  569. //
  570. if (Console == NULL) {
  571. Console = INIT_DEFAULT_CONSOLE;
  572. setenv("CONSOLE", Console, 1);
  573. }
  574. if (Console != NULL) {
  575. Descriptor = open(Console, O_RDWR | O_NONBLOCK | O_NOCTTY);
  576. if (Descriptor >= 0) {
  577. dup2(Descriptor, STDIN_FILENO);
  578. dup2(Descriptor, STDOUT_FILENO);
  579. dup2(Descriptor, STDERR_FILENO);
  580. if (Descriptor > STDERR_FILENO) {
  581. close(Descriptor);
  582. }
  583. }
  584. InitLog(Context, INIT_LOG_SYSLOG, "CONSOLE=%s", Console);
  585. }
  586. TermVariable = getenv("TERM");
  587. if (TermVariable == NULL) {
  588. setenv("TERM", INIT_DEFAULT_TERMINAL_TYPE, 1);
  589. }
  590. return;
  591. }
  592. VOID
  593. InitConfigureTerminal (
  594. VOID
  595. )
  596. /*++
  597. Routine Description:
  598. This routine sets some sane defaults for the terminal.
  599. Arguments:
  600. None.
  601. Return Value:
  602. None.
  603. --*/
  604. {
  605. struct termios Settings;
  606. if (tcgetattr(STDIN_FILENO, &Settings) != 0) {
  607. return;
  608. }
  609. Settings.c_cc[VINTR] = INIT_CONTROL('C');
  610. Settings.c_cc[VQUIT] = INIT_CONTROL('\\');
  611. Settings.c_cc[VERASE] = INIT_CONTROL('?');
  612. Settings.c_cc[VKILL] = INIT_CONTROL('U');
  613. Settings.c_cc[VEOF] = INIT_CONTROL('D');
  614. Settings.c_cc[VSTART] = INIT_CONTROL('Q');
  615. Settings.c_cc[VSTOP] = INIT_CONTROL('S');
  616. Settings.c_cc[VSUSP] = INIT_CONTROL('Z');
  617. //
  618. // Save the character size, stop bits, and parity configuration. Add in
  619. // receiver enable, hangup on close, and the local flag.
  620. //
  621. Settings.c_cflag &= CSIZE | CSTOPB | PARENB | PARODD;
  622. Settings.c_cflag |= CREAD | HUPCL | CLOCAL;
  623. Settings.c_iflag = ICRNL | IXON | IXOFF | IMAXBEL;
  624. Settings.c_oflag = OPOST | ONLCR;
  625. Settings.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOKE | ECHOCTL | IEXTEN;
  626. tcsetattr(STDIN_FILENO, TCSANOW, &Settings);
  627. return;
  628. }
  629. BOOL
  630. InitCheckSignals (
  631. PINIT_CONTEXT Context
  632. )
  633. /*++
  634. Routine Description:
  635. This routine checks for any signals that might have occurred recently.
  636. Arguments:
  637. Context - Supplies a pointer to the application context.
  638. Return Value:
  639. TRUE if a signal was processed.
  640. FALSE if no signals were processed.
  641. --*/
  642. {
  643. INT Signal;
  644. BOOL SignalsSeen;
  645. SignalsSeen = FALSE;
  646. while (TRUE) {
  647. //
  648. // Exit quickly if no signals occurred.
  649. //
  650. if (InitSignalCounts[0] == 0) {
  651. break;
  652. }
  653. //
  654. // Clear the "signals seen" boolean before checking.
  655. //
  656. InitSignalCounts[0] = 0;
  657. for (Signal = 1; Signal < NSIG; Signal += 1) {
  658. if (InitSignalCounts[Signal] != 0) {
  659. SignalsSeen = TRUE;
  660. InitSignalCounts[Signal] = 0;
  661. if (Signal == SIGINT) {
  662. InitRunActions(Context, InitActionCtrlAltDel, 0);
  663. } else if (Signal == SIGQUIT) {
  664. InitReexec(Context);
  665. } else if (Signal == SIGHUP) {
  666. InitReloadInittab(Context);
  667. } else if (Signal == SIGALRM) {
  668. if (Context->RebootPhase == InitRebootTerm) {
  669. Context->RebootPhase = InitRebootKill;
  670. InitRunResetSystem(Context, Signal);
  671. } else if (Context->RebootPhase == InitRebootKill) {
  672. Context->RebootPhase = InitRebootComplete;
  673. InitRunResetSystem(Context, Signal);
  674. }
  675. //
  676. // Other signals initiate a reboot.
  677. //
  678. } else {
  679. if (Context->RebootPhase == InitNotRebooting) {
  680. InitRunResetSystem(Context, Signal);
  681. }
  682. }
  683. }
  684. }
  685. }
  686. return SignalsSeen;
  687. }
  688. VOID
  689. InitReloadInittab (
  690. PINIT_CONTEXT Context
  691. )
  692. /*++
  693. Routine Description:
  694. This routine attempts to reload the inittab file, and reconcile the
  695. processes.
  696. Arguments:
  697. Context - Supplies a pointer to the application context.
  698. Return Value:
  699. None.
  700. --*/
  701. {
  702. PINIT_ACTION Action;
  703. pid_t Child;
  704. PLIST_ENTRY CurrentEntry;
  705. InitLog(Context,
  706. INIT_LOG_SYSLOG | INIT_LOG_DEBUG,
  707. "Reloading inittab");
  708. //
  709. // Clear out all the action types to know which entries don't show up
  710. // in the new file.
  711. //
  712. CurrentEntry = Context->ActionList.Next;
  713. while (CurrentEntry != &(Context->ActionList)) {
  714. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  715. Action->Type = InitActionInvalid;
  716. CurrentEntry = CurrentEntry->Next;
  717. }
  718. Context->PreviousRunLevel = Context->CurrentRunLevel;
  719. InitParseInittab(Context);
  720. //
  721. // Remove any leftover entries.
  722. //
  723. CurrentEntry = Context->ActionList.Next;
  724. while (CurrentEntry != &(Context->ActionList)) {
  725. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  726. CurrentEntry = CurrentEntry->Next;
  727. //
  728. // Kill a running entry that's either 1) not in the new inittab or
  729. // 2) Got a runlevel and it's not the current runlevel.
  730. //
  731. if ((Action->ProcessId > 0) &&
  732. ((Action->Type == InitActionInvalid) ||
  733. ((Action->RunLevels != 0) &&
  734. ((Action->RunLevels & Context->CurrentRunLevel) == 0)))) {
  735. InitLog(Context,
  736. INIT_LOG_DEBUG,
  737. "Killing: %d: %s",
  738. Action->ProcessId,
  739. Action->Command);
  740. kill(Action->ProcessId, SIGTERM);
  741. }
  742. }
  743. //
  744. // Fork, wait a bit, and then send kill to all these processes.
  745. //
  746. Child = fork();
  747. if (Child == 0) {
  748. sleep(INIT_KILL_DELAY);
  749. CurrentEntry = Context->ActionList.Next;
  750. while (CurrentEntry != &(Context->ActionList)) {
  751. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  752. if ((Action->ProcessId > 0) &&
  753. ((Action->Type == InitActionInvalid) ||
  754. ((Action->RunLevels != 0) &&
  755. ((Action->RunLevels & Context->CurrentRunLevel) == 0)))) {
  756. kill(Action->ProcessId, SIGKILL);
  757. }
  758. CurrentEntry = CurrentEntry->Next;
  759. }
  760. _exit(0);
  761. }
  762. //
  763. // Remove the unused entries. Also take the opportunity to free sysinit and
  764. // boot entries, which are never used again.
  765. //
  766. CurrentEntry = Context->ActionList.Next;
  767. while (CurrentEntry != &(Context->ActionList)) {
  768. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  769. CurrentEntry = CurrentEntry->Next;
  770. if ((Action->Type == InitActionInvalid) ||
  771. (Action->Type == InitActionSysinit) ||
  772. (Action->Type == InitActionBoot) ||
  773. (Action->Type == InitActionBootWait)) {
  774. LIST_REMOVE(&(Action->ListEntry));
  775. free(Action);
  776. }
  777. }
  778. return;
  779. }
  780. VOID
  781. InitReexec (
  782. PINIT_CONTEXT Context
  783. )
  784. /*++
  785. Routine Description:
  786. This routine attempts to run the restart action, execing init into that
  787. action.
  788. Arguments:
  789. Context - Supplies a pointer to the application context.
  790. Return Value:
  791. None. Does not return on success.
  792. --*/
  793. {
  794. PINIT_ACTION Action;
  795. PLIST_ENTRY CurrentEntry;
  796. CurrentEntry = Context->ActionList.Next;
  797. while (CurrentEntry != &(Context->ActionList)) {
  798. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  799. if (Action->Type == InitActionRestart) {
  800. break;
  801. }
  802. CurrentEntry = CurrentEntry->Next;
  803. }
  804. if (CurrentEntry == &(Context->ActionList)) {
  805. InitLog(Context, INIT_LOG_SYSLOG, "No restart action found");
  806. return;
  807. }
  808. InitResetSignalHandlers();
  809. InitShutdownAndKillProcesses(Context);
  810. InitLog(Context,
  811. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  812. "Re-exec init: %s",
  813. Action->Command);
  814. InitExec(Context, Action->Command);
  815. InitReboot(Context, RebootTypeHalt);
  816. return;
  817. }
  818. VOID
  819. InitRunResetSystem (
  820. PINIT_CONTEXT Context,
  821. INT Signal
  822. )
  823. /*++
  824. Routine Description:
  825. This routine runs the tasks associated with resetting the system, and then
  826. resets the system.
  827. Arguments:
  828. Context - Supplies a pointer to the application context.
  829. Signal - Supplies the signal, which dictates the type of actions and
  830. power state to enter.
  831. Return Value:
  832. None.
  833. --*/
  834. {
  835. PSTR Message;
  836. SWISS_REBOOT_TYPE RebootType;
  837. switch (Context->RebootPhase) {
  838. case InitNotRebooting:
  839. Context->RebootPhase = InitRebootRunningActions;
  840. Context->RebootSignal = Signal;
  841. InitResetSignalHandlers();
  842. case InitRebootRunningActions:
  843. InitShutdownAndKillProcesses(Context);
  844. Context->RebootPhase = InitRebootTerm;
  845. //
  846. // Fall through.
  847. //
  848. case InitRebootTerm:
  849. case InitRebootKill:
  850. InitShutdownAndKillProcesses(Context);
  851. alarm(10);
  852. break;
  853. case InitRebootComplete:
  854. Signal = Context->RebootSignal;
  855. Message = "halt";
  856. RebootType = RebootTypeHalt;
  857. if (Signal == SIGTERM) {
  858. Message = "reboot";
  859. RebootType = RebootTypeWarm;
  860. } else if (Signal == SIGUSR2) {
  861. Message = "poweroff";
  862. }
  863. InitLog(Context,
  864. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  865. "Requesting system %s.",
  866. Message);
  867. InitReboot(Context, RebootType);
  868. break;
  869. default:
  870. assert(FALSE);
  871. break;
  872. }
  873. return;
  874. }
  875. VOID
  876. InitShutdownAndKillProcesses (
  877. PINIT_CONTEXT Context
  878. )
  879. /*++
  880. Routine Description:
  881. This routine runs the shutdown action and attempts to kill all processes.
  882. Arguments:
  883. Context - Supplies a pointer to the application context.
  884. Return Value:
  885. None.
  886. --*/
  887. {
  888. if (Context->RebootPhase == InitNotRebooting) {
  889. InitRunActions(Context, InitActionShutdown, 0);
  890. InitLog(Context,
  891. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  892. "The system is going down.");
  893. kill(-1, SIGTERM);
  894. sleep(1);
  895. kill(-1, SIGKILL);
  896. sync();
  897. } else if (Context->RebootPhase == InitRebootRunningActions) {
  898. InitRunActions(Context, InitActionShutdown, 0);
  899. InitLog(Context,
  900. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  901. "The system is going down.");
  902. } else if (Context->RebootPhase == InitRebootTerm) {
  903. kill(-1, SIGTERM);
  904. InitLog(Context,
  905. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  906. "Sent SIG%s to all processes.",
  907. "TERM");
  908. } else if (Context->RebootPhase == InitRebootKill) {
  909. kill(-1, SIGKILL);
  910. InitLog(Context,
  911. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  912. "Sent SIG%s to all processes.",
  913. "KILL");
  914. }
  915. return;
  916. }
  917. VOID
  918. InitReboot (
  919. PINIT_CONTEXT Context,
  920. SWISS_REBOOT_TYPE RebootType
  921. )
  922. /*++
  923. Routine Description:
  924. This routine actually resets the system.
  925. Arguments:
  926. Context - Supplies a pointer to the application context.
  927. RebootType - Supplies the type of reboot to perform.
  928. Return Value:
  929. None.
  930. --*/
  931. {
  932. pid_t Child;
  933. sleep(1);
  934. //
  935. // Do this in a child process since some reboot implementations exit,
  936. // which some OSes might have a problem with for pid 1.
  937. //
  938. Child = fork();
  939. if (Child == 0) {
  940. SwResetSystem(RebootType);
  941. _exit(0);
  942. }
  943. _exit(0);
  944. return;
  945. }
  946. VOID
  947. InitParseInittab (
  948. PINIT_CONTEXT Context
  949. )
  950. /*++
  951. Routine Description:
  952. This routine parses the inittab file.
  953. Arguments:
  954. Context - Supplies a pointer to the application context.
  955. Return Value:
  956. None.
  957. --*/
  958. {
  959. INIT_ACTION_TYPE ActionType;
  960. CHAR Character;
  961. PSTR Colon;
  962. PSTR Fields[4];
  963. FILE *File;
  964. UINTN Index;
  965. char *Line;
  966. size_t LineBufferSize;
  967. ssize_t LineSize;
  968. ULONG RunLevelMask;
  969. INT Status;
  970. PSTR String;
  971. Line = NULL;
  972. LineBufferSize = 0;
  973. File = fopen(INIT_INITTAB_PATH, "r");
  974. if (File == NULL) {
  975. Status = errno;
  976. //
  977. // If there is no inittab, create a basic one.
  978. //
  979. if (Status == ENOENT) {
  980. InitCreateAction(Context,
  981. "1",
  982. INIT_RUNLEVEL_1,
  983. InitActionSysinit,
  984. INIT_INIT_SCRIPT);
  985. InitCreateAction(Context,
  986. "2",
  987. INIT_RUNLEVEL_1,
  988. InitActionOnce,
  989. USER_FALLBACK_SHELL);
  990. InitCreateAction(Context,
  991. "3",
  992. INIT_RUNLEVEL_1,
  993. InitActionInitDefault,
  994. NULL);
  995. InitCreateAction(Context,
  996. "4",
  997. 0,
  998. InitActionCtrlAltDel,
  999. "reboot");
  1000. InitCreateAction(Context,
  1001. "5",
  1002. 0,
  1003. InitActionShutdown,
  1004. "reboot -h");
  1005. InitCreateAction(Context,
  1006. "6",
  1007. 0,
  1008. InitActionRestart,
  1009. "init");
  1010. Status = 0;
  1011. }
  1012. goto ParseInittabEnd;
  1013. }
  1014. //
  1015. // Loop parsing entries in the following form:
  1016. // id:runlevels:action:command...
  1017. //
  1018. while (TRUE) {
  1019. LineSize = getline(&Line, &LineBufferSize, File);
  1020. if (LineSize < 0) {
  1021. break;
  1022. }
  1023. while ((LineSize != 0) && (isspace(Line[LineSize - 1]))) {
  1024. LineSize -= 1;
  1025. }
  1026. String = Line;
  1027. String[LineSize] = '\0';
  1028. //
  1029. // Get past whitespace.
  1030. //
  1031. while (isspace(*String)) {
  1032. String += 1;
  1033. }
  1034. //
  1035. // Skip any commented lines.
  1036. //
  1037. if ((*String == '\0') || (*String == '#')) {
  1038. continue;
  1039. }
  1040. //
  1041. // Parse out the first three fields that have colons after them.
  1042. //
  1043. for (Index = 0; Index < 3; Index += 1) {
  1044. Fields[Index] = String;
  1045. Colon = strchr(String, ':');
  1046. if (Colon == NULL) {
  1047. InitLog(Context,
  1048. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1049. "Ignoring: %s",
  1050. Line);
  1051. break;
  1052. }
  1053. *Colon = '\0';
  1054. String = Colon + 1;
  1055. }
  1056. if (Index != 3) {
  1057. continue;
  1058. }
  1059. //
  1060. // The last field gets the rest of the line.
  1061. //
  1062. Fields[Index] = String;
  1063. //
  1064. // Figure out the action type, the third field.
  1065. //
  1066. for (Index = 0; Index < InitActionCount; Index += 1) {
  1067. if (strcmp(Fields[2], InitActionTypeNames[Index]) == 0) {
  1068. ActionType = Index;
  1069. break;
  1070. }
  1071. }
  1072. if (Index == InitActionCount) {
  1073. InitLog(Context,
  1074. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1075. "Unknown action type: %s",
  1076. Fields[2]);
  1077. continue;
  1078. }
  1079. //
  1080. // Figure out the runlevel mask.
  1081. //
  1082. RunLevelMask = 0;
  1083. String = Fields[1];
  1084. while (*String != '\0') {
  1085. Index = 0;
  1086. Character = toupper(*String);
  1087. while (INIT_RUNLEVEL_NAMES[Index] != '\0') {
  1088. if (Character == INIT_RUNLEVEL_NAMES[Index]) {
  1089. RunLevelMask |= 1 << Index;
  1090. break;
  1091. }
  1092. Index += 1;
  1093. }
  1094. if (INIT_RUNLEVEL_NAMES[Index] == '\0') {
  1095. InitLog(Context,
  1096. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1097. "Ignoring unknown runlevel %c",
  1098. Character);
  1099. }
  1100. String += 1;
  1101. }
  1102. InitCreateAction(Context,
  1103. Fields[0],
  1104. RunLevelMask,
  1105. ActionType,
  1106. Fields[3]);
  1107. }
  1108. Status = 0;
  1109. ParseInittabEnd:
  1110. if (File != NULL) {
  1111. fclose(File);
  1112. }
  1113. if (Line != NULL) {
  1114. free(Line);
  1115. }
  1116. if (Status != 0) {
  1117. InitLog(Context,
  1118. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1119. "Failed to parse inittab, adding default entry: %s",
  1120. strerror(Status));
  1121. InitCreateAction(Context,
  1122. "0",
  1123. INIT_RUNLEVEL_MASK,
  1124. InitActionRespawn,
  1125. USER_FALLBACK_SHELL);
  1126. }
  1127. return;
  1128. }
  1129. VOID
  1130. InitCreateAction (
  1131. PINIT_CONTEXT Context,
  1132. PSTR Id,
  1133. ULONG RunLevels,
  1134. INIT_ACTION_TYPE ActionType,
  1135. PSTR Command
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. This routine creates and adds a new init action to the application context.
  1140. Arguments:
  1141. Context - Supplies a pointer to the application context.
  1142. Id - Supplies up to 4 characters of ID information.
  1143. RunLevels - Supplies the mask of runlevels this action is active for.
  1144. ActionType - Supplies the type of action.
  1145. Command - Supplies a pointer to the command to run.
  1146. Return Value:
  1147. None.
  1148. --*/
  1149. {
  1150. PINIT_ACTION Action;
  1151. size_t AllocationSize;
  1152. PLIST_ENTRY CurrentEntry;
  1153. if (Id == NULL) {
  1154. Id = "";
  1155. }
  1156. //
  1157. // If this is an "init default" action, just save the default run-level
  1158. // but don't bother creating a full action.
  1159. //
  1160. if (ActionType == InitActionInitDefault) {
  1161. Context->DefaultRunLevel = RunLevels;
  1162. return;
  1163. }
  1164. //
  1165. // Search for an action that exists already. Use this to avoid losing
  1166. // running actions.
  1167. //
  1168. CurrentEntry = Context->ActionList.Next;
  1169. while (CurrentEntry != &(Context->ActionList)) {
  1170. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  1171. if ((strcmp(Id, Action->Id) == 0) &&
  1172. (strcmp(Command, Action->Command) == 0)) {
  1173. LIST_REMOVE(&(Action->ListEntry));
  1174. break;
  1175. }
  1176. CurrentEntry = CurrentEntry->Next;
  1177. }
  1178. //
  1179. // Allocate a new entry if one was not found.
  1180. //
  1181. if (CurrentEntry == &(Context->ActionList)) {
  1182. AllocationSize = sizeof(INIT_ACTION) + strlen(Command) + 1;
  1183. Action = malloc(AllocationSize);
  1184. if (Action == NULL) {
  1185. return;
  1186. }
  1187. memset(Action, 0, AllocationSize);
  1188. Action->Command = (PSTR)(Action + 1);
  1189. }
  1190. strncpy(Action->Id, Id, sizeof(Action->Id) - 1);
  1191. strcpy(Action->Command, Command);
  1192. Action->Type = ActionType;
  1193. Action->RunLevels = RunLevels;
  1194. INSERT_BEFORE(&(Action->ListEntry), &(Context->ActionList));
  1195. InitLog(Context,
  1196. INIT_LOG_DEBUG,
  1197. "New Action: %s:%x:%s:%s",
  1198. Action->Id,
  1199. Action->RunLevels,
  1200. InitActionTypeNames[Action->Type],
  1201. Action->Command);
  1202. return;
  1203. }
  1204. VOID
  1205. InitRunActions (
  1206. PINIT_CONTEXT Context,
  1207. INIT_ACTION_TYPE ActionType,
  1208. ULONG RunLevelMask
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This routine runs all actions with a given action type that have a bit set
  1213. in the given runlevel mask.
  1214. Arguments:
  1215. Context - Supplies a pointer to the application context.
  1216. ActionType - Supplies the action type to filter.
  1217. RunLevelMask - Supplies the run-level mask to filter.
  1218. Return Value:
  1219. None.
  1220. --*/
  1221. {
  1222. PINIT_ACTION Action;
  1223. PLIST_ENTRY CurrentEntry;
  1224. CurrentEntry = Context->ActionList.Next;
  1225. while (CurrentEntry != &(Context->ActionList)) {
  1226. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  1227. CurrentEntry = CurrentEntry->Next;
  1228. if (Action->Type != ActionType) {
  1229. continue;
  1230. }
  1231. if ((RunLevelMask != 0) && ((Action->RunLevels & RunLevelMask) == 0)) {
  1232. continue;
  1233. }
  1234. //
  1235. // For respawn actions, only run them if they're not already running.
  1236. //
  1237. if (ActionType == InitActionRespawn) {
  1238. if (Action->ProcessId <= 0) {
  1239. Action->ProcessId = InitRunAction(Context, Action);
  1240. }
  1241. } else {
  1242. Action->ProcessId = InitRunAction(Context, Action);
  1243. if ((ActionType == InitActionSysinit) ||
  1244. (ActionType == InitActionWait) ||
  1245. (ActionType == InitActionOnce) ||
  1246. (ActionType == InitActionCtrlAltDel) ||
  1247. (ActionType == InitActionShutdown)) {
  1248. InitWaitForProcess(Context, Action->ProcessId);
  1249. }
  1250. }
  1251. }
  1252. return;
  1253. }
  1254. pid_t
  1255. InitRunAction (
  1256. PINIT_CONTEXT Context,
  1257. PINIT_ACTION Action
  1258. )
  1259. /*++
  1260. Routine Description:
  1261. This routine fires up the given action.
  1262. Arguments:
  1263. Context - Supplies a pointer to the application context.
  1264. Action - Supplies a pointer to the action to run.
  1265. Return Value:
  1266. Returns the process ID of the newly running process.
  1267. --*/
  1268. {
  1269. int Flags;
  1270. pid_t ProcessId;
  1271. ProcessId = fork();
  1272. if (ProcessId < 0) {
  1273. InitLog(Context,
  1274. INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
  1275. "Failed to fork: %s",
  1276. strerror(errno));
  1277. return 0;
  1278. }
  1279. //
  1280. // If this is the parent, just walk right back out with the new process ID
  1281. // in hand.
  1282. //
  1283. if (ProcessId > 0) {
  1284. return ProcessId;
  1285. }
  1286. //
  1287. // Put signals back to their standard configuration.
  1288. //
  1289. InitResetSignalHandlers();
  1290. //
  1291. // Create a new session and process group.
  1292. //
  1293. setsid();
  1294. //
  1295. // For certain types of entries, force the console to be the controlling
  1296. // terminal.
  1297. //
  1298. if ((Action->Type == InitActionSysinit) ||
  1299. (Action->Type == InitActionBootWait) ||
  1300. (Action->Type == InitActionWait)) {
  1301. ioctl(STDIN_FILENO, TIOCSCTTY, 1);
  1302. Flags = fcntl(STDIN_FILENO, F_GETFL);
  1303. if (Flags != -1) {
  1304. Flags &= ~O_NONBLOCK;
  1305. fcntl(STDIN_FILENO, F_SETFL, Flags);
  1306. }
  1307. }
  1308. InitLog(Context,
  1309. INIT_LOG_SYSLOG,
  1310. "Starting ID %s, PID %d: %s",
  1311. Action->Id,
  1312. getpid(),
  1313. Action->Command);
  1314. InitExec(Context, Action->Command);
  1315. _exit(-1);
  1316. }
  1317. VOID
  1318. InitExec (
  1319. PINIT_CONTEXT Context,
  1320. PSTR Command
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. This routine executes the given command.
  1325. Arguments:
  1326. Context - Supplies a pointer to the application context.
  1327. Command - Supplies a pointer to the command to execute.
  1328. Return Value:
  1329. None.
  1330. --*/
  1331. {
  1332. PSTR *Array;
  1333. UINTN ArrayCount;
  1334. UINTN CommandLength;
  1335. BOOL HasDash;
  1336. UINTN Index;
  1337. BOOL WasBlank;
  1338. HasDash = FALSE;
  1339. if (Command[0] == '-') {
  1340. HasDash = TRUE;
  1341. Command += 1;
  1342. }
  1343. CommandLength = strlen(Command);
  1344. //
  1345. // If there is anything weird in the command, let the shell navigate it.
  1346. // The login shell define has a leading dash in front of it.
  1347. //
  1348. if (strpbrk(Command, "~`!$^&*()=\\|[]{};'\"<>?") != NULL) {
  1349. Array = alloca(sizeof(PSTR) * 5);
  1350. if (HasDash != FALSE) {
  1351. Array[0] = USER_DEFAULT_LOGIN_SHELL;
  1352. } else {
  1353. Array[0] = USER_DEFAULT_LOGIN_SHELL + 1;
  1354. }
  1355. Array[1] = "-c";
  1356. Array[2] = alloca(CommandLength + 6);
  1357. snprintf(Array[2], CommandLength + 6, "exec %s", Command);
  1358. Array[3] = NULL;
  1359. Command = USER_DEFAULT_LOGIN_SHELL + 1;
  1360. } else {
  1361. ArrayCount = (CommandLength / 2) + 2;
  1362. Array = alloca(sizeof(PSTR) * ArrayCount);
  1363. Index = 0;
  1364. WasBlank = TRUE;
  1365. while (*Command != '\0') {
  1366. //
  1367. // The previous character was blank. If this one is too, keep
  1368. // going, otherwise mark a new argument.
  1369. //
  1370. if (WasBlank != FALSE) {
  1371. if (!isblank(*Command)) {
  1372. Array[Index] = Command;
  1373. Index += 1;
  1374. WasBlank = FALSE;
  1375. }
  1376. //
  1377. // The previous character was not blank. If it becomes blank,
  1378. // null out this blank character to delimit the previous argument.
  1379. //
  1380. } else {
  1381. if (isblank(*Command)) {
  1382. WasBlank = TRUE;
  1383. *Command = '\0';
  1384. }
  1385. }
  1386. Command += 1;
  1387. }
  1388. Array[Index] = NULL;
  1389. assert(Index < ArrayCount);
  1390. }
  1391. //
  1392. // If there's a dash, then this is an interactive session. Attempt to set
  1393. // the controlling terminal if it's not already set. Don't be forceful
  1394. // though.
  1395. //
  1396. if (HasDash != FALSE) {
  1397. ioctl(STDIN_FILENO, TIOCSCTTY, 0);
  1398. }
  1399. execve(Array[0], Array, environ);
  1400. InitLog(Context,
  1401. INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
  1402. "Failed to exec %s: %s",
  1403. Array[0],
  1404. strerror(errno));
  1405. return;
  1406. }
  1407. VOID
  1408. InitWaitForProcess (
  1409. PINIT_CONTEXT Context,
  1410. pid_t ProcessId
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. This routine waits for a specific process to complete.
  1415. Arguments:
  1416. Context - Supplies a pointer to the application context.
  1417. ProcessId - Supplies the process ID to wait for.
  1418. Return Value:
  1419. None.
  1420. --*/
  1421. {
  1422. pid_t DeadProcess;
  1423. int Status;
  1424. if (ProcessId <= 0) {
  1425. return;
  1426. }
  1427. while (TRUE) {
  1428. DeadProcess = wait(&Status);
  1429. InitMarkProcessTerminated(Context, DeadProcess, Status);
  1430. if (DeadProcess == ProcessId) {
  1431. break;
  1432. }
  1433. }
  1434. return;
  1435. }
  1436. PINIT_ACTION
  1437. InitMarkProcessTerminated (
  1438. PINIT_CONTEXT Context,
  1439. pid_t ProcessId,
  1440. int Status
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. This routine cleans up after a dead process.
  1445. Arguments:
  1446. Context - Supplies a pointer to the application context.
  1447. ProcessId - Supplies the process ID that ended.
  1448. Status - Supplies the exit status of the process.
  1449. Return Value:
  1450. Returns a pointer to the action associated with the process ID if it's
  1451. one of init's processes.
  1452. NULL if the process is not a tracked process.
  1453. --*/
  1454. {
  1455. PINIT_ACTION Action;
  1456. PLIST_ENTRY CurrentEntry;
  1457. PINIT_ACTION FoundAction;
  1458. FoundAction = NULL;
  1459. if (ProcessId > 0) {
  1460. SwUpdateUtmp(ProcessId, DEAD_PROCESS, NULL, NULL, NULL);
  1461. CurrentEntry = Context->ActionList.Next;
  1462. while (CurrentEntry != &(Context->ActionList)) {
  1463. Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
  1464. CurrentEntry = CurrentEntry->Next;
  1465. if (Action->ProcessId == ProcessId) {
  1466. Action->ProcessId = 0;
  1467. FoundAction = Action;
  1468. break;
  1469. }
  1470. }
  1471. }
  1472. if ((FoundAction != NULL) && (Action->Type == InitActionRespawn)) {
  1473. InitLog(Context,
  1474. INIT_LOG_DEBUG | INIT_LOG_SYSLOG,
  1475. "Process '%s' (pid %d) exited with status %d. Scheduling for "
  1476. "restart",
  1477. FoundAction->Command,
  1478. ProcessId,
  1479. Status);
  1480. } else {
  1481. InitLog(Context,
  1482. INIT_LOG_DEBUG,
  1483. "Process id %d exited with status %d.",
  1484. ProcessId,
  1485. Status);
  1486. }
  1487. return FoundAction;
  1488. }
  1489. VOID
  1490. InitResetSignalHandlers (
  1491. VOID
  1492. )
  1493. /*++
  1494. Routine Description:
  1495. This routine resets signal handlers back to their default values.
  1496. Arguments:
  1497. None.
  1498. Return Value:
  1499. None.
  1500. --*/
  1501. {
  1502. struct sigaction SignalAction;
  1503. memset(&SignalAction, 0, sizeof(SignalAction));
  1504. sigemptyset(&(SignalAction.sa_mask));
  1505. SignalAction.sa_handler = SIG_DFL;
  1506. sigaction(SIGTSTP, &SignalAction, NULL);
  1507. sigaction(SIGINT, &SignalAction, NULL);
  1508. sigaction(SIGQUIT, &SignalAction, NULL);
  1509. sigaction(SIGUSR1, &SignalAction, NULL);
  1510. sigaction(SIGUSR2, &SignalAction, NULL);
  1511. sigaction(SIGTERM, &SignalAction, NULL);
  1512. sigaction(SIGHUP, &SignalAction, NULL);
  1513. sigprocmask(SIG_SETMASK, &(SignalAction.sa_mask), NULL);
  1514. return;
  1515. }
  1516. VOID
  1517. InitLog (
  1518. PINIT_CONTEXT Context,
  1519. ULONG Destination,
  1520. PSTR Format,
  1521. ...
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. This routine prints a message to the system log, console, or both.
  1526. Arguments:
  1527. Context - Supplies a pointer to the application context.
  1528. Destination - Supplies the bitfield of destinations the message should be
  1529. printed to. See INIT_LOG_* definitions.
  1530. Format - Supplies the printf-style format of the message.
  1531. ... - Supplies the additional arguments dictated by the format.
  1532. Return Value:
  1533. None.
  1534. --*/
  1535. {
  1536. va_list ArgumentList;
  1537. if ((Destination & INIT_LOG_DEBUG) != 0) {
  1538. if ((Context->Options & INIT_OPTION_DEBUG) != 0) {
  1539. Destination |= INIT_LOG_SYSLOG | INIT_LOG_CONSOLE;
  1540. }
  1541. }
  1542. if ((Destination & INIT_LOG_SYSLOG) != 0) {
  1543. if (Context->SyslogOpen == FALSE) {
  1544. openlog("init", 0, LOG_DAEMON);
  1545. Context->SyslogOpen = TRUE;
  1546. }
  1547. va_start(ArgumentList, Format);
  1548. vsyslog(LOG_INFO, Format, ArgumentList);
  1549. va_end(ArgumentList);
  1550. }
  1551. if ((Destination & INIT_LOG_CONSOLE) != 0) {
  1552. va_start(ArgumentList, Format);
  1553. vfprintf(stderr, Format, ArgumentList);
  1554. va_end(ArgumentList);
  1555. fprintf(stderr, "\n");
  1556. }
  1557. return;
  1558. }
  1559. void
  1560. InitSignalHandler (
  1561. int Signal
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. This routine is called when a signal fires. It simply records that the
  1566. signal occurred.
  1567. Arguments:
  1568. Signal - Supplies the signal that fired.
  1569. Return Value:
  1570. None.
  1571. --*/
  1572. {
  1573. assert(Signal < NSIG);
  1574. //
  1575. // Mark that a signal was seen in slot 0, and then increment the count for
  1576. // the particular signal.
  1577. //
  1578. InitSignalCounts[0] = 1;
  1579. InitSignalCounts[Signal] += 1;
  1580. return;
  1581. }