Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/kinit.c
Parent Directory | Revision Log
Revision 1122 -
(hide annotations)
(download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 6302 byte(s)
Wed Aug 18 21:11:40 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 6302 byte(s)
-updated to klibc-1.5.19
1 | niro | 532 | #include <sys/mount.h> |
2 | #include <sys/stat.h> | ||
3 | #include <errno.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <alloca.h> | ||
9 | #include <limits.h> | ||
10 | #include <ctype.h> | ||
11 | #include <termios.h> | ||
12 | |||
13 | #include "kinit.h" | ||
14 | #include "ipconfig.h" | ||
15 | #include "run-init.h" | ||
16 | #include "resume.h" | ||
17 | |||
18 | const char *progname = "kinit"; | ||
19 | int mnt_procfs; | ||
20 | int mnt_sysfs; | ||
21 | |||
22 | niro | 1122 | #ifdef DEBUG |
23 | niro | 532 | void dump_args(int argc, char *argv[]) |
24 | { | ||
25 | int i; | ||
26 | |||
27 | printf(" argc == %d\n", argc); | ||
28 | |||
29 | for (i = 0; i < argc; i++) { | ||
30 | printf(" argv[%d]: \"%s\"\n", i, argv[i]); | ||
31 | } | ||
32 | |||
33 | if (argv[argc] != NULL) { | ||
34 | printf(" argv[%d]: \"%s\" (SHOULD BE NULL)\n", | ||
35 | niro | 1122 | argc, argv[argc]); |
36 | niro | 532 | } |
37 | } | ||
38 | niro | 1122 | #endif /* DEBUG */ |
39 | niro | 532 | |
40 | |||
41 | static int do_ipconfig(int argc, char *argv[]) | ||
42 | { | ||
43 | int i, a = 0; | ||
44 | char **args = alloca((argc + 3) * sizeof(char *)); | ||
45 | |||
46 | if (!args) | ||
47 | return -1; | ||
48 | |||
49 | args[a++] = (char *)"IP-Config"; | ||
50 | args[a++] = (char *)"-i"; | ||
51 | args[a++] = (char *)"Linux kinit"; | ||
52 | |||
53 | niro | 1122 | dprintf("Running ipconfig\n"); |
54 | niro | 532 | |
55 | for (i = 1; i < argc; i++) { | ||
56 | if (strncmp(argv[i], "ip=", 3) == 0 || | ||
57 | strncmp(argv[i], "nfsaddrs=", 9) == 0) { | ||
58 | args[a++] = argv[i]; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | if (a > 1) { | ||
63 | args[a] = NULL; | ||
64 | dump_args(a, args); | ||
65 | return ipconfig_main(a, args); | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int split_cmdline(int cmdcmax, char *cmdv[], char *argv0, | ||
72 | char *cmdlines[], char *args[]) | ||
73 | { | ||
74 | int was_space; | ||
75 | char c, *p; | ||
76 | int vmax = cmdcmax; | ||
77 | int v = 1; | ||
78 | int space; | ||
79 | |||
80 | if (cmdv) | ||
81 | cmdv[0] = argv0; | ||
82 | |||
83 | /* First, add the parsable command lines */ | ||
84 | |||
85 | while (*cmdlines) { | ||
86 | p = *cmdlines++; | ||
87 | was_space = 1; | ||
88 | while (v < vmax) { | ||
89 | c = *p; | ||
90 | space = isspace(c); | ||
91 | if ((space || !c) && !was_space) { | ||
92 | if (cmdv) | ||
93 | *p = '\0'; | ||
94 | v++; | ||
95 | } else if (was_space) { | ||
96 | if (cmdv) | ||
97 | cmdv[v] = p; | ||
98 | } | ||
99 | |||
100 | if (!c) | ||
101 | break; | ||
102 | |||
103 | was_space = space; | ||
104 | p++; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | /* Second, add the explicit command line arguments */ | ||
109 | |||
110 | while (*args && v < vmax) { | ||
111 | if (cmdv) | ||
112 | cmdv[v] = *args; | ||
113 | v++; | ||
114 | args++; | ||
115 | } | ||
116 | |||
117 | if (cmdv) | ||
118 | cmdv[v] = NULL; | ||
119 | |||
120 | return v; | ||
121 | } | ||
122 | |||
123 | static int mount_sys_fs(const char *check, const char *fsname, | ||
124 | const char *fstype) | ||
125 | { | ||
126 | struct stat st; | ||
127 | |||
128 | if (stat(check, &st) == 0) { | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | mkdir(fsname, 0555); | ||
133 | |||
134 | if (mount("none", fsname, fstype, 0, NULL) == -1) { | ||
135 | fprintf(stderr, "%s: could not mount %s as %s\n", | ||
136 | progname, fsname, fstype); | ||
137 | return -1; | ||
138 | } | ||
139 | |||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | static void check_path(const char *path) | ||
144 | { | ||
145 | struct stat st; | ||
146 | |||
147 | if (stat(path, &st) == -1) { | ||
148 | if (errno != ENOENT) { | ||
149 | perror("stat"); | ||
150 | exit(1); | ||
151 | } | ||
152 | if (mkdir(path, 0755) == -1) { | ||
153 | perror("mkdir"); | ||
154 | exit(1); | ||
155 | } | ||
156 | } else if (!S_ISDIR(st.st_mode)) { | ||
157 | fprintf(stderr, "%s: '%s' not a directory\n", progname, path); | ||
158 | exit(1); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static const char *find_init(const char *root, const char *user) | ||
163 | { | ||
164 | const char *init_paths[] = { | ||
165 | "/sbin/init", "/bin/init", "/etc/init", "/bin/sh", NULL | ||
166 | }; | ||
167 | const char **p; | ||
168 | const char *path; | ||
169 | |||
170 | if (chdir(root)) { | ||
171 | perror("chdir"); | ||
172 | exit(1); | ||
173 | } | ||
174 | |||
175 | if (user) | ||
176 | niro | 1122 | dprintf("Checking for init: %s\n", user); |
177 | niro | 532 | |
178 | if (user && user[0] == '/' && !access(user+1, X_OK)) { | ||
179 | path = user; | ||
180 | } else { | ||
181 | for (p = init_paths; *p; p++) { | ||
182 | niro | 1122 | dprintf("Checking for init: %s\n", *p); |
183 | niro | 532 | if (!access(*p+1, X_OK)) |
184 | break; | ||
185 | } | ||
186 | path = *p; | ||
187 | } | ||
188 | chdir("/"); | ||
189 | return path; | ||
190 | } | ||
191 | |||
192 | /* This is the argc and argv we pass to init */ | ||
193 | const char *init_path; | ||
194 | int init_argc; | ||
195 | char **init_argv; | ||
196 | |||
197 | extern ssize_t readfile(const char *, char **); | ||
198 | |||
199 | int main(int argc, char *argv[]) | ||
200 | { | ||
201 | char **cmdv, **args; | ||
202 | char *cmdlines[3]; | ||
203 | int i; | ||
204 | const char *errmsg; | ||
205 | int ret = 0; | ||
206 | int cmdc; | ||
207 | int fd; | ||
208 | struct timeval now; | ||
209 | |||
210 | gettimeofday(&now, NULL); | ||
211 | srand48(now.tv_usec ^ (now.tv_sec << 24)); | ||
212 | |||
213 | /* Default parameters for anything init-like we execute */ | ||
214 | init_argc = argc; | ||
215 | init_argv = alloca((argc+1)*sizeof(char *)); | ||
216 | memcpy(init_argv, argv, (argc+1)*sizeof(char *)); | ||
217 | |||
218 | if ((fd = open("/dev/console", O_RDWR)) != -1) { | ||
219 | dup2(fd, STDIN_FILENO); | ||
220 | dup2(fd, STDOUT_FILENO); | ||
221 | dup2(fd, STDERR_FILENO); | ||
222 | |||
223 | if (fd > STDERR_FILENO) { | ||
224 | close(fd); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | mnt_procfs = mount_sys_fs("/proc/cmdline", "/proc", "proc") >= 0; | ||
229 | if (!mnt_procfs) { | ||
230 | ret = 1; | ||
231 | goto bail; | ||
232 | } | ||
233 | |||
234 | mnt_sysfs = mount_sys_fs("/sys/bus", "/sys", "sysfs") >= 0; | ||
235 | if (!mnt_sysfs) { | ||
236 | ret = 1; | ||
237 | goto bail; | ||
238 | } | ||
239 | |||
240 | /* Construct the effective kernel command line. The | ||
241 | effective kernel command line consists of /arch.cmd, if | ||
242 | it exists, /proc/cmdline, plus any arguments after an -- | ||
243 | argument on the proper command line, in that order. */ | ||
244 | |||
245 | ret = readfile("/arch.cmd", &cmdlines[0]); | ||
246 | if (ret < 0) | ||
247 | cmdlines[0] = ""; | ||
248 | |||
249 | ret = readfile("/proc/cmdline", &cmdlines[1]); | ||
250 | if (ret < 0) { | ||
251 | fprintf(stderr, "%s: cannot read /proc/cmdline\n", progname); | ||
252 | ret = 1; | ||
253 | goto bail; | ||
254 | } | ||
255 | |||
256 | cmdlines[2] = NULL; | ||
257 | |||
258 | /* Find an -- argument, and if so append to the command line */ | ||
259 | for (i = 1; i < argc; i++) { | ||
260 | if (!strcmp(argv[i], "--")) { | ||
261 | i++; | ||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | args = &argv[i]; /* Points either to first argument past -- or | ||
266 | to the final NULL */ | ||
267 | |||
268 | /* Count the number of arguments */ | ||
269 | cmdc = split_cmdline(INT_MAX, NULL, argv[0], cmdlines, args); | ||
270 | |||
271 | /* Actually generate the cmdline array */ | ||
272 | cmdv = (char **)alloca((cmdc+1)*sizeof(char *)); | ||
273 | if (split_cmdline(cmdc, cmdv, argv[0], cmdlines, args) != cmdc) { | ||
274 | ret = 1; | ||
275 | goto bail; | ||
276 | } | ||
277 | |||
278 | /* Debugging... */ | ||
279 | dump_args(cmdc, cmdv); | ||
280 | |||
281 | /* Resume from suspend-to-disk, if appropriate */ | ||
282 | /* If successful, does not return */ | ||
283 | do_resume(cmdc, cmdv); | ||
284 | |||
285 | /* Initialize networking, if applicable */ | ||
286 | do_ipconfig(cmdc, cmdv); | ||
287 | |||
288 | check_path("/root"); | ||
289 | do_mounts(cmdc, cmdv); | ||
290 | |||
291 | if (mnt_procfs) { | ||
292 | umount2("/proc", 0); | ||
293 | mnt_procfs = 0; | ||
294 | } | ||
295 | |||
296 | if (mnt_sysfs) { | ||
297 | umount2("/sys", 0); | ||
298 | mnt_sysfs = 0; | ||
299 | } | ||
300 | |||
301 | init_path = find_init("/root", get_arg(cmdc, cmdv, "init=")); | ||
302 | if (!init_path) { | ||
303 | fprintf(stderr, "%s: init not found!\n", progname); | ||
304 | ret = 2; | ||
305 | goto bail; | ||
306 | } | ||
307 | |||
308 | init_argv[0] = strrchr(init_path, '/') + 1; | ||
309 | |||
310 | errmsg = run_init("/root", "/dev/console", init_path, init_argv); | ||
311 | |||
312 | /* If run_init returned, something went bad */ | ||
313 | fprintf(stderr, "%s: %s: %s\n", progname, errmsg, strerror(errno)); | ||
314 | ret = 2; | ||
315 | goto bail; | ||
316 | |||
317 | bail: | ||
318 | if (mnt_procfs) | ||
319 | umount2("/proc", 0); | ||
320 | |||
321 | if (mnt_sysfs) | ||
322 | umount2("/sys", 0); | ||
323 | |||
324 | /* | ||
325 | * If we get here, something bad probably happened, and the kernel | ||
326 | * will most likely panic. Drain console output so the user can | ||
327 | * figure out what happened. | ||
328 | */ | ||
329 | tcdrain(2); | ||
330 | tcdrain(1); | ||
331 | |||
332 | return ret; | ||
333 | } |