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_conf_dir.c
169 lines (136 loc) · 4.35 KB
/
init_conf_dir.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
168
169
#define _GNU_SOURCE
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "config.h"
#include "init.h"
#include "init_conf.h"
#include "sys.h"
static char debuf[DENTBUFSIZE];
static char fname[FULLNAMEMAX];
/* Some direntries in initdir should be silently ignored */
static int skipdirent(struct dirent64* de)
{
char dt;
int len = strlen(de->d_name);
/* skip hidden files */
if(de->d_name[0] == '.')
return 1;
/* skip temp files */
if(len > 0 && de->d_name[len - 1] == '~')
return 1;
/* skip uppercase files (this is bad but keeps README out for now) */
if(len > 0 && de->d_name[0] >= 'A' && de->d_name[0] <= 'Z')
return 1;
/* skip non-files early if the kernel was kind enough to warn us */
if((dt = de->d_type) && dt != DT_LNK && dt != DT_REG)
return 1;
return 0;
}
/* The default values for flags and runlevels are chosen so that
the most typical respawning entries would not need to specify
either explicitly. For initdir entries, flags are optional.
With initdir entries, there is also the special case of executable
scripts. Regular entries are compiled like this:
cmd = `cat INITDIR/somefile`
but with executable scripts, we do
cmd = INITDIR/somescript
instead, leaving the parsing job mostly to the shebang interpreter.
This makes it possible to use regular shell scripts as init entries
directly, without the need for extra shims to call them.
Whenever explicit flags are needed, the go in a #-comment line,
which must be line 1 for raw entries and line 2 for script
(scripts have shebang for line 1). */
static int comment(const char* s)
{
while(*s == ' ' || *s == '\t') s++;
return !*s || *s == '#';
}
static int parsesrvfile(char* fullname, char* basename)
{
int shebang = 0;
char* cmd;
const char* rlvls = "S";
char* ls;
ls = nextline();
/* Check for, and skip #! line if present */
if(ls && ls[0] == '#' && ls[1] == '!') {
shebang = 1;
ls = nextline();
}
/* Same for #: runlevels line */
if(ls && ls[0] == '#' && ls[1] == ':') {
ls[1] = *rlvls;
rlvls = ls + 1;
ls = nextline();
}
if(shebang) {
/* No need to parse anything anymore, it's a script. */
cmd = fullname;
} else {
/* Get to first non-comment line, and that's it, the rest
will be done in addinitrec. */
while(ls && comment(ls))
ls = nextline();
cmd = ls;
}
if(!ls) /* could be just cmd, but empty scripts are not ok */
retwarn(-1, "%s: no command found", FBN);
return addinitrec(basename, rlvls, cmd, shebang);
}
/* Initdir is one-file-per-entry structure, while inittab is
one-line-per-entry. Other than that, they are very similar.
Both call addinitrec() the same way.
Only the proper contents of INITDIR is checked, with no recursion.
This simplifies the code *and* allows storing auxilliary scripts
in a directory under INITDIR without init trying to pick them up.
File basename is used as the entry name for initdir entries.
Just like with readinitdir, the files are mmaped whole.
Here however init may come across a large script of which only
the two initial lines are needed to make an initrec, so there is
a limit on the mmaped block size.
The assumption is that raw entries (non-scripts) must be short. */
int readinitdir(const char* dir, int strict)
{
int dirfd;
struct dirent64* de;
int nr, ni; /* getdents ret and index */
int ret = -1;
const int delen = sizeof(debuf);
const int fnlen = sizeof(fname);
int bnoff; /* basename offset in fname */
int bnlen;
/* | |<---- bnlen ---->| */
/* fname: |/path/to/dir/filename | */
/* |--- bnoff ---^ */
strncpy(fname, dir, fnlen - 1);
bnoff = strlen(fname);
fname[bnoff++] = '/';
bnlen = fnlen - bnoff;
if((dirfd = open(dir, O_RDONLY | O_DIRECTORY)) < 0) {
if(errno == ENOENT)
return 0;
else
retwarn(ret, "Can't open %s", dir);
}
while((nr = getdents64(dirfd, (void*)debuf, delen)) > 0) {
for(ni = 0; ni < nr; ni += de->d_reclen) {
de = (struct dirent64*)(debuf + ni);
if(skipdirent(de))
continue;
strncpy(fname + bnoff, de->d_name, bnlen);
if(!(ret = mmapfile(fname, 1024))) {
ret = parsesrvfile(fname, de->d_name);
munmapfile();
} if(ret && strict)
goto out;
else if(ret)
warn("%s: skipping %s", dir, de->d_name);
}
}
ret = 0;
out: close(dirfd);
return ret;
}