The Pedigree Project 0.1
init/main.c
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <config.h>
21#include <ctype.h>
22#include <dirent.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <libgen.h>
26#include <limits.h>
27#include <signal.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#include <utmp.h>
34#include <utmpx.h>
35
36#include <pedigree/log.h>
37#include <sys/stat.h>
38#include <sys/time.h>
39#include <sys/wait.h>
40
41extern void pedigree_reboot();
42
43static int g_Running = 1;
44
45// SIGTERM handler - shutdown.
46static void sigterm(int sig) {
48 g_Running = 0;
49}
50
51static pid_t start(const char* proc) {
52 pid_t f = fork();
53 if (f == -1) {
54 int fork_errno = errno;
55 pedigree_log(LOG_ALERT, "init: fork failed for %s: errno=%d (%s)", proc, fork_errno,
56 strerror(fork_errno));
57 exit(fork_errno);
58 }
59 if (f == 0) {
60 pedigree_log(LOG_INFO, "init: starting %s...", proc);
61 execl(proc, proc, 0);
62 int exec_errno = errno;
63 pedigree_log(LOG_ALERT, "init: loading %s failed: errno=%d (%s)", proc, exec_errno,
64 strerror(exec_errno));
65 exit(exec_errno);
66 }
67 pedigree_log(LOG_INFO, "init: fork succeeded for %s: child=%d", proc, f);
68
69 // Avoid calling basename() on the given parameter, as basename is
70 // non-const.
71 char basename_buf[PATH_MAX];
72 strncpy(basename_buf, proc, PATH_MAX);
73
74 // Add a utmp entry.
75 setutxent();
76 struct utmpx init;
77 struct timeval tv;
78 memset(&init, 0, sizeof(init));
79 gettimeofday(&tv, NULL);
80 init.ut_type = INIT_PROCESS;
81 init.ut_pid = f;
82 init.ut_tv = tv;
83 strncpy(init.ut_id, basename(basename_buf), sizeof(init.ut_id));
84 pututxline(&init);
85 endutxent();
86
87 return f;
88}
89
90static void startAndWait(const char* proc) {
91 pid_t f = start(proc);
92 waitpid(f, 0, 0);
93}
94
95static void runScripts() {
96 struct dirent** namelist;
97
98 int count = scandir("/etc/init.d", &namelist, 0, alphasort);
99 if (count < 0) {
100 pedigree_log(LOG_CRIT, "could not scan /etc/init.d: %s", strerror(errno));
101 } else {
102 pedigree_log(LOG_INFO, "init: %d init script entries found", count);
103 for (int i = 0; i < count; ++i) {
104 char script[PATH_MAX];
105 snprintf(script, PATH_MAX, "/etc/init.d/%s", namelist[i]->d_name);
106
107 if (!strcmp(namelist[i]->d_name, ".") || !strcmp(namelist[i]->d_name, "..")) {
108 free(namelist[i]);
109 continue;
110 }
111
112 free(namelist[i]);
113
114 struct stat st;
115 int r = stat(script, &st);
116 if (r == 0) {
117 if (S_ISREG(st.st_mode) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
118 // OK - we can run this.
119 pedigree_log(LOG_INFO, "init: running %s", script);
120 startAndWait(script);
121 } else {
122 pedigree_log(LOG_INFO, "init: not running %s (not a file, or not executable)", script);
123 }
124 } else {
125 pedigree_log(LOG_INFO, "init: cannot stat %s (broken symlink?)", script);
126 }
127 }
128
129 free(namelist);
130 }
131}
132
133int main(int argc, char** argv) {
134 pedigree_log(LOG_INFO, "init: starting...");
135
136 // Make sure we have a utmp file.
137 int fd = open(UTMP_FILE, O_CREAT | O_RDWR, 0664);
138 if (fd >= 0)
139 close(fd);
140
141 // Set default umask to be inherited by all our children.
142 umask(0022);
143
144 // Set up utmp.
145 setutxent();
146
147 // Boot time (for uptime etc).
148 struct timeval tv;
149 gettimeofday(&tv, NULL);
150
151 struct utmpx boot;
152 memset(&boot, 0, sizeof(boot));
153 boot.ut_type = BOOT_TIME;
154 boot.ut_tv = tv;
155 pututxline(&boot);
156
157 // All done with utmp.
158 endutxent();
159
160 // Prepare signals.
161 signal(SIGTERM, sigterm);
162
163 if (HOSTED) {
164 // Reboot the system instead of starting up.
165 pedigree_log(LOG_INFO, "init: hosted build, triggering a reboot");
166 pedigree_reboot();
167 } else {
168 runScripts();
169 }
170
171 // Done, enter PID reaping loop.
172 pedigree_log(LOG_INFO, "init: complete!");
173 while (1) {
176 int status = 0;
177 pid_t changer = waitpid(-1, &status, g_Running == 0 ? WNOHANG : 0);
178 if (changer > 0) {
179 pedigree_log(LOG_INFO, "init: child %d exited with status %d", changer, WEXITSTATUS(status));
180 } else if (!g_Running) {
181 pedigree_log(LOG_INFO,
182 "init: no more children and have been asked to "
183 "terminate, terminating...");
184 break;
185 } else {
186 continue;
187 }
188
189 // Register the dead process now.
190 struct utmpx* p = 0;
191 setutxent();
192 do {
193 p = getutxent();
194 if (p && (p->ut_type == INIT_PROCESS && p->ut_pid == changer))
195 break;
196 } while (p);
197
198 if (!p) {
199 endutxent();
200 continue;
201 }
202
203 setutxent();
204 struct utmpx dead;
205 memset(&dead, 0, sizeof(dead));
206 gettimeofday(&tv, NULL);
207 dead.ut_type = DEAD_PROCESS;
208 dead.ut_pid = changer;
209 dead.ut_tv = tv;
210 strncpy(dead.ut_id, p->ut_id, sizeof(dead.ut_id));
211 pututxline(&dead);
212 endutxent();
213 }
214 return 0;
215}