Heavy fix
[meinos.git] / apps / init / init.c
blob0c21452b5ec12011edcdb2ec73e916a5bade4a12
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <limits.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <misc.h>
25 #include <unistd.h>
26 #include <proc.h>
27 #include <rpc.h>
28 #include <libgen.h>
30 #include "exe_elf.h"
31 #include "init.conf.h"
33 static int sigusr1_count;
35 /**
36 * SIGUSR1 Handler. Is called when process finishs initialzation
37 * @param sig Signal. MUST be SIGUSR1
39 static void sigusr1_handler(int sig) {
40 sigusr1_count++;
43 /**
44 * Initializes Initialization ;)
46 static void init_init() {
47 signal(SIGUSR1,sigusr1_handler);
50 /**
51 * Runs a program (Sends SIGCONT)
52 * @param name Name of program to run
54 static void init_run(const char *name) {
55 pid_t pid = getpidbyname(name);
56 sigusr1_count = 0;
57 proc_run(pid);
60 /**
61 * Waits for a program to initialize
62 * @param name Name of program to wait for
63 * @return If waiting was successful or timeout occured
65 static int init_wait(const char *name) {
66 useconds_t t = 0;
67 const useconds_t timeout = 10000; // 10 seconds
68 while (sigusr1_count==0 && t<timeout) {
69 t += 10;
70 usleep(10000);
72 return (t<timeout);
75 typedef struct {
76 int fh;
77 void *data;
78 enum {
79 EXE_ELF
80 } type;
81 } exe_t;
83 static exe_t *exe_create(const char *file) {
84 exe_t *exe = malloc(sizeof(exe_t*));
86 // try ELF
87 exe->data = elf_create(file);
88 if (exe->data!=NULL) {
89 exe->type = EXE_ELF;
90 return exe;
92 else elf_destroy((elf_t*)exe->data);
94 // not an executable
95 free(exe);
96 return NULL;
99 static void *exe_load(exe_t *exe,pid_t pid) {
100 if (exe->type==EXE_ELF) return elf_load((elf_t*)exe->data,pid);
101 else return NULL;
104 static void exe_destroy(exe_t *exe) {
105 if (exe->type==EXE_ELF) elf_destroy((elf_t*)exe->data);
108 static pid_t proc_fork(void *child_entry) {
109 // Create process
111 char *name = getname(rpc_curpid);
112 pid_t pid = proc_create(name,getuidbypid(rpc_curpid),getgidbypid(rpc_curpid),rpc_curpid);
114 if (pid!=-1) {
115 // Copy userspace memory
116 size_t num_pages,i;
117 void **pages = proc_mempagelist(rpc_curpid,&num_pages);
119 if (pages!=NULL) {
120 for (i=0;i<num_pages;i++) {
121 int writable,swappable;
122 void *srcp = proc_memget(rpc_curpid,pages[i],NULL,&writable,&swappable,NULL);
124 if (srcp!=NULL) {
125 // Map parent's page to init
126 void *srcv = proc_memmap(1,NULL,srcp,0,0,0);
128 // Allocate child's page in init's addrspace
129 void *dstv = proc_memmap(1,NULL,NULL,1,0,0);
130 void *dstp = mem_getphysaddr(dstv);
132 // Map child's page to child
133 proc_memmap(pid,pages[i],dstp,writable,swappable,0);
135 // Copy
136 memcpy(dstv,srcv,PAGE_SIZE);
138 proc_memunmap(1,srcv);
139 proc_memunmap(1,dstv);
141 else proc_memmap(pid,pages[i],NULL,writable,swappable,0);
145 // Set entrypoint of child
146 proc_jump(pid,child_entry);
149 return pid;
152 static int proc_exec(const char *file,int var) {
153 dbgmsg("proc_exec(%s,%d)\n",file,var);
154 // Change process
155 char *_file = strdup(file);
156 proc_setname(rpc_curpid,basename(_file));
157 proc_setvar(rpc_curpid,var);
159 // Load executable
160 exe_t *exe = exe_create(file);
161 if (exe!=NULL) {
162 // Remove old addrspace
163 size_t num_pages,i;
164 void **pages = proc_mempagelist(rpc_curpid,&num_pages);
165 if (pages!=NULL) {
166 for (i=0;i<num_pages;i++) proc_memfree(rpc_curpid,pages[i]);
169 void *entrypoint = exe_load(exe,rpc_curpid);
171 if (entrypoint!=NULL) {
172 proc_jump(rpc_curpid,entrypoint);
173 proc_createstack(rpc_curpid);
175 else {
176 dbgmsg("failed loading executable!");
177 dbgmsg("TODO: destroy process\n");
178 while (1);
181 exe_destroy(exe);
182 return 0;
184 else return errno;
187 static void init_computer_shutdown() {
188 pid_t child;
189 while ((child = getchild(0))!=-1) kill(child,SIGKILL);
190 exit(0);
193 int main(int argc,char *argv[]) {
194 size_t i;
196 init_init();
197 for (i=0;INIT_PROGRAM(i);i++) {
198 //dbgmsg("init: starting %s...",INIT_PROGRAM(i));
199 init_run(INIT_PROGRAM(i));
201 if (!init_wait(INIT_PROGRAM(i))) {
202 dbgmsg("init: %s does not respond. initialization failed!\n",init_programs[i]);
203 return 1;
205 //dbgmsg("done\n");
207 if (strcmp(INIT_PROGRAM(i),"iso9660")==0) {
208 // Initial mount of boot device
209 vfs_mount(BOOT_FS,BOOT_MP,BOOT_DEV,BOOT_RO);
210 sleep(1);
214 rpc_func(proc_fork,"i",sizeof(int));
215 rpc_func(proc_exec,"$i",PATH_MAX+sizeof(int));
216 rpc_func_create("computer_shutdown",init_computer_shutdown,"",0);
218 init_run(INIT2_PROGRAM);
220 rpc_mainloop(-1);
222 return 0;