xref: /plan9-contrib/sys/src/9/port/sysfile.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 /*
9  * The sys*() routines needn't poperror() as they return directly to syscall().
10  */
11 
12 int
13 newfd(Chan *c)
14 {
15 	Fgrp *f = u->p->fgrp;
16 	int i;
17 
18 	lock(f);
19 	for(i=0; i<NFD; i++)
20 		if(f->fd[i] == 0){
21 			if(i > f->maxfd)
22 				f->maxfd = i;
23 			f->fd[i] = c;
24 			unlock(f);
25 			return i;
26 		}
27 	unlock(f);
28 	exhausted("file descriptors");
29 	return 0;
30 }
31 
32 Chan*
33 fdtochan(int fd, int mode, int chkmnt, int iref)
34 {
35 	Chan *c;
36 	Fgrp *f;
37 
38 	c = 0;
39 	f = u->p->fgrp;
40 
41 	lock(f);
42 	if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) {
43 		unlock(f);
44 		error(Ebadfd);
45 	}
46 	if(iref)
47 		incref(c);
48 	unlock(f);
49 
50 	if(chkmnt && (c->flag&CMSG)) {
51 		if(iref)
52 			close(c);
53 		error(Ebadusefd);
54 	}
55 
56 	if(mode<0 || c->mode==ORDWR)
57 		return c;
58 
59 	if((mode&OTRUNC) && c->mode==OREAD) {
60 		if(iref)
61 			close(c);
62 		error(Ebadusefd);
63 	}
64 
65 	if((mode&~OTRUNC) != c->mode) {
66 		if(iref)
67 			close(c);
68 		error(Ebadusefd);
69 	}
70 
71 	return c;
72 }
73 
74 int
75 openmode(ulong o)
76 {
77 	if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC))
78 		error(Ebadarg);
79 	o &= ~(OTRUNC|OCEXEC|ORCLOSE);
80 	if(o > OEXEC)
81 		error(Ebadarg);
82 	if(o == OEXEC)
83 		return OREAD;
84 	return o;
85 }
86 
87 long
88 syspipe(ulong *arg)
89 {
90 	int fd[2];
91 	Chan *c[2];
92 	Dev *d;
93 	Fgrp *f = u->p->fgrp;
94 
95 	validaddr(arg[0], 2*BY2WD, 1);
96 	evenaddr(arg[0]);
97 	d = &devtab[devno('|', 0)];
98 	c[0] = (*d->attach)(0);
99 	c[1] = 0;
100 	fd[0] = -1;
101 	fd[1] = -1;
102 	if(waserror()){
103 		close(c[0]);
104 		if(c[1])
105 			close(c[1]);
106 		if(fd[0] >= 0)
107 			f->fd[fd[0]]=0;
108 		if(fd[1] >= 0)
109 			f->fd[fd[1]]=0;
110 		nexterror();
111 	}
112 	c[1] = (*d->clone)(c[0], 0);
113 	(*d->walk)(c[0], "data");
114 	(*d->walk)(c[1], "data1");
115 	c[0] = (*d->open)(c[0], ORDWR);
116 	c[1] = (*d->open)(c[1], ORDWR);
117 	fd[0] = newfd(c[0]);
118 	fd[1] = newfd(c[1]);
119 	((long*)arg[0])[0] = fd[0];
120 	((long*)arg[0])[1] = fd[1];
121 	poperror();
122 	return 0;
123 }
124 
125 long
126 sysdup(ulong *arg)
127 {
128 	int fd;
129 	Chan *c, *oc;
130 	Fgrp *f = u->p->fgrp;
131 
132 	/*
133 	 * Close after dup'ing, so date > #d/1 works
134 	 */
135 	c = fdtochan(arg[0], -1, 0, 1);
136 	fd = arg[1];
137 	if(fd != -1){
138 		if(fd<0 || NFD<=fd) {
139 			close(c);
140 			error(Ebadfd);
141 		}
142 		lock(f);
143 		if(fd > f->maxfd)
144 			f->maxfd = fd;
145 
146 		oc = f->fd[fd];
147 		f->fd[fd] = c;
148 		unlock(f);
149 		if(oc)
150 			close(oc);
151 	}else{
152 		if(waserror()) {
153 			close(c);
154 			nexterror();
155 		}
156 		fd = newfd(c);
157 		poperror();
158 	}
159 
160 	return fd;
161 }
162 
163 long
164 sysopen(ulong *arg)
165 {
166 	int fd;
167 	Chan *c = 0;
168 
169 	openmode(arg[1]);	/* error check only */
170 	if(waserror()){
171 		if(c)
172 			close(c);
173 		nexterror();
174 	}
175 	validaddr(arg[0], 1, 0);
176 	c = namec((char*)arg[0], Aopen, arg[1], 0);
177 	fd = newfd(c);
178 	poperror();
179 	return fd;
180 }
181 
182 void
183 fdclose(int fd, int flag)
184 {
185 	int i;
186 	Chan *c;
187 	Fgrp *f = u->p->fgrp;
188 
189 	lock(f);
190 	c = f->fd[fd];
191 	if(c == 0){
192 		/* can happen for users with shared fd tables */
193 		unlock(f);
194 		return;
195 	}
196 	if(flag){
197 		if(c==0 || !(c->flag&flag)){
198 			unlock(f);
199 			return;
200 		}
201 	}
202 	f->fd[fd] = 0;
203 	if(fd == f->maxfd)
204 		for(i=fd; --i>=0 && f->fd[i]==0; )
205 			f->maxfd = i;
206 
207 	unlock(f);
208 	close(c);
209 }
210 
211 long
212 sysclose(ulong *arg)
213 {
214 	fdtochan(arg[0], -1, 0, 0);
215 	fdclose(arg[0], 0);
216 
217 	return 0;
218 }
219 
220 long
221 unionread(Chan *c, void *va, long n)
222 {
223 	long nr;
224 	Chan *nc;
225 	Pgrp *pg;
226 
227 	pg = u->p->pgrp;
228 	rlock(&pg->ns);
229 
230 	for(;;) {
231 		/* Error causes component of union to be skipped */
232 		if(waserror())
233 			goto next;
234 
235 		nc = clone(c->mnt->to, 0);
236 		poperror();
237 
238 		if(c->mountid != c->mnt->mountid) {
239 			pprint("unionread: changed underfoot?\n");
240 			runlock(&pg->ns);
241 			close(nc);
242 			return 0;
243 		}
244 
245 		if(waserror()) {
246 			close(nc);
247 			goto next;
248 		}
249 
250 		nc = (*devtab[nc->type].open)(nc, OREAD);
251 		nc->offset = c->offset;
252 		nr = (*devtab[nc->type].read)(nc, va, n, nc->offset);
253 		/* devdirread e.g. changes it */
254 		c->offset = nc->offset;
255 		poperror();
256 
257 		close(nc);
258 		if(nr > 0) {
259 			runlock(&pg->ns);
260 			return nr;
261 		}
262 		/* Advance to next element */
263 	next:
264 		c->mnt = c->mnt->next;
265 		if(c->mnt == 0)
266 			break;
267 		c->mountid = c->mnt->mountid;
268 		c->offset = 0;
269 	}
270 	runlock(&pg->ns);
271 	return 0;
272 }
273 
274 long
275 sysread(ulong *arg)
276 {
277 	int dir;
278 	long n;
279 	Chan *c;
280 
281 	validaddr(arg[1], arg[2], 1);
282 	c = fdtochan(arg[0], OREAD, 1, 1);
283 	if(waserror()) {
284 		close(c);
285 		nexterror();
286 	}
287 
288 	n = arg[2];
289 	dir = c->qid.path&CHDIR;
290 
291 	if(dir) {
292 		n -= n%DIRLEN;
293 		if(c->offset%DIRLEN || n==0)
294 			error(Etoosmall);
295 	}
296 
297 	if(dir && c->mnt)
298 		n = unionread(c, (void*)arg[1], n);
299 	else
300 		n = (*devtab[c->type].read)(c, (void*)arg[1], n, c->offset);
301 
302 	lock(c);
303 	c->offset += n;
304 	unlock(c);
305 
306 	poperror();
307 	close(c);
308 
309 	return n;
310 }
311 
312 long
313 syswrite(ulong *arg)
314 {
315 	Chan *c;
316 	long n;
317 
318 	validaddr(arg[1], arg[2], 0);
319 	c = fdtochan(arg[0], OWRITE, 1, 1);
320 	if(waserror()) {
321 		close(c);
322 		nexterror();
323 	}
324 
325 	if(c->qid.path & CHDIR)
326 		error(Eisdir);
327 
328 	n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2], c->offset);
329 
330 	lock(c);
331 	c->offset += n;
332 	unlock(c);
333 
334 	poperror();
335 	close(c);
336 
337 	return n;
338 }
339 
340 long
341 sysseek(ulong *arg)
342 {
343 	Chan *c;
344 	char buf[DIRLEN];
345 	Dir dir;
346 	long off;
347 
348 	c = fdtochan(arg[0], -1, 1, 0);
349 	if(c->qid.path & CHDIR)
350 		error(Eisdir);
351 
352 	if(devchar[c->type] == '|')
353 		error(Eisstream);
354 
355 	off = 0;
356 	switch(arg[2]){
357 	case 0:
358 		off = c->offset = arg[1];
359 		break;
360 
361 	case 1:
362 		lock(c);	/* lock for read/write update */
363 		c->offset += (long)arg[1];
364 		off = c->offset;
365 		unlock(c);
366 		break;
367 
368 	case 2:
369 		(*devtab[c->type].stat)(c, buf);
370 		convM2D(buf, &dir);
371 		c->offset = dir.length + (long)arg[1];
372 		off = c->offset;
373 		break;
374 	}
375 	return off;
376 }
377 
378 long
379 sysfstat(ulong *arg)
380 {
381 	Chan *c;
382 
383 	validaddr(arg[1], DIRLEN, 1);
384 	evenaddr(arg[1]);
385 	c = fdtochan(arg[0], -1, 0, 1);
386 	if(waserror()) {
387 		close(c);
388 		nexterror();
389 	}
390 	(*devtab[c->type].stat)(c, (char*)arg[1]);
391 	poperror();
392 	close(c);
393 	return 0;
394 }
395 
396 long
397 sysstat(ulong *arg)
398 {
399 	Chan *c;
400 
401 	validaddr(arg[1], DIRLEN, 1);
402 	evenaddr(arg[1]);
403 	validaddr(arg[0], 1, 0);
404 	c = namec((char*)arg[0], Aaccess, 0, 0);
405 	if(waserror()){
406 		close(c);
407 		nexterror();
408 	}
409 	(*devtab[c->type].stat)(c, (char*)arg[1]);
410 	poperror();
411 	close(c);
412 	return 0;
413 }
414 
415 long
416 syschdir(ulong *arg)
417 {
418 	Chan *c;
419 
420 	validaddr(arg[0], 1, 0);
421 	c = namec((char*)arg[0], Atodir, 0, 0);
422 	close(u->dot);
423 	u->dot = c;
424 	return 0;
425 }
426 
427 long
428 bindmount(ulong *arg, int ismount)
429 {
430 	Chan *c0, *c1, *bc;
431 	ulong flag;
432 	long ret;
433 	int fd;
434 	struct{
435 		Chan	*chan;
436 		char	*spec;
437 	}bogus;
438 
439 	flag = arg[2];
440 	fd = arg[0];
441 	if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER))
442 		error(Ebadarg);
443 	if(ismount){
444 		bc = fdtochan(fd, 2, 0, 1);
445 		if(waserror()) {
446 			close(bc);
447 			nexterror();
448 		}
449 		bogus.chan = bc;
450 
451 		validaddr(arg[3], 1, 0);
452 		if(vmemchr((char*)arg[3], '\0', NAMELEN) == 0)
453 			error(Ebadarg);
454 
455 		bogus.spec = (char*)arg[3];
456 
457 		ret = devno('M', 0);
458 		c0 = (*devtab[ret].attach)((char*)&bogus);
459 
460 		poperror();
461 		close(bc);
462 	}
463 	else {
464 		validaddr(arg[0], 1, 0);
465 		c0 = namec((char*)arg[0], Aaccess, 0, 0);
466 	}
467 	if(waserror()){
468 		close(c0);
469 		nexterror();
470 	}
471 	validaddr(arg[1], 1, 0);
472 	c1 = namec((char*)arg[1], Amount, 0, 0);
473 	if(waserror()){
474 		close(c1);
475 		nexterror();
476 	}
477 	if((c0->qid.path^c1->qid.path) & CHDIR)
478 		error(Emount);
479 	if(flag && !(c0->qid.path&CHDIR))
480 		error(Emount);
481 	ret = mount(c0, c1, flag);
482 	poperror();
483 	close(c1);
484 	poperror();
485 	close(c0);
486 	if(ismount)
487 		fdclose(fd, 0);
488 	return ret;
489 }
490 
491 long
492 sysbind(ulong *arg)
493 {
494 	return bindmount(arg, 0);
495 }
496 
497 long
498 sysmount(ulong *arg)
499 {
500 	return bindmount(arg, 1);
501 }
502 
503 long
504 sysunmount(ulong *arg)
505 {
506 	Chan *cmount, *cmounted;
507 
508 	cmounted = 0;
509 
510 	validaddr(arg[1], 1, 0);
511 	cmount = namec((char *)arg[1], Amount, 0, 0);
512 
513 	if(arg[0]) {
514 		if(waserror()) {
515 			close(cmount);
516 			nexterror();
517 		}
518 		validaddr(arg[0], 1, 0);
519 		cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
520 		poperror();
521 	}
522 
523 	if(waserror()) {
524 		close(cmount);
525 		if(cmounted)
526 			close(cmounted);
527 		nexterror();
528 	}
529 	unmount(cmount, cmounted);
530 	close(cmount);
531 	if(cmounted)
532 		close(cmounted);
533 	poperror();
534 	return 0;
535 }
536 
537 long
538 syscreate(ulong *arg)
539 {
540 	int fd;
541 	Chan *c = 0;
542 
543 	openmode(arg[1]);	/* error check only */
544 	if(waserror()) {
545 		if(c)
546 			close(c);
547 		nexterror();
548 	}
549 	validaddr(arg[0], 1, 0);
550 	c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
551 	fd = newfd(c);
552 	poperror();
553 	return fd;
554 }
555 
556 long
557 sysremove(ulong *arg)
558 {
559 	Chan *c;
560 
561 	validaddr(arg[0], 1, 0);
562 	c = namec((char*)arg[0], Aaccess, 0, 0);
563 	if(waserror()){
564 		c->type = 0;	/* see below */
565 		close(c);
566 		nexterror();
567 	}
568 	(*devtab[c->type].remove)(c);
569 	/*
570 	 * Remove clunks the fid, but we need to recover the Chan
571 	 * so fake it up.  rootclose() is known to be a nop.
572 	 */
573 	c->type = 0;
574 	poperror();
575 	close(c);
576 	return 0;
577 }
578 
579 long
580 syswstat(ulong *arg)
581 {
582 	Chan *c;
583 
584 	validaddr(arg[1], DIRLEN, 0);
585 	nameok((char*)arg[1]);
586 	validaddr(arg[0], 1, 0);
587 	c = namec((char*)arg[0], Aaccess, 0, 0);
588 	if(waserror()){
589 		close(c);
590 		nexterror();
591 	}
592 	(*devtab[c->type].wstat)(c, (char*)arg[1]);
593 	poperror();
594 	close(c);
595 	return 0;
596 }
597 
598 long
599 sysfwstat(ulong *arg)
600 {
601 	Chan *c;
602 
603 	validaddr(arg[1], DIRLEN, 0);
604 	nameok((char*)arg[1]);
605 	c = fdtochan(arg[0], -1, 1, 1);
606 	if(waserror()) {
607 		close(c);
608 		nexterror();
609 	}
610 	(*devtab[c->type].wstat)(c, (char*)arg[1]);
611 	poperror();
612 	close(c);
613 	return 0;
614 }
615