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