Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/kinit.c
Parent Directory | Revision Log
Revision 1122 -
(show annotations)
(download)
Wed Aug 18 21:11:40 2010 UTC (14 years, 1 month ago) by niro
File MIME type: text/plain
File size: 6302 byte(s)
Wed Aug 18 21:11:40 2010 UTC (14 years, 1 month ago) by niro
File MIME type: text/plain
File size: 6302 byte(s)
-updated to klibc-1.5.19
1 | #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 | #ifdef DEBUG |
23 | 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 | argc, argv[argc]); |
36 | } |
37 | } |
38 | #endif /* DEBUG */ |
39 | |
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 | dprintf("Running ipconfig\n"); |
54 | |
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 | dprintf("Checking for init: %s\n", user); |
177 | |
178 | if (user && user[0] == '/' && !access(user+1, X_OK)) { |
179 | path = user; |
180 | } else { |
181 | for (p = init_paths; *p; p++) { |
182 | dprintf("Checking for init: %s\n", *p); |
183 | 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 | } |