xref: /plan9/sys/src/cmd/init.c (revision f19e7b749ec99577072cd8e44030fe810f42c7ad)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <authsrv.h>
5 
6 char*	readenv(char*);
7 void	setenv(char*, char*);
8 void	cpenv(char*, char*);
9 void	closefds(void);
10 void	fexec(void(*)(void));
11 void	rcexec(void);
12 void	cpustart(void);
13 void	pass(int);
14 
15 char	*service;
16 char	*cmd;
17 char	*cpu;
18 char	*systemname;
19 int	manual;
20 int	iscpu;
21 
22 void
23 main(int argc, char *argv[])
24 {
25 	char *user;
26 	int fd;
27 	char ctl[128];
28 
29 	closefds();
30 
31 	service = "cpu";
32 	manual = 0;
33 	ARGBEGIN{
34 	case 'c':
35 		service = "cpu";
36 		break;
37 	case 'm':
38 		manual = 1;
39 		break;
40 	case 't':
41 		service = "terminal";
42 		break;
43 	}ARGEND
44 	cmd = *argv;
45 
46 	snprint(ctl, sizeof(ctl), "#p/%d/ctl", getpid());
47 	fd = open(ctl, OWRITE);
48 	if(fd < 0)
49 		print("init: warning: can't open %s: %r\n", ctl);
50 	else
51 		if(write(fd, "pri 10", 6) != 6)
52 			print("init: warning: can't set priority: %r\n");
53 	close(fd);
54 
55 	cpu = readenv("#e/cputype");
56 	setenv("#e/objtype", cpu);
57 	setenv("#e/service", service);
58 	cpenv("/adm/timezone/local", "#e/timezone");
59 	user = readenv("#c/user");
60 	systemname = readenv("#c/sysname");
61 
62 	newns(user, 0);
63 	iscpu = strcmp(service, "cpu")==0;
64 
65 	if(iscpu && manual == 0)
66 		fexec(cpustart);
67 
68 	for(;;){
69 		print("\ninit: starting /bin/rc\n");
70 		fexec(rcexec);
71 		manual = 1;
72 		cmd = 0;
73 		sleep(1000);
74 	}
75 }
76 
77 void
78 pass(int fd)
79 {
80 	char key[DESKEYLEN];
81 	char typed[32];
82 	char crypted[DESKEYLEN];
83 	int i;
84 
85 	for(;;){
86 		print("\n%s password:", systemname);
87 		for(i=0; i<sizeof typed; i++){
88 			if(read(0, typed+i, 1) != 1){
89 				print("init: can't read password; insecure\n");
90 				return;
91 			}
92 			if(typed[i] == '\n'){
93 				typed[i] = 0;
94 				break;
95 			}
96 		}
97 		if(i == sizeof typed)
98 			continue;
99 		if(passtokey(crypted, typed) == 0)
100 			continue;
101 		seek(fd, 0, 0);
102 		if(read(fd, key, DESKEYLEN) != DESKEYLEN){
103 			print("init: can't read key; insecure\n");
104 			return;
105 		}
106 		if(memcmp(crypted, key, sizeof key))
107 			continue;
108 		/* clean up memory */
109 		memset(crypted, 0, sizeof crypted);
110 		memset(key, 0, sizeof key);
111 		return;
112 	}
113 }
114 
115 static int gotnote;
116 
117 void
118 pinhead(void*, char *msg)
119 {
120 	gotnote = 1;
121 	fprint(2, "init got note '%s'\n", msg);
122 	noted(NCONT);
123 }
124 
125 void
126 fexec(void (*execfn)(void))
127 {
128 	Waitmsg *w;
129 	int pid;
130 
131 	switch(pid=fork()){
132 	case 0:
133 		rfork(RFNOTEG);
134 		(*execfn)();
135 		print("init: exec error: %r\n");
136 		exits("exec");
137 	case -1:
138 		print("init: fork error: %r\n");
139 		exits("fork");
140 	default:
141 	casedefault:
142 		notify(pinhead);
143 		gotnote = 0;
144 		w = wait();
145 		if(w == nil){
146 			if(gotnote)
147 				goto casedefault;
148 			print("init: wait error: %r\n");
149 			break;
150 		}
151 		if(w->pid != pid){
152 			free(w);
153 			goto casedefault;
154 		}
155 		if(strstr(w->msg, "exec error") != 0){
156 			print("init: exit string %s\n", w->msg);
157 			print("init: sleeping because exec failed\n");
158 			free(w);
159 			for(;;)
160 				sleep(1000);
161 		}
162 		if(w->msg[0])
163 			print("init: rc exit status: %s\n", w->msg);
164 		free(w);
165 		break;
166 	}
167 }
168 
169 void
170 rcexec(void)
171 {
172 	if(cmd)
173 		execl("/bin/rc", "rc", "-c", cmd, nil);
174 	else if(manual || iscpu)
175 		execl("/bin/rc", "rc", nil);
176 	else if(strcmp(service, "terminal") == 0)
177 		execl("/bin/rc", "rc", "-c", ". /rc/bin/termrc; home=/usr/$user; cd; . lib/profile", nil);
178 	else
179 		execl("/bin/rc", "rc", nil);
180 }
181 
182 void
183 cpustart(void)
184 {
185 	execl("/bin/rc", "rc", "-c", "/rc/bin/cpurc", nil);
186 }
187 
188 char*
189 readenv(char *name)
190 {
191 	int f, len;
192 	Dir *d;
193 	char *val;
194 
195 	f = open(name, OREAD);
196 	if(f < 0){
197 		print("init: can't open %s: %r\n", name);
198 		return "*unknown*";
199 	}
200 	d = dirfstat(f);
201 	if(d == nil){
202 		print("init: can't stat %s: %r\n", name);
203 		return "*unknown*";
204 	}
205 	len = d->length;
206 	free(d);
207 	if(len == 0)	/* device files can be zero length but have contents */
208 		len = 64;
209 	val = malloc(len+1);
210 	if(val == nil){
211 		print("init: can't malloc %s: %r\n", name);
212 		return "*unknown*";
213 	}
214 	len = read(f, val, len);
215 	close(f);
216 	if(len < 0){
217 		print("init: can't read %s: %r\n", name);
218 		return "*unknown*";
219 	}else
220 		val[len] = '\0';
221 	return val;
222 }
223 
224 void
225 setenv(char *var, char *val)
226 {
227 	int fd;
228 
229 	fd = create(var, OWRITE, 0644);
230 	if(fd < 0)
231 		print("init: can't open %s\n", var);
232 	else{
233 		fprint(fd, val);
234 		close(fd);
235 	}
236 }
237 
238 void
239 cpenv(char *file, char *var)
240 {
241 	int i, fd;
242 	char buf[8192];
243 
244 	fd = open(file, OREAD);
245 	if(fd < 0)
246 		print("init: can't open %s\n", file);
247 	else{
248 		i = read(fd, buf, sizeof(buf)-1);
249 		if(i <= 0)
250 			print("init: can't read %s: %r\n", file);
251 		else{
252 			close(fd);
253 			buf[i] = 0;
254 			setenv(var, buf);
255 		}
256 	}
257 }
258 
259 /*
260  *  clean up after /boot
261  */
262 void
263 closefds(void)
264 {
265 	int i;
266 
267 	for(i = 3; i < 30; i++)
268 		close(i);
269 }
270