1 #include <sys/types.h>
2 #include <time.h>
3 #include <termios.h>
4 #include <signal.h>
5 #include <pwd.h>
6 #include <sched.h>
7 #include <sys/resource.h>
8 #include <sys/wait.h>
9 #include <sys/time.h>
10
11 #include <stdint.h>
12
13 #include "dat.h"
14 #include "fns.h"
15 #include "error.h"
16
17 #include <semaphore.h>
18
19 #include <raise.h>
20
21 /* glibc 2.3.3-NTPL messes up getpid() by trying to cache the result, so we'll do it ourselves */
22 #include <sys/syscall.h>
23 #define getpid() syscall(SYS_getpid)
24
25 enum
26 {
27 DELETE = 0x7f,
28 CTRLC = 'C'-'@',
29 NSTACKSPERALLOC = 16,
30 X11STACK= 256*1024
31 };
32 char *hosttype = "Linux";
33
34 typedef sem_t Sem;
35
36 extern int dflag;
37
38 int gidnobody = -1;
39 int uidnobody = -1;
40 static struct termios tinit;
41
42 static void
sysfault(char * what,void * addr)43 sysfault(char *what, void *addr)
44 {
45 char buf[64];
46
47 snprint(buf, sizeof(buf), "sys: %s%#p", what, addr);
48 disfault(nil, buf);
49 }
50
51 static void
trapILL(int signo,siginfo_t * si,void * a)52 trapILL(int signo, siginfo_t *si, void *a)
53 {
54 USED(signo);
55 USED(a);
56 sysfault("illegal instruction pc=", si->si_addr);
57 }
58
59 static int
isnilref(siginfo_t * si)60 isnilref(siginfo_t *si)
61 {
62 return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512);
63 }
64
65 static void
trapmemref(int signo,siginfo_t * si,void * a)66 trapmemref(int signo, siginfo_t *si, void *a)
67 {
68 USED(a); /* ucontext_t*, could fetch pc in machine-dependent way */
69 if(isnilref(si))
70 disfault(nil, exNilref);
71 else if(signo == SIGBUS)
72 sysfault("bad address addr=", si->si_addr); /* eg, misaligned */
73 else
74 sysfault("segmentation violation addr=", si->si_addr);
75 }
76
77 static void
trapFPE(int signo,siginfo_t * si,void * a)78 trapFPE(int signo, siginfo_t *si, void *a)
79 {
80 char buf[64];
81
82 USED(signo);
83 USED(a);
84 snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux pc=%#p", getfsr(), si->si_addr);
85 disfault(nil, buf);
86 }
87
88 static void
trapUSR1(int signo)89 trapUSR1(int signo)
90 {
91 int intwait;
92
93 USED(signo);
94
95 intwait = up->intwait;
96 up->intwait = 0; /* clear it to let proc continue in osleave */
97
98 if(up->type != Interp) /* Used to unblock pending I/O */
99 return;
100
101 if(intwait == 0) /* Not posted so it's a sync error */
102 disfault(nil, Eintr); /* Should never happen */
103 }
104
105 void
oslongjmp(void * regs,osjmpbuf env,int val)106 oslongjmp(void *regs, osjmpbuf env, int val)
107 {
108 USED(regs);
109 siglongjmp(env, val);
110 }
111
112 static void
termset(void)113 termset(void)
114 {
115 struct termios t;
116
117 tcgetattr(0, &t);
118 tinit = t;
119 t.c_lflag &= ~(ICANON|ECHO|ISIG);
120 t.c_cc[VMIN] = 1;
121 t.c_cc[VTIME] = 0;
122 tcsetattr(0, TCSANOW, &t);
123 }
124
125 static void
termrestore(void)126 termrestore(void)
127 {
128 tcsetattr(0, TCSANOW, &tinit);
129 }
130
131 void
cleanexit(int x)132 cleanexit(int x)
133 {
134 USED(x);
135
136 if(up->intwait) {
137 up->intwait = 0;
138 return;
139 }
140
141 if(dflag == 0)
142 termrestore();
143
144 kill(0, SIGKILL);
145 exit(0);
146 }
147
148 void
osreboot(char * file,char ** argv)149 osreboot(char *file, char **argv)
150 {
151 if(dflag == 0)
152 termrestore();
153 execvp(file, argv);
154 error("reboot failure");
155 }
156
157 void
libinit(char * imod)158 libinit(char *imod)
159 {
160 struct sigaction act;
161 struct passwd *pw;
162 Proc *p;
163 char sys[64];
164
165 setsid();
166
167 gethostname(sys, sizeof(sys));
168 kstrdup(&ossysname, sys);
169 pw = getpwnam("nobody");
170 if(pw != nil) {
171 uidnobody = pw->pw_uid;
172 gidnobody = pw->pw_gid;
173 }
174
175 if(dflag == 0)
176 termset();
177
178 memset(&act, 0, sizeof(act));
179 act.sa_handler = trapUSR1;
180 sigaction(SIGUSR1, &act, nil);
181
182 act.sa_handler = SIG_IGN;
183 sigaction(SIGCHLD, &act, nil);
184
185 /*
186 * For the correct functioning of devcmd in the
187 * face of exiting slaves
188 */
189 signal(SIGPIPE, SIG_IGN);
190 if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
191 signal(SIGTERM, cleanexit);
192 if(signal(SIGINT, SIG_IGN) != SIG_IGN)
193 signal(SIGINT, cleanexit);
194
195 if(sflag == 0) {
196 act.sa_flags = SA_SIGINFO;
197 act.sa_sigaction = trapILL;
198 sigaction(SIGILL, &act, nil);
199 act.sa_sigaction = trapFPE;
200 sigaction(SIGFPE, &act, nil);
201 act.sa_sigaction = trapmemref;
202 sigaction(SIGBUS, &act, nil);
203 sigaction(SIGSEGV, &act, nil);
204 act.sa_flags &= ~SA_SIGINFO;
205 }
206
207 p = newproc();
208 kprocinit(p);
209
210 pw = getpwuid(getuid());
211 if(pw != nil)
212 kstrdup(&eve, pw->pw_name);
213 else
214 print("cannot getpwuid\n");
215
216 p->env->uid = getuid();
217 p->env->gid = getgid();
218
219 emuinit(imod);
220 }
221
222 int
readkbd(void)223 readkbd(void)
224 {
225 int n;
226 char buf[1];
227
228 n = read(0, buf, sizeof(buf));
229 if(n < 0)
230 print("keyboard close (n=%d, %s)\n", n, strerror(errno));
231 if(n <= 0)
232 pexit("keyboard thread", 0);
233
234 switch(buf[0]) {
235 case '\r':
236 buf[0] = '\n';
237 break;
238 case DELETE:
239 buf[0] = 'H' - '@';
240 break;
241 case CTRLC:
242 cleanexit(0);
243 break;
244 }
245 return buf[0];
246 }
247
248 /*
249 * Return an abitrary millisecond clock time
250 */
251 long
osmillisec(void)252 osmillisec(void)
253 {
254 static long sec0 = 0, usec0;
255 struct timeval t;
256
257 if(gettimeofday(&t,(struct timezone*)0)<0)
258 return 0;
259
260 if(sec0 == 0) {
261 sec0 = t.tv_sec;
262 usec0 = t.tv_usec;
263 }
264 return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
265 }
266
267 /*
268 * Return the time since the epoch in nanoseconds and microseconds
269 * The epoch is defined at 1 Jan 1970
270 */
271 vlong
osnsec(void)272 osnsec(void)
273 {
274 struct timeval t;
275
276 gettimeofday(&t, nil);
277 return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
278 }
279
280 vlong
osusectime(void)281 osusectime(void)
282 {
283 struct timeval t;
284
285 gettimeofday(&t, nil);
286 return (vlong)t.tv_sec * 1000000 + t.tv_usec;
287 }
288
289 int
osmillisleep(ulong milsec)290 osmillisleep(ulong milsec)
291 {
292 struct timespec time;
293
294 time.tv_sec = milsec/1000;
295 time.tv_nsec= (milsec%1000)*1000000;
296 nanosleep(&time, NULL);
297 return 0;
298 }
299
300 int
limbosleep(ulong milsec)301 limbosleep(ulong milsec)
302 {
303 return osmillisleep(milsec);
304 }
305