Enable mount/umount, add rc/init programs

This commit is contained in:
Mark
2020-07-07 22:56:11 +03:00
parent 9a70b3fc95
commit e18a7e329d
11 changed files with 327 additions and 282 deletions
+1 -5
View File
@@ -5,7 +5,6 @@ KERNEL_HDRS?=kernel-hdr
CC=x86_64-elf-yggdrasil-gcc
DIRS=$(STAGE)
STAGE_BIN=$(STAGE)/init
all: mkdirs $(O)/initrd.img
@@ -15,7 +14,7 @@ clean:
make -C $(dir) clean; \
)
$(O)/initrd.img: mkstage-etc $(STAGE_BIN) mkstage-progs
$(O)/initrd.img: mkstage-etc mkstage-progs
cd $(STAGE) && tar czf $(abspath $@) *
mkdirs:
@@ -33,6 +32,3 @@ mkstage-progs:
$(foreach dir,$(wildcard progs/*), \
CC=$(CC) DESTDIR=$(abspath $(STAGE)) make -C $(dir) install || exit 1; \
)
$(STAGE)/init: init.c
$(CC) -o $@ $(usr_CFLAGS) $(usr_LDFLAGS) init.c
+2
View File
@@ -1,3 +1,5 @@
# Runlevels: 1
init:1:wait:/sbin/rc default
l0:1:once:/bin/login
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
echo Mounting /dev
mount -t devfs /dev
echo Mounting /sys
mount -t sysfs /sys
-75
View File
@@ -1,75 +0,0 @@
#include <ygg/netctl.h>
// TODO:
//#include <sys/mount.h>
#include <sys/wait.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
// TODO
int mount(const char *source, const char *target,
const char *fs, unsigned long flags,
void *data);
// The only thing init does now
static int start_login(void) {
const char *login = "/bin/login";
const char *const argp[] = {
login, NULL
};
int pid = fork();
int res;
switch (pid) {
case 0:
exit(execve(login, (char *const *) argp, environ));
case -1:
fprintf(stderr, "Init program failed\n");
return -1;
default:
waitpid(pid, &res, 0);
return 0;
}
}
static int start_acpid(void) {
const char *acpid = "/sbin/acpid";
const char *const argp[] = {
acpid, NULL
};
int pid = fork();
int res;
switch (pid) {
case 0:
exit(execve(acpid, (char *const *) argp, environ));
case -1:
fprintf(stderr, "acpid failed to start\n");
return -1;
default:
return 0;
}
}
int main(int argc, char **argv) {
if (getpid() != 1) {
printf("Won't work if PID is not 1\n");
return -1;
}
mount(NULL, "/dev", "devfs", 0, NULL);
mount(NULL, "/sys", "sysfs", 0, NULL);
//mount("/dev/sda", "/mnt", NULL, 0, NULL);
uint32_t inaddr = 0x0A000001;
netctl("eth0", NETCTL_SET_INADDR, &inaddr);
// Start acpid
start_acpid();
return start_login();
}
+2
View File
@@ -23,6 +23,8 @@ BINS=$(O)/bin/ls \
$(O)/bin/mkfifo \
$(O)/bin/sleep \
$(O)/bin/ucat \
$(O)/sbin/mount \
$(O)/sbin/umount \
$(O)/sbin/lspci \
$(O)/sbin/insmod \
$(O)/sbin/reboot \
+4 -5
View File
@@ -9,6 +9,10 @@ int main(int argc, char **argv) {
fclose(stdin);
FILE *fp = fopen("/dev/acpi", "rb");
if (!fp) {
perror("/dev/acpi");
return -1;
}
int ch;
// TODO: fix fopen for tty
@@ -19,11 +23,6 @@ int main(int argc, char **argv) {
fclose(stderr);
if (!fp) {
perror("/dev/acpi");
return -1;
}
while ((ch = fgetc(fp)) > 0) {
switch (ch) {
case ACEV_POWER_BUTTON:
+8 -5
View File
@@ -10,8 +10,9 @@ LDFLAGS?=-lgcc
O=build
rc_OBJS=$(O)/rc.o
init_OBJS=$(O)/init.o
all: mkdirs $(O)/rc
all: mkdirs $(O)/init $(O)/rc
mkdirs:
mkdir -p $(O)
@@ -19,14 +20,16 @@ mkdirs:
clean:
rm -rf $(O)
install: mkdirs $(O)/rc
install -m0755 $(O)/rc $(DESTDIR)/init
# TODO: symlinks in tarfs
#ln -sf /bin/rc $(DESTDIR)/init
install: mkdirs $(O)/init $(O)/rc
install -m0755 $(O)/init $(DESTDIR)/init
install -m0755 $(O)/rc $(DESTDIR)/sbin/rc
$(O)/rc: $(rc_OBJS)
$(CC) $(LDFLAGS) -o $@ $(rc_OBJS)
$(O)/init: $(init_OBJS)
$(CC) $(LDFLAGS) -o $@ $(init_OBJS)
$(O)/%.o: src/%.c
$(CC) $(CFLAGS) -c -o $@ $<
+247
View File
@@ -0,0 +1,247 @@
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
//#include <wait.h>
#define INITTAB "/etc/inittab"
// Default runlevel
#define RUNLEVEL_1 (1 << 0)
extern void ygg_debug_trace(const char *fmt, ...);
enum rc_action {
RC_ONCE,
RC_BOOT,
RC_WAIT
};
struct rc_rule {
char id[4];
uint32_t runlevels;
enum rc_action action;
char process[256];
char *argv[16];
int argc;
struct rc_rule *prev, *next;
};
static void sig_handler(int signum) {
if (signum == SIGTERM) {
// TODO: reap children
fprintf(stderr, "init received SIGTERM\n");
return;
}
}
static void rc_inittab_error(int line, const char *msg) {
ygg_debug_trace("rc: error on line %d\n", line);
ygg_debug_trace("rc: %s\n", msg);
}
static int load_inittab(struct rc_rule **_head) {
struct rc_rule *head = NULL, *tail = NULL;
FILE *fp;
char buf[1024];
char *r;
char *e;
// Parse and execute rules from inittab
fp = fopen(INITTAB, "r");
if (!fp) {
perror(INITTAB);
return -1;
}
while (fgets(buf, sizeof(buf), fp) != NULL) {
// Terminate with either a newline or a comment
if (buf[0] && (r = strpbrk(buf, "\n\r#")) != NULL) {
*r = 0;
}
// Skip leading whitespace
r = buf;
while (isspace(*r)) {
++r;
}
if (!*r) {
continue;
}
// Parse the rule
struct rc_rule *rule = malloc(sizeof(struct rc_rule));
rule->runlevels = 0;
// {id}:...
e = strchr(r, ':');
if (!e) {
fprintf(stderr, "Syntax error: `%s`\n", r);
goto error;
}
if (e - r > 4 || e == r) {
fprintf(stderr, "Rule ID must be 1-4 symbols: `%s`\n", r);
goto error;
}
strncpy(rule->id, r, e - r);
rule->id[e - r] = 0;
// ...:{runlevels}:...
r = e + 1;
while (1) {
if (*r == ':') {
++r;
break;
}
if (!*r || !isdigit(*r)) {
goto error;
}
switch (*r) {
case '1':
rule->runlevels |= RUNLEVEL_1;
break;
default:
goto error;
}
++r;
}
// ...:{action}:...
e = strchr(r, ':');
if (!e) {
rc_inittab_error(0, r);
goto error;
}
*e = 0;
if (!strcmp(r, "once")) {
rule->action = RC_ONCE;
} else if (!strcmp(r, "wait")) {
rule->action = RC_WAIT;
} else {
rc_inittab_error(0, r);
goto error;
}
r = e + 1;
// ...:{process}
strcpy(rule->process, r);
// Split "process" string
r = rule->process;
while (1) {
e = strchr(r, ' ');
if (!e) {
if (*r) {
rule->argv[rule->argc++] = r;
}
break;
} else {
*e = 0;
rule->argv[rule->argc++] = r;
}
r = e + 1;
while (isspace(*r)) {
++r;
}
if (!*r) {
break;
}
}
rule->argv[rule->argc] = NULL;
if (tail) {
tail->next = rule;
} else {
head = rule;
}
rule->next = NULL;
rule->prev = tail;
tail = rule;
}
*_head = head;
fclose(fp);
return 0;
error:
fclose(fp);
return -1;
}
static int rc_start(const struct rc_rule *rule) {
int pid;
ygg_debug_trace("rc: start `%s`\n", rule->argv[0]);
if ((pid = fork()) < 0) {
perror("fork()");
return -1;
}
if (pid == 0) {
exit(execve(rule->argv[0], rule->argv, environ));
} else {
return pid;
}
}
static int rc_enter_runlevel(const struct rc_rule *head, int runlevel) {
// Run "once" and "wait" rules
int n_failed = 0;
for (const struct rc_rule *r = head; r; r = r->next) {
if ((r->runlevels & runlevel) && (r->action == RC_ONCE || r->action == RC_WAIT)) {
int pid = rc_start(r);
if (pid < 0) {
ygg_debug_trace("rc: rule start failed: fork() failed\n");
++n_failed;
} else {
if (r->action == RC_WAIT) {
int status;
int r = waitpid(pid, &status, 0);
if (r < 0) {
ygg_debug_trace("rc: rule waitpid() failed\n");
}
}
}
}
}
return n_failed;
}
int main(int argc, char **argv) {
int runlevel = RUNLEVEL_1;
signal(SIGTERM, sig_handler);
struct rc_rule *head;
if (load_inittab(&head) != 0) {
ygg_debug_trace("rc: failed to load inittab\n");
return -1;
}
ygg_debug_trace("rc: inittab loaded\n");
// Run all "boot" rules
ygg_debug_trace("rc: running `boot` ruleset\n");
for (struct rc_rule *r = head; r; r = r->next) {
if (r->action == RC_BOOT) {
rc_start(r);
}
}
// Enter target runlevel
rc_enter_runlevel(head, runlevel);
while (1) {
usleep(1000000);
}
}
+56 -192
View File
@@ -1,213 +1,77 @@
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
//#include <wait.h>
#include <wait.h>
#define INITTAB "/etc/inittab"
// Default runlevel
#define RUNLEVEL_1 (1 << 0)
#define DIR_DEFAULT "/etc/rc.d"
enum rc_action {
RC_ONCE,
RC_BOOT
};
static int rc_script_exec(const char *path, const char *arg) {
int pid = fork();
struct rc_rule {
char id[4];
uint32_t runlevels;
enum rc_action action;
char process[256];
char *argv[16];
int argc;
struct rc_rule *prev, *next;
};
static void sig_handler(int signum) {
if (signum == SIGTERM) {
// TODO: reap children
fprintf(stderr, "init received SIGTERM\n");
return;
}
}
static int load_inittab(struct rc_rule **_head) {
struct rc_rule *head = NULL, *tail = NULL;
FILE *fp;
char buf[1024];
char *r;
char *e;
// Parse and execute rules from inittab
fp = fopen(INITTAB, "r");
if (!fp) {
perror(INITTAB);
return -1;
}
while (fgets(buf, sizeof(buf), fp) != NULL) {
// Terminate with either a newline or a comment
if (buf[0] && (r = strpbrk(buf, "\n\r#")) != NULL) {
*r = 0;
}
// Skip leading whitespace
r = buf;
while (isspace(*r)) {
++r;
}
if (!*r) {
continue;
}
// Parse the rule
struct rc_rule *rule = malloc(sizeof(struct rc_rule));
rule->runlevels = 0;
// {id}:...
e = strchr(r, ':');
if (!e) {
fprintf(stderr, "Syntax error: `%s`\n", r);
goto error;
}
if (e - r >= 4 || e == r) {
fprintf(stderr, "Rule ID must be 1-4 symbols: `%s`\n", r);
goto error;
}
strncpy(rule->id, r, e - r);
rule->id[e - r] = 0;
// ...:{runlevels}:...
r = e + 1;
while (1) {
if (*r == ':') {
++r;
break;
}
if (!*r || !isdigit(*r)) {
goto error;
}
switch (*r) {
case '1':
rule->runlevels |= RUNLEVEL_1;
break;
default:
goto error;
}
++r;
}
// ...:{action}:...
e = strchr(r, ':');
if (!e) {
goto error;
}
*e = 0;
if (!strcmp(r, "once")) {
rule->action = RC_ONCE;
} else {
goto error;
}
r = e + 1;
// ...:{process}
strcpy(rule->process, r);
// Split "process" string
r = rule->process;
while (1) {
e = strchr(r, ' ');
if (!e) {
if (*r) {
rule->argv[rule->argc++] = r;
}
break;
} else {
*e = 0;
rule->argv[rule->argc++] = r;
}
r = e + 1;
while (isspace(*r)) {
++r;
}
if (!*r) {
break;
}
}
rule->argv[rule->argc] = NULL;
if (tail) {
tail->next = rule;
} else {
head = rule;
}
rule->next = NULL;
rule->prev = tail;
tail = rule;
}
*_head = head;
fclose(fp);
return 0;
error:
fclose(fp);
return -1;
}
static int rc_start(const struct rc_rule *rule) {
int pid;
if ((pid = fork()) < 0) {
perror("fork()");
if (pid < 0) {
return -1;
}
if (pid == 0) {
exit(execve(rule->argv[0], rule->argv, environ));
const char *const argv[] = {
path, arg, NULL
};
exit(execve(argv[0], (char *const *) argv, environ));
} else {
// TODO: "wait" action
return 0;
int res, t;
t = waitpid(pid, &res, 0);
if (t < 0) {
perror("waitpid()");
return -1;
}
return res;
}
}
static int rc_load_dir(const char *path, const char *action) {
DIR *dir = opendir(path);
if (!dir) {
perror(path);
return -1;
}
struct dirent *ent;
char script[256];
// TODO: readdir doesn't guarantee ordering
while ((ent = readdir(dir))) {
if (ent->d_name[0] == '.') {
continue;
}
snprintf(script, sizeof(script), "%s/%s", path, ent->d_name);
rc_script_exec(script, "start");
}
closedir(dir);
return 0;
}
static void usage(const char *name) {
fprintf(stderr, "usage: %s default|shutdown\n", name ? name : "/sbin/rc");
}
int main(int argc, char **argv) {
int runlevel = RUNLEVEL_1;
signal(SIGTERM, sig_handler);
struct rc_rule *head;
if (load_inittab(&head) != 0) {
if (argc != 2) {
usage(argv[0]);
return -1;
}
// Run all "boot" rules
for (struct rc_rule *r = head; r; r = r->next) {
if (r->action == RC_BOOT) {
rc_start(r);
}
}
// Run all "once" rules
for (struct rc_rule *r = head; r; r = r->next) {
if ((r->runlevels & runlevel) && r->action == RC_ONCE) {
rc_start(r);
}
}
while (1) {
usleep(1000000);
if (!strcmp(argv[1], "default")) {
return rc_load_dir(DIR_DEFAULT, "start");
} else {
usage(argv[0]);
return -1;
}
}