Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Plan 9 versions of system-specific functions
3
 *	By convention, exported routines herein have names beginning with an
4
 *	upper case letter.
5
 */
6
#include "rc.h"
7
#include "exec.h"
8
#include "io.h"
9
#include "fns.h"
10
#include "getflags.h"
11
 
12
enum {
13
	Maxenvname = 256,	/* undocumented limit */
14
};
15
 
16
char *Signame[] = {
17
	"sigexit",	"sighup",	"sigint",	"sigquit",
18
	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
19
 
20
};
21
char *syssigname[] = {
22
	"exit",		/* can't happen */
23
	"hangup",
24
	"interrupt",
25
	"quit",		/* can't happen */
26
	"alarm",
27
	"kill",
28
	"sys: fp: ",
29
	"term",
30
 
31
};
32
char *Rcmain = "/rc/lib/rcmain";
33
char *Fdprefix = "/fd/";
34
 
35
void execfinit(void);
36
void execbind(void);
37
void execmount(void);
38
void execnewpgrp(void);
39
 
40
builtin Builtin[] = {
41
	"cd",		execcd,
42
	"whatis",	execwhatis,
43
	"eval",		execeval,
44
	"exec",		execexec,	/* but with popword first */
45
	"exit",		execexit,
46
	"shift",	execshift,
47
	"wait",		execwait,
48
	".",		execdot,
49
	"finit",	execfinit,
50
	"flag",		execflag,
51
	"rfork",	execnewpgrp,
52
 
53
};
54
 
55
void
56
execnewpgrp(void)
57
{
58
	int arg;
59
	char *s;
60
	switch(count(runq->argv->words)){
61
	case 1:
62
		arg = RFENVG|RFNAMEG|RFNOTEG;
63
		break;
64
	case 2:
65
		arg = 0;
66
		for(s = runq->argv->words->next->word;*s;s++) switch(*s){
67
		default:
68
			goto Usage;
69
		case 'n':
70
			arg|=RFNAMEG;  break;
71
		case 'N':
72
			arg|=RFCNAMEG;
73
			break;
74
		case 'm':
75
			arg|=RFNOMNT;  break;
76
		case 'e':
77
			arg|=RFENVG;   break;
78
		case 'E':
79
			arg|=RFCENVG;  break;
80
		case 's':
81
			arg|=RFNOTEG;  break;
82
		case 'f':
83
			arg|=RFFDG;    break;
84
		case 'F':
85
			arg|=RFCFDG;   break;
86
		}
87
		break;
88
	default:
89
	Usage:
90
		pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
91
		setstatus("rfork usage");
92
		poplist();
93
		return;
94
	}
95
	if(rfork(arg)==-1){
96
		pfmt(err, "rc: %s failed\n", runq->argv->words->word);
97
		setstatus("rfork failed");
98
	}
99
	else
100
		setstatus("");
101
	poplist();
102
}
103
 
104
void
105
Vinit(void)
106
{
107
	int dir, f, len, i, n, nent;
108
	char *buf, *s;
109
	char envname[Maxenvname];
110
	word *val;
111
	Dir *ent;
112
 
113
	dir = open("/env", OREAD);
114
	if(dir<0){
115
		pfmt(err, "rc: can't open /env: %r\n");
116
		return;
117
	}
118
	ent = nil;
119
	for(;;){
120
		nent = dirread(dir, &ent);
121
		if(nent <= 0)
122
			break;
123
		for(i = 0; i<nent; i++){
124
			len = ent[i].length;
125
			if(len && strncmp(ent[i].name, "fn#", 3)!=0){
126
				snprint(envname, sizeof envname, "/env/%s", ent[i].name);
127
				if((f = open(envname, 0))>=0){
128
					buf = emalloc(len+1);
129
					n = readn(f, buf, len);
130
					if (n <= 0)
131
						buf[0] = '\0';
132
					else
133
						buf[n] = '\0';
134
					val = 0;
135
					/* Charitably add a 0 at the end if need be */
136
					if(buf[len-1])
137
						buf[len++]='\0';
138
					s = buf+len-1;
139
					for(;;){
140
						while(s!=buf && s[-1]!='\0') --s;
141
						val = newword(s, val);
142
						if(s==buf)
143
							break;
144
						--s;
145
					}
146
					setvar(ent[i].name, val);
147
					vlook(ent[i].name)->changed = 0;
148
					close(f);
149
					efree(buf);
150
				}
151
			}
152
		}
153
		free(ent);
154
	}
155
	close(dir);
156
}
157
int envdir;
158
 
159
void
160
Xrdfn(void)
161
{
162
	int f, len;
163
	Dir *e;
164
	char envname[Maxenvname];
165
	static Dir *ent, *allocent;
166
	static int nent;
167
 
168
	for(;;){
169
		if(nent == 0){
170
			free(allocent);
171
			nent = dirread(envdir, &allocent);
172
			ent = allocent;
173
		}
174
		if(nent <= 0)
175
			break;
176
		while(nent){
177
			e = ent++;
178
			nent--;
179
			len = e->length;
180
			if(len && strncmp(e->name, "fn#", 3)==0){
181
				snprint(envname, sizeof envname, "/env/%s", e->name);
182
				if((f = open(envname, 0))>=0){
183
					execcmds(openfd(f));
184
					return;
185
				}
186
			}
187
		}
188
	}
189
	close(envdir);
190
	Xreturn();
191
}
192
union code rdfns[4];
193
 
194
void
195
execfinit(void)
196
{
197
	static int first = 1;
198
	if(first){
199
		rdfns[0].i = 1;
200
		rdfns[1].f = Xrdfn;
201
		rdfns[2].f = Xjump;
202
		rdfns[3].i = 1;
203
		first = 0;
204
	}
205
	Xpopm();
206
	envdir = open("/env", 0);
207
	if(envdir<0){
208
		pfmt(err, "rc: can't open /env: %r\n");
209
		return;
210
	}
211
	start(rdfns, 1, runq->local);
212
}
213
 
214
int
215
Waitfor(int pid, int)
216
{
217
	thread *p;
218
	Waitmsg *w;
219
	char errbuf[ERRMAX];
220
 
221
	if(pid >= 0 && !havewaitpid(pid))
222
		return 0;
223
 
224
	while((w = wait()) != nil){
225
		delwaitpid(w->pid);
226
		if(w->pid==pid){
227
			setstatus(w->msg);
228
			free(w);
229
			return 0;
230
		}
231
		for(p = runq->ret;p;p = p->ret)
232
			if(p->pid==w->pid){
233
				p->pid=-1;
234
				strcpy(p->status, w->msg);
235
			}
236
		free(w);
237
	}
238
 
239
	errstr(errbuf, sizeof errbuf);
240
	if(strcmp(errbuf, "interrupted")==0) return -1;
241
	return 0;
242
}
243
 
244
char **
245
mkargv(word *a)
246
{
247
	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
248
	char **argp = argv+1;	/* leave one at front for runcoms */
249
	for(;a;a = a->next) *argp++=a->word;
250
	*argp = 0;
251
	return argv;
252
}
253
 
254
void
255
addenv(var *v)
256
{
257
	char envname[Maxenvname];
258
	word *w;
259
	int f;
260
	io *fd;
261
	if(v->changed){
262
		v->changed = 0;
263
		snprint(envname, sizeof envname, "/env/%s", v->name);
264
		if((f = Creat(envname))<0)
265
			pfmt(err, "rc: can't open %s: %r\n", envname);
266
		else{
267
			for(w = v->val;w;w = w->next)
268
				write(f, w->word, strlen(w->word)+1L);
269
			close(f);
270
		}
271
	}
272
	if(v->fnchanged){
273
		v->fnchanged = 0;
274
		snprint(envname, sizeof envname, "/env/fn#%s", v->name);
275
		if((f = Creat(envname))<0)
276
			pfmt(err, "rc: can't open %s: %r\n", envname);
277
		else{
278
			if(v->fn){
279
				fd = openfd(f);
280
				pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
281
				closeio(fd);
282
			}
283
			close(f);
284
		}
285
	}
286
}
287
 
288
void
289
updenvlocal(var *v)
290
{
291
	if(v){
292
		updenvlocal(v->next);
293
		addenv(v);
294
	}
295
}
296
 
297
void
298
Updenv(void)
299
{
300
	var *v, **h;
301
	for(h = gvar;h!=&gvar[NVAR];h++)
302
		for(v=*h;v;v = v->next)
303
			addenv(v);
304
	if(runq)
305
		updenvlocal(runq->local);
306
}
307
 
308
/* not used on plan 9 */
309
int
310
ForkExecute(char *file, char **argv, int sin, int sout, int serr)
311
{
312
	int pid;
313
 
314
	if(access(file, 1) != 0)
315
		return -1;
316
	switch(pid = fork()){
317
	case -1:
318
		return -1;
319
	case 0:
320
		if(sin >= 0)
321
			dup(sin, 0);
322
		else
323
			close(0);
324
		if(sout >= 0)
325
			dup(sout, 1);
326
		else
327
			close(1);
328
		if(serr >= 0)
329
			dup(serr, 2);
330
		else
331
			close(2);
332
		exec(file, argv);
333
		exits(file);
334
	}
335
	return pid;
336
}
337
 
338
void
339
Execute(word *args, word *path)
340
{
341
	char **argv = mkargv(args);
342
	char file[1024], errstr[1024];
343
	int nc;
344
 
345
	Updenv();
346
	errstr[0] = '\0';
347
	for(;path;path = path->next){
348
		nc = strlen(path->word);
349
		if(nc < sizeof file - 1){	/* 1 for / */
350
			strcpy(file, path->word);
351
			if(file[0]){
352
				strcat(file, "/");
353
				nc++;
354
			}
355
			if(nc + strlen(argv[1]) < sizeof file){
356
				strcat(file, argv[1]);
357
				exec(file, argv+1);
358
				rerrstr(errstr, sizeof errstr);
359
				/*
360
				 * if file exists and is executable, exec should
361
				 * have worked, unless it's a directory or an
362
				 * executable for another architecture.  in
363
				 * particular, if it failed due to lack of
364
				 * swap/vm (e.g., arg. list too long) or other
365
				 * allocation failure, stop searching and print
366
				 * the reason for failure.
367
				 */
368
				if (strstr(errstr, " allocat") != nil ||
369
				    strstr(errstr, " full") != nil)
370
					break;
371
			}
372
			else werrstr("command name too long");
373
		}
374
	}
375
	pfmt(err, "%s: %s\n", argv[1], errstr);
376
	efree((char *)argv);
377
}
378
#define	NDIR	256		/* shoud be a better way */
379
 
380
int
381
Globsize(char *p)
382
{
383
	int isglob = 0, globlen = NDIR+1;
384
	for(;*p;p++){
385
		if(*p==GLOB){
386
			p++;
387
			if(*p!=GLOB)
388
				isglob++;
389
			globlen+=*p=='*'?NDIR:1;
390
		}
391
		else
392
			globlen++;
393
	}
394
	return isglob?globlen:0;
395
}
396
#define	NFD	50
397
 
398
struct{
399
	Dir	*dbuf;
400
	int	i;
401
	int	n;
402
}dir[NFD];
403
 
404
int
405
Opendir(char *name)
406
{
407
	Dir *db;
408
	int f;
409
	f = open(name, 0);
410
	if(f==-1)
411
		return f;
412
	db = dirfstat(f);
413
	if(db!=nil && (db->mode&DMDIR)){
414
		if(f<NFD){
415
			dir[f].i = 0;
416
			dir[f].n = 0;
417
		}
418
		free(db);
419
		return f;
420
	}
421
	free(db);
422
	close(f);
423
	return -1;
424
}
425
 
426
static int
427
trimdirs(Dir *d, int nd)
428
{
429
	int r, w;
430
 
431
	for(r=w=0; r<nd; r++)
432
		if(d[r].mode&DMDIR)
433
			d[w++] = d[r];
434
	return w;
435
}
436
 
437
/*
438
 * onlydirs is advisory -- it means you only
439
 * need to return the directories.  it's okay to
440
 * return files too (e.g., on unix where you can't
441
 * tell during the readdir), but that just makes 
442
 * the globber work harder.
443
 */
444
int
445
Readdir(int f, void *p, int onlydirs)
446
{
447
	int n;
448
 
449
	if(f<0 || f>=NFD)
450
		return 0;
451
Again:
452
	if(dir[f].i==dir[f].n){	/* read */
453
		free(dir[f].dbuf);
454
		dir[f].dbuf = 0;
455
		n = dirread(f, &dir[f].dbuf);
456
		if(n>0){
457
			if(onlydirs){
458
				n = trimdirs(dir[f].dbuf, n);
459
				if(n == 0)
460
					goto Again;
461
			}	
462
			dir[f].n = n;
463
		}else
464
			dir[f].n = 0;
465
		dir[f].i = 0;
466
	}
467
	if(dir[f].i == dir[f].n)
468
		return 0;
469
	strcpy(p, dir[f].dbuf[dir[f].i].name);
470
	dir[f].i++;
471
	return 1;
472
}
473
 
474
void
475
Closedir(int f)
476
{
477
	if(f>=0 && f<NFD){
478
		free(dir[f].dbuf);
479
		dir[f].i = 0;
480
		dir[f].n = 0;
481
		dir[f].dbuf = 0;
482
	}
483
	close(f);
484
}
485
int interrupted = 0;
486
void
487
notifyf(void*, char *s)
488
{
489
	int i;
490
	for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
491
		if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
492
		goto Out;
493
	}
494
	pfmt(err, "rc: note: %s\n", s);
495
	noted(NDFLT);
496
	return;
497
Out:
498
	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
499
		trap[i]++;
500
		ntrap++;
501
	}
502
	if(ntrap>=32){	/* rc is probably in a trap loop */
503
		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
504
		abort();
505
	}
506
	noted(NCONT);
507
}
508
 
509
void
510
Trapinit(void)
511
{
512
	notify(notifyf);
513
}
514
 
515
void
516
Unlink(char *name)
517
{
518
	remove(name);
519
}
520
 
521
long
522
Write(int fd, void *buf, long cnt)
523
{
524
	return write(fd, buf, cnt);
525
}
526
 
527
long
528
Read(int fd, void *buf, long cnt)
529
{
530
	return read(fd, buf, cnt);
531
}
532
 
533
long
534
Seek(int fd, long cnt, long whence)
535
{
536
	return seek(fd, cnt, whence);
537
}
538
 
539
int
540
Executable(char *file)
541
{
542
	Dir *statbuf;
543
	int ret;
544
 
545
	statbuf = dirstat(file);
546
	if(statbuf == nil)
547
		return 0;
548
	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
549
	free(statbuf);
550
	return ret;
551
}
552
 
553
int
554
Creat(char *file)
555
{
556
	return create(file, 1, 0666L);
557
}
558
 
559
int
560
Dup(int a, int b)
561
{
562
	return dup(a, b);
563
}
564
 
565
int
566
Dup1(int)
567
{
568
	return -1;
569
}
570
 
571
void
572
Exit(char *stat)
573
{
574
	Updenv();
575
	setstatus(stat);
576
	exits(truestatus()?"":getstatus());
577
}
578
 
579
int
580
Eintr(void)
581
{
582
	return interrupted;
583
}
584
 
585
void
586
Noerror(void)
587
{
588
	interrupted = 0;
589
}
590
 
591
int
592
Isatty(int fd)
593
{
594
	char buf[64];
595
 
596
	if(fd2path(fd, buf, sizeof buf) != 0)
597
		return 0;
598
 
599
	/* might be #c/cons during boot - fixed 22 april 2005, remove this later */
600
	if(strcmp(buf, "#c/cons") == 0)
601
		return 1;
602
 
603
	/* might be /mnt/term/dev/cons */
604
	return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
605
}
606
 
607
void
608
Abort(void)
609
{
610
	pfmt(err, "aborting\n");
611
	flush(err);
612
	Exit("aborting");
613
}
614
 
615
void
616
Memcpy(void *a, void *b, long n)
617
{
618
	memmove(a, b, n);
619
}
620
 
621
void*
622
Malloc(ulong n)
623
{
624
	return mallocz(n, 1);
625
}
626
 
627
int *waitpids;
628
int nwaitpids;
629
 
630
void
631
addwaitpid(int pid)
632
{
633
	waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
634
	if(waitpids == 0)
635
		panic("Can't realloc %d waitpids", nwaitpids+1);
636
	waitpids[nwaitpids++] = pid;
637
}
638
 
639
void
640
delwaitpid(int pid)
641
{
642
	int r, w;
643
 
644
	for(r=w=0; r<nwaitpids; r++)
645
		if(waitpids[r] != pid)
646
			waitpids[w++] = waitpids[r];
647
	nwaitpids = w;
648
}
649
 
650
void
651
clearwaitpids(void)
652
{
653
	nwaitpids = 0;
654
}
655
 
656
int
657
havewaitpid(int pid)
658
{
659
	int i;
660
 
661
	for(i=0; i<nwaitpids; i++)
662
		if(waitpids[i] == pid)
663
			return 1;
664
	return 0;
665
}
666
 
667
/* avoid loading any floating-point library code */
668
int
669
_efgfmt(Fmt *)
670
{
671
	return -1;
672
}