Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/kinit.c

Parent Directory Parent Directory | Revision Log 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)
-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     }