4 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <libubox/uloop.h>
20 #include <libubox/runqueue.h>
26 #include <sys/types.h>
31 #include <libubox/ustream.h>
36 static struct runqueue q
, r
;
40 struct runqueue_process proc
;
41 struct timespec ts_start
;
46 static void pipe_cb(struct ustream
*s
, int bytes
)
48 struct initd
*initd
= container_of(s
, struct initd
, fd
.stream
);
53 str
= ustream_get_read_buf(s
, NULL
);
56 newline
= strchr(str
, '\n');
60 len
= newline
+ 1 - str
;
61 ULOG_NOTE("%s: %s", initd
->file
, str
);
62 #ifdef SHOW_BOOT_ON_CONSOLE
63 fprintf(stderr
, "%s: %s\n", initd
->file
, str
);
65 ustream_consume(s
, len
);
69 static void q_initd_run(struct runqueue
*q
, struct runqueue_task
*t
)
71 struct initd
*s
= container_of(t
, struct initd
, proc
.task
);
75 clock_gettime(CLOCK_MONOTONIC_RAW
, &s
->ts_start
);
76 DEBUG(2, "start %s %s \n", s
->file
, s
->param
);
77 if (pipe(pipefd
) == -1) {
78 ERROR("Failed to create pipe: %m\n");
88 fcntl(pipefd
[0], F_SETFD
, FD_CLOEXEC
);
89 s
->fd
.stream
.string_data
= true,
90 s
->fd
.stream
.notify_read
= pipe_cb
,
91 runqueue_process_add(q
, &s
->proc
, pid
);
92 ustream_fd_init(&s
->fd
, pipefd
[0]);
97 int devnull
= open("/dev/null", O_RDONLY
);
98 dup2(devnull
, STDIN_FILENO
);
99 dup2(pipefd
[1], STDOUT_FILENO
);
100 dup2(pipefd
[1], STDERR_FILENO
);
102 if (devnull
> STDERR_FILENO
)
105 execlp(s
->file
, s
->file
, s
->param
, NULL
);
109 static void q_initd_complete(struct runqueue
*q
, struct runqueue_task
*p
)
111 struct initd
*s
= container_of(p
, struct initd
, proc
.task
);
112 struct timespec ts_stop
, ts_res
;
114 clock_gettime(CLOCK_MONOTONIC_RAW
, &ts_stop
);
115 ts_res
.tv_sec
= ts_stop
.tv_sec
- s
->ts_start
.tv_sec
;
116 ts_res
.tv_nsec
= ts_stop
.tv_nsec
- s
->ts_start
.tv_nsec
;
117 if (ts_res
.tv_nsec
< 0) {
119 ts_res
.tv_nsec
+= 1000000000;
122 DEBUG(2, "stop %s %s - took %" PRId64
".%09" PRId64
"s\n", s
->file
, s
->param
, (int64_t)ts_res
.tv_sec
, (int64_t)ts_res
.tv_nsec
);
123 ustream_free(&s
->fd
.stream
);
128 static void add_initd(struct runqueue
*q
, char *file
, char *param
)
130 static const struct runqueue_task_type initd_type
= {
132 .cancel
= runqueue_process_cancel_cb
,
133 .kill
= runqueue_process_kill_cb
,
138 s
= calloc_a(sizeof(*s
), &f
, strlen(file
) + 1, &p
, strlen(param
) + 1);
140 ERROR("Out of memory in %s.\n", file
);
143 s
->proc
.task
.type
= &initd_type
;
144 s
->proc
.task
.complete
= q_initd_complete
;
145 if (!strcmp(param
, "stop") || !strcmp(param
, "shutdown")) {
146 s
->proc
.task
.run_timeout
= 15000;
147 s
->proc
.task
.cancel_timeout
= 10000;
151 strcpy(s
->param
, param
);
152 strcpy(s
->file
, file
);
153 runqueue_task_add(q
, &s
->proc
.task
, false);
156 static int _rc(struct runqueue
*q
, char *path
, const char *file
, char *pattern
, char *param
)
158 char *dir
= alloca(2 + strlen(path
) + strlen(file
) + strlen(pattern
));
163 ERROR("Out of memory in %s.\n", file
);
167 DEBUG(2, "running %s/%s%s %s\n", path
, file
, pattern
, param
);
168 sprintf(dir
, "%s/%s%s", path
, file
, pattern
);
169 if (glob(dir
, GLOB_NOESCAPE
| GLOB_MARK
, NULL
, &gl
)) {
170 DEBUG(2, "glob failed on %s\n", dir
);
174 for (j
= 0; j
< gl
.gl_pathc
; j
++)
175 add_initd(q
, gl
.gl_pathv
[j
], param
);
182 int rcS(char *pattern
, char *param
, void (*q_empty
)(struct runqueue
*))
185 q
.empty_cb
= q_empty
;
186 q
.max_running_tasks
= 1;
188 return _rc(&q
, "/etc/rc.d", pattern
, "*", param
);
191 int rc(const char *file
, char *param
)
193 return _rc(&r
, "/etc/init.d", file
, "", param
);
196 static void r_empty(struct runqueue
*q
)
201 static void __attribute__((constructor
)) rc_init() {
203 r
.empty_cb
= r_empty
;
204 r
.max_running_tasks
= 8;