PatchworkOS  3984a1d
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/io.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 {
60 const char* data = sreadfile(F("/net/%s/addrs", family));
61 if (data == NULL)
62 {
63 close(addrs);
64 return ERR;
65 }
66
67 if (strstr(data, addr) != NULL)
68 {
69 free((void*)data);
70 break;
71 }
72
73 free((void*)data);
74
76
77 if (uptime() - start > CLOCKS_PER_SEC * 30)
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
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 != INODE_DIR || 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 {
180 printf("init: spawned service '%s'\n", services->items[i]);
181 const char* argv[] = {services->items[i], NULL};
183 {
184 printf("init: failed to spawn service '%s' (%s)\n", services->items[i], strerror(errno));
185 }
186 }
187
188 config_array_t* sockets = config_get_array(config, "startup", "sockets");
189 for (uint64_t i = 0; i < sockets->length; i++)
190 {
191 if (init_socket_addr_wait("local", sockets->items[i]) == ERR)
192 {
193 printf("init: timeout waiting for socket '%s' (%s)\n", sockets->items[i], strerror(errno));
194 }
195 }
196
197 config_array_t* programs = config_get_array(config, "startup", "programs");
198 for (uint64_t i = 0; i < programs->length; i++)
199 {
200 printf("init: spawned program '%s'\n", programs->items[i]);
201 const char* argv[] = {programs->items[i], NULL};
203 {
204 printf("init: failed to spawn program '%s' (%s)\n", programs->items[i], strerror(errno));
205 }
206 }
207
209}
210
211int main(void)
212{
213 init_root_ns();
214
215 fd_t klog = open("/dev/klog:rw");
216 if (klog == ERR)
217 {
218 return EXIT_FAILURE;
219 }
221 {
222 close(klog);
223 return EXIT_FAILURE;
224 }
225 close(klog);
226
228
230
232
233 printf("init: all startup tasks completed!\n");
234
235 return EXIT_SUCCESS;
236}
int main(void)
Definition main.c:5
int64_t y
Definition main.c:153
static void start()
Definition main.c:542
#define CLOCKS_PER_SEC
Definition clock_t.h:15
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
#define F(format,...)
Allocates a formatted string on the stack.
Definition io.h:66
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 io.h:35
char * sreadfile(const char *path)
Wrapper for reading an entire file directly into a null-terminated string.
Definition sreadfile.c:3
#define STDERR_FILENO
Standard error file descriptor.
Definition io.h:36
size_t readdir(fd_t fd, dirent_t **buffer, uint64_t *count)
Helper for reading all directory entries.
Definition readdir.c:8
@ INODE_DIR
Is a directory.
Definition io.h:343
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:65
@ SPAWN_EMPTY_FDS
Dont inherit the file descriptors of the parent process.
Definition proc.h:61
@ SPAWN_DEFAULT
Default spawn behaviour.
Definition proc.h:52
@ SPAWN_EMPTY_ENV
Don't inherit the parent's environment variables.
Definition proc.h:63
@ SPAWN_EMPTY_CWD
Don't inherit the parent's current working directory, starts at root (/).
Definition proc.h:64
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
__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 io.h:443