unix/dualinit

src/exec/dualinit.c in master
Repositories | Summary | Log | Files | LICENSE

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", &section_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 = &sections[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, &section->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}