This repository has been archived by the owner on Sep 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
init_pass.c
167 lines (134 loc) · 4.36 KB
/
init_pass.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#define _GNU_SOURCE
#include "init.h"
#include "config.h"
/* bits for waitfor */
#define DYING (1<<0)
#define RUNNING (1<<1)
#define once(p) (p->flags & C_ONCE)
#define onceonly(p) ((p->flags & (C_ONCE | C_WAIT)) == (C_ONCE))
#define oncewait(p) ((p->flags & (C_ONCE | C_WAIT)) == (C_ONCE | C_WAIT))
#define slippery(rlvl) (SLIPPERY & rlvl)
/* Should we start $p for nextlevel?
PRIMASK: xxxxxxxxxx
nextlevel: --dc--------3---
p->rlvl: ---c-a----5432--
SUBMASK: xxxxxx
To say yes, we need to make sure there'a a bit for
current primary runlevel, and that if there are bits
set for sublevels, at least one of them matches a bit
in nextlevel.
Note (p->rlvl & SUBMASK == 0) means "disregard sublevels", but
(p->rlvl & SUBMASK == SUBMASK) means "run in *any* sublevel"
and excludes no-active-sublevels case. */
static int shouldberunning(struct initrec* p)
{
if(p->flags & (P_MANUAL | P_FAILED))
return 0; /* disabled (telinit or respawning too fast) */
else
return levelmatch(p, nextlevel);
}
/* transferpids() needs to call this as well, but using currlevel
instead of nextlevel, so there is shouldberunning() for local
use and levelmatch there. */
int levelmatch(struct initrec* p, int level)
{
int go = (p->flags & C_INVERT ? 0 : 1);
if(!(p->rlvl & level & PRIMASK))
/* not in this primary level */
return !go;
if(!(p->rlvl & SUBMASK))
/* sublevels not defined = run in all sublevels */
return go;
if(!(p->rlvl & level & SUBMASK))
return !go;
return go;
}
static void swapi(int* a, int* b)
{
int t = *b; *b = *a; *a = t;
}
static void switchtonextlevel(void)
{
struct initrec** inittab = cfg->inittab;
struct initrec** pp;
struct initrec* p;
/* One we're here, reset pid for r-type entries, to run them when
entering another runlevel with shouldberunning(p) true. */
for(pp = inittab; (p = *pp); pp++)
if(!shouldberunning(p) && once(p) && (p->pid < 0))
p->pid = 0;
if(slippery(nextlevel) && !slippery(currlevel)) {
/* nextlevel is slippery, turn back to currlevel */
swapi(&currlevel, &nextlevel);
/* We've got to make sure pollfds will return immediately. */
timetowait = 0;
} else {
currlevel = nextlevel;
}
}
/* Initpass: go through inittab, (re)starting entries
that need to be (re)started and killing entries that should be killed.
There are two principal passes over inittab: bottom-to-top that kills
processes first, and top-to-bottom that spawns processes. Backwards
pass is needed to C_WAIT without C_ONCE, i.e. waiting for things to
die before killing certain s-type records (syslog primarily).
In case a C_WAIT entry is reached during either pass, relevant action
is performed and initpass return.
SIGCHLD will arrive on entry completition, triggering another initpass.
Blocking wait is never used, init waits for w-type entries in ppoll().
Because no explicit list pointer is kept during runlevel switching,
things get a bit tricky with r-type entries which are traversed
several times but should only be run once.
Note to have pid reset to 0, and thus allow re-run, at least one pass
must be completed with !shouldberunning(p) for the entry. */
void initpass(void)
{
int waitfor = 0;
struct initrec** pp;
struct initrec* p;
if(!cfg->inittab || cfg->initnum <= 0)
goto done; /* should never happen, but who knows */
struct initrec** inittab = cfg->inittab;
struct initrec** initend = cfg->inittab + cfg->initnum - 1;
/* Kill pass, reverse order */
for(pp = initend; (p = *pp); pp--)
if(!shouldberunning(p) && p->pid > 0)
{
stop(p);
waitfor |= DYING;
if(onceonly(p))
return;
}
/* Run pass, direct order */
for(pp = inittab; (p = *pp); pp++)
if(shouldberunning(p))
{
if(p->pid > 0) {
if(oncewait(p))
return;
else if(once(p))
waitfor |= RUNNING;
continue;
}
if(p->pid < 0 && once(p))
continue; /* has been run already */
if(waitfor && oncewait(p))
return;
if(!once(p) && slippery(nextlevel))
continue; /* these will be killed anyway */
spawn(p);
if(once(p))
waitfor |= RUNNING;
if(oncewait(p))
return;
}
if(waitfor)
return;
done: if(nextlevel == (1<<0)) {
/* level 0 is slippery in its own particular way */
currlevel = nextlevel;
nextlevel = 0;
timetowait = 0;
} else if(currlevel != nextlevel)
switchtonextlevel();
}