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 Dir *dir; 81 Srv *srv; 82 int srvfd; 83 char *mntpnt; 84 85 vtLock(sbox.lock); 86 for(srv = sbox.head; srv != nil; srv = srv->next){ 87 if(strcmp(srv->service, service) != 0) 88 continue; 89 /* 90 * If the service exists, but is stale, 91 * free it up and let the name be reused. 92 */ 93 if((dir = dirfstat(srv->srvfd)) != nil){ 94 free(dir); 95 vtSetError("srv: already serving '%s'", service); 96 vtUnlock(sbox.lock); 97 return nil; 98 } 99 srvFree(srv); 100 break; 101 } 102 103 if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ 104 vtUnlock(sbox.lock); 105 return nil; 106 } 107 close(fd); 108 109 srv = vtMemAllocZ(sizeof(Srv)); 110 srv->srvfd = srvfd; 111 srv->service = vtStrDup(service); 112 srv->mntpnt = mntpnt; 113 114 if(sbox.tail != nil){ 115 srv->prev = sbox.tail; 116 sbox.tail->next = srv; 117 } 118 else{ 119 sbox.head = srv; 120 srv->prev = nil; 121 } 122 sbox.tail = srv; 123 vtUnlock(sbox.lock); 124 125 return srv; 126 } 127 128 static int 129 cmdSrv(int argc, char* argv[]) 130 { 131 Con *con; 132 Srv *srv; 133 char *usage = "usage: srv [-APWdp] [service]"; 134 int Aflag, Pflag, Wflag, dflag, fd[2], mode, pflag, r; 135 136 Aflag = Pflag = Wflag = dflag = pflag = 0; 137 mode = 0666; 138 139 ARGBEGIN{ 140 default: 141 return cliError(usage); 142 case 'A': 143 Aflag = 1; 144 break; 145 case 'P': 146 Pflag = 1; 147 mode = 0600; 148 break; 149 case 'W': 150 Wflag = 1; 151 mode = 0600; 152 break; 153 case 'd': 154 dflag = 1; 155 break; 156 case 'p': 157 pflag = 1; 158 mode = 0600; 159 break; 160 }ARGEND 161 162 if(pflag && Pflag){ 163 vtSetError("srv: cannot use -P with -p"); 164 return 0; 165 } 166 167 switch(argc){ 168 default: 169 return cliError(usage); 170 case 0: 171 vtRLock(sbox.lock); 172 for(srv = sbox.head; srv != nil; srv = srv->next) 173 consPrint("\t%s\t%d\n", srv->service, srv->srvfd); 174 vtRUnlock(sbox.lock); 175 176 return 1; 177 case 1: 178 if(!dflag) 179 break; 180 181 vtLock(sbox.lock); 182 for(srv = sbox.head; srv != nil; srv = srv->next){ 183 if(strcmp(srv->service, argv[0]) != 0) 184 continue; 185 srvFree(srv); 186 break; 187 } 188 vtUnlock(sbox.lock); 189 190 if(srv == nil){ 191 vtSetError("srv: '%s' not found", argv[0]); 192 return 0; 193 } 194 195 return 1; 196 } 197 198 if(pipe(fd) < 0){ 199 vtSetError("srv pipe: %r"); 200 return 0; 201 } 202 if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ 203 close(fd[0]); close(fd[1]); 204 return 0; 205 } 206 207 if(pflag) 208 r = consOpen(fd[1], srv->srvfd, -1); 209 else{ 210 con = conAlloc(fd[1], srv->mntpnt); 211 if(con == nil) 212 r = 0; 213 else{ 214 r = 1; 215 con->noauth = Aflag; 216 con->noperm = Pflag; 217 con->wstatallow = Wflag; 218 } 219 } 220 if(r == 0){ 221 close(fd[1]); 222 vtLock(sbox.lock); 223 srvFree(srv); 224 vtUnlock(sbox.lock); 225 } 226 227 return r; 228 } 229 230 int 231 srvInit(void) 232 { 233 sbox.lock = vtLockAlloc(); 234 235 cliAddCmd("srv", cmdSrv); 236 237 return 1; 238 } 239