+ exec* functions
[meinos.git] / apps / init / init.c
blob157d0b9ade76bed63655b0c7eaf2451b7ba92f5c
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 // Change process
154 char *_file = strdup(file);
155 proc_setname(rpc_curpid,basename(_file));
156 proc_setvar(rpc_curpid,var);
158 // Load executable
159 exe_t *exe = exe_create(file);
160 if (exe!=NULL) {
161 // Remove old addrspace
162 size_t num_pages,i;
163 void **pages = proc_mempagelist(rpc_curpid,&num_pages);
164 if (pages!=NULL) {
165 for (i=0;i<num_pages;i++) proc_memfree(rpc_curpid,pages[i]);
168 void *entrypoint = exe_load(exe,rpc_curpid);
170 if (entrypoint!=NULL) {
171 proc_jump(rpc_curpid,entrypoint);
172 proc_createstack(rpc_curpid);
174 else {
175 dbgmsg("failed loading executable!");
176 dbgmsg("TODO: destroy process\n");
177 while (1);
180 exe_destroy(exe);
181 return 0;
183 else return errno;
186 static void init_computer_shutdown() {
187 pid_t child;
188 while ((child = getchild(0))!=-1) kill(child,SIGKILL);
189 exit(0);
192 int main(int argc,char *argv[]) {
193 size_t i;
195 init_init();
196 for (i=0;INIT_PROGRAM(i);i++) {
197 //dbgmsg("init: starting %s...",INIT_PROGRAM(i));
198 init_run(INIT_PROGRAM(i));
200 if (!init_wait(INIT_PROGRAM(i))) {
201 dbgmsg("init: %s does not respond. initialization failed!\n",init_programs[i]);
202 return 1;
204 //dbgmsg("done\n");
206 if (strcmp(INIT_PROGRAM(i),"iso9660")==0) {
207 // Initial mount of boot device
208 vfs_mount(BOOT_FS,BOOT_MP,BOOT_DEV,BOOT_RO);
209 sleep(1);
213 rpc_func(proc_fork,"i",sizeof(int));
214 rpc_func(proc_exec,"$i",PATH_MAX+sizeof(int));
215 rpc_func_create("computer_shutdown",init_computer_shutdown,"",0);
217 init_run(INIT2_PROGRAM);
219 rpc_mainloop(-1);
221 return 0;