Merge lp:~xnox/ubuntu/utopic/sysvinit/upstart-task into lp:ubuntu/utopic/sysvinit

Proposed by Dimitri John Ledkov
Status: Rejected
Rejected by: Martin Pitt
Proposed branch: lp:~xnox/ubuntu/utopic/sysvinit/upstart-task
Merge into: lp:ubuntu/utopic/sysvinit
Diff against target: 812 lines (+739/-4) (has conflicts)
7 files modified
.pc/applied-patches (+1/-0)
.pc/startpar-upstart-tasks.patch/startpar/makeboot.c (+688/-0)
debian/changelog (+10/-0)
debian/patches/series (+1/-0)
debian/patches/startpar-upstart-tasks.patch (+28/-0)
debian/src/sysv-rc/etc/init.d/rc (+1/-3)
startpar/makeboot.c (+10/-1)
Text conflict in debian/changelog
To merge this branch: bzr merge lp:~xnox/ubuntu/utopic/sysvinit/upstart-task
Reviewer Review Type Date Requested Status
Martin Pitt Needs Fixing
Adam Conrad Pending
Stéphane Graber Pending
Steve Langasek Pending
Ubuntu branches Pending
Review via email: mp+221493@code.launchpad.net

Description of the change

Some of the init.d scripts have been converted to tasks. Given the way ubuntu boots (e.g. udev based assembly of lvm/raid etc); and the fact that upstart-native tasks are typically complete before invoking rc; and no way to tell that an upstart task has been run. It should be sufficient to consider all task jobs as complete from startpar bridge point of view, and thus not block rc, waiting to execute a task job.

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

The way I understand it the really clean way to implement this would be to tell apart the case "this task job never ran" from "it ran at least once, but is stopped". This could either be by a different status message (like "stop/waiting" vs. "finished/waiting", or similar), or creating a stamp file in /run for every ran task. Both of which would be upstart changes.

This also introduces the assumption that upstart's tasks will always run before startpar so that the init.d dependencies will always be satisfied for tasks. That's not quite correct and sounds like introducing race conditions.

That said, if this is supposed to be a better workaround instead of an actual solution, it seems ok to me for the time being. It's at least better than running all init.d scripts.

Thanks!

Revision history for this message
Steve Langasek (vorlon) wrote :

On Fri, May 30, 2014 at 08:19:15AM -0000, Martin Pitt wrote:
> The way I understand it the really clean way to implement this would be to
> tell apart the case "this task job never ran" from "it ran at least once,
> but is stopped". This could either be by a different status message (like
> "stop/waiting" vs. "finished/waiting", or similar), or creating a stamp
> file in /run for every ran task. Both of which would be upstart changes.

> This also introduces the assumption that upstart's tasks will always run
> before startpar so that the init.d dependencies will always be satisfied
> for tasks. That's not quite correct and sounds like introducing race
> conditions.

In practice, *everything* in /etc/rcS.d is supposed to be redundant with
upstart jobs in the upstart case, and the impact of a race condition - as
opposed to hang - should be nil.

If we have task jobs that map to scripts in /etc/rc2.d, I think we should
take a close look at this. However, for the "unofficial upstart jobs" case,
I don't think we should put the effort into ensuring there are no race
conditions when the user has both created an upstart task job that conflicts
with an init script *and* has another init script depending on that first
task. Clearly we would want to address this if we were sticking with
upstart longer-term, but I don't think it's relevant on a transitional
basis.

Revision history for this message
Steve Langasek (vorlon) wrote :

> --- startpar/makeboot.c 2012-06-27 23:00:45 +0000
> +++ startpar/makeboot.c 2014-05-30 07:54:58 +0000
> @@ -451,6 +451,13 @@
> t->name);
> }
> ret = system(command);
> + if (WEXITSTATUS(ret) != 0) {
> + free(command);
> + asprintf(&command,
> + "grep -q '^task$' %s",
> + path);
> + ret = system(command);
> + }
> if (WEXITSTATUS(ret) == 0) {
> nodevec[count] = t;
> finish_task(t);
>

This appears to give task jobs a free pass both when checking if they're
started, but also when checking if they're stopped. The reason for making
this change is because we can't detect if a task has run and already stopped
again; but if it's currently running we can certainly detect that. Should
we do so, to avoid letting an init script be called on shutdown while a task
is still running?

I had a look at the code around timeouts in startpar, and don't think it's
worth trying to hook the task handling up to it for what should be a
short-term solution.

209. By Dimitri John Ledkov

Give tasks a free-pass on boot only.

Revision history for this message
Martin Pitt (pitti) wrote :

This updated version looks ok to me as per the discussion above. I'd still like the ^task$ to be extended to allow whitespace (as I suggested in my previous inline diff comments, but they might have drowned). Also, I think this should revert http://launchpadlibrarian.net/176540378/sysvinit_2.88dsf-41ubuntu14_2.88dsf-41ubuntu15.diff.gz at the same time. Finally, I think it makes more sense to fold this into the existing debian/patches/upstart_support.patch instead of yet another patch (but fine for now for experimentation).

I built this branch with CONCURRENCY back to "makefile" so that this has any effect. But now my VM hangs at early shutdown, and also I don't see anything at all during boot (even without "quiet splash"), so something is still wrong here. In which environment did you try this?

Thanks!

review: Needs Fixing
210. By Dimitri John Ledkov

Improve task grep pattern.

211. By Dimitri John Ledkov

Re-enable startpar.

Revision history for this message
Martin Pitt (pitti) wrote :

Setting to work in progress for now, to get it out of the sponsoring queue. However, we might just bury this completely, as we discussed to not support startpar after all? It'd be more trouble than it's worth IMHO. So please feel free to delete this.

Revision history for this message
Martin Pitt (pitti) wrote :

I think it's safe to say that we won't pursue this direction. We disabled startpar support in sysvinit and removed startpar from the archive.

Unmerged revisions

211. By Dimitri John Ledkov

Re-enable startpar.

210. By Dimitri John Ledkov

Improve task grep pattern.

209. By Dimitri John Ledkov

Give tasks a free-pass on boot only.

208. By Dimitri John Ledkov

Add 'task' knowledge to startpar.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pc/applied-patches'
2--- .pc/applied-patches 2013-05-17 20:53:22 +0000
3+++ .pc/applied-patches 2014-06-05 13:25:18 +0000
4@@ -23,3 +23,4 @@
5 93_run_initctl.patch
6 94_kfreebsd_xterm.patch
7 upstart_support.patch
8+startpar-upstart-tasks.patch
9
10=== added directory '.pc/startpar-upstart-tasks.patch'
11=== added directory '.pc/startpar-upstart-tasks.patch/startpar'
12=== added file '.pc/startpar-upstart-tasks.patch/startpar/makeboot.c'
13--- .pc/startpar-upstart-tasks.patch/startpar/makeboot.c 1970-01-01 00:00:00 +0000
14+++ .pc/startpar-upstart-tasks.patch/startpar/makeboot.c 2014-06-05 13:25:18 +0000
15@@ -0,0 +1,688 @@
16+/*
17+ * very very simple makefile parser
18+ *
19+ * Copyright (c) 2003 SuSE Linux AG
20+ *
21+ * This program is free software; you can redistribute it and/or modify
22+ * it under the terms of the GNU General Public License as published by
23+ * the Free Software Foundation; either version 2, or (at your option)
24+ * any later version.
25+ *
26+ * This program is distributed in the hope that it will be useful,
27+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
28+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29+ * GNU General Public License for more details.
30+ *
31+ * You should have received a copy of the GNU General Public License
32+ * along with this program (see the file COPYING); if not, write to the
33+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
34+ * MA 02110-1301, USA.
35+ *
36+ */
37+
38+#include <stdio.h>
39+#include <stddef.h>
40+#include <string.h>
41+#include <malloc.h>
42+#include <ctype.h>
43+#include <stdlib.h>
44+#include <dirent.h>
45+#include <unistd.h>
46+#include <stdarg.h>
47+#include <errno.h>
48+#include <limits.h>
49+#include <sys/socket.h>
50+#include <sys/un.h>
51+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
52+# include <sys/types.h>
53+# include <sys/stat.h>
54+# include <fcntl.h>
55+#ifndef POSIX_FADV_SEQUENTIAL
56+#define posix_fadvise(fd, off, len, adv) (-1)
57+#endif
58+#ifndef O_DIRECT
59+#define O_DIRECT 0
60+#endif
61+static int o_flags = O_RDONLY;
62+#endif
63+#ifdef USE_BLOGD
64+# include <libblogger.h>
65+#endif
66+#include "makeboot.h"
67+
68+#define DBUS_ADDRESS_UPSTART "@/com/ubuntu/upstart"
69+
70+int tree_entries = 0;
71+struct makenode *tree_list = NULL;
72+
73+/*
74+ * search for the node with the given name
75+ * returns the node pointer or NULL if not found.
76+ *
77+ * FIXME: we should use hash for the effective search.
78+ */
79+struct makenode *lookup_target(const char *name)
80+{
81+ struct makenode *t;
82+
83+ for (t = tree_list; t; t = t->next)
84+ if (! strcmp(t->name, name))
85+ return t;
86+ return NULL;
87+}
88+
89+/*
90+ * look for the node with the given name. if not exist,
91+ * create a new one and append to the node list.
92+ */
93+static struct makenode *add_target(const char *name)
94+{
95+ struct makenode *__restrict node;
96+ struct makenode *prev, *t;
97+
98+ node = lookup_target(name);
99+ if (node)
100+ return node;
101+ if (posix_memalign((void*)&node, sizeof(void*), alignof(struct makenode)+strsize(name)) < 0) {
102+ fprintf(stderr, "Can't malloc: %s\n", strerror(errno));
103+ exit(1);
104+ }
105+ memset(node, 0, alignof(struct makenode)+strsize(name));
106+ node->name = ((char*)node)+alignof(struct makenode);
107+ strcpy(node->name, name);
108+
109+ /* append to the list in alphabetical order */
110+ prev = NULL;
111+ for (t = tree_list; t; prev = t, t = t->next)
112+ if (strcmp(node->name, t->name) < 0)
113+ break;
114+ if (prev)
115+ prev->next = node;
116+ else
117+ tree_list = node;
118+ node->next = t;
119+ tree_entries++;
120+ return node;
121+}
122+
123+/*
124+ * Set and propagate importance of a node to all depencies of this node
125+ */
126+static void add_importance(struct makenode *node, int importance)
127+{
128+ struct makelist *s = node->depend;
129+
130+ node->importance += importance;
131+ for (s = node->depend; s; s = s->next)
132+ add_importance(s->node, importance);
133+}
134+
135+/*
136+ * create a dependecy/selection node
137+ */
138+static struct makelist *new_list(struct makenode *node, struct makelist *next)
139+{
140+ struct makelist *x;
141+
142+ x = xcalloc(1, sizeof(*x));
143+ x->node = node;
144+ x->next = next;
145+ return x;
146+}
147+
148+/*
149+ * check whether the given target would create an infinte loop
150+ */
151+static int loop;
152+static int check_loop(struct makenode *dep, struct makenode *src)
153+{
154+ struct makelist *s;
155+ for (s = dep->depend; s; s = s->next) {
156+ if (s->node == src) {
157+ fprintf(stderr, "loop exists %s in %s!\n", dep->name, src->name);
158+ return 1;
159+ }
160+ if (loop++ > 99999) {
161+ fprintf(stderr, "too many loops! (loop=%d, dep->name=%s, src->name=%s)\n",
162+ loop, dep->name, src->name);
163+ return 1;
164+ }
165+ if (check_loop(s->node, src))
166+ return 1;
167+ }
168+ return 0;
169+}
170+
171+/*
172+ * add to the dependecy and selection lists
173+ */
174+static void add_depend(struct makenode *node, const char *dst)
175+{
176+ struct makenode *dep;
177+
178+ dep = add_target(dst);
179+ loop = 0;
180+ if (check_loop(dep, node))
181+ return;
182+ dep->select = new_list(node, dep->select);
183+ dep->num_sels++;
184+ node->depend = new_list(dep, node->depend);
185+ node->num_deps++;
186+}
187+
188+/*
189+ * mark the selected service as an interactive task
190+ * that should run solely
191+ */
192+static void mark_interactive(const char *name)
193+{
194+ struct makenode *node = lookup_target(name);
195+ if (node)
196+ node->interactive = 1;
197+}
198+
199+
200+#define DELIMITER " \t\r\n"
201+
202+/*
203+ * parse (pseudo) makefile
204+ *
205+ * it may have only the following form:
206+ *
207+ * TARGETS = xxx ...
208+ * INTERACTIVE = yyy ...
209+ * aaa:
210+ * bbb: xxx ddd ...
211+ *
212+ * other lines are ignored.
213+ */
214+void parse_makefile(const char *path)
215+{
216+ FILE *fp;
217+ char buf[LINE_MAX]; /* FIXME: is this enough big? */
218+ char *s, *strp, *p;
219+ struct makenode *node;
220+
221+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
222+ int fd;
223+
224+ if (getuid() == (uid_t)0)
225+ o_flags |= O_NOATIME;
226+ if ((fd = open(path, o_flags)) < 0) {
227+ fprintf(stderr, "Can't open %s: %s\n", path, strerror(errno));
228+ exit(1);
229+ }
230+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
231+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
232+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
233+
234+ if ((fp = fdopen(fd, "r")) == NULL)
235+#else
236+ if ((fp = fopen(path, "r")) == NULL)
237+#endif
238+ {
239+ fprintf(stderr, "Can't open %s: %s\n", path, strerror(errno));
240+ exit(1);
241+ }
242+
243+ while (fgets(buf, sizeof(buf), fp)) {
244+ for (s = buf; *s && isspace(*s); s++)
245+ ;
246+ if (! *s || *s == '#')
247+ continue;
248+ if (! strncmp(s, "TARGETS =", 9)) {
249+ s += 9;
250+ strp = s;
251+ while ((s = strsep(&strp, DELIMITER))) {
252+ if (! *s)
253+ continue;
254+ add_target(s);
255+ }
256+ } else if (! strncmp(s, "INTERACTIVE =", 13)) {
257+ s += 13;
258+ strp = s;
259+ while ((s = strsep(&strp, DELIMITER))) {
260+ if (! *s)
261+ continue;
262+ mark_interactive(s);
263+ }
264+ } else {
265+ p = strchr(s, ':');
266+ if (! p)
267+ continue;
268+ *p = 0;
269+ node = add_target(s);
270+ strp = p + 1;
271+ while ((s = strsep(&strp, DELIMITER))) {
272+ if (! *s)
273+ continue;
274+ add_depend(node, s);
275+ }
276+ }
277+ }
278+
279+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
280+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
281+#endif
282+
283+ fclose(fp);
284+
285+ for (node = tree_list; node; node = node->next) {
286+ int importance = 0;
287+
288+ if (! strcmp(node->name, "xdm")
289+ || ! strncmp(node->name, "gdm", 3)
290+ || ! strncmp(node->name, "kdm", 3)
291+ || ! strcmp(node->name, "boot.udev")
292+ || ! strcmp(node->name, "udev"))
293+ importance = 100;
294+
295+ if (! strcmp(node->name, "sshd"))
296+ importance = 2000;
297+
298+ if (! strncmp(node->name, "early", 5))
299+ importance = 8000;
300+
301+ if (importance)
302+ add_importance(node, importance);
303+ }
304+}
305+
306+/*
307+ * filter out the list targets
308+ */
309+
310+static int filter_prefix;
311+static int dirfilter(const struct dirent *d)
312+{
313+ return *d->d_name == filter_prefix &&
314+ strlen(d->d_name) >= 4; /* to be sure */
315+}
316+
317+static void filter_files(const char *dir, int prefix, int inverse)
318+{
319+ char path[64];
320+ int i, ndirs;
321+ static struct dirent **dirlist;
322+ struct makenode *t, *next;
323+
324+ filter_prefix = prefix;
325+#ifdef SUSE /* SuSE */
326+ snprintf(path, sizeof(path), "/etc/init.d/%s.d", dir);
327+#else /* Debian */
328+ snprintf(path, sizeof(path), "/etc/%s.d", dir);
329+#endif
330+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
331+ if ((i = open(path, o_flags|O_DIRECTORY|O_LARGEFILE)) >= 0) {
332+ (void)posix_fadvise(i, 0, 0, POSIX_FADV_SEQUENTIAL);
333+ (void)posix_fadvise(i, 0, 0, POSIX_FADV_NOREUSE);
334+ }
335+#endif
336+ ndirs = scandir(path, &dirlist, dirfilter, alphasort);
337+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
338+ if (i >= 0) {
339+ (void)posix_fadvise(i, 0, 0, POSIX_FADV_DONTNEED);
340+ close(i);
341+ }
342+#endif
343+ /* mark all matching nodes */
344+ if (ndirs >= 0) {
345+ for (i = 0; i < ndirs; i++) {
346+ t = lookup_target(dirlist[i]->d_name + 3);
347+ if (t) {
348+ t->status = 1;
349+ t->filter_prefix = filter_prefix;
350+ if (asprintf(&t->arg0, "%s/%s", path, dirlist[i]->d_name) < 0)
351+ t->arg0 = (char*)0;
352+ }
353+ free(dirlist[i]);
354+ }
355+ free(dirlist);
356+ }
357+ /* deselect non-matching nodes */
358+ for (t = tree_list; t; t = next) {
359+ next = t->next;
360+ if ((! t->status && ! inverse) || (t->status && inverse)) {
361+ /* remove from the list */
362+ struct makelist *x, *nx;
363+ struct makenode *p;
364+ for (x = t->select; x; x = nx) {
365+ nx = x->next;
366+ x->node->num_deps--;
367+ free(x);
368+ }
369+ for (x = t->depend; x; x = nx) {
370+ nx = x->next;
371+ x->node->num_sels--;
372+ free(x);
373+ }
374+ if (t == tree_list)
375+ tree_list = next;
376+ else {
377+ for (p = tree_list; p->next != t; p = p->next)
378+ ;
379+ p->next = next;
380+ }
381+ /* don't free the node instance itself - it may be selected
382+ * by others
383+ */
384+ tree_entries--;
385+ continue;
386+ }
387+ t->status = 0;
388+ }
389+}
390+
391+/*
392+ * mark the unnecessary services as finished.
393+ *
394+ * action is either boot, start or stop.
395+ * prev and run are the previous and the next runlevel.
396+ */
397+void check_run_files(const char *action, const char *prev, const char *run)
398+{
399+ char buf[4] = "rc0";
400+ if (! strcmp(action, "boot")) {
401+#ifdef SUSE /* SuSE */
402+ filter_files("boot", 'S', 0);
403+ } else if (! strcmp(action, "halt")) {
404+ filter_files("boot", 'K', 0);
405+ } else if (! strcmp(action, "start")) {
406+ buf[2] = *prev;
407+ filter_files(buf, 'K', 1);
408+ buf[2] = *run;
409+ filter_files(buf, 'S', 0);
410+ } else {
411+ buf[2] = *prev;
412+ filter_files(buf, 'K', 0);
413+ buf[2] = *run;
414+ filter_files(buf, 'S', 1);
415+#else /* Debian */
416+ filter_files("rcS", 'S', 0);
417+ } else if (! strcmp(action, "start")) {
418+ buf[2] = *prev;
419+ filter_files(buf, 'S', 1);
420+ buf[2] = *run;
421+ filter_files(buf, 'S', 0);
422+ } else {
423+ buf[2] = *prev;
424+ filter_files(buf, 'K', 1);
425+ buf[2] = *run;
426+ filter_files(buf, 'K', 0);
427+#endif
428+ }
429+}
430+
431+#ifdef __linux__
432+/*
433+ * mark upstart services as finished.
434+ *
435+ * action is either boot, start or stop.
436+ */
437+int check_upstart_jobs(const char *action, const struct makenode **nodevec)
438+{
439+ struct makenode *t;
440+ int count = 0;
441+
442+ if (!init_is_upstart())
443+ return 0;
444+
445+ for (t = tree_list; t; t = t->next)
446+ {
447+ char path[131]; /* three bytes longer than the max allowed init script name... */
448+ struct stat job;
449+
450+ snprintf(path, sizeof(path), "/etc/init/%s.conf", t->name);
451+ if (!stat(path,&job)) {
452+ int ret;
453+ char *command;
454+
455+ t->upstart = 1;
456+ /* Upstart jobs are never interactive in this sense */
457+ t->interactive = 0;
458+ if (!strcmp(action,"start") || !strcmp(action,"boot"))
459+ {
460+ asprintf(&command,
461+ "/sbin/initctl status %s | grep -q start/running",
462+ t->name);
463+ } else {
464+ asprintf(&command,
465+ "/sbin/initctl status %s | grep -q stop/waiting",
466+ t->name);
467+ }
468+ ret = system(command);
469+ if (WEXITSTATUS(ret) == 0) {
470+ nodevec[count] = t;
471+ finish_task(t);
472+ count++;
473+ }
474+ free(command);
475+ }
476+ }
477+ return count;
478+}
479+
480+/*
481+ * return true if PID 1 is upstart, false otherwise.
482+ */
483+boolean init_is_upstart(void) {
484+ static int is_upstart = -1;
485+ int fd;
486+ struct sockaddr_un saddr;
487+ socklen_t addrlen;
488+ struct ucred ucred;
489+ socklen_t slen;
490+
491+ if (is_upstart != -1)
492+ return is_upstart;
493+
494+ fd = socket(AF_LOCAL, SOCK_STREAM, 0);
495+ /* Weird, but we'll just have to assume no upstart. */
496+ if (fd < 0)
497+ goto fail;
498+
499+ saddr.sun_family = AF_LOCAL;
500+ strcpy(saddr.sun_path, DBUS_ADDRESS_UPSTART);
501+ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
502+
503+ /* translate leading '@' to abstract namespace */
504+ if (saddr.sun_path[0] == '@')
505+ saddr.sun_path[0] = '\0';
506+
507+ if (connect(fd, (struct sockaddr *)&saddr, addrlen) < 0)
508+ goto fail;
509+
510+ /* Make sure it's really upstart and not something lying to us! */
511+ slen = sizeof(ucred);
512+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0)
513+ goto fail;
514+
515+ close(fd);
516+ if (ucred.uid == 0)
517+ is_upstart = 1;
518+ else
519+ is_upstart = 0;
520+
521+ return is_upstart;
522+
523+fail:
524+ if (fd >= 0)
525+ close(fd);
526+ is_upstart = 0;
527+ return is_upstart;
528+}
529+#endif
530+
531+/*
532+ * call blogd
533+ */
534+#ifndef USE_BLOGD
535+# define bootlog(arg...)
536+# define closeblog()
537+#endif
538+
539+/*
540+ * pick up the next running task
541+ * return NULL if not found.
542+ */
543+struct makenode *pickup_task(void)
544+{
545+ struct makenode *node, *best = (struct makenode*)0;
546+
547+ for (node = tree_list; node; node = node->next) {
548+ if (node->status != T_READY)
549+ continue;
550+ if (node->num_deps > 0)
551+ continue;
552+ if (!best || (node->importance > best->importance))
553+ best = node;
554+ }
555+ if (best) {
556+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
557+ char path[128];
558+ int fd;
559+ snprintf(path, sizeof(path), "/etc/init.d/%s", best->name);
560+ if ((fd = open(path, o_flags|O_DIRECT)) >= 0) {
561+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
562+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
563+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
564+ close(fd);
565+ }
566+#endif
567+ bootlog(B_NOTICE, "service %s %s", best->name, (best->filter_prefix == 'K') ? "stop" : "start");
568+ best->status = T_RUNNING;
569+ }
570+ return best;
571+}
572+
573+/*
574+ * finish the running task
575+ */
576+void finish_task(struct makenode *node)
577+{
578+ struct makelist *n;
579+
580+ if (! node)
581+ return;
582+ /* Ignore any further upstart signals for this job */
583+ node->upstart = 0;
584+ for (n = node->select; n; n = n->next)
585+ n->node->num_deps--;
586+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
587+ {
588+ char path[128];
589+ int fd;
590+ snprintf(path, sizeof(path), "/etc/init.d/%s", node->name);
591+ if ((fd = open(path, o_flags|O_DIRECT)) >= 0) {
592+ (void)posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
593+ close(fd);
594+ }
595+ }
596+#endif
597+ node->status = T_FINISHED;
598+ bootlog(B_NOTICE, "service %s done", node->name);
599+}
600+
601+
602+/*
603+ * Print out the status that bash can run eval.
604+ * The following things will be printed:
605+ * failed services, skipped services and the current progress value.
606+ */
607+void print_run_result(int *resvec, struct makenode **nodevec, const char *action)
608+{
609+ int i, r, stop = (! strcmp(action, "stop"));
610+
611+ printf("failed_service=\"");
612+ i = r = 0;
613+ for (i = 0; i < tree_entries; i++) {
614+#if DEBUG
615+ if (resvec[i] == 255) {
616+ fprintf(stderr, "ERROR: forgotten process??\n");
617+ exit(1);
618+ }
619+#endif
620+ if (resvec[i] >= 1 && resvec[i] <= 4) {
621+ if (r)
622+ printf(" ");
623+ printf("%s", nodevec[i]->name);
624+ r++;
625+ } else if (!stop && resvec[i] == 7) {
626+ if (r)
627+ printf(" ");
628+ printf("%s", nodevec[i]->name);
629+ r++;
630+ }
631+ }
632+ printf("\"\n");
633+ printf("skipped_service_not_installed=\"");
634+ i = r = 0;
635+ for (i = 0; i < tree_entries; i++) {
636+ if (resvec[i] == 5) {
637+ if (r)
638+ printf(" ");
639+ printf("%s", nodevec[i]->name);
640+ r++;
641+ }
642+ }
643+ printf("\"\n");
644+ printf("skipped_service_not_configured=\"");
645+ i = r = 0;
646+ for (i = 0; i < tree_entries; i++) {
647+ if (resvec[i] == 6) {
648+ if (r)
649+ printf(" ");
650+ printf("%s", nodevec[i]->name);
651+ r++;
652+ }
653+ }
654+ printf("\"\n");
655+}
656+
657+#if DEBUG
658+void dump_status(void)
659+{
660+ struct makenode *node;
661+
662+ for (node = tree_list; node; node = node->next)
663+ fprintf(stderr, "XXX %s: status = %d, dep = %d, int = %d, imp = %d\n",
664+ node->name, node->status, node->num_deps, node->interactive, node->importance);
665+}
666+#endif
667+
668+#ifdef TEST
669+void *xcalloc(size_t nmemb, size_t size)
670+{
671+ void *r;
672+ if ((r = (void *)calloc(nmemb, size)) == 0) {
673+ fprintf(stderr, "calloc: out of memory\n");
674+ exit(1);
675+ }
676+ return r;
677+}
678+
679+int main(int argc, char **argv)
680+{
681+ struct makenode *nodevec;
682+ char makefile[64];
683+
684+ if (argc != 4) {
685+ fprintf(stderr, "usage: makeboot <action> [<prev> <run>]\n");
686+ goto out;
687+ }
688+
689+ snprintf(makefile, sizeof(makefile), "depend.%s", argv[1]);
690+ parse_makefile(makefile);
691+
692+ fprintf(stderr, "check_run_files(%s, %s, %s)\n", argv[1], argv[2],
693+ argv[3]);
694+ check_run_files(argv[1], argv[2], argv[3]);
695+out:
696+ while ((nodevec = pickup_task())) {
697+ fprintf(stdout, "%s (%s)\n", nodevec->name, nodevec->arg0);
698+ finish_task(nodevec);
699+ }
700+
701+ return 0;
702+}
703+#endif
704
705=== modified file 'debian/changelog'
706--- debian/changelog 2014-05-30 11:44:23 +0000
707+++ debian/changelog 2014-06-05 13:25:18 +0000
708@@ -1,3 +1,4 @@
709+<<<<<<< TREE
710 sysvinit (2.88dsf-41ubuntu16) utopic; urgency=medium
711
712 * Move sourcing of lsb/init-functions above the sourcing of helpers which we
713@@ -6,6 +7,15 @@
714
715 -- Martin Pitt <martin.pitt@ubuntu.com> Fri, 30 May 2014 11:44:23 +0200
716
717+=======
718+sysvinit (2.88dsf-41ubuntu16) UNRELEASED; urgency=medium
719+
720+ * Add 'task' knowledge to startpar.
721+ * Re-enable startpar.
722+
723+ -- Dimitri John Ledkov <xnox@ubuntu.com> Fri, 30 May 2014 08:24:42 +0100
724+
725+>>>>>>> MERGE-SOURCE
726 sysvinit (2.88dsf-41ubuntu15) utopic; urgency=medium
727
728 * Disable startpar. It wreaks havoc with "task" upstart jobs as init.d
729
730=== modified file 'debian/patches/series'
731--- debian/patches/series 2013-05-17 06:03:10 +0000
732+++ debian/patches/series 2014-06-05 13:25:18 +0000
733@@ -23,3 +23,4 @@
734 93_run_initctl.patch
735 94_kfreebsd_xterm.patch
736 upstart_support.patch
737+startpar-upstart-tasks.patch
738
739=== added file 'debian/patches/startpar-upstart-tasks.patch'
740--- debian/patches/startpar-upstart-tasks.patch 1970-01-01 00:00:00 +0000
741+++ debian/patches/startpar-upstart-tasks.patch 2014-06-05 13:25:18 +0000
742@@ -0,0 +1,28 @@
743+Description: Add 'task' knowledge to startpar.
744+Author: Dimitri John Ledkov <xnox@ubuntu.com>
745+
746+--- a/startpar/makeboot.c
747++++ b/startpar/makeboot.c
748+@@ -445,12 +445,21 @@
749+ asprintf(&command,
750+ "/sbin/initctl status %s | grep -q start/running",
751+ t->name);
752++ ret = system(command);
753++ if (WEXITSTATUS(ret) != 0) {
754++ free(command);
755++ asprintf(&command,
756++ "grep -q '^[ \t]*task[ \t]*$' %s",
757++ path);
758++ ret = system(command);
759++ }
760++
761+ } else {
762+ asprintf(&command,
763+ "/sbin/initctl status %s | grep -q stop/waiting",
764+ t->name);
765++ ret = system(command);
766+ }
767+- ret = system(command);
768+ if (WEXITSTATUS(ret) == 0) {
769+ nodevec[count] = t;
770+ finish_task(t);
771
772=== modified file 'debian/src/sysv-rc/etc/init.d/rc'
773--- debian/src/sysv-rc/etc/init.d/rc 2014-05-29 10:15:57 +0000
774+++ debian/src/sysv-rc/etc/init.d/rc 2014-06-05 13:25:18 +0000
775@@ -69,9 +69,7 @@
776 # insserv package to be enabled. Boot concurrency also requires
777 # startpar to be installed.
778 #
779-#CONCURRENCY=makefile
780-# disable startpar, incompatible with "task" upstart jobs
781-CONCURRENCY=none
782+CONCURRENCY=makefile
783 test -s /etc/init.d/.depend.boot || CONCURRENCY="none"
784 test -s /etc/init.d/.depend.start || CONCURRENCY="none"
785 test -s /etc/init.d/.depend.stop || CONCURRENCY="none"
786
787=== modified file 'startpar/makeboot.c'
788--- startpar/makeboot.c 2012-06-27 23:00:45 +0000
789+++ startpar/makeboot.c 2014-06-05 13:25:18 +0000
790@@ -445,12 +445,21 @@
791 asprintf(&command,
792 "/sbin/initctl status %s | grep -q start/running",
793 t->name);
794+ ret = system(command);
795+ if (WEXITSTATUS(ret) != 0) {
796+ free(command);
797+ asprintf(&command,
798+ "grep -q '^[ \t]*task[ \t]*$' %s",
799+ path);
800+ ret = system(command);
801+ }
802+
803 } else {
804 asprintf(&command,
805 "/sbin/initctl status %s | grep -q stop/waiting",
806 t->name);
807+ ret = system(command);
808 }
809- ret = system(command);
810 if (WEXITSTATUS(ret) == 0) {
811 nodevec[count] = t;
812 finish_task(t);

Subscribers

People subscribed via source and target branches