dualinit.c (3341B) download
1#include "common.h"
2#include "config.h"
3#include "console.h"
4#include "default.h"
5
6#include <dirent.h>
7#include <errno.h>
8#include <fcntl.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/mount.h>
13#include <unistd.h>
14
15// mounts `mnt` relative to `root`
16static void mount_chroot(const char* root, const mount_t* mnt) {
17 static char dest[100];
18 strcpy(dest, root);
19 strcat(dest, mnt->target);
20
21 INFO("mounting %s -> %s", mnt->source, dest);
22 if (mnt->type != NULL)
23 printf(" (%s)", mnt->type);
24 if (mnt->options != NULL)
25 printf(" [%s]", mnt->options);
26
27 printf("\n");
28
29 if (mount(mnt->source, dest, mnt->type, mnt->flags, mnt->options) != 0) {
30 if (mnt->try) {
31 WARN("mounting %s to %s failed: %s\n", mnt->source, dest, strerror(errno));
32 } else {
33 PANIC("mounting %s to %s failed: %s\n", mnt->source, dest, strerror(errno));
34 }
35 }
36}
37
38int main() {
39 if (getpid() != 1) {
40 PANIC("must run as PID 1\n");
41 }
42
43 // initiates the console as it's not initiated if init-system
44 init_console();
45
46 // opens the config file (`fopen` is not working yet)
47 int config_file = open(DEFAULT_CONFIG, O_RDONLY | O_NONBLOCK);
48 if (config_file == -1) {
49 // if it can't be opened, die!
50 PANIC("cannot open %s: %s\n", DEFAULT_CONFIG, strerror(errno));
51 }
52
53 // parse the config
54 parse_error_t parse_code = config_parse(config_file, DEFAULT_CONFIG);
55 if (parse_code != 0) {
56 // if config can't be parse, die! (again lol)
57 PANIC("invalid config");
58 }
59 // and close the file as it's not needed anymore
60 close(config_file);
61
62 int section_index;
63 while (1) {
64 // politely asking for which init you want to load
65 printf("which init do you want to start?\n");
66 // listing the sections
67 for (int i = 0; i < section_size; i++) {
68 printf("[%d] %s at %s\n", i, sections[i].name, sections[i].root);
69 }
70
71 printf(": ");
72 fflush(stdout);
73
74 scanf("%d", §ion_index);
75 if (section_index >= 0 && section_index < section_size)
76 break;
77
78 // mmph, you didn't enter a valid number
79 WARN("your choice %d must be lower than %d\n\n", section_index, section_size);
80 }
81
82 section_t* section = §ions[section_index];
83 bool is_root = strcmp(section->root, "/") == 0;
84
85 // if the section is not `/` (as it should be), mount everything
86 if (!is_root) {
87 mount_t self_mount = {
88 .type = NULL,
89 .source = section->root,
90 .target = "/",
91 .options = NULL,
92 .flags = MS_BIND,
93 .try = false,
94 };
95
96 mount_chroot(section->root, &self_mount);
97
98 for (int i = 0; i < mount_size; i++) {
99 mount_chroot(section->root, &mounts[i]);
100 }
101 }
102
103 for (int i = 0; i < section->mount_size; i++) {
104 mount_chroot(section->root, §ion->mounts[i]);
105 }
106
107 if (!is_root) {
108 // if it's not '/', chroot into it
109 INFO("chrooting into %s\n", section->root);
110
111 if (chroot(section->root) == -1) {
112 PANIC("cannot chroot into %s: %s\n", section->root, strerror(errno));
113 }
114 }
115
116 // chdir '/', otherwise the init-system will have funny errors
117 if (chdir("/") == -1) {
118 PANIC("error: cannot chdir into '/': %s\n", strerror(errno));
119 }
120
121 // aaand finally entering `init`
122 char init[PATH_MAX] = DEFAULT_INIT;
123 if (section->init != NULL)
124 strcpy(init, section->init);
125
126 config_cleanup();
127
128 INFO("entering %s\n\n", init);
129
130 execlp(section->init, section->init, NULL);
131
132 PANIC("error: cannot execute %s: %s\n", section->init, strerror(errno));
133}