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