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