1 #include "stdinc.h" 2 3 #include "9.h" 4 5 typedef struct Srv Srv; 6 struct Srv { 7 int fd; 8 int srvfd; 9 char* service; 10 char* mntpnt; 11 12 Srv* next; 13 Srv* prev; 14 }; 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 conflags, dflag, fd[2], mode, pflag, r; 135 136 dflag = 0; 137 pflag = 0; 138 conflags = 0; 139 mode = 0666; 140 141 ARGBEGIN{ 142 default: 143 return cliError(usage); 144 case 'A': 145 conflags |= ConNoAuthCheck; 146 break; 147 case 'I': 148 conflags |= ConIPCheck; 149 break; 150 case 'N': 151 conflags |= ConNoneAllow; 152 break; 153 case 'P': 154 conflags |= ConNoPermCheck; 155 mode = 0600; 156 break; 157 case 'W': 158 conflags |= ConWstatAllow; 159 mode = 0600; 160 break; 161 case 'd': 162 dflag = 1; 163 break; 164 case 'p': 165 pflag = 1; 166 mode = 0600; 167 break; 168 }ARGEND 169 170 if(pflag && (conflags&ConNoPermCheck)){ 171 vtSetError("srv: cannot use -P with -p"); 172 return 0; 173 } 174 175 switch(argc){ 176 default: 177 return cliError(usage); 178 case 0: 179 vtRLock(sbox.lock); 180 for(srv = sbox.head; srv != nil; srv = srv->next) 181 consPrint("\t%s\t%d\n", srv->service, srv->srvfd); 182 vtRUnlock(sbox.lock); 183 184 return 1; 185 case 1: 186 if(!dflag) 187 break; 188 189 vtLock(sbox.lock); 190 for(srv = sbox.head; srv != nil; srv = srv->next){ 191 if(strcmp(srv->service, argv[0]) != 0) 192 continue; 193 srvFree(srv); 194 break; 195 } 196 vtUnlock(sbox.lock); 197 198 if(srv == nil){ 199 vtSetError("srv: '%s' not found", argv[0]); 200 return 0; 201 } 202 203 return 1; 204 } 205 206 if(pipe(fd) < 0){ 207 vtSetError("srv pipe: %r"); 208 return 0; 209 } 210 if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ 211 close(fd[0]); close(fd[1]); 212 return 0; 213 } 214 215 if(pflag) 216 r = consOpen(fd[1], srv->srvfd, -1); 217 else{ 218 con = conAlloc(fd[1], srv->mntpnt, conflags); 219 if(con == nil) 220 r = 0; 221 else 222 r = 1; 223 } 224 if(r == 0){ 225 close(fd[1]); 226 vtLock(sbox.lock); 227 srvFree(srv); 228 vtUnlock(sbox.lock); 229 } 230 231 return r; 232 } 233 234 int 235 srvInit(void) 236 { 237 sbox.lock = vtLockAlloc(); 238 239 cliAddCmd("srv", cmdSrv); 240 241 return 1; 242 } 243