1 #include "stdinc.h" 2 3 #include "9.h" 4 5 typedef struct Srv Srv; 6 typedef struct Srv { 7 int fd; 8 int srvfd; 9 char* service; 10 char* mntpnt; 11 12 Srv* next; 13 Srv* prev; 14 } Srv; 15 16 static struct { 17 VtLock* lock; 18 19 Srv* head; 20 Srv* tail; 21 } sbox; 22 23 static int 24 srvFd(char* name, int mode, int fd, char** mntpnt) 25 { 26 int n, srvfd; 27 char *p, buf[10]; 28 29 /* 30 * Drop a file descriptor with given name and mode into /srv. 31 * Create with ORCLOSE and don't close srvfd so it will be removed 32 * automatically on process exit. 33 */ 34 p = smprint("/srv/%s", name); 35 if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ 36 vtMemFree(p); 37 p = smprint("#s/%s", name); 38 if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ 39 vtSetError("create %s: %r", p); 40 vtMemFree(p); 41 return -1; 42 } 43 } 44 45 n = snprint(buf, sizeof(buf), "%d", fd); 46 if(write(srvfd, buf, n) < 0){ 47 close(srvfd); 48 vtSetError("write %s: %r", p); 49 vtMemFree(p); 50 return -1; 51 } 52 53 *mntpnt = p; 54 55 return srvfd; 56 } 57 58 static void 59 srvFree(Srv* srv) 60 { 61 if(srv->prev != nil) 62 srv->prev->next = srv->next; 63 else 64 sbox.head = srv->next; 65 if(srv->next != nil) 66 srv->next->prev = srv->prev; 67 else 68 sbox.tail = srv->prev; 69 70 if(srv->srvfd != -1) 71 close(srv->srvfd); 72 vtMemFree(srv->service); 73 vtMemFree(srv->mntpnt); 74 vtMemFree(srv); 75 } 76 77 static Srv* 78 srvAlloc(char* service, int mode, int fd) 79 { 80 Srv *srv; 81 int srvfd; 82 char *mntpnt; 83 84 vtLock(sbox.lock); 85 for(srv = sbox.head; srv != nil; srv = srv->next){ 86 if(strcmp(srv->service, service) != 0) 87 continue; 88 vtSetError("srv: already serving '%s'", service); 89 vtUnlock(sbox.lock); 90 return nil; 91 } 92 93 if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ 94 vtUnlock(sbox.lock); 95 return nil; 96 } 97 close(fd); 98 99 srv = vtMemAllocZ(sizeof(Srv)); 100 srv->srvfd = srvfd; 101 srv->service = vtStrDup(service); 102 srv->mntpnt = mntpnt; 103 104 if(sbox.tail != nil){ 105 srv->prev = sbox.tail; 106 sbox.tail->next = srv; 107 } 108 else{ 109 sbox.head = srv; 110 srv->prev = nil; 111 } 112 sbox.tail = srv; 113 vtUnlock(sbox.lock); 114 115 return srv; 116 } 117 118 static int 119 cmdSrv(int argc, char* argv[]) 120 { 121 Con *con; 122 Srv *srv; 123 char *usage = "usage: srv [-APWdp] [service]"; 124 int Aflag, Pflag, Wflag, dflag, fd[2], mode, pflag, r; 125 126 Aflag = Pflag = Wflag = dflag = pflag = 0; 127 mode = 0666; 128 129 ARGBEGIN{ 130 default: 131 return cliError(usage); 132 case 'A': 133 Aflag = 1; 134 break; 135 case 'P': 136 Pflag = 1; 137 mode = 0600; 138 break; 139 case 'W': 140 Wflag = 1; 141 mode = 0600; 142 break; 143 case 'd': 144 dflag = 1; 145 break; 146 case 'p': 147 pflag = 1; 148 mode = 0600; 149 break; 150 }ARGEND 151 152 if(pflag && Pflag){ 153 vtSetError("srv: cannot use -P with -p"); 154 return 0; 155 } 156 157 switch(argc){ 158 default: 159 return cliError(usage); 160 case 0: 161 vtRLock(sbox.lock); 162 for(srv = sbox.head; srv != nil; srv = srv->next) 163 consPrint("\t%s\t%d\n", srv->service, srv->srvfd); 164 vtRUnlock(sbox.lock); 165 166 return 1; 167 case 1: 168 if(!dflag) 169 break; 170 171 vtLock(sbox.lock); 172 for(srv = sbox.head; srv != nil; srv = srv->next){ 173 if(strcmp(srv->service, argv[0]) != 0) 174 continue; 175 srvFree(srv); 176 break; 177 } 178 vtUnlock(sbox.lock); 179 180 if(srv == nil){ 181 vtSetError("srv: '%s' not found", argv[0]); 182 return 0; 183 } 184 185 return 1; 186 } 187 188 if(pipe(fd) < 0){ 189 vtSetError("srv pipe: %r"); 190 return 0; 191 } 192 if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ 193 close(fd[0]); close(fd[1]); 194 return 0; 195 } 196 197 if(pflag) 198 r = consOpen(fd[1], srv->srvfd, -1); 199 else{ 200 con = conAlloc(fd[1], srv->mntpnt); 201 if(con == nil) 202 r = 0; 203 else{ 204 r = 1; 205 con->noauth = Aflag; 206 con->noperm = Pflag; 207 con->wstatallow = Wflag; 208 } 209 } 210 if(r == 0){ 211 close(fd[1]); 212 vtLock(sbox.lock); 213 srvFree(srv); 214 vtUnlock(sbox.lock); 215 } 216 217 return r; 218 } 219 220 int 221 srvInit(void) 222 { 223 sbox.lock = vtLockAlloc(); 224 225 cliAddCmd("srv", cmdSrv); 226 227 return 1; 228 } 229