123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- init.c
- Abstract:
- This module implements the init utility, which serves as the first user
- process on most Unix-like operating systems.
- Author:
- Evan Green 18-Mar-2015
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <alloca.h>
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <stdlib.h>
- #include <string.h>
- #include <syslog.h>
- #include <sys/ioctl.h>
- #include <sys/wait.h>
- #include <termios.h>
- #include <unistd.h>
- #include <utmpx.h>
- #include "swlib.h"
- #include "login/lutil.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro converts the given character into its control code.
- //
- #define INIT_CONTROL(_Character) ((_Character) ^ 0x40)
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define INIT_VERSION_MAJOR 1
- #define INIT_VERSION_MINOR 0
- #define INIT_USAGE \
- "usage: init [options] [runlevel]\n" \
- "The init utility performs system initialization steps. The runlevel be \n"\
- "1-6, a-c (for on-demand runlevels), q to re-examine inittab, s to \n" \
- "switch to single user mode, or u to re-execute. Options are:\n" \
- " -d, --debug -- Debug mode, prints more things.\n" \
- " -s, -S, --single -- Single-user mode. Examines /etc/inittab and runs \n"\
- " bootup rc scripts, then runs a single user shell.\n" \
- " -b, --emergency -- Boot directly into a single user shell without\n" \
- " running any other startup scripts.\n" \
- " --help -- Displays this help text and exits.\n" \
- " --version -- Displays the application version and exits.\n"
- #define INIT_OPTIONS_STRING "bdsS:hV"
- #define INIT_DEFAULT_TERMINAL_TYPE "xterm"
- #define INIT_INITTAB_PATH "/etc/inittab"
- #define INIT_DEFAULT_CONSOLE "/dev/console"
- #define INIT_INIT_SCRIPT "/etc/init.d/rcS"
- //
- // Define the time between sending SIGTERM and SIGKILL when reloading inittab
- // or switching runlevels.
- //
- #define INIT_KILL_DELAY 5
- //
- // Define application options.
- //
- //
- // Set this option to to boot into a single user shell, non-emergency.
- //
- #define INIT_OPTION_SINGLE_USER 0x00000001
- //
- // Set this option to boot into a single user shell, emergency mode.
- //
- #define INIT_OPTION_EMERGENCY 0x00000002
- //
- // Set this option to enable debug mode.
- //
- #define INIT_OPTION_DEBUG 0x00000004
- //
- // Define init log destinations.
- //
- #define INIT_LOG_SYSLOG 0x00000001
- #define INIT_LOG_CONSOLE 0x00000002
- #define INIT_LOG_DEBUG 0x00000004
- //
- // Define the init runlevel masks.
- //
- #define INIT_RUNLEVEL_0 0x00000001
- #define INIT_RUNLEVEL_1 0x00000002
- #define INIT_RUNLEVEL_2 0x00000004
- #define INIT_RUNLEVEL_3 0x00000008
- #define INIT_RUNLEVEL_4 0x00000010
- #define INIT_RUNLEVEL_5 0x00000020
- #define INIT_RUNLEVEL_6 0x00000040
- #define INIT_RUNLEVEL_7 0x00000080
- #define INIT_RUNLEVEL_8 0x00000100
- #define INIT_RUNLEVEL_9 0x00000200
- #define INIT_RUNLEVEL_A 0x00000400
- #define INIT_RUNLEVEL_B 0x00000800
- #define INIT_RUNLEVEL_C 0x00001000
- #define INIT_RUNLEVEL_S 0x00002000
- #define INIT_RUNLEVEL_MASK 0x00003FFF
- #define INIT_RUNLEVEL_NAMES "0123456789ABCS"
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _INIT_ACTION_TYPE {
- InitActionInvalid,
- InitActionNone,
- InitActionSysinit,
- InitActionBoot,
- InitActionBootWait,
- InitActionWait,
- InitActionOnce,
- InitActionRespawn,
- InitActionCtrlAltDel,
- InitActionShutdown,
- InitActionRestart,
- InitActionOnDemand,
- InitActionInitDefault,
- InitActionCount
- } INIT_ACTION_TYPE, *PINIT_ACTION_TYPE;
- typedef enum _INIT_REBOOT_PHASE {
- InitNotRebooting,
- InitRebootRunningActions,
- InitRebootTerm,
- InitRebootKill,
- InitRebootComplete
- } INIT_REBOOT_PHASE, *PINIT_REBOOT_PHASE;
- /*++
- Structure Description:
- This structure stores information about an init action.
- Members:
- ListEntry - Stores pointers to the next and previous init actions.
- ProcessId - Stores the process ID if the action is currently running.
- Id - Stores the ID of the command.
- RunLevels - Stores the bitmask of runlevels this action applies to.
- Type - Stores the action flavor.
- Command - Stores the command to execute.
- --*/
- typedef struct _INIT_ACTION {
- LIST_ENTRY ListEntry;
- pid_t ProcessId;
- CHAR Id[5];
- ULONG RunLevels;
- INIT_ACTION_TYPE Type;
- PSTR Command;
- } INIT_ACTION, *PINIT_ACTION;
- /*++
- Structure Description:
- This structure stores information about an init application instance.
- Members:
- SyslogOpen - Stores a boolean indicating whether the system log has been
- opened yet or not.
- Options - Stores the application options. See INIT_OPTION_* definitions.
- ActionList - Stores the head of the list of init actions.
- DefaultRunLevel - Stores the default runlevel (mask) to go to. Only one
- bit should be set here.
- CurrentRunLevel - Stores the current runlevel (mask). Only one bit should
- be set here.
- PreviousRunLevel - Stores the previous runlevel (mask). Only one bit should
- be set.
- RebootPhase - Stores the phase of system reboot init is currently working
- towards.
- RebootSignal - Stores the signal that initiated the reboot action, which
- also dictates the type.
- --*/
- typedef struct _INIT_CONTEXT {
- BOOL SyslogOpen;
- ULONG Options;
- LIST_ENTRY ActionList;
- ULONG DefaultRunLevel;
- ULONG CurrentRunLevel;
- ULONG PreviousRunLevel;
- INIT_REBOOT_PHASE RebootPhase;
- ULONG RebootSignal;
- } INIT_CONTEXT, *PINIT_CONTEXT;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- InitInitializeConsole (
- PINIT_CONTEXT Context
- );
- VOID
- InitConfigureTerminal (
- VOID
- );
- BOOL
- InitCheckSignals (
- PINIT_CONTEXT Context
- );
- VOID
- InitReloadInittab (
- PINIT_CONTEXT Context
- );
- VOID
- InitReexec (
- PINIT_CONTEXT Context
- );
- VOID
- InitRunResetSystem (
- PINIT_CONTEXT Context,
- INT Signal
- );
- VOID
- InitShutdownAndKillProcesses (
- PINIT_CONTEXT Context
- );
- VOID
- InitReboot (
- PINIT_CONTEXT Context,
- SWISS_REBOOT_TYPE RebootType
- );
- VOID
- InitParseInittab (
- PINIT_CONTEXT Context
- );
- VOID
- InitCreateAction (
- PINIT_CONTEXT Context,
- PSTR Id,
- ULONG RunLevels,
- INIT_ACTION_TYPE ActionType,
- PSTR Command
- );
- VOID
- InitRunActions (
- PINIT_CONTEXT Context,
- INIT_ACTION_TYPE ActionType,
- ULONG RunLevelMask
- );
- pid_t
- InitRunAction (
- PINIT_CONTEXT Context,
- PINIT_ACTION Action
- );
- VOID
- InitExec (
- PINIT_CONTEXT Context,
- PSTR Command
- );
- VOID
- InitWaitForProcess (
- PINIT_CONTEXT Context,
- pid_t ProcessId
- );
- PINIT_ACTION
- InitMarkProcessTerminated (
- PINIT_CONTEXT Context,
- pid_t ProcessId,
- int Status
- );
- VOID
- InitResetSignalHandlers (
- VOID
- );
- VOID
- InitLog (
- PINIT_CONTEXT Context,
- ULONG Destination,
- PSTR Format,
- ...
- );
- void
- InitSignalHandler (
- int Signal
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- extern char **environ;
- struct option InitLongOptions[] = {
- {"debug", no_argument, 0, 'd'},
- {"single", no_argument, 0, 's'},
- {"emergency", no_argument, 0, 'b'},
- {"help", no_argument, 0, 'H'},
- {"version", no_argument, 0, 'V'},
- {NULL, 0, 0, 0},
- };
- const PSTR InitActionTypeNames[InitActionCount] = {
- "INVALID",
- "off",
- "sysinit",
- "boot",
- "bootwait",
- "wait",
- "once",
- "respawn",
- "ctrlaltdel",
- "shutdown",
- "restart",
- "ondemand",
- "initdefault"
- };
- PUINTN InitSignalCounts = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- InitMain (
- INT ArgumentCount,
- CHAR **Arguments
- )
- /*++
- Routine Description:
- This routine is the main entry point for the init utility.
- Arguments:
- ArgumentCount - Supplies the number of command line arguments the program
- was invoked with.
- Arguments - Supplies a tokenized array of command line arguments.
- Return Value:
- Returns an integer exit code. 0 for success, nonzero otherwise.
- --*/
- {
- PINIT_ACTION Action;
- ULONG ArgumentIndex;
- CHAR Character;
- INIT_CONTEXT Context;
- PLIST_ENTRY CurrentEntry;
- UINTN Index;
- int NoHang;
- INT Option;
- ULONG Options;
- pid_t ProcessId;
- PSTR RunLevelString;
- struct sigaction SignalAction;
- UINTN SignalCounts[NSIG];
- int Status;
- Options = 0;
- RunLevelString = NULL;
- memset(&Context, 0, sizeof(INIT_CONTEXT));
- INITIALIZE_LIST_HEAD(&(Context.ActionList));
- memset(SignalCounts, 0, sizeof(SignalCounts));
- InitSignalCounts = SignalCounts;
- //
- // Process the control arguments.
- //
- while (TRUE) {
- Option = getopt_long(ArgumentCount,
- Arguments,
- INIT_OPTIONS_STRING,
- InitLongOptions,
- NULL);
- if (Option == -1) {
- break;
- }
- if ((Option == '?') || (Option == ':')) {
- Status = 1;
- goto MainEnd;
- }
- switch (Option) {
- case 'b':
- Options |= INIT_OPTION_EMERGENCY;
- break;
- case 'd':
- Options |= INIT_OPTION_DEBUG;
- break;
- case 'S':
- case 's':
- Options |= INIT_OPTION_SINGLE_USER;
- break;
- case 'V':
- SwPrintVersion(INIT_VERSION_MAJOR, INIT_VERSION_MINOR);
- return 1;
- case 'h':
- printf(INIT_USAGE);
- return 1;
- default:
- assert(FALSE);
- Status = 1;
- goto MainEnd;
- }
- }
- ArgumentIndex = optind;
- if (ArgumentIndex > ArgumentCount) {
- ArgumentIndex = ArgumentCount;
- }
- if (ArgumentIndex < ArgumentCount) {
- RunLevelString = Arguments[ArgumentIndex];
- ArgumentIndex += 1;
- }
- Context.Options = Options;
- InitInitializeConsole(&Context);
- InitConfigureTerminal();
- Status = chdir("/");
- if (Status != 0) {
- Status = errno;
- goto MainEnd;
- }
- setsid();
- //
- // Set some default environment variables.
- //
- setenv("HOME", "/", 0);
- setenv("PATH", SUPERUSER_DEFAULT_PATH, 0);
- setenv("SHELL", USER_FALLBACK_SHELL, 0);
- if (RunLevelString != NULL) {
- setenv("RUNLEVEL", RunLevelString, 1);
- }
- InitLog(&Context,
- INIT_LOG_SYSLOG | INIT_LOG_DEBUG,
- "Minoca init v%d.%d.%d",
- INIT_VERSION_MAJOR,
- INIT_VERSION_MINOR,
- SwGetSerialVersion());
- Status = 0;
- //
- // In emergency mode, just specify a shell to drop into.
- //
- if ((Options & INIT_OPTION_EMERGENCY) != 0) {
- InitCreateAction(&Context,
- "0",
- INIT_RUNLEVEL_MASK,
- InitActionRespawn,
- USER_FALLBACK_SHELL);
- } else {
- InitParseInittab(&Context);
- }
- //
- // In single-user mode, shoot for S.
- //
- if ((Options & INIT_OPTION_SINGLE_USER) != 0) {
- Context.DefaultRunLevel = INIT_RUNLEVEL_S;
- //
- // Shoot for whatever runlevel is on the command line.
- //
- } else if (RunLevelString != NULL) {
- if (strlen(RunLevelString) != 1) {
- InitLog(&Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Invalid runlevel argument: %s",
- RunLevelString);
- } else {
- Index = 0;
- Character = toupper(*RunLevelString);
- while (INIT_RUNLEVEL_NAMES[Index] != '\0') {
- if (INIT_RUNLEVEL_NAMES[Index] == Character) {
- Context.DefaultRunLevel = 1 << Index;
- break;
- }
- }
- if (INIT_RUNLEVEL_NAMES[Index] == '\0') {
- InitLog(&Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Invalid runlevel argument: %s",
- RunLevelString);
- }
- }
- }
- Context.CurrentRunLevel = Context.DefaultRunLevel;
- Context.PreviousRunLevel = Context.CurrentRunLevel;
- //
- // Set up the signal handlers.
- //
- memset(&SignalAction, 0, sizeof(SignalAction));
- sigfillset(&(SignalAction.sa_mask));
- SignalAction.sa_handler = SIG_IGN;
- sigaction(SIGTSTP, &SignalAction, NULL);
- SignalAction.sa_handler = InitSignalHandler;
- sigaction(SIGINT, &SignalAction, NULL);
- sigaction(SIGQUIT, &SignalAction, NULL);
- sigaction(SIGUSR1, &SignalAction, NULL);
- sigaction(SIGUSR2, &SignalAction, NULL);
- sigaction(SIGTERM, &SignalAction, NULL);
- sigaction(SIGHUP, &SignalAction, NULL);
- sigaction(SIGALRM, &SignalAction, NULL);
- //
- // Perform the actions.
- //
- InitRunActions(&Context, InitActionSysinit, 0);
- InitCheckSignals(&Context);
- InitRunActions(&Context, InitActionBoot, 0);
- InitCheckSignals(&Context);
- InitRunActions(&Context, InitActionBootWait, 0);
- InitCheckSignals(&Context);
- InitRunActions(&Context, InitActionWait, Context.CurrentRunLevel);
- InitCheckSignals(&Context);
- InitRunActions(&Context, InitActionOnce, Context.CurrentRunLevel);
- //
- // Now loop forever.
- //
- while (TRUE) {
- NoHang = 0;
- if (InitCheckSignals(&Context) != FALSE) {
- NoHang = WNOHANG;
- }
- //
- // Respawn processes unless a reboot is in progress.
- //
- if (Context.RebootPhase == InitNotRebooting) {
- InitRunActions(&Context,
- InitActionRespawn,
- Context.CurrentRunLevel);
- }
- if (InitCheckSignals(&Context) != FALSE) {
- NoHang = WNOHANG;
- }
- if (Context.RebootPhase == InitNotRebooting) {
- sleep(1);
- }
- if (InitCheckSignals(&Context) != FALSE) {
- NoHang = WNOHANG;
- }
- //
- // Loop getting all dead processes. There is a race in here where if a
- // new signal were to come in now but no child processes were ready,
- // the wait would just block, leaving a signal delivered but not dealt
- // with. That signal will be dealt with once the next child dies.
- //
- while (TRUE) {
- ProcessId = waitpid(-1, &Status, NoHang);
- if (ProcessId <= 0) {
- //
- // If there are no more children left and a reboot is requested,
- // go do it now.
- //
- if ((Context.RebootPhase > InitRebootRunningActions) &&
- (errno == ECHILD) && (NoHang == 0)) {
- Context.RebootPhase = InitRebootComplete;
- InitRunResetSystem(&Context, 0);
- }
- break;
- }
- InitMarkProcessTerminated(&Context, ProcessId, Status);
- NoHang = WNOHANG;
- }
- }
- Status = 0;
- MainEnd:
- InitResetSignalHandlers();
- CurrentEntry = Context.ActionList.Next;
- while (CurrentEntry != &(Context.ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- free(Action);
- }
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- InitInitializeConsole (
- PINIT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine initializes the console.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- PSTR Console;
- int Descriptor;
- PSTR TermVariable;
- Console = getenv("CONSOLE");
- if (Console == NULL) {
- Console = getenv("console");
- }
- //
- // Set it to a default.
- //
- if (Console == NULL) {
- Console = INIT_DEFAULT_CONSOLE;
- setenv("CONSOLE", Console, 1);
- }
- if (Console != NULL) {
- Descriptor = open(Console, O_RDWR | O_NONBLOCK | O_NOCTTY);
- if (Descriptor >= 0) {
- dup2(Descriptor, STDIN_FILENO);
- dup2(Descriptor, STDOUT_FILENO);
- dup2(Descriptor, STDERR_FILENO);
- if (Descriptor > STDERR_FILENO) {
- close(Descriptor);
- }
- }
- InitLog(Context, INIT_LOG_SYSLOG, "CONSOLE=%s", Console);
- }
- TermVariable = getenv("TERM");
- if (TermVariable == NULL) {
- setenv("TERM", INIT_DEFAULT_TERMINAL_TYPE, 1);
- }
- return;
- }
- VOID
- InitConfigureTerminal (
- VOID
- )
- /*++
- Routine Description:
- This routine sets some sane defaults for the terminal.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- struct termios Settings;
- if (tcgetattr(STDIN_FILENO, &Settings) != 0) {
- return;
- }
- Settings.c_cc[VINTR] = INIT_CONTROL('C');
- Settings.c_cc[VQUIT] = INIT_CONTROL('\\');
- Settings.c_cc[VERASE] = INIT_CONTROL('?');
- Settings.c_cc[VKILL] = INIT_CONTROL('U');
- Settings.c_cc[VEOF] = INIT_CONTROL('D');
- Settings.c_cc[VSTART] = INIT_CONTROL('Q');
- Settings.c_cc[VSTOP] = INIT_CONTROL('S');
- Settings.c_cc[VSUSP] = INIT_CONTROL('Z');
- //
- // Save the character size, stop bits, and parity configuration. Add in
- // receiver enable, hangup on close, and the local flag.
- //
- Settings.c_cflag &= CSIZE | CSTOPB | PARENB | PARODD;
- Settings.c_cflag |= CREAD | HUPCL | CLOCAL;
- Settings.c_iflag = ICRNL | IXON | IXOFF;
- Settings.c_oflag = OPOST | ONLCR;
- Settings.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOKE | ECHOCTL | IEXTEN;
- tcsetattr(STDIN_FILENO, TCSANOW, &Settings);
- return;
- }
- BOOL
- InitCheckSignals (
- PINIT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine checks for any signals that might have occurred recently.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- TRUE if a signal was processed.
- FALSE if no signals were processed.
- --*/
- {
- INT Signal;
- BOOL SignalsSeen;
- SignalsSeen = FALSE;
- while (TRUE) {
- //
- // Exit quickly if no signals occurred.
- //
- if (InitSignalCounts[0] == 0) {
- break;
- }
- //
- // Clear the "signals seen" boolean before checking.
- //
- InitSignalCounts[0] = 0;
- for (Signal = 1; Signal < NSIG; Signal += 1) {
- if (InitSignalCounts[Signal] != 0) {
- SignalsSeen = TRUE;
- InitSignalCounts[Signal] = 0;
- if (Signal == SIGINT) {
- InitRunActions(Context, InitActionCtrlAltDel, 0);
- } else if (Signal == SIGQUIT) {
- InitReexec(Context);
- } else if (Signal == SIGHUP) {
- InitReloadInittab(Context);
- } else if (Signal == SIGALRM) {
- if (Context->RebootPhase == InitRebootTerm) {
- Context->RebootPhase = InitRebootKill;
- InitRunResetSystem(Context, Signal);
- } else if (Context->RebootPhase == InitRebootKill) {
- Context->RebootPhase = InitRebootComplete;
- InitRunResetSystem(Context, Signal);
- }
- //
- // Other signals initiate a reboot.
- //
- } else {
- if (Context->RebootPhase == InitNotRebooting) {
- InitRunResetSystem(Context, Signal);
- }
- }
- }
- }
- }
- return SignalsSeen;
- }
- VOID
- InitReloadInittab (
- PINIT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine attempts to reload the inittab file, and reconcile the
- processes.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- PINIT_ACTION Action;
- pid_t Child;
- PLIST_ENTRY CurrentEntry;
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_DEBUG,
- "Reloading inittab");
- //
- // Clear out all the action types to know which entries don't show up
- // in the new file.
- //
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- Action->Type = InitActionInvalid;
- CurrentEntry = CurrentEntry->Next;
- }
- Context->PreviousRunLevel = Context->CurrentRunLevel;
- InitParseInittab(Context);
- //
- // Remove any leftover entries.
- //
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Kill a running entry that's either 1) not in the new inittab or
- // 2) Got a runlevel and it's not the current runlevel.
- //
- if ((Action->ProcessId > 0) &&
- ((Action->Type == InitActionInvalid) ||
- ((Action->RunLevels != 0) &&
- ((Action->RunLevels & Context->CurrentRunLevel) == 0)))) {
- InitLog(Context,
- INIT_LOG_DEBUG,
- "Killing: %d: %s",
- Action->ProcessId,
- Action->Command);
- kill(Action->ProcessId, SIGTERM);
- }
- }
- //
- // Fork, wait a bit, and then send kill to all these processes.
- //
- Child = fork();
- if (Child == 0) {
- sleep(INIT_KILL_DELAY);
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- if ((Action->ProcessId > 0) &&
- ((Action->Type == InitActionInvalid) ||
- ((Action->RunLevels != 0) &&
- ((Action->RunLevels & Context->CurrentRunLevel) == 0)))) {
- kill(Action->ProcessId, SIGKILL);
- }
- CurrentEntry = CurrentEntry->Next;
- }
- _exit(0);
- }
- //
- // Remove the unused entries. Also take the opportunity to free sysinit and
- // boot entries, which are never used again.
- //
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((Action->Type == InitActionInvalid) ||
- (Action->Type == InitActionSysinit) ||
- (Action->Type == InitActionBoot) ||
- (Action->Type == InitActionBootWait)) {
- LIST_REMOVE(&(Action->ListEntry));
- free(Action);
- }
- }
- return;
- }
- VOID
- InitReexec (
- PINIT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine attempts to run the restart action, execing init into that
- action.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None. Does not return on success.
- --*/
- {
- PINIT_ACTION Action;
- PLIST_ENTRY CurrentEntry;
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- if (Action->Type == InitActionRestart) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &(Context->ActionList)) {
- InitLog(Context, INIT_LOG_SYSLOG, "No restart action found");
- return;
- }
- InitResetSignalHandlers();
- InitShutdownAndKillProcesses(Context);
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Re-exec init: %s",
- Action->Command);
- InitExec(Context, Action->Command);
- InitReboot(Context, RebootTypeHalt);
- return;
- }
- VOID
- InitRunResetSystem (
- PINIT_CONTEXT Context,
- INT Signal
- )
- /*++
- Routine Description:
- This routine runs the tasks associated with resetting the system, and then
- resets the system.
- Arguments:
- Context - Supplies a pointer to the application context.
- Signal - Supplies the signal, which dictates the type of actions and
- power state to enter.
- Return Value:
- None.
- --*/
- {
- PSTR Message;
- SWISS_REBOOT_TYPE RebootType;
- switch (Context->RebootPhase) {
- case InitNotRebooting:
- Context->RebootPhase = InitRebootRunningActions;
- Context->RebootSignal = Signal;
- InitResetSignalHandlers();
- case InitRebootRunningActions:
- InitShutdownAndKillProcesses(Context);
- Context->RebootPhase = InitRebootTerm;
- //
- // Fall through.
- //
- case InitRebootTerm:
- case InitRebootKill:
- InitShutdownAndKillProcesses(Context);
- alarm(10);
- break;
- case InitRebootComplete:
- Signal = Context->RebootSignal;
- Message = "halt";
- RebootType = RebootTypeHalt;
- if (Signal == SIGTERM) {
- Message = "reboot";
- RebootType = RebootTypeWarm;
- } else if (Signal == SIGUSR2) {
- Message = "poweroff";
- }
- InitLog(Context,
- INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
- "Requesting system %s.",
- Message);
- InitReboot(Context, RebootType);
- break;
- default:
- assert(FALSE);
- break;
- }
- return;
- }
- VOID
- InitShutdownAndKillProcesses (
- PINIT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine runs the shutdown action and attempts to kill all processes.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- if (Context->RebootPhase == InitNotRebooting) {
- InitRunActions(Context, InitActionShutdown, 0);
- InitLog(Context,
- INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
- "The system is going down.");
- kill(-1, SIGTERM);
- sleep(1);
- kill(-1, SIGKILL);
- sync();
- } else if (Context->RebootPhase == InitRebootRunningActions) {
- InitRunActions(Context, InitActionShutdown, 0);
- InitLog(Context,
- INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
- "The system is going down.");
- } else if (Context->RebootPhase == InitRebootTerm) {
- kill(-1, SIGTERM);
- InitLog(Context,
- INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
- "Sent SIG%s to all processes.",
- "TERM");
- } else if (Context->RebootPhase == InitRebootKill) {
- kill(-1, SIGKILL);
- InitLog(Context,
- INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
- "Sent SIG%s to all processes.",
- "KILL");
- }
- return;
- }
- VOID
- InitReboot (
- PINIT_CONTEXT Context,
- SWISS_REBOOT_TYPE RebootType
- )
- /*++
- Routine Description:
- This routine actually resets the system.
- Arguments:
- Context - Supplies a pointer to the application context.
- RebootType - Supplies the type of reboot to perform.
- Return Value:
- None.
- --*/
- {
- pid_t Child;
- sleep(1);
- //
- // Do this in a child process since some reboot implementations exit,
- // which some OSes might have a problem with for pid 1.
- //
- Child = fork();
- if (Child == 0) {
- SwResetSystem(RebootType);
- _exit(0);
- }
- _exit(0);
- return;
- }
- VOID
- InitParseInittab (
- PINIT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine parses the inittab file.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- INIT_ACTION_TYPE ActionType;
- CHAR Character;
- PSTR Colon;
- PSTR Fields[4];
- FILE *File;
- UINTN Index;
- char *Line;
- size_t LineBufferSize;
- ssize_t LineSize;
- ULONG RunLevelMask;
- INT Status;
- PSTR String;
- Line = NULL;
- LineBufferSize = 0;
- File = fopen(INIT_INITTAB_PATH, "r");
- if (File == NULL) {
- Status = errno;
- //
- // If there is no inittab, create a basic one.
- //
- if (Status == ENOENT) {
- InitCreateAction(Context,
- "1",
- INIT_RUNLEVEL_1,
- InitActionSysinit,
- INIT_INIT_SCRIPT);
- InitCreateAction(Context,
- "2",
- INIT_RUNLEVEL_1,
- InitActionOnce,
- USER_FALLBACK_SHELL);
- InitCreateAction(Context,
- "3",
- INIT_RUNLEVEL_1,
- InitActionInitDefault,
- NULL);
- InitCreateAction(Context,
- "4",
- 0,
- InitActionCtrlAltDel,
- "reboot");
- InitCreateAction(Context,
- "5",
- 0,
- InitActionShutdown,
- "reboot -h");
- InitCreateAction(Context,
- "6",
- 0,
- InitActionRestart,
- "init");
- Status = 0;
- }
- goto ParseInittabEnd;
- }
- //
- // Loop parsing entries in the following form:
- // id:runlevels:action:command...
- //
- while (TRUE) {
- LineSize = getline(&Line, &LineBufferSize, File);
- if (LineSize < 0) {
- break;
- }
- while ((LineSize != 0) && (isspace(Line[LineSize - 1]))) {
- LineSize -= 1;
- }
- String = Line;
- String[LineSize] = '\0';
- //
- // Get past whitespace.
- //
- while (isspace(*String)) {
- String += 1;
- }
- //
- // Skip any commented lines.
- //
- if ((*String == '\0') || (*String == '#')) {
- continue;
- }
- //
- // Parse out the first three fields that have colons after them.
- //
- for (Index = 0; Index < 3; Index += 1) {
- Fields[Index] = String;
- Colon = strchr(String, ':');
- if (Colon == NULL) {
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Ignoring: %s",
- Line);
- break;
- }
- *Colon = '\0';
- String = Colon + 1;
- }
- if (Index != 3) {
- continue;
- }
- //
- // The last field gets the rest of the line.
- //
- Fields[Index] = String;
- //
- // Figure out the action type, the third field.
- //
- for (Index = 0; Index < InitActionCount; Index += 1) {
- if (strcmp(Fields[2], InitActionTypeNames[Index]) == 0) {
- ActionType = Index;
- break;
- }
- }
- if (Index == InitActionCount) {
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Unknown action type: %s",
- Fields[2]);
- continue;
- }
- //
- // Figure out the runlevel mask.
- //
- RunLevelMask = 0;
- String = Fields[1];
- while (*String != '\0') {
- Index = 0;
- Character = toupper(*String);
- while (INIT_RUNLEVEL_NAMES[Index] != '\0') {
- if (Character == INIT_RUNLEVEL_NAMES[Index]) {
- RunLevelMask |= 1 << Index;
- break;
- }
- Index += 1;
- }
- if (INIT_RUNLEVEL_NAMES[Index] == '\0') {
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Ignoring unknown runlevel %c",
- Character);
- }
- String += 1;
- }
- InitCreateAction(Context,
- Fields[0],
- RunLevelMask,
- ActionType,
- Fields[3]);
- }
- Status = 0;
- ParseInittabEnd:
- if (File != NULL) {
- fclose(File);
- }
- if (Line != NULL) {
- free(Line);
- }
- if (Status != 0) {
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Failed to parse inittab, adding default entry: %s",
- strerror(Status));
- InitCreateAction(Context,
- "0",
- INIT_RUNLEVEL_MASK,
- InitActionRespawn,
- USER_FALLBACK_SHELL);
- }
- return;
- }
- VOID
- InitCreateAction (
- PINIT_CONTEXT Context,
- PSTR Id,
- ULONG RunLevels,
- INIT_ACTION_TYPE ActionType,
- PSTR Command
- )
- /*++
- Routine Description:
- This routine creates and adds a new init action to the application context.
- Arguments:
- Context - Supplies a pointer to the application context.
- Id - Supplies up to 4 characters of ID information.
- RunLevels - Supplies the mask of runlevels this action is active for.
- ActionType - Supplies the type of action.
- Command - Supplies a pointer to the command to run.
- Return Value:
- None.
- --*/
- {
- PINIT_ACTION Action;
- size_t AllocationSize;
- PLIST_ENTRY CurrentEntry;
- if (Id == NULL) {
- Id = "";
- }
- //
- // If this is an "init default" action, just save the default run-level
- // but don't bother creating a full action.
- //
- if (ActionType == InitActionInitDefault) {
- Context->DefaultRunLevel = RunLevels;
- return;
- }
- //
- // Search for an action that exists already. Use this to avoid losing
- // running actions.
- //
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- if ((strcmp(Id, Action->Id) == 0) &&
- (strcmp(Command, Action->Command) == 0)) {
- LIST_REMOVE(&(Action->ListEntry));
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Allocate a new entry if one was not found.
- //
- if (CurrentEntry == &(Context->ActionList)) {
- AllocationSize = sizeof(INIT_ACTION) + strlen(Command) + 1;
- Action = malloc(AllocationSize);
- if (Action == NULL) {
- return;
- }
- memset(Action, 0, AllocationSize);
- Action->Command = (PSTR)(Action + 1);
- }
- strncpy(Action->Id, Id, sizeof(Action->Id) - 1);
- strcpy(Action->Command, Command);
- Action->Type = ActionType;
- Action->RunLevels = RunLevels;
- INSERT_BEFORE(&(Action->ListEntry), &(Context->ActionList));
- InitLog(Context,
- INIT_LOG_DEBUG,
- "New Action: %s:%x:%s:%s",
- Action->Id,
- Action->RunLevels,
- InitActionTypeNames[Action->Type],
- Action->Command);
- return;
- }
- VOID
- InitRunActions (
- PINIT_CONTEXT Context,
- INIT_ACTION_TYPE ActionType,
- ULONG RunLevelMask
- )
- /*++
- Routine Description:
- This routine runs all actions with a given action type that have a bit set
- in the given runlevel mask.
- Arguments:
- Context - Supplies a pointer to the application context.
- ActionType - Supplies the action type to filter.
- RunLevelMask - Supplies the run-level mask to filter.
- Return Value:
- None.
- --*/
- {
- PINIT_ACTION Action;
- PLIST_ENTRY CurrentEntry;
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Action->Type != ActionType) {
- continue;
- }
- if ((RunLevelMask != 0) && ((Action->RunLevels & RunLevelMask) == 0)) {
- continue;
- }
- //
- // For respawn actions, only run them if they're not already running.
- //
- if (ActionType == InitActionRespawn) {
- if (Action->ProcessId <= 0) {
- Action->ProcessId = InitRunAction(Context, Action);
- }
- } else {
- Action->ProcessId = InitRunAction(Context, Action);
- if ((ActionType == InitActionSysinit) ||
- (ActionType == InitActionWait) ||
- (ActionType == InitActionOnce) ||
- (ActionType == InitActionCtrlAltDel) ||
- (ActionType == InitActionShutdown)) {
- InitWaitForProcess(Context, Action->ProcessId);
- }
- }
- }
- return;
- }
- pid_t
- InitRunAction (
- PINIT_CONTEXT Context,
- PINIT_ACTION Action
- )
- /*++
- Routine Description:
- This routine fires up the given action.
- Arguments:
- Context - Supplies a pointer to the application context.
- Action - Supplies a pointer to the action to run.
- Return Value:
- Returns the process ID of the newly running process.
- --*/
- {
- int Flags;
- pid_t ProcessId;
- ProcessId = fork();
- if (ProcessId < 0) {
- InitLog(Context,
- INIT_LOG_CONSOLE | INIT_LOG_SYSLOG,
- "Failed to fork: %s",
- strerror(errno));
- return 0;
- }
- //
- // If this is the parent, just walk right back out with the new process ID
- // in hand.
- //
- if (ProcessId > 0) {
- return ProcessId;
- }
- //
- // Put signals back to their standard configuration.
- //
- InitResetSignalHandlers();
- //
- // Create a new session and process group.
- //
- setsid();
- //
- // For certain types of entries, force the console to be the controlling
- // terminal.
- //
- if ((Action->Type == InitActionSysinit) ||
- (Action->Type == InitActionBootWait) ||
- (Action->Type == InitActionWait)) {
- ioctl(STDIN_FILENO, TIOCSCTTY, 1);
- Flags = fcntl(STDIN_FILENO, F_GETFL);
- if (Flags != -1) {
- Flags &= ~O_NONBLOCK;
- fcntl(STDIN_FILENO, F_SETFL, Flags);
- }
- }
- InitLog(Context,
- INIT_LOG_SYSLOG,
- "Starting ID %s, PID %d: %s",
- Action->Id,
- getpid(),
- Action->Command);
- InitExec(Context, Action->Command);
- _exit(-1);
- }
- VOID
- InitExec (
- PINIT_CONTEXT Context,
- PSTR Command
- )
- /*++
- Routine Description:
- This routine executes the given command.
- Arguments:
- Context - Supplies a pointer to the application context.
- Command - Supplies a pointer to the command to execute.
- Return Value:
- None.
- --*/
- {
- PSTR *Array;
- UINTN ArrayCount;
- UINTN CommandLength;
- BOOL HasDash;
- UINTN Index;
- BOOL WasBlank;
- HasDash = FALSE;
- if (Command[0] == '-') {
- HasDash = TRUE;
- Command += 1;
- }
- CommandLength = strlen(Command);
- //
- // If there is anything weird in the command, let the shell navigate it.
- // The login shell define has a leading dash in front of it.
- //
- if (strpbrk(Command, "~`!$^&*()=\\|[]{};'\"<>?") != NULL) {
- Array = alloca(sizeof(PSTR) * 5);
- if (HasDash != FALSE) {
- Array[0] = USER_DEFAULT_LOGIN_SHELL;
- } else {
- Array[0] = USER_DEFAULT_LOGIN_SHELL + 1;
- }
- Array[1] = "-c";
- Array[2] = alloca(CommandLength + 6);
- snprintf(Array[2], CommandLength + 6, "exec %s", Command);
- Array[3] = NULL;
- Command = USER_DEFAULT_LOGIN_SHELL + 1;
- } else {
- ArrayCount = (CommandLength / 2) + 2;
- Array = alloca(sizeof(PSTR) * ArrayCount);
- Index = 0;
- WasBlank = TRUE;
- while (*Command != '\0') {
- //
- // The previous character was blank. If this one is too, keep
- // going, otherwise mark a new argument.
- //
- if (WasBlank != FALSE) {
- if (!isblank(*Command)) {
- Array[Index] = Command;
- Index += 1;
- WasBlank = FALSE;
- }
- //
- // The previous character was not blank. If it becomes blank,
- // null out this blank character to delimit the previous argument.
- //
- } else {
- if (isblank(*Command)) {
- WasBlank = TRUE;
- *Command = '\0';
- }
- }
- Command += 1;
- }
- Array[Index] = NULL;
- assert(Index < ArrayCount);
- }
- //
- // If there's a dash, then this is an interactive session. Attempt to set
- // the controlling terminal if it's not already set. Don't be forceful
- // though.
- //
- if (HasDash != FALSE) {
- ioctl(STDIN_FILENO, TIOCSCTTY, 0);
- }
- execve(Array[0], Array, environ);
- InitLog(Context,
- INIT_LOG_SYSLOG | INIT_LOG_CONSOLE,
- "Failed to exec %s: %s",
- Array[0],
- strerror(errno));
- return;
- }
- VOID
- InitWaitForProcess (
- PINIT_CONTEXT Context,
- pid_t ProcessId
- )
- /*++
- Routine Description:
- This routine waits for a specific process to complete.
- Arguments:
- Context - Supplies a pointer to the application context.
- ProcessId - Supplies the process ID to wait for.
- Return Value:
- None.
- --*/
- {
- pid_t DeadProcess;
- int Status;
- if (ProcessId <= 0) {
- return;
- }
- while (TRUE) {
- DeadProcess = wait(&Status);
- InitMarkProcessTerminated(Context, DeadProcess, Status);
- if (DeadProcess == ProcessId) {
- break;
- }
- }
- return;
- }
- PINIT_ACTION
- InitMarkProcessTerminated (
- PINIT_CONTEXT Context,
- pid_t ProcessId,
- int Status
- )
- /*++
- Routine Description:
- This routine cleans up after a dead process.
- Arguments:
- Context - Supplies a pointer to the application context.
- ProcessId - Supplies the process ID that ended.
- Status - Supplies the exit status of the process.
- Return Value:
- Returns a pointer to the action associated with the process ID if it's
- one of init's processes.
- NULL if the process is not a tracked process.
- --*/
- {
- PINIT_ACTION Action;
- PLIST_ENTRY CurrentEntry;
- PINIT_ACTION FoundAction;
- FoundAction = NULL;
- if (ProcessId > 0) {
- SwUpdateUtmp(ProcessId, DEAD_PROCESS, NULL, NULL, NULL);
- CurrentEntry = Context->ActionList.Next;
- while (CurrentEntry != &(Context->ActionList)) {
- Action = LIST_VALUE(CurrentEntry, INIT_ACTION, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Action->ProcessId == ProcessId) {
- Action->ProcessId = 0;
- FoundAction = Action;
- break;
- }
- }
- }
- if ((FoundAction != NULL) && (Action->Type == InitActionRespawn)) {
- InitLog(Context,
- INIT_LOG_DEBUG | INIT_LOG_SYSLOG,
- "Process '%s' (pid %d) exited with status %d. Scheduling for "
- "restart",
- FoundAction->Command,
- ProcessId,
- Status);
- } else {
- InitLog(Context,
- INIT_LOG_DEBUG,
- "Process id %d exited with status %d.",
- ProcessId,
- Status);
- }
- return FoundAction;
- }
- VOID
- InitResetSignalHandlers (
- VOID
- )
- /*++
- Routine Description:
- This routine resets signal handlers back to their default values.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- struct sigaction SignalAction;
- memset(&SignalAction, 0, sizeof(SignalAction));
- sigemptyset(&(SignalAction.sa_mask));
- SignalAction.sa_handler = SIG_DFL;
- sigaction(SIGTSTP, &SignalAction, NULL);
- sigaction(SIGINT, &SignalAction, NULL);
- sigaction(SIGQUIT, &SignalAction, NULL);
- sigaction(SIGUSR1, &SignalAction, NULL);
- sigaction(SIGUSR2, &SignalAction, NULL);
- sigaction(SIGTERM, &SignalAction, NULL);
- sigaction(SIGHUP, &SignalAction, NULL);
- sigprocmask(SIG_SETMASK, &(SignalAction.sa_mask), NULL);
- return;
- }
- VOID
- InitLog (
- PINIT_CONTEXT Context,
- ULONG Destination,
- PSTR Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a message to the system log, console, or both.
- Arguments:
- Context - Supplies a pointer to the application context.
- Destination - Supplies the bitfield of destinations the message should be
- printed to. See INIT_LOG_* definitions.
- Format - Supplies the printf-style format of the message.
- ... - Supplies the additional arguments dictated by the format.
- Return Value:
- None.
- --*/
- {
- va_list ArgumentList;
- if ((Destination & INIT_LOG_DEBUG) != 0) {
- if ((Context->Options & INIT_OPTION_DEBUG) != 0) {
- Destination |= INIT_LOG_SYSLOG | INIT_LOG_CONSOLE;
- }
- }
- if ((Destination & INIT_LOG_SYSLOG) != 0) {
- if (Context->SyslogOpen == FALSE) {
- openlog("init", 0, LOG_DAEMON);
- Context->SyslogOpen = TRUE;
- }
- va_start(ArgumentList, Format);
- vsyslog(LOG_INFO, Format, ArgumentList);
- va_end(ArgumentList);
- }
- if ((Destination & INIT_LOG_CONSOLE) != 0) {
- va_start(ArgumentList, Format);
- vfprintf(stderr, Format, ArgumentList);
- va_end(ArgumentList);
- fprintf(stderr, "\n");
- }
- return;
- }
- void
- InitSignalHandler (
- int Signal
- )
- /*++
- Routine Description:
- This routine is called when a signal fires. It simply records that the
- signal occurred.
- Arguments:
- Signal - Supplies the signal that fired.
- Return Value:
- None.
- --*/
- {
- assert(Signal < NSIG);
- //
- // Mark that a signal was seen in slot 0, and then increment the count for
- // the particular signal.
- //
- InitSignalCounts[0] = 1;
- InitSignalCounts[Signal] += 1;
- return;
- }
|