PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1#include <errno.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/fs.h>
7#include <sys/proc.h>
8#include <threads.h>
9#include <time.h>
10
11/**
12 * @brief Init Process.
13 * @defgroup programs_init Init
14 * @ingroup programs
15 *
16 * The init process is the first user space process started by the kernel. It is responsible for setting up the "root
17 * namespace", the namespace the init process and boxd run in, and for spawning initial processes.
18 *
19 * ## Root Namespace
20 *
21 * The init process creates the root namespace, which is the parent of all other user-space namespaces. Included below
22 * is an overview of the root namespace.
23 *
24 * <div align="center">
25 * | Name | Type | Description |
26 * |-------------------------------------|-----------|--------------------------------------------|
27 * | `/base` | directory | Base system directory. |
28 * | `/base/bin` | directory | Non-essential system binaries. |
29 * | `/base/lib` | directory | System libraries. |
30 * | `/base/include` | directory | System header files. |
31 * | `/base/data` | directory | System data files. |
32 * | `/box` | directory | Installed boxes directory. |
33 * | `/cfg` | directory | System configuration files. |
34 * | `/dev` | devfs | Device filesystem. |
35 * | `/efi` | directory | EFI files. |
36 * | `/efi/boot` | directory | EFI bootloader files. |
37 * | `/kernel` | directory | Kernel related files. |
38 * | `/kernel/modules` | directory | Kernel modules directory. |
39 * | `/kernel/modules/<kernel_verion>` | directory | Version specific kernel modules. |
40 * | `/net` | netfs | Network filesystem. |
41 * | `/proc` | procfs | Process filesystem. |
42 * | `/sbin` | directory | Essential system binaries. |
43 * | `/sys` | sysfs | System filesystem, mounted by the kernel. |
44 * | `/tmp` | tmpfs | Temporary filesystem. |
45 * </div>
46 *
47 */
48
49static uint64_t init_socket_addr_wait(const char* family, const char* addr)
50{
51 fd_t addrs = open(F("/net/%s/addrs", family));
52 if (addrs == ERR)
53 {
54 return ERR;
55 }
56
58 while (true)
59 {
61
62 const char* data = readfiles(F("/net/%s/addrs", family));
63 if (data == NULL)
64 {
65 close(addrs);
66 return ERR;
67 }
68
69 if (strstr(data, addr) != NULL)
70 {
71 free((void*)data);
72 break;
73 }
74
75 free((void*)data);
76
77 if ((uptime() - start) >= CLOCKS_PER_SEC * 10)
78 {
79 close(addrs);
80 return ERR;
81 }
82 }
83
84 close(addrs);
85 return 0;
86}
87
88static void init_root_ns(void)
89{
90 if (mount("/dev:rwL", "/sys/fs/devfs", NULL) == ERR)
91 {
92 printf("init: failed to mount devfs (%s)\n", strerror(errno));
93 abort();
94 }
95
96 if (mount("/net:rwL", "/sys/fs/netfs", NULL) == ERR)
97 {
98 printf("init: failed to mount netfs (%s)\n", strerror(errno));
99 abort();
100 }
101
102 if (mount("/proc:rwL", "/sys/fs/procfs", NULL) == ERR)
103 {
104 printf("init: failed to mount procfs (%s)\n", strerror(errno));
105 abort();
106 }
107
108 if (mount("/tmp:rwL", "/sys/fs/tmpfs", NULL) == ERR)
109 {
110 printf("init: failed to mount tmpfs (%s)\n", strerror(errno));
111 abort();
112 }
113}
114
115static void init_spawn_boxd(void)
116{
117 const char* argv[] = {"/sbin/boxd", NULL};
118 if (spawn(argv, SPAWN_DEFAULT) == ERR)
119 {
120 printf("init: failed to spawn boxd (%s)\n", strerror(errno));
121 abort();
122 }
123
124 if (init_socket_addr_wait("local", "boxspawn") == ERR)
125 {
126 printf("init: timeout waiting for boxd to create boxspawn socket (%s)\n", strerror(errno));
127 abort();
128 }
129}
130
131static void init_create_pkg_links(void)
132{
133 fd_t box = open("/box");
134 if (box == ERR)
135 {
136 printf("init: failed to open /box (%s)\n", strerror(errno));
137 abort();
138 }
139
140 dirent_t* dirents;
141 uint64_t amount;
142 if (readdir(box, &dirents, &amount) == ERR)
143 {
144 close(box);
145 printf("init: failed to read /box (%s)\n", strerror(errno));
146 abort();
147 }
148 close(box);
149
150 for (uint64_t i = 0; i < amount; i++)
151 {
152 if (dirents[i].type != VDIR || dirents[i].path[0] == '.')
153 {
154 continue;
155 }
156
157 if (symlink("boxspawn", F("/base/bin/%s", dirents[i].path)) == ERR && errno != EEXIST)
158 {
159 free(dirents);
160 printf("init: failed to create launch symlink for box '%s' (%s)\n", dirents[i].path, strerror(errno));
161 abort();
162 }
163 }
164
165 free(dirents);
166}
167
168static void init_config_load(void)
169{
170 config_t* config = config_open("init", "main");
171 if (config == NULL)
172 {
173 printf("init: failed to open config file (%s)\n", strerror(errno));
174 abort();
175 }
176
177 config_array_t* services = config_get_array(config, "startup", "services");
178 for (uint64_t i = 0; i < services->length; i++)
179 {
181 printf("init: spawned service '%s'\n", services->items[i]);
182 const char* argv[] = {services->items[i], NULL};
184 {
185 printf("init: failed to spawn service '%s' (%s)\n", services->items[i], strerror(errno));
186 }
187 }
188
189 config_array_t* sockets = config_get_array(config, "startup", "sockets");
190 for (uint64_t i = 0; i < sockets->length; i++)
191 {
192 if (init_socket_addr_wait("local", sockets->items[i]) == ERR)
193 {
194 printf("init: timeout waiting for socket '%s' (%s)\n", sockets->items[i], strerror(errno));
195 }
196 }
197
198 config_array_t* programs = config_get_array(config, "startup", "programs");
199 for (uint64_t i = 0; i < programs->length; i++)
200 {
202 printf("init: spawn program '%s'\n", programs->items[i]);
203 const char* argv[] = {programs->items[i], NULL};
205 {
206 printf("init: failed to spawn program '%s' (%s)\n", programs->items[i], strerror(errno));
207 }
208 }
209
210 config_close(config);
211}
212
213int main(void)
214{
215 init_root_ns();
216
217 fd_t klog = open("/dev/klog:rw");
218 if (klog == ERR)
219 {
220 return EXIT_FAILURE;
221 }
223 {
224 close(klog);
225 return EXIT_FAILURE;
226 }
227 close(klog);
228
230
232
234
235 printf("init: all startup tasks completed!\n");
236
237 return EXIT_SUCCESS;
238}
int main(void)
Definition main.c:5
static void start()
Definition main.c:542
#define CLOCKS_PER_SEC
Definition clock_t.h:15
#define CLOCKS_PER_MS
Definition clock_t.h:16
static fd_t data
Definition dwm.c:21
config_array_t * config_get_array(config_t *config, const char *section, const char *key)
Get an array of strings from a configuration file.
Definition config.c:335
config_t * config_open(const char *prefix, const char *name)
Open a configuration file.
Definition config.c:93
void config_close(config_t *config)
Close a configuration file.
Definition config.c:202
#define EEXIST
File exists.
Definition errno.h:117
#define errno
Error number variable.
Definition errno.h:27
fd_t dup2(fd_t oldFd, fd_t newFd)
System call for duplicating file descriptors, with a destination.
Definition dup2.c:8
fd_t open(const char *path)
System call for opening files.
Definition open.c:8
uint64_t close(fd_t fd)
System call for closing files.
Definition close.c:8
char * readfiles(const char *path)
Wrapper for reading an entire file directly into a null-terminated string.
Definition sreadfile.c:3
#define F(format,...)
Allocates a formatted string on the stack.
Definition fs.h:67
uint64_t mount(const char *mountpoint, const char *fs, const char *options)
System call for mounting a filesystem.
Definition mount.c:5
uint64_t symlink(const char *target, const char *linkpath)
System call for creating a symbolic link.
Definition symlink.c:8
#define STDOUT_FILENO
Standard output file descriptor.
Definition fs.h:36
#define STDERR_FILENO
Standard error file descriptor.
Definition fs.h:37
size_t readdir(fd_t fd, dirent_t **buffer, uint64_t *count)
Helper for reading all directory entries.
Definition readdir.c:8
@ VDIR
Is a directory.
Definition fs.h:344
pid_t spawn(const char **argv, spawn_flags_t flags)
System call for spawning new processes.
Definition spawn.c:6
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
uint64_t nanosleep(clock_t timeout)
System call for sleeping.
Definition nanosleep.c:6
@ SPAWN_EMPTY_GROUP
Don't inherit the parent's process group, instead create a new group.
Definition proc.h:66
@ SPAWN_EMPTY_FDS
Dont inherit the file descriptors of the parent process.
Definition proc.h:62
@ SPAWN_DEFAULT
Default spawn behaviour.
Definition proc.h:53
@ SPAWN_EMPTY_ENV
Don't inherit the parent's environment variables.
Definition proc.h:64
@ SPAWN_EMPTY_CWD
Don't inherit the parent's current working directory, starts at root (/).
Definition proc.h:65
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ fd_t
File descriptor type.
Definition fd_t.h:10
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static dentry_t * klog
Definition log.c:29
static void init_config_load(void)
Definition main.c:168
static void init_root_ns(void)
Definition main.c:88
static uint64_t init_socket_addr_wait(const char *family, const char *addr)
Definition main.c:49
static void init_create_pkg_links(void)
Definition main.c:131
static void init_spawn_boxd(void)
Definition main.c:115
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int printf(const char *_RESTRICT format,...)
Definition printf.c:3
#define EXIT_SUCCESS
Definition stdlib.h:46
#define EXIT_FAILURE
Definition stdlib.h:47
_PUBLIC _NORETURN void abort(void)
Definition abort.c:9
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strerror(int errnum)
Definition strerror.c:6
_PUBLIC char * strstr(const char *s1, const char *s2)
Definition strstr.c:3
Configuration array structure.
Definition config.h:38
char ** items
Definition config.h:39
uint64_t length
Definition config.h:40
Opaque configuration structure.
Definition config.c:28
Directory entry struct.
Definition fs.h:455