Skip to content

Commit ad5e765

Browse files
modified system config
1 parent 23d3808 commit ad5e765

File tree

5 files changed

+399
-16
lines changed

5 files changed

+399
-16
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ run: img
132132
$(QEMU_ARGS) \
133133
-kernel $(KERNEL_IMAGE) \
134134
-append "root=/dev/vda rw console=tty1" \
135-
-drive file=$(IMAGE),if=virtio,format=raw \
135+
-drive file=$(IMAGE),if=virtio,format=raw
136136

137137
run-iso: iso
138138
qemu-system-x86_64 \

code.txt

Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
#define _GNU_SOURCE
2+
#include <sys/mount.h>
3+
#include <sys/types.h>
4+
#include <sys/stat.h>
5+
#include <sys/wait.h>
6+
#include <sys/socket.h>
7+
#include <sys/ioctl.h>
8+
#include <sys/sysmacros.h>
9+
#include <net/if.h>
10+
#include <arpa/inet.h>
11+
#include <netinet/in.h>
12+
#include <net/route.h>
13+
#include <fcntl.h>
14+
#include <unistd.h>
15+
#include <signal.h>
16+
#include <stdio.h>
17+
#include <stdlib.h>
18+
#include <errno.h>
19+
#include <string.h>
20+
#include <dirent.h>
21+
#include <time.h>
22+
#include <stdarg.h>
23+
#include <linux/fb.h>
24+
#include <sys/mman.h>
25+
26+
#include "log.h"
27+
#include "insmod.c"
28+
#include "acl.h"
29+
30+
void load_modules(const char* modules[]);
31+
32+
/* safe mkdir -p wrapper (unchanged) */
33+
static int ensure_dir(const char *path, mode_t mode) {
34+
log_debug("enter ensure_dir(path='%s', mode=%o)\n", path, mode);
35+
struct stat st;
36+
if (stat(path, &st) == 0) {
37+
log_warn("ensure_dir: %s already exists\n", path);
38+
log_debug("exit ensure_dir => 0\n");
39+
return 0;
40+
}
41+
42+
log_info("ensure_dir: %s does not exist, attempting mkdir\n", path);
43+
if (mkdir(path, mode) == 0) {
44+
log_info("ensure_dir: created %s\n", path);
45+
log_debug("exit ensure_dir => 0\n");
46+
return 0;
47+
}
48+
49+
if (errno == ENOENT) {
50+
log_warn("ensure_dir: parent missing for %s, creating parents\n", path);
51+
52+
char tmp[256];
53+
strncpy(tmp, path, sizeof(tmp)-1);
54+
tmp[sizeof(tmp)-1] = '\0';
55+
56+
for (char *p = tmp + 1; *p; ++p) {
57+
if (*p == '/') {
58+
*p = '\0';
59+
log_debug("ensure_dir: mkdir parent %s\n", tmp);
60+
if (mkdir(tmp, 0755) == 0) {
61+
log_info("ensure_dir: created parent %s\n", tmp);
62+
} else if (errno != EEXIST) {
63+
log_warn("ensure_dir: failed to create parent %s: %s\n", tmp, strerror(errno));
64+
} else {
65+
log_debug("ensure_dir: parent %s already exists\n", tmp);
66+
}
67+
*p = '/';
68+
}
69+
}
70+
71+
if (mkdir(path, mode) == 0) {
72+
log_info("ensure_dir: successfully created %s after creating parents\n", path);
73+
log_debug("exit ensure_dir => 0\n");
74+
return 0;
75+
} else {
76+
log_error("ensure_dir: failed to create %s even after parents: %s\n", path, strerror(errno));
77+
}
78+
} else {
79+
log_warn("ensure_dir: mkdir %s failed: %s\n", path, strerror(errno));
80+
}
81+
82+
log_debug("exit ensure_dir => -1\n");
83+
return -1;
84+
}
85+
86+
/* small helpers for reading config (wrappers around your libacl API) */
87+
static int cfg_get_int(AclBlock *cfg, const char *path, int def) {
88+
if (!cfg) return def;
89+
long v = 0;
90+
if (acl_get_int(cfg, path, &v)) return (int)v;
91+
return def;
92+
}
93+
94+
static char *cfg_get_string_dup(AclBlock *cfg, const char *path, const char *def) {
95+
if (!cfg) return def ? strdup(def) : NULL;
96+
char *tmp = NULL;
97+
if (acl_get_string(cfg, path, &tmp) && tmp) return strdup(tmp);
98+
return def ? strdup(def) : NULL;
99+
}
100+
101+
/* spawn login (unchanged except small log phrasing) */
102+
static void spawn_login(const char *tty) {
103+
log_info("spawn_login: starting login on %s\n", tty);
104+
pid_t pid;
105+
for (;;) {
106+
pid = fork();
107+
if (pid < 0) { log_error("fork failed: %s\n", strerror(errno)); sleep(1); continue; }
108+
if (pid == 0) {
109+
log_debug("child process %d starting login on %s\n", getpid(), tty);
110+
setsid();
111+
int fd = open(tty, O_RDWR);
112+
if (fd < 0) { perror("open tty"); _exit(1); }
113+
ioctl(fd, TIOCSCTTY, 0);
114+
dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO);
115+
if (fd > STDERR_FILENO) close(fd);
116+
char *envp[] = {"PATH=/bin:/sbin","LD_LIBRARY_PATH=/lib",NULL};
117+
char *argv[] = {"/sbin/login", NULL};
118+
execve(argv[0], argv, envp);
119+
perror("execve"); _exit(1);
120+
}
121+
log_debug("parent: spawned child %d for %s\n", pid, tty);
122+
int status; waitpid(pid, &status, 0);
123+
log_debug("child %d exited with status %d\n", pid, status);
124+
sleep(1);
125+
}
126+
}
127+
128+
/* setup /dev and devices (unchanged) */
129+
static void setup_dev(void) {
130+
log_debug("enter setup_dev()\n");
131+
ensure_dir("/dev", 0755);
132+
133+
if (mount("devtmpfs","/dev","devtmpfs",MS_NOSUID|MS_NOEXEC|MS_RELATIME,NULL) == 0)
134+
log_info("mounted devtmpfs on /dev\n");
135+
else {
136+
log_warn("devtmpfs mount failed: %s, fallback tmpfs\n", strerror(errno));
137+
if (mount("tmpfs","/dev","tmpfs",MS_NOSUID|MS_STRICTATIME,"mode=0755")<0)
138+
log_error("tmpfs mount failed: %s\n", strerror(errno));
139+
else log_info("mounted tmpfs on /dev\n");
140+
141+
struct { const char *path; mode_t mode; dev_t dev; } nodes[] = {
142+
{"/dev/console",0600,makedev(5,1)},
143+
{"/dev/null",0666,makedev(1,3)},
144+
{"/dev/zero",0666,makedev(1,5)},
145+
{"/dev/full",0666,makedev(1,7)},
146+
{"/dev/random",0666,makedev(1,8)},
147+
{"/dev/urandom",0666,makedev(1,9)},
148+
{"/dev/tty",0666,makedev(5,0)},
149+
{"/dev/ptmx",0666,makedev(5,2)},
150+
{"/dev/tty0",0600,makedev(4,0)},
151+
{"/dev/tty1",0620,makedev(4,1)},
152+
{"/dev/tty2",0620,makedev(4,2)},
153+
{"/dev/tty3",0620,makedev(4,3)}
154+
};
155+
for(size_t i=0;i<sizeof(nodes)/sizeof(nodes[0]);i++){
156+
struct stat st; if(stat(nodes[i].path,&st)==0) continue;
157+
if(mknod(nodes[i].path,S_IFCHR|nodes[i].mode,nodes[i].dev)<0)
158+
log_warn("mknod %s failed: %s\n",nodes[i].path,strerror(errno));
159+
else { chmod(nodes[i].path,nodes[i].mode); log_debug("created node %s\n",nodes[i].path);}
160+
}
161+
}
162+
163+
ensure_dir("/dev/pts",0755);
164+
if(mount("devpts","/dev/pts","devpts",0,"mode=0620,ptmxmode=0666")==0)
165+
log_info("mounted devpts\n");
166+
else log_warn("devpts mount failed: %s\n", strerror(errno));
167+
168+
struct stat st; if(stat("/dev/ptmx",&st)!=0){ mknod("/dev/ptmx",S_IFCHR|0666,makedev(5,2)); log_debug("created /dev/ptmx\n");}
169+
170+
ensure_dir("/dev/shm",01777);
171+
if(mount("tmpfs","/dev/shm","tmpfs",MS_NOSUID|MS_NODEV,"size=64M,mode=1777")==0)
172+
log_info("mounted /dev/shm\n");
173+
else log_warn("/dev/shm mount failed: %s\n", strerror(errno));
174+
175+
unlink("/dev/fd"); symlink("/proc/self/fd","/dev/fd");
176+
unlink("/dev/stdin"); unlink("/dev/stdout"); unlink("/dev/stderr");
177+
symlink("/proc/self/fd/0","/dev/stdin");
178+
symlink("/proc/self/fd/1","/dev/stdout");
179+
symlink("/proc/self/fd/2","/dev/stderr");
180+
181+
log_info("/dev setup complete\n");
182+
log_debug("exit setup_dev()\n");
183+
}
184+
185+
/* framebuffer setup unchanged */
186+
static int setup_framebuffer(void) {
187+
log_debug("enter setup_framebuffer()\n");
188+
189+
int fb = open("/dev/fb0", O_RDWR);
190+
if (fb < 0) {
191+
log_warn("cannot open /dev/fb0: %s\n", strerror(errno));
192+
return -1;
193+
}
194+
195+
struct fb_var_screeninfo vinfo;
196+
struct fb_fix_screeninfo finfo;
197+
198+
if (ioctl(fb, FBIOGET_FSCREENINFO, &finfo) < 0) {
199+
log_warn("FBIOGET_FSCREENINFO failed: %s\n", strerror(errno));
200+
close(fb);
201+
return -1;
202+
}
203+
204+
if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
205+
log_warn("FBIOGET_VSCREENINFO failed: %s\n", strerror(errno));
206+
close(fb);
207+
return -1;
208+
}
209+
210+
log_info("Framebuffer: %dx%d, %dbpp, line_length=%d\n",
211+
vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, finfo.line_length);
212+
213+
size_t screensize = finfo.smem_len;
214+
void *fbp = mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
215+
if (fbp == MAP_FAILED) {
216+
log_warn("mmap framebuffer failed: %s\n", strerror(errno));
217+
close(fb);
218+
return -1;
219+
}
220+
221+
// clear the screen
222+
memset(fbp, 0, screensize);
223+
log_info("framebuffer cleared\n");
224+
225+
// re-map if we need to draw later
226+
munmap(fbp, screensize);
227+
228+
log_debug("exit setup_framebuffer()\n");
229+
return 0;
230+
}
231+
232+
/* helper: check if file is executable */
233+
static int is_executable(const char *path) {
234+
struct stat st;
235+
if (stat(path, &st) < 0) return 0;
236+
if (!S_ISREG(st.st_mode)) return 0;
237+
if (st.st_mode & S_IXUSR) return 1; // owner executable
238+
return 0;
239+
}
240+
241+
/* load modules from config: Modules.load[0], Modules.load[1], ... */
242+
static void load_modules_from_config(AclBlock *cfg) {
243+
const int MAX_MODULES = 256;
244+
char path[256];
245+
int found = 0;
246+
for (int i = 0; i < MAX_MODULES; ++i) {
247+
snprintf(path, sizeof(path), "Modules.load[%d]", i);
248+
char *mod = NULL;
249+
if (!acl_get_string(cfg, path, &mod) || !mod) break;
250+
log_info("config: loading module '%s'\n", mod);
251+
insmod(mod);
252+
found = 1;
253+
}
254+
255+
if (!found) {
256+
/* fallback to previous hard-coded list */
257+
const char *defaults[] = { "e1000", "virtio_dma_buf", "virtio-gpu", NULL };
258+
log_info("config: no Modules.load[], falling back to defaults\n");
259+
load_modules(defaults);
260+
}
261+
}
262+
263+
/* launch services directory (configurable) */
264+
static void launch_services_from_dir(const char *dir) {
265+
DIR *d = opendir(dir);
266+
if (!d) {
267+
log_warn("launch_services: opendir(%s): %s\n", dir, strerror(errno));
268+
return;
269+
}
270+
271+
struct dirent *entry;
272+
while ((entry = readdir(d)) != NULL) {
273+
if (entry->d_name[0] == '.') continue;
274+
char path[PATH_MAX];
275+
int n = snprintf(path, sizeof(path), "%s/%s", dir, entry->d_name);
276+
if (n < 0 || n >= (int)sizeof(path)) { log_warn("path too long: %s/%s\n", dir, entry->d_name); continue; }
277+
struct stat st;
278+
if (stat(path, &st) < 0) { log_warn("stat(%s): %s\n", path, strerror(errno)); continue; }
279+
if (!S_ISREG(st.st_mode) || !(st.st_mode & S_IXUSR)) continue;
280+
pid_t pid = fork();
281+
if (pid < 0) { log_warn("fork failed for %s: %s\n", path, strerror(errno)); continue; }
282+
if (pid == 0) { execl(path, path, NULL); perror("execl"); _exit(1); }
283+
/* parent continues; no supervision here (simple) */
284+
}
285+
closedir(d);
286+
}
287+
288+
/* Load modules helper for fallback usage (calls insmod for each name) */
289+
void load_modules(const char* modules[]) {
290+
for (int i = 0; modules[i] != NULL; i++) {
291+
insmod(modules[i]);
292+
}
293+
}
294+
295+
/* main init (now config-aware) */
296+
int main(void) {
297+
/* create logger and console sink first */
298+
logger = logger_create(LOG_INFO);
299+
LogSink* console_sink = console_sink_create();
300+
logger_add_sink(logger, console_sink);
301+
log_debug("enter main()\n");
302+
303+
/* try to parse /conf/system.acl (non-fatal) */
304+
AclBlock *cfg = acl_parse_file("/conf/system.acl");
305+
if (cfg) {
306+
if (!acl_resolve_all(cfg)) {
307+
log_warn("acl: /conf/system.acl parsed but failed to resolve references\n");
308+
} else {
309+
log_info("acl: /conf/system.acl loaded\n");
310+
}
311+
} else {
312+
log_info("acl: /conf/system.acl not found or failed to parse, continuing with defaults\n");
313+
}
314+
315+
/* Logging path override (optional) */
316+
char *logpath = cfg_get_string_dup(cfg, "Logging.path", "/log/init.log");
317+
LogSink* file_sink = file_sink_create(logpath);
318+
if (file_sink) logger_add_sink(logger, file_sink);
319+
free(logpath);
320+
321+
signal(SIGCHLD,SIG_IGN);
322+
signal(SIGHUP,SIG_IGN);
323+
log_debug("signals set\n");
324+
325+
ensure_dir("/proc",0555); ensure_dir("/sys",0555);
326+
ensure_dir("/dev",0755); ensure_dir("/etc",0755); ensure_dir("/var",0755);
327+
328+
if(mount("proc","/proc","proc",0,NULL)<0) log_warn("/proc mount failed: %s\n", strerror(errno));
329+
else log_info("mounted /proc\n");
330+
331+
if(mount("sysfs","/sys","sysfs",0,NULL)<0) log_warn("/sys mount failed: %s\n", strerror(errno));
332+
else log_info("mounted /sys\n");
333+
334+
setup_dev();
335+
setup_framebuffer();
336+
337+
ensure_dir("/tmp",01777); chmod("/tmp",01777);
338+
ensure_dir("/var/tmp",01777); chmod("/var/tmp",01777);
339+
if(mount("tmpfs","/tmp","tmpfs",MS_NOSUID|MS_NODEV,"size=128M,mode=1777")<0)
340+
log_warn("/tmp mount failed: %s\n", strerror(errno));
341+
else log_info("mounted /tmp\n");
342+
343+
ensure_dir("/var/run",0755);
344+
if(mount("tmpfs","/var/run","tmpfs",MS_NOSUID|MS_NODEV,"size=16M,mode=0755")<0)
345+
log_warn("/var/run mount failed: %s\n", strerror(errno));
346+
else log_info("mounted /var/run\n");
347+
348+
ensure_dir("/var/cache",0755);
349+
350+
symlink("/usr/bin","/bin");
351+
symlink("/usr/lib","/lib");
352+
symlink("/usr/lib64","/lib64");
353+
symlink("/var/run", "/run");
354+
355+
log_info("AtlasLinux init starting...\n");
356+
357+
/* load modules from config or defaults */
358+
if (cfg) load_modules_from_config(cfg);
359+
else load_modules((const char*[]){ "e1000", "virtio_dma_buf", "virtio-gpu", NULL });
360+
361+
/* launch services: directory may be overridden in config */
362+
char *svcdir = cfg_get_string_dup(cfg, "Services.dir", "/sbin/services");
363+
launch_services_from_dir(svcdir);
364+
free(svcdir);
365+
366+
/* get how many ttys to spawn from config (default 3) */
367+
int ttys = cfg_get_int(cfg, "System.spawn_getty_ttys", 3);
368+
369+
/* spawn login processes on tty1..ttyN */
370+
for (int i = 1; i <= ttys && i <= 12; ++i) {
371+
pid_t p = fork();
372+
if (p == 0) {
373+
char ttypath[32];
374+
snprintf(ttypath, sizeof(ttypath), "/dev/tty%d", i);
375+
spawn_login(ttypath);
376+
_exit(0);
377+
}
378+
}
379+
380+
log_debug("main: parent entering infinite pause loop\n");
381+
for(;;) pause();
382+
}

0 commit comments

Comments
 (0)