xref: /plan9/sys/src/cmd/upas/common/libsys.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include "common.h"
2 #include <auth.h>
3 #include <ndb.h>
4 
5 /*
6  *  number of predefined fd's
7  */
8 int nsysfile=3;
9 
10 static char err[ERRLEN];
11 
12 /*
13  *  return the date
14  */
15 extern char *
16 thedate(void)
17 {
18 	static char now[64];
19 	char *cp;
20 
21 	strcpy(now, ctime(time(0)));
22 	cp = strchr(now, '\n');
23 	if(cp)
24 		*cp = 0;
25 	return now;
26 }
27 
28 /*
29  *  return the user id of the current user
30  */
31 extern char *
32 getlog(void)
33 {
34 	static char user[64];
35 	int fd;
36 	int n;
37 
38 	fd = open("/dev/user", 0);
39 	if(fd < 0)
40 		return nil;
41 	if((n=read(fd, user, sizeof(user)-1)) <= 0)
42 		return nil;
43 	close(fd);
44 	user[n] = 0;
45 	return user;
46 }
47 
48 /*
49  *  return the lock name
50  */
51 static String *
52 lockname(char *path)
53 {
54 	String *lp;
55 	char *cp;
56 
57 	/*
58 	 *  get the name of the lock file
59 	 */
60 	lp = s_new();
61 	cp = strrchr(path, '/');
62 	if(cp){
63 		cp++;
64 		s_nappend(lp, path, cp - path);
65 	} else {
66 
67 		cp = path;
68 	}
69 	s_append(lp, "L.");
70 	s_nappend(lp, cp, NAMELEN-3);
71 
72 	return lp;
73 }
74 
75 int
76 syscreatelocked(char *path, int mode, int perm)
77 {
78 	return create(path, mode, CHEXCL|perm);
79 }
80 
81 int
82 sysopenlocked(char *path, int mode)
83 {
84 /*	return open(path, OEXCL|mode);/**/
85 	return open(path, mode);		/* until system call is fixed */
86 }
87 
88 int
89 sysunlockfile(int fd)
90 {
91 	return close(fd);
92 }
93 
94 /*
95  *  try opening a lock file.  If it doesn't exist try creating it.
96  */
97 static int
98 openlockfile(Mlock *l)
99 {
100 	int fd;
101 	Dir d;
102 	char *p;
103 
104 	fd = open(s_to_c(l->name), OWRITE);
105 	if(fd >= 0){
106 		l->fd = fd;
107 		return 0;
108 	}
109 
110 	if(dirstat(s_to_c(l->name), &d) < 0){
111 		/* file doesn't exist */
112 		/* try creating it */
113 		fd = create(s_to_c(l->name), OWRITE, CHEXCL|0666);
114 		if(fd >= 0){
115 			if(dirfstat(fd, &d) >= 0){
116 				d.mode |= CHEXCL|0666;
117 				dirfwstat(fd, &d);
118 			}
119 			l->fd = fd;
120 			return 0;
121 		}
122 
123 		/* couldn't create */
124 		/* do we have write access to the directory? */
125 		p = strrchr(s_to_c(l->name), '/');
126 		if(p != 0){
127 			*p = 0;
128 			fd = access(s_to_c(l->name), 2);
129 			*p = '/';
130 			if(fd < 0)
131 				return -1;	/* give up */
132 		} else {
133 			fd = access(".", 2);
134 			if(fd < 0)
135 				return -1;	/* give up */
136 		}
137 	}
138 
139 	return 1; /* try again later */
140 }
141 
142 #define LSECS 5*60
143 
144 /*
145  *  Set a lock for a particular file.  The lock is a file in the same directory
146  *  and has L. prepended to the name of the last element of the file name.
147  */
148 extern Mlock *
149 syslock(char *path)
150 {
151 	Mlock *l;
152 	int tries;
153 
154 	l = mallocz(sizeof(Mlock), 1);
155 	if(l == 0)
156 		return nil;
157 
158 	l->name = lockname(path);
159 
160 	/*
161 	 *  wait LSECS seconds for it to unlock
162 	 */
163 	for(tries = 0; tries < LSECS*2; tries++){
164 		switch(openlockfile(l)){
165 		case 0:
166 			return l;
167 		case 1:
168 			sleep(500);
169 			break;
170 		default:
171 			goto noway;
172 		}
173 	}
174 
175 noway:
176 	s_free(l->name);
177 	free(l);
178 	return nil;
179 }
180 
181 /*
182  *  like lock except don't wait
183  */
184 extern Mlock *
185 trylock(char *path)
186 {
187 	Mlock *l;
188 	char buf[1];
189 	int fd;
190 
191 	l = malloc(sizeof(Mlock));
192 	if(l == 0)
193 		return 0;
194 
195 	l->name = lockname(path);
196 	if(openlockfile(l) != 0){
197 		s_free(l->name);
198 		free(l);
199 		return 0;
200 	}
201 
202 	/* fork process to keep lock alive */
203 	switch(l->pid = rfork(RFPROC)){
204 	default:
205 		break;
206 	case 0:
207 		fd = l->fd;
208 		for(;;){
209 			sleep(1000*60);
210 			seek(fd, 0, 0);
211 			if(write(fd, buf, 1) < 0)
212 				break;
213 		}
214 		_exits(0);
215 	}
216 	return l;
217 }
218 
219 extern void
220 syslockrefresh(Mlock *l)
221 {
222 	char buf[1];
223 
224 	seek(l->fd, 0, 0);
225 	read(l->fd, buf, 1);
226 }
227 
228 extern void
229 sysunlock(Mlock *l)
230 {
231 	if(l == 0)
232 		return;
233 	if(l->name){
234 		s_free(l->name);
235 	}
236 	if(l->fd >= 0)
237 		close(l->fd);
238 	if(l->pid > 0)
239 		postnote(PNPROC, l->pid, "time to die");
240 	free(l);
241 }
242 
243 /*
244  *  Open a file.  The modes are:
245  *
246  *	l	- locked
247  *	a	- set append permissions
248  *	r	- readable
249  *	w	- writable
250  *	A	- append only (doesn't exist in Bio)
251  */
252 extern Biobuf *
253 sysopen(char *path, char *mode, ulong perm)
254 {
255 	int sysperm;
256 	int sysmode;
257 	int fd;
258 	int docreate;
259 	int append;
260 	int truncate;
261 	Dir d;
262 	Biobuf *bp;
263 
264 	/*
265 	 *  decode the request
266 	 */
267 	sysperm = 0;
268 	sysmode = -1;
269 	docreate = 0;
270 	append = 0;
271 	truncate = 0;
272  	for(; mode && *mode; mode++)
273 		switch(*mode){
274 		case 'A':
275 			sysmode = OWRITE;
276 			append = 1;
277 			break;
278 		case 'c':
279 			docreate = 1;
280 			break;
281 		case 'l':
282 			sysperm |= CHEXCL;
283 			break;
284 		case 'a':
285 			sysperm |= CHAPPEND;
286 			break;
287 		case 'w':
288 			if(sysmode == -1)
289 				sysmode = OWRITE;
290 			else
291 				sysmode = ORDWR;
292 			break;
293 		case 'r':
294 			if(sysmode == -1)
295 				sysmode = OREAD;
296 			else
297 				sysmode = ORDWR;
298 			break;
299 		case 't':
300 			truncate = 1;
301 			break;
302 		default:
303 			break;
304 		}
305 	switch(sysmode){
306 	case OREAD:
307 	case OWRITE:
308 	case ORDWR:
309 		break;
310 	default:
311 		if(sysperm&CHAPPEND)
312 			sysmode = OWRITE;
313 		else
314 			sysmode = OREAD;
315 		break;
316 	}
317 
318 	/*
319 	 *  create file if we need to
320 	 */
321 	if(truncate)
322 		sysmode |= OTRUNC;
323 	fd = open(path, sysmode);
324 	if(fd < 0){
325 		if(dirstat(path, &d) < 0){
326 			if(docreate == 0)
327 				return 0;
328 
329 			fd = create(path, sysmode, sysperm|perm);
330 			if(fd < 0)
331 				return 0;
332 			if(dirfstat(fd, &d) >= 0){
333 				d.mode |= sysperm|perm;
334 				dirfwstat(fd, &d);
335 			}
336 		} else
337 			return 0;
338 	}
339 
340 	bp = (Biobuf*)malloc(sizeof(Biobuf));
341 	if(bp == 0){
342 		close(fd);
343 		return 0;
344 	}
345 	memset(bp, 0, sizeof(Biobuf));
346 	Binit(bp, fd, sysmode&~OTRUNC);
347 
348 	if(append)
349 		Bseek(bp, 0, 2);
350 	return bp;
351 }
352 
353 /*
354  *  close the file, etc.
355  */
356 int
357 sysclose(Biobuf *bp)
358 {
359 	int rv;
360 
361 	rv = Bterm(bp);
362 	close(Bfildes(bp));
363 	free(bp);
364 	return rv;
365 }
366 
367 /*
368  *  create a file
369  */
370 int
371 syscreate(char *file, int mode, ulong perm)
372 {
373 	return create(file, mode, perm);
374 }
375 
376 /*
377  *  make a directory
378  */
379 int
380 sysmkdir(char *file, ulong perm)
381 {
382 	int fd;
383 
384 	if((fd = create(file, OREAD, CHDIR|perm)) < 0)
385 		return -1;
386 	close(fd);
387 	return 0;
388 }
389 
390 /*
391  *  change the group of a file
392  */
393 int
394 syschgrp(char *file, char *group)
395 {
396 	Dir d;
397 
398 	if(group == 0)
399 		return -1;
400 	if(dirstat(file, &d) < 0)
401 		return -1;
402 	strncpy(d.gid, group, sizeof(d.gid));
403 	return dirwstat(file, &d);
404 }
405 
406 extern int
407 sysdirread(int fd, Dir *d, int n)
408 {
409 	return read(fd, d, n);
410 }
411 
412 /*
413  *  read in the system name
414  */
415 extern char *
416 sysname_read(void)
417 {
418 	static char name[128];
419 	char *cp;
420 
421 	cp = getenv("site");
422 	if(cp == 0 || *cp == 0)
423 		cp = alt_sysname_read();
424 	if(cp == 0 || *cp == 0)
425 		cp = "kremvax";
426 	strcpy(name, cp);
427 	return name;
428 }
429 extern char *
430 alt_sysname_read(void)
431 {
432 	static char name[128];
433 	int n, fd;
434 
435 	fd = open("/dev/sysname", OREAD);
436 	if(fd < 0)
437 		return 0;
438 	n = read(fd, name, sizeof(name)-1);
439 	close(fd);
440 	if(n <= 0)
441 		return 0;
442 	name[n] = 0;
443 	return name;
444 }
445 
446 /*
447  *  get all names
448  */
449 extern char**
450 sysnames_read(void)
451 {
452 	static char **namev;
453 	Ndbtuple *t, *nt;
454 	char domain[Ndbvlen];
455 	int n;
456 	char *cp;
457 
458 	if(namev)
459 		return namev;
460 
461 	t = csgetval(0, "sys", alt_sysname_read(), "dom", domain);
462 	n = 0;
463 	for(nt = t; nt; nt = nt->entry)
464 		if(strcmp(nt->attr, "dom") == 0)
465 			n++;
466 
467 	namev = (char**)malloc(sizeof(char *)*(n+3));
468 
469 	if(namev){
470 		n = 0;
471 		namev[n++] = strdup(sysname_read());
472 		cp = alt_sysname_read();
473 		if(cp)
474 			namev[n++] = strdup(cp);
475 		for(nt = t; nt; nt = nt->entry)
476 			if(strcmp(nt->attr, "dom") == 0)
477 				namev[n++] = strdup(nt->val);
478 		namev[n] = 0;
479 	}
480 	if(t)
481 		ndbfree(t);
482 
483 	return namev;
484 }
485 
486 /*
487  *  read in the domain name
488  */
489 extern char *
490 domainname_read(void)
491 {
492 	char **namev;
493 
494 	for(namev = sysnames_read(); *namev; namev++)
495 		if(strchr(*namev, '.'))
496 			return *namev;
497 	return 0;
498 }
499 
500 /*
501  *  return true if the last error message meant file
502  *  did not exist.
503  */
504 extern int
505 e_nonexistent(void)
506 {
507 	errstr(err);
508 	return strcmp(err, "file does not exist") == 0;
509 }
510 
511 /*
512  *  return true if the last error message meant file
513  *  was locked.
514  */
515 extern int
516 e_locked(void)
517 {
518 	errstr(err);
519 	return strcmp(err, "open/create -- file is locked") == 0;
520 }
521 
522 /*
523  *  return the length of a file
524  */
525 extern long
526 sysfilelen(Biobuf *fp)
527 {
528 	Dir	d;
529 
530 	if(dirfstat(Bfildes(fp), &d)<0)
531 		return -1;
532 	return d.length;
533 }
534 
535 /*
536  *  remove a file
537  */
538 extern int
539 sysremove(char *path)
540 {
541 	return remove(path);
542 }
543 
544 /*
545  *  rename a file, fails unless both are in the same directory
546  */
547 extern int
548 sysrename(char *old, char *new)
549 {
550 	Dir d;
551 	char *obase;
552 	char *nbase;
553 
554 	obase = strrchr(old, '/');
555 	nbase = strrchr(new, '/');
556 	if(obase){
557 		if(nbase == 0)
558 			return -1;
559 		if(strncmp(old, new, obase-old) != 0)
560 			return -1;
561 		nbase++;
562 	} else {
563 		if(nbase)
564 			return -1;
565 		nbase = new;
566 	}
567 	if(dirstat(old, &d) < 0)
568 		return -1;
569 	memset(d.name, 0, sizeof(d.name));
570 	strcpy(d.name, nbase);
571 	return dirwstat(old, &d);
572 }
573 
574 /*
575  *  see if a file exists
576  */
577 extern int
578 sysexist(char *file)
579 {
580 	Dir	d;
581 
582 	return dirstat(file, &d) == 0;
583 }
584 
585 /*
586  * kill a process or process group
587  */
588 
589 static int
590 stomp(int pid, char *file)
591 {
592 	char name[64];
593 	int fd;
594 
595 	snprint(name, sizeof(name), "/proc/%d/%s", pid, file);
596 	fd = open(name, 1);
597 	if(fd < 0)
598 		return -1;
599 	if(write(fd, "die: yankee pig dog\n", sizeof("die: yankee pig dog\n") - 1) <= 0){
600 		close(fd);
601 		return -1;
602 	}
603 	close(fd);
604 	return 0;
605 
606 }
607 
608 /*
609  *  kill a process
610  */
611 extern int
612 syskill(int pid)
613 {
614 	return stomp(pid, "note");
615 
616 }
617 
618 /*
619  *  kill a process group
620  */
621 extern int
622 syskillpg(int pid)
623 {
624 	return stomp(pid, "notepg");
625 }
626 
627 extern int
628 sysdetach(void)
629 {
630 	if(rfork(RFENVG|RFNAMEG|RFNOTEG) < 0) {
631 		werrstr("rfork failed");
632 		return -1;
633 	}
634 	return 0;
635 }
636 
637 /*
638  *  catch a write on a closed pipe
639  */
640 static int *closedflag;
641 static int
642 catchpipe(void *a, char *msg)
643 {
644 	static char *foo = "sys: write on closed pipe";
645 
646 	USED(a);
647 	if(strncmp(msg, foo, strlen(foo)) == 0){
648 		if(closedflag)
649 			*closedflag = 1;
650 		return 1;
651 	}
652 	return 0;
653 }
654 void
655 pipesig(int *flagp)
656 {
657 	closedflag = flagp;
658 	atnotify(catchpipe, 1);
659 }
660 void
661 pipesigoff(void)
662 {
663 	atnotify(catchpipe, 0);
664 }
665 
666 void
667 exit(int i)
668 {
669 	char buf[32];
670 
671 	if(i == 0)
672 		exits(0);
673 	snprint(buf, sizeof(buf), "%d", i);
674 	exits(buf);
675 }
676 
677 /*
678  *  become powerless user
679  */
680 int
681 become(char **cmd, char *who)
682 {
683 	int fd;
684 
685 	USED(cmd);
686 	if(strcmp(who, "none") == 0) {
687 		fd = open("#c/user", OWRITE);
688 		if(fd < 0 || write(fd, "none", strlen("none")) < 0) {
689 			werrstr("can't become none");
690 			return -1;
691 		}
692 		close(fd);
693 		if(newns("none", 0)) {
694 			werrstr("can't set new namespace");
695 			return -1;
696 		}
697 	}
698 	return 0;
699 }
700 
701 static int
702 islikeatty(int fd)
703 {
704 	Dir d;
705 
706 	if(dirfstat(fd, &d) < 0)
707 		return 0;
708 	return strcmp(d.name, "cons") == 0;
709 }
710 
711 extern int
712 holdon(void)
713 {
714 	int fd;
715 
716 	if(!islikeatty(0))
717 		return -1;
718 
719 	fd = open("/dev/consctl", OWRITE);
720 	write(fd, "holdon", 6);
721 
722 	return fd;
723 }
724 
725 extern int
726 sysopentty(void)
727 {
728 	return open("/dev/cons", ORDWR);
729 }
730 
731 extern void
732 holdoff(int fd)
733 {
734 	write(fd, "holdoff", 7);
735 	close(fd);
736 }
737 
738 extern int
739 sysfiles(void)
740 {
741 	return 128;
742 }
743 
744 /*
745  *  expand a path relative to the user's mailbox directory
746  *
747  *  if the path starts with / or ./, don't change it
748  *
749  */
750 extern String *
751 mboxpath(char *path, char *user, String *to, int dot)
752 {
753 	if (dot || *path=='/' || strncmp(path, "./", 2) == 0
754 			      || strncmp(path, "../", 3) == 0) {
755 		to = s_append(to, path);
756 	} else {
757 		to = s_append(to, MAILROOT);
758 		to = s_append(to, "/box/");
759 		to = s_append(to, user);
760 		to = s_append(to, "/");
761 		to = s_append(to, path);
762 	}
763 	return to;
764 }
765 
766 extern String *
767 mboxname(char *user, String *to)
768 {
769 	return mboxpath("mbox", user, to, 0);
770 }
771 
772 extern String *
773 deadletter(String *to)		/* pass in sender??? */
774 {
775 	char *cp;
776 
777 	cp = getlog();
778 	if(cp == 0)
779 		return 0;
780 	return mboxpath("dead.letter", cp, to, 0);
781 }
782 
783 char *
784 homedir(char *user)
785 {
786 	USED(user);
787 	return getenv("home");
788 }
789 
790 String *
791 readlock(String *file)
792 {
793 	char *cp;
794 
795 	cp = getlog();
796 	if(cp == 0)
797 		return 0;
798 	return mboxpath("reading", cp, file, 0);
799 }
800 
801 String *
802 username(String *from)
803 {
804 	int n;
805 	Biobuf *bp;
806 	char *p, *q;
807 	String *s;
808 
809 	bp = Bopen("/adm/keys.who", OREAD);
810 	if(bp == 0)
811 		bp = Bopen("/adm/netkeys.who", OREAD);
812 	if(bp == 0)
813 		return 0;
814 
815 	s = 0;
816 	n = strlen(s_to_c(from));
817 	for(;;) {
818 		p = Brdline(bp, '\n');
819 		if(p == 0)
820 			break;
821 		p[Blinelen(bp)-1] = 0;
822 		if(strncmp(p, s_to_c(from), n))
823 			continue;
824 		p += n;
825 		if(*p != ' ' && *p != '\t')	/* must be full match */
826 			continue;
827 		while(*p && (*p == ' ' || *p == '\t'))
828 				p++;
829 		if(*p == 0)
830 			continue;
831 		for(q = p; *q; q++)
832 			if(('0' <= *q && *q <= '9') || *q == '<')
833 				break;
834 		while(q > p && q[-1] != ' ' && q[-1] != '\t')
835 			q--;
836 		while(q > p && (q[-1] == ' ' || q[-1] == '\t'))
837 			q--;
838 		*q = 0;
839 		s = s_new();
840 		s_append(s, "\"");
841 		s_append(s, p);
842 		s_append(s, "\"");
843 		break;
844 	}
845 	Bterm(bp);
846 	return s;
847 }
848 
849 char *
850 remoteaddr(int fd, char *dir)
851 {
852 	char buf[128], *p;
853 	int n;
854 
855 	if(dir == 0){
856 			/* parse something of the form /net/tcp/nnnn/data */
857 		if(fd2path(fd, buf, sizeof(buf)) == 0) {
858 			p = strrchr(buf, '/');
859 			if(p == 0)
860 				return "";
861 			strncpy(p+1, "remote", sizeof(buf)-(p-buf)-2);
862 		}
863 	} else
864 		snprint(buf, sizeof buf, "%s/remote", dir);
865 	buf[sizeof(buf)-1] = 0;
866 	fd = open(buf, OREAD);
867 	if(fd < 0)
868 		return "";
869 	n = read(fd, buf, sizeof(buf));
870 	close(fd);
871 	if(n > 0){
872 		buf[n] = 0;
873 		p = strchr(buf, '!');
874 		if(p)
875 			*p = 0;
876 		return strdup(buf);
877 	}
878 	return "";
879 }
880 
881 /*
882  *	stub to read locked current directory - this is different in unix version
883  */
884 int
885 sysreaddot(int fd, Dir *dir, long n)
886 {
887 	return dirread(fd, dir, n);
888 
889 }
890