xref: /plan9/sys/src/cmd/unix/drawterm/kern/unused/syscall.c (revision bd2f137306843ada51788e7326a4138ee3a27647)
1 #include	"u.h"
2 #include	"lib.h"
3 #include	"dat.h"
4 #include	"fns.h"
5 #include	"error.h"
6 
7 Chan*
fdtochan(int fd,int mode,int chkmnt,int iref)8 fdtochan(int fd, int mode, int chkmnt, int iref)
9 {
10 	Fgrp *f;
11 	Chan *c;
12 
13 	c = 0;
14 	f = up->fgrp;
15 
16 	lock(&f->ref.lk);
17 	if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) {
18 		unlock(&f->ref.lk);
19 		error(Ebadfd);
20 	}
21 	if(iref)
22 		refinc(&c->ref);
23 	unlock(&f->ref.lk);
24 
25 	if(chkmnt && (c->flag&CMSG))
26 		goto bad;
27 	if(mode<0 || c->mode==ORDWR)
28 		return c;
29 	if((mode&OTRUNC) && c->mode==OREAD)
30 		goto bad;
31 	if((mode&~OTRUNC) != c->mode)
32 		goto bad;
33 	return c;
34 bad:
35 	if(iref)
36 		cclose(c);
37 	error(Ebadusefd);
38 	return nil; /* shut up compiler */
39 }
40 
41 static void
fdclose(int fd,int flag)42 fdclose(int fd, int flag)
43 {
44 	int i;
45 	Chan *c;
46 	Fgrp *f;
47 
48 	f = up->fgrp;
49 
50 	lock(&f->ref.lk);
51 	c = f->fd[fd];
52 	if(c == 0) {
53 		unlock(&f->ref.lk);
54 		return;
55 	}
56 	if(flag) {
57 		if(c==0 || !(c->flag&flag)) {
58 			unlock(&f->ref.lk);
59 			return;
60 		}
61 	}
62 	f->fd[fd] = 0;
63 	if(fd == f->maxfd)
64 		for(i=fd; --i>=0 && f->fd[i]==0; )
65 			f->maxfd = i;
66 
67 	unlock(&f->ref.lk);
68 	cclose(c);
69 }
70 
71 static int
newfd(Chan * c)72 newfd(Chan *c)
73 {
74 	int i;
75 	Fgrp *f;
76 
77 	f = up->fgrp;
78 	lock(&f->ref.lk);
79 	for(i=0; i<NFD; i++)
80 		if(f->fd[i] == 0){
81 			if(i > f->maxfd)
82 				f->maxfd = i;
83 			f->fd[i] = c;
84 			unlock(&f->ref.lk);
85 			return i;
86 		}
87 	unlock(&f->ref.lk);
88 	error("no file descriptors");
89 	return 0;
90 }
91 
92 int
sysclose(int fd)93 sysclose(int fd)
94 {
95 	if(waserror())
96 		return -1;
97 
98 	fdtochan(fd, -1, 0, 0);
99 	fdclose(fd, 0);
100 	poperror();
101 	return 0;
102 }
103 
104 int
syscreate(char * path,int mode,ulong perm)105 syscreate(char *path, int mode, ulong perm)
106 {
107 	int fd;
108 	Chan *c = 0;
109 
110 	if(waserror()) {
111 		cclose(c);
112 		return -1;
113 	}
114 
115 	openmode(mode);			/* error check only */
116 	c = namec(path, Acreate, mode, perm);
117 	fd = newfd((Chan*)c);
118 	poperror();
119 	return fd;
120 }
121 
122 int
sysdup(int old,int new)123 sysdup(int old, int new)
124 {
125 	Chan *oc;
126 	Fgrp *f = up->fgrp;
127 	Chan *c = 0;
128 
129 	if(waserror())
130 		return -1;
131 
132 	c = fdtochan(old, -1, 0, 1);
133 	if(new != -1) {
134 		if(new < 0 || NFD <= new) {
135 			cclose(c);
136 			error(Ebadfd);
137 		}
138 		lock(&f->ref.lk);
139 		if(new > f->maxfd)
140 			f->maxfd = new;
141 		oc = f->fd[new];
142 		f->fd[new] = (Chan*)c;
143 		unlock(&f->ref.lk);
144 		if(oc != 0)
145 			cclose(oc);
146 	}
147 	else {
148 		if(waserror()) {
149 			cclose(c);
150 			nexterror();
151 		}
152 		new = newfd((Chan*)c);
153 		poperror();
154 	}
155 	poperror();
156 	return new;
157 }
158 
159 int
sysfstat(int fd,char * buf)160 sysfstat(int fd, char *buf)
161 {
162 	Chan *c = 0;
163 
164 	if(waserror()) {
165 		cclose(c);
166 		return -1;
167 	}
168 	c = fdtochan(fd, -1, 0, 1);
169 	devtab[c->type]->stat((Chan*)c, buf);
170 	poperror();
171 	cclose(c);
172 	return 0;
173 }
174 
175 int
sysfwstat(int fd,char * buf)176 sysfwstat(int fd, char *buf)
177 {
178 	Chan *c = 0;
179 
180 	if(waserror()) {
181 		cclose(c);
182 		return -1;
183 	}
184 	nameok(buf);
185 	c = fdtochan(fd, -1, 1, 1);
186 	devtab[c->type]->wstat((Chan*)c, buf);
187 	poperror();
188 	cclose(c);
189 	return 0;
190 }
191 
192 int
syschdir(char * dir)193 syschdir(char *dir)
194 {
195 	return 0;
196 }
197 
198 long
bindmount(Chan * c0,char * old,int flag,char * spec)199 bindmount(Chan *c0, char *old, int flag, char *spec)
200 {
201 	int ret;
202 	Chan *c1 = 0;
203 
204 	if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
205 		error(Ebadarg);
206 
207 	c1 = namec(old, Amount, 0, 0);
208 	if(waserror()){
209 		cclose(c1);
210 		nexterror();
211 	}
212 
213 	ret = cmount(c0, c1, flag, spec);
214 
215 	poperror();
216 	cclose(c1);
217 	return ret;
218 }
219 
220 int
sysbind(char * new,char * old,int flags)221 sysbind(char *new, char *old, int flags)
222 {
223 	long r;
224 	Chan *c0 = 0;
225 
226 	if(waserror()) {
227 		cclose(c0);
228 		return -1;
229 	}
230 	c0 = namec(new, Aaccess, 0, 0);
231 	r = bindmount(c0, old, flags, "");
232 	poperror();
233 	cclose(c0);
234 	return 0;
235 }
236 
237 int
sysmount(int fd,char * old,int flags,char * spec)238 sysmount(int fd, char *old, int flags, char *spec)
239 {
240 	long r;
241 	Chan *c0 = 0, *bc = 0;
242 	struct {
243 		Chan*	chan;
244 		char*	spec;
245 		int	flags;
246 	} mntparam;
247 
248 	if(waserror()) {
249 		cclose(bc);
250 		cclose(c0);
251 		return -1;
252 	}
253 	bc = fdtochan(fd, ORDWR, 0, 1);
254 	mntparam.chan = (Chan*)bc;
255 	mntparam.spec = spec;
256 	mntparam.flags = flags;
257 	c0 = (*devtab[devno('M', 0)].attach)(&mntparam);
258 	cclose(bc);
259 	r = bindmount(c0, old, flags, spec);
260 	poperror();
261 	cclose(c0);
262 
263 	return r;
264 }
265 
266 int
sysunmount(char * old,char * new)267 sysunmount(char *old, char *new)
268 {
269 	Chan *cmount = 0, *cmounted = 0;
270 
271 	if(waserror()) {
272 		cclose(cmount);
273 		cclose(cmounted);
274 		return -1;
275 	}
276 
277 	cmount = namec(new, Amount, OREAD, 0);
278 	if(old != 0)
279 		cmounted = namec(old, Aopen, OREAD, 0);
280 
281 	cunmount(cmount, cmounted);
282 	poperror();
283 	cclose(cmount);
284 	cclose(cmounted);
285 	return 0;
286 }
287 
288 int
sysopen(char * path,int mode)289 sysopen(char *path, int mode)
290 {
291 	int fd;
292 	Chan *c = 0;
293 
294 	if(waserror()){
295 		cclose(c);
296 		return -1;
297 	}
298 	openmode(mode);				/* error check only */
299 	c = namec(path, Aopen, mode, 0);
300 	fd = newfd((Chan*)c);
301 	poperror();
302 	return fd;
303 }
304 
305 long
unionread(Chan * c,void * va,long n)306 unionread(Chan *c, void *va, long n)
307 {
308 	long nr;
309 	Chan *nc = 0;
310 	Pgrp *pg = 0;
311 
312 	pg = up->pgrp;
313 	rlock(&pg->ns);
314 
315 	for(;;) {
316 		if(waserror()) {
317 			runlock(&pg->ns);
318 			nexterror();
319 		}
320 		nc = clone(c->mnt->to, 0);
321 		poperror();
322 
323 		if(c->mountid != c->mnt->mountid) {
324 			runlock(&pg->ns);
325 			cclose(nc);
326 			return 0;
327 		}
328 
329 		/* Error causes component of union to be skipped */
330 		if(waserror()) {
331 			cclose(nc);
332 			goto next;
333 		}
334 
335 		nc = (*devtab[nc->type].open)((Chan*)nc, OREAD);
336 		nc->offset = c->offset;
337 		nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset);
338 		/* devdirread e.g. changes it */
339 		c->offset = nc->offset;
340 		poperror();
341 
342 		cclose(nc);
343 		if(nr > 0) {
344 			runlock(&pg->ns);
345 			return nr;
346 		}
347 		/* Advance to next element */
348 	next:
349 		c->mnt = c->mnt->next;
350 		if(c->mnt == 0)
351 			break;
352 		c->mountid = c->mnt->mountid;
353 		c->offset = 0;
354 	}
355 	runlock(&pg->ns);
356 	return 0;
357 }
358 
359 long
sysread(int fd,void * va,long n)360 sysread(int fd, void *va, long n)
361 {
362 	int dir;
363 	Lock *cl;
364 	Chan *c = 0;
365 
366 	if(waserror()) {
367 		cclose(c);
368 		return -1;
369 	}
370 	c = fdtochan(fd, OREAD, 1, 1);
371 
372 	dir = c->qid.path&CHDIR;
373 	if(dir) {
374 		n -= n%DIRLEN;
375 		if(c->offset%DIRLEN || n==0)
376 			error(Etoosmall);
377 	}
378 
379 	if(dir && c->mnt)
380 		n = unionread((Chan*)c, va, n);
381 	else
382 		n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset);
383 
384 	cl = (Lock*)&c->r.l;
385 	lock(cl);
386 	c->offset += n;
387 	unlock(cl);
388 
389 	poperror();
390 	cclose(c);
391 
392 	return n;
393 }
394 
395 int
sysremove(char * path)396 sysremove(char *path)
397 {
398 	Chan *c = 0;
399 
400 	if(waserror()) {
401 		if(c != 0)
402 			c->type = 0;	/* see below */
403 		cclose(c);
404 		return -1;
405 	}
406 	c = namec(path, Aaccess, 0, 0);
407 	(*devtab[c->type].remove)((Chan*)c);
408 	/*
409 	 * Remove clunks the fid, but we need to recover the Chan
410 	 * so fake it up.  rootclose() is known to be a nop.
411 	 */
412 	c->type = 0;
413 	poperror();
414 	cclose(c);
415 	return 0;
416 }
417 
418 long
sysseek(int fd,long off,int whence)419 sysseek(int fd, long off, int whence)
420 {
421 	Dir dir;
422 	Chan *c;
423 	char buf[DIRLEN];
424 
425 	if(waserror())
426 		return -1;
427 
428 	c = fdtochan(fd, -1, 1, 0);
429 	if(c->qid.path & CHDIR)
430 		error(Eisdir);
431 
432 	switch(whence) {
433 	case 0:
434 		c->offset = off;
435 		break;
436 
437 	case 1:
438 		lock(&c->r.l);	/* lock for read/write update */
439 		c->offset += off;
440 		off = c->offset;
441 		unlock(&c->r.l);
442 		break;
443 
444 	case 2:
445 		(*devtab[c->type].stat)(c, buf);
446 		convM2D(buf, &dir);
447 		c->offset = dir.length + off;
448 		off = c->offset;
449 		break;
450 	}
451 	poperror();
452 	return off;
453 }
454 
455 int
sysstat(char * path,char * buf)456 sysstat(char *path, char *buf)
457 {
458 	Chan *c = 0;
459 
460 	if(waserror()){
461 		cclose(c);
462 		return -1;
463 	}
464 	c = namec(path, Aaccess, 0, 0);
465 	(*devtab[c->type].stat)((Chan*)c, buf);
466 	poperror();
467 	cclose(c);
468 	return 0;
469 }
470 
471 long
syswrite(int fd,void * va,long n)472 syswrite(int fd, void *va, long n)
473 {
474 	Lock *cl;
475 	Chan *c = 0;
476 
477 	if(waserror()) {
478 		cclose(c);
479 		return -1;
480 	}
481 	c = fdtochan(fd, OWRITE, 1, 1);
482 	if(c->qid.path & CHDIR)
483 		error(Eisdir);
484 
485 	n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset);
486 
487 	cl = (Lock*)&c->r.l;
488 	lock(cl);
489 	c->offset += n;
490 	unlock(cl);
491 
492 	poperror();
493 	cclose(c);
494 
495 	return n;
496 }
497 
498 int
syswstat(char * path,char * buf)499 syswstat(char *path, char *buf)
500 {
501 	Chan *c = 0;
502 
503 	if(waserror()) {
504 		cclose(c);
505 		return -1;
506 	}
507 
508 	nameok(buf);
509 	c = namec(path, Aaccess, 0, 0);
510 	(*devtab[c->type].wstat)((Chan*)c, buf);
511 	poperror();
512 	cclose(c);
513 	return 0;
514 }
515 
516 int
sysdirstat(char * name,Dir * dir)517 sysdirstat(char *name, Dir *dir)
518 {
519 	char buf[DIRLEN];
520 
521 	if(sysstat(name, buf) == -1)
522 		return -1;
523 	convM2D(buf, dir);
524 	return 0;
525 }
526 
527 int
sysdirfstat(int fd,Dir * dir)528 sysdirfstat(int fd, Dir *dir)
529 {
530 	char buf[DIRLEN];
531 
532 	if(sysfstat(fd, buf) == -1)
533 		return -1;
534 
535 	convM2D(buf, dir);
536 	return 0;
537 }
538 
539 int
sysdirwstat(char * name,Dir * dir)540 sysdirwstat(char *name, Dir *dir)
541 {
542 	char buf[DIRLEN];
543 
544 	convD2M(dir, buf);
545 	return syswstat(name, buf);
546 }
547 
548 int
sysdirfwstat(int fd,Dir * dir)549 sysdirfwstat(int fd, Dir *dir)
550 {
551 	char buf[DIRLEN];
552 
553 	convD2M(dir, buf);
554 	return sysfwstat(fd, buf);
555 }
556 
557 long
sysdirread(int fd,Dir * dbuf,long count)558 sysdirread(int fd, Dir *dbuf, long count)
559 {
560 	int c, n, i, r;
561 	char buf[DIRLEN*50];
562 
563 	n = 0;
564 	count = (count/sizeof(Dir)) * DIRLEN;
565 	while(n < count) {
566 		c = count - n;
567 		if(c > sizeof(buf))
568 			c = sizeof(buf);
569 		r = sysread(fd, buf, c);
570 		if(r == 0)
571 			break;
572 		if(r < 0 || r % DIRLEN)
573 			return -1;
574 		for(i=0; i<r; i+=DIRLEN) {
575 			convM2D(buf+i, dbuf);
576 			dbuf++;
577 		}
578 		n += r;
579 		if(r != c)
580 			break;
581 	}
582 
583 	return (n/DIRLEN) * sizeof(Dir);
584 }
585 
586 static int
call(char * clone,char * dest,int * cfdp,char * dir,char * local)587 call(char *clone, char *dest, int *cfdp, char *dir, char *local)
588 {
589 	int fd, cfd, n;
590 	char *p, name[3*NAMELEN+5], data[3*NAMELEN+10];
591 
592 	cfd = sysopen(clone, ORDWR);
593 	if(cfd < 0){
594 		werrstr("%s: %r", clone);
595 		return -1;
596 	}
597 
598 	/* get directory name */
599 	n = sysread(cfd, name, sizeof(name)-1);
600 	if(n < 0) {
601 		sysclose(cfd);
602 		return -1;
603 	}
604 	name[n] = 0;
605 	sprint(name, "%d", strtoul(name, 0, 0));
606 	p = strrchr(clone, '/');
607 	*p = 0;
608 	if(dir)
609 		snprint(dir, 2*NAMELEN, "%s/%s", clone, name);
610 	snprint(data, sizeof(data), "%s/%s/data", clone, name);
611 
612 	/* connect */
613 	/* set local side (port number, for example) if we need to */
614 	if(local)
615 		snprint(name, sizeof(name), "connect %s %s", dest, local);
616 	else
617 		snprint(name, sizeof(name), "connect %s", dest);
618 	if(syswrite(cfd, name, strlen(name)) < 0){
619 		werrstr("%s failed: %r", name);
620 		sysclose(cfd);
621 		return -1;
622 	}
623 
624 	/* open data connection */
625 	fd = sysopen(data, ORDWR);
626 	if(fd < 0){
627 		werrstr("can't open %s: %r", data);
628 		sysclose(cfd);
629 		return -1;
630 	}
631 	if(cfdp)
632 		*cfdp = cfd;
633 	else
634 		sysclose(cfd);
635 	return fd;
636 }
637 
638 int
sysdial(char * dest,char * local,char * dir,int * cfdp)639 sysdial(char *dest, char *local, char *dir, int *cfdp)
640 {
641 	int n, fd, rv;
642 	char *p, net[128], clone[NAMELEN+12];
643 
644 	/* go for a standard form net!... */
645 	p = strchr(dest, '!');
646 	if(p == 0){
647 		snprint(net, sizeof(net), "net!%s", dest);
648 	} else {
649 		strncpy(net, dest, sizeof(net)-1);
650 		net[sizeof(net)-1] = 0;
651 	}
652 
653 	/* call the connection server */
654 	fd = sysopen("/net/cs", ORDWR);
655 	if(fd < 0){
656 		/* no connection server, don't translate */
657 		p = strchr(net, '!');
658 		*p++ = 0;
659 		snprint(clone, sizeof(clone), "/net/%s/clone", net);
660 		return call(clone, p, cfdp, dir, local);
661 	}
662 
663 	/*
664 	 *  send dest to connection to translate
665 	 */
666 	if(syswrite(fd, net, strlen(net)) < 0){
667 		werrstr("%s: %r", net);
668 		sysclose(fd);
669 		return -1;
670 	}
671 
672 	/*
673 	 *  loop through each address from the connection server till
674 	 *  we get one that works.
675 	 */
676 	rv = -1;
677 	sysseek(fd, 0, 0);
678 	while((n = sysread(fd, net, sizeof(net) - 1)) > 0){
679 		net[n] = 0;
680 		p = strchr(net, ' ');
681 		if(p == 0)
682 			continue;
683 		*p++ = 0;
684 		rv = call(net, p, cfdp, dir, local);
685 		if(rv >= 0)
686 			break;
687 	}
688 	sysclose(fd);
689 	return rv;
690 }
691 
692 static int
identtrans(char * addr,char * naddr,int na,char * file,int nf)693 identtrans(char *addr, char *naddr, int na, char *file, int nf)
694 {
695 	char *p;
696 	char reply[4*NAMELEN];
697 
698 	/* parse the network */
699 	strncpy(reply, addr, sizeof(reply));
700 	reply[sizeof(reply)-1] = 0;
701 	p = strchr(reply, '!');
702 	if(p)
703 		*p++ = 0;
704 
705 	sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply);
706 	strncpy(naddr, p, na);
707 	naddr[na-1] = 0;
708 	return 1;
709 }
710 
711 static int
nettrans(char * addr,char * naddr,int na,char * file,int nf)712 nettrans(char *addr, char *naddr, int na, char *file, int nf)
713 {
714 	long n;
715 	int fd;
716 	char *cp;
717 	char reply[4*NAMELEN];
718 
719 	/*
720 	 *  ask the connection server
721 	 */
722 	fd = sysopen("/net/cs", ORDWR);
723 	if(fd < 0)
724 		return identtrans(addr, naddr, na, file, nf);
725 	if(syswrite(fd, addr, strlen(addr)) < 0){
726 		sysclose(fd);
727 		return -1;
728 	}
729 	sysseek(fd, 0, 0);
730 	n = sysread(fd, reply, sizeof(reply)-1);
731 	sysclose(fd);
732 	if(n <= 0)
733 		return -1;
734 	reply[n] = '\0';
735 
736 	/*
737 	 *  parse the reply
738 	 */
739 	cp = strchr(reply, ' ');
740 	if(cp == 0)
741 		return -1;
742 	*cp++ = 0;
743 	strncpy(naddr, cp, na);
744 	naddr[na-1] = 0;
745 	strncpy(file, reply, nf);
746 	file[nf-1] = 0;
747 	return 0;
748 }
749 
750 int
sysannounce(char * addr,char * dir)751 sysannounce(char *addr, char *dir)
752 {
753 	char *cp;
754 	int ctl, n, m;
755 	char buf[3*NAMELEN];
756 	char buf2[3*NAMELEN];
757 	char netdir[2*NAMELEN];
758 	char naddr[3*NAMELEN];
759 
760 	/*
761 	 *  translate the address
762 	 */
763 	if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){
764 		werrstr("can't translate address");
765 		return -1;
766 	}
767 
768 	/*
769 	 * get a control channel
770 	 */
771 	ctl = sysopen(netdir, ORDWR);
772 	if(ctl<0){
773 		werrstr("can't open control channel");
774 		return -1;
775 	}
776 	cp = strrchr(netdir, '/');
777 	*cp = 0;
778 
779 	/*
780 	 *  find out which line we have
781 	 */
782 	n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir);
783 	m = sysread(ctl, &buf[n], sizeof(buf)-n-1);
784 	if(m <= 0) {
785 		sysclose(ctl);
786 		werrstr("can't read control file");
787 		return -1;
788 	}
789 	buf[n+m] = 0;
790 
791 	/*
792 	 *  make the call
793 	 */
794 	n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr);
795 	if(syswrite(ctl, buf2, n) != n) {
796 		sysclose(ctl);
797 		werrstr("announcement fails");
798 		return -1;
799 	}
800 
801 	strcpy(dir, buf);
802 
803 	return ctl;
804 }
805 
806 int
syslisten(char * dir,char * newdir)807 syslisten(char *dir, char *newdir)
808 {
809 	char *cp;
810 	int ctl, n, m;
811 	char buf[3*NAMELEN];
812 
813 	/*
814 	 *  open listen, wait for a call
815 	 */
816 	sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir);
817 	ctl = sysopen(buf, ORDWR);
818 	if(ctl < 0)
819 		return -1;
820 
821 	/*
822 	 *  find out which line we have
823 	 */
824 	strcpy(buf, dir);
825 	cp = strrchr(buf, '/');
826 	*++cp = 0;
827 	n = cp-buf;
828 	m = sysread(ctl, cp, sizeof(buf) - n - 1);
829 	if(n<=0){
830 		sysclose(ctl);
831 		return -1;
832 	}
833 	buf[n+m] = 0;
834 
835 	strcpy(newdir, buf);
836 	return ctl;
837 }
838