1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128 |
- /*++
- 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);
- }
- InitSignalCounts = NULL;
- 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 | IMAXBEL;
- 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;
- }
|