2
* very very simple makefile parser
16
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
17
# include <sys/types.h>
18
# include <sys/stat.h>
20
#ifndef POSIX_FADV_SEQUENTIAL
21
#define posix_fadvise(fd, off, len, adv) (-1)
26
static int o_flags = O_RDONLY;
31
struct makenode *tree_list = NULL;
34
* search for the node with the given name
35
* returns the node pointer or NULL if not found.
37
* FIXME: we should use hash for the effective search.
39
static struct makenode *lookup_target(const char *name)
43
for (t = tree_list; t; t = t->next)
44
if (! strcmp(t->name, name))
50
* look for the node with the given name. if not exist,
51
* create a new one and append to the node list.
53
static struct makenode *add_target(const char *name)
55
struct makenode *__restrict node;
56
struct makenode *prev, *t;
58
node = lookup_target(name);
61
if (posix_memalign((void*)&node, sizeof(void*), alignof(struct makenode)+strsize(name)) < 0) {
62
fprintf(stderr, "Can't malloc: %s\n", strerror(errno));
65
memset(node, 0, alignof(struct makenode)+strsize(name));
66
node->name = ((char*)node)+alignof(struct makenode);
67
strcpy(node->name, name);
69
/* append to the list in alphabetical order */
71
for (t = tree_list; t; prev = t, t = t->next)
72
if (strcmp(node->name, t->name) < 0)
84
* Set and propagate importance of a node to all depencies of this node
86
static void add_importance(struct makenode *node, int importance)
88
struct makelist *s = node->depend;
90
node->importance += importance;
91
for (s = node->depend; s; s = s->next)
92
add_importance(s->node, importance);
96
* create a dependecy/selection node
98
static struct makelist *new_list(struct makenode *node, struct makelist *next)
102
x = xcalloc(1, sizeof(*x));
109
* check whether the given target would create an infinte loop
112
static int check_loop(struct makenode *dep, struct makenode *src)
115
for (s = dep->depend; s; s = s->next) {
116
if (s->node == src) {
117
fprintf(stderr, "loop exists %s in %s!\n", dep->name, src->name);
120
if (loop++ > 99999) {
121
fprintf(stderr, "too many loops! (loop=%d, dep->name=%s, src->name=%s)\n",
122
loop, dep->name, src->name);
125
if (check_loop(s->node, src))
132
* add to the dependecy and selection lists
134
static void add_depend(struct makenode *node, const char *dst)
136
struct makenode *dep;
138
dep = add_target(dst);
140
if (check_loop(dep, node))
142
dep->select = new_list(node, dep->select);
144
node->depend = new_list(dep, node->depend);
149
* mark the selected service as an interactive task
150
* that should run solely
152
static void mark_interactive(const char *name)
154
struct makenode *node = lookup_target(name);
156
node->interactive = 1;
160
#define DELIMITER " \t\r\n"
163
* parse (pseudo) makefile
165
* it may have only the following form:
168
* INTERACTIVE = yyy ...
172
* other lines are ignored.
174
void parse_makefile(const char *path)
177
char buf[LINE_MAX]; /* FIXME: is this enough big? */
179
struct makenode *node;
181
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
184
if (getuid() == (uid_t)0)
185
o_flags |= O_NOATIME;
186
if ((fd = open(path, o_flags)) < 0) {
187
fprintf(stderr, "Can't open %s: %s\n", path, strerror(errno));
190
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
191
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
192
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
194
if ((fp = fdopen(fd, "r")) == NULL)
196
if ((fp = fopen(path, "r")) == NULL)
199
fprintf(stderr, "Can't open %s: %s\n", path, strerror(errno));
203
while (fgets(buf, sizeof(buf), fp)) {
204
for (s = buf; *s && isspace(*s); s++)
206
if (! *s || *s == '#')
208
if (! strncmp(s, "TARGETS =", 9)) {
211
while ((s = strsep(&strp, DELIMITER))) {
216
} else if (! strncmp(s, "INTERACTIVE =", 13)) {
219
while ((s = strsep(&strp, DELIMITER))) {
229
node = add_target(s);
231
while ((s = strsep(&strp, DELIMITER))) {
239
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
240
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
245
for (node = tree_list; node; node = node->next) {
248
if (! strcmp(node->name, "xdm"))
251
if (! strncmp(node->name, "early", 5))
255
add_importance(node, importance);
260
* filter out the list targets
263
static int filter_prefix;
264
static int dirfilter(const struct dirent *d)
266
return *d->d_name == filter_prefix &&
267
strlen(d->d_name) >= 4; /* to be sure */
270
static void filter_files(const char *dir, int prefix, int inverse)
274
static struct dirent **dirlist;
275
struct makenode *t, *next;
277
filter_prefix = prefix;
278
#ifdef SUSE /* SuSE */
279
snprintf(path, sizeof(path), "/etc/init.d/%s.d", dir);
281
snprintf(path, sizeof(path), "/etc/%s.d", dir);
283
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
284
if ((i = open(path, o_flags|O_DIRECTORY|O_LARGEFILE)) >= 0) {
285
(void)posix_fadvise(i, 0, 0, POSIX_FADV_SEQUENTIAL);
286
(void)posix_fadvise(i, 0, 0, POSIX_FADV_NOREUSE);
289
ndirs = scandir(path, &dirlist, dirfilter, alphasort);
290
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
292
(void)posix_fadvise(i, 0, 0, POSIX_FADV_DONTNEED);
296
/* mark all matching nodes */
298
for (i = 0; i < ndirs; i++) {
299
t = lookup_target(dirlist[i]->d_name + 3);
302
if (asprintf(&t->arg0, "%s/%s", path, dirlist[i]->d_name) < 0)
309
/* deselect non-matching nodes */
310
for (t = tree_list; t; t = next) {
312
if ((! t->status && ! inverse) || (t->status && inverse)) {
313
/* remove from the list */
314
struct makelist *x, *nx;
316
for (x = t->select; x; x = nx) {
321
for (x = t->depend; x; x = nx) {
329
for (p = tree_list; p->next != t; p = p->next)
333
/* don't free the node instance itself - it may be selected
344
* mark the unnecessary services as finished.
346
* action is either boot, start or stop.
347
* prev and run are the previous and the next runlevel.
349
void check_run_files(const char *action, const char *prev, const char *run)
352
if (! strcmp(action, "boot")) {
353
#ifdef SUSE /* SuSE */
354
filter_files("boot", 'S', 0);
355
} else if (! strcmp(action, "halt")) {
356
filter_files("boot", 'K', 0);
357
} else if (! strcmp(action, "start")) {
359
filter_files(buf, 'K', 1);
361
filter_files(buf, 'S', 0);
364
filter_files(buf, 'K', 0);
366
filter_files(buf, 'S', 1);
368
filter_files("rcS", 'S', 0);
369
} else if (! strcmp(action, "start")) {
371
filter_files(buf, 'S', 1);
373
filter_files(buf, 'S', 0);
376
filter_files(buf, 'K', 1);
378
filter_files(buf, 'K', 0);
388
static void blogger(char *fmt, ...)
394
strcpy(buf, "blogger \"");
397
vsnprintf(buf + len, sizeof(buf) - len - 1, fmt, ap);
403
# define blogger(arg...)
408
* pick up the next running task
409
* return NULL if not found.
411
struct makenode *pickup_task(void)
413
struct makenode *node, *best = (struct makenode*)0;
415
for (node = tree_list; node; node = node->next) {
416
if ((! node->status) && (! node->num_deps) &&
417
((! best) || (node->importance > best->importance))) {
422
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
425
snprintf(path, sizeof(path), "/etc/init.d/%s", best->name);
426
if ((fd = open(path, o_flags|O_DIRECT)) >= 0) {
427
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
428
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
429
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
433
blogger("service %s", best->name);
434
best->status = T_RUNNING;
440
* finish the running task
442
void finish_task(struct makenode *node)
448
for (n = node->select; n; n = n->next)
450
#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
454
snprintf(path, sizeof(path), "/etc/init.d/%s", node->name);
455
if ((fd = open(path, o_flags|O_DIRECT)) >= 0) {
456
(void)posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
461
node->status = T_FINISHED;
462
blogger("service %s done", node->name);
467
* Print out the status that bash can run eval.
468
* The following things will be printed:
469
* failed services, skipped services and the current progress value.
471
void print_run_result(int *resvec, struct makenode **nodevec, const char *action)
473
int i, r, stop = (! strcmp(action, "stop"));
475
printf("failed_service=\"");
477
for (i = 0; i < tree_entries; i++) {
479
if (resvec[i] == 255) {
480
fprintf(stderr, "ERROR: forgotten process??\n");
484
if (resvec[i] >= 1 && resvec[i] <= 4) {
487
printf("%s", nodevec[i]->name);
489
} else if (!stop && resvec[i] == 7) {
492
printf("%s", nodevec[i]->name);
497
printf("skipped_service=\"");
499
for (i = 0; i < tree_entries; i++) {
500
if (resvec[i] == 5 || resvec[i] == 6) {
503
printf("%s", nodevec[i]->name);
511
void dump_status(void)
513
struct makenode *node;
515
for (node = tree_list; node; node = node->next)
516
fprintf(stderr, "XXX %s: status = %d, dep = %d, int = %d, imp = %d\n",
517
node->name, node->status, node->num_deps, node->interactive, node->importance);
522
void *xcalloc(size_t nmemb, size_t size)
525
if ((r = (void *)calloc(nmemb, size)) == 0) {
526
fprintf(stderr, "calloc: out of memory\n");
532
int main(int argc, char **argv)
534
struct makenode *nodevec;
538
fprintf(stderr, "usage: makeboot <action> [<prev> <run>]\n");
542
snprintf(makefile, sizeof(makefile), "depend.%s", argv[1]);
543
parse_makefile(makefile);
545
fprintf(stderr, "check_run_files(%s, %s, %s)\n", argv[1], argv[2],
547
check_run_files(argv[1], argv[2], argv[3]);
549
while ((nodevec = pickup_task())) {
550
fprintf(stdout, "%s (%s)\n", nodevec->name, nodevec->arg0);
551
finish_task(nodevec);