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 Srv *srv; 122 int dflag, fd[2], mode, pflag, r; 123 char *usage = "usage: srv [-dp] [service]"; 124 125 dflag = pflag = 0; 126 mode = 0666; 127 128 ARGBEGIN{ 129 default: 130 return cliError(usage); 131 case 'd': 132 dflag = 1; 133 break; 134 case 'p': 135 pflag = 1; 136 mode = 0600; 137 break; 138 }ARGEND 139 140 switch(argc){ 141 default: 142 return cliError(usage); 143 case 0: 144 vtRLock(sbox.lock); 145 for(srv = sbox.head; srv != nil; srv = srv->next) 146 consPrint("\t%s\t%d\n", srv->service, srv->srvfd); 147 vtRUnlock(sbox.lock); 148 149 return 1; 150 case 1: 151 if(!dflag) 152 break; 153 154 vtLock(sbox.lock); 155 for(srv = sbox.head; srv != nil; srv = srv->next){ 156 if(strcmp(srv->service, argv[0]) != 0) 157 continue; 158 srvFree(srv); 159 break; 160 } 161 vtUnlock(sbox.lock); 162 163 if(srv == nil){ 164 vtSetError("srv: '%s' not found", argv[0]); 165 return 0; 166 } 167 168 return 1; 169 } 170 171 if(pipe(fd) < 0){ 172 vtSetError("srv pipe: %r"); 173 return 0; 174 } 175 if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ 176 close(fd[0]); close(fd[1]); 177 return 0; 178 } 179 180 if(pflag) 181 r = consOpen(fd[1], srv->srvfd, -1); 182 else 183 r = (conAlloc(fd[1], srv->mntpnt) != nil); 184 if(r == 0){ 185 close(fd[1]); 186 vtLock(sbox.lock); 187 srvFree(srv); 188 vtUnlock(sbox.lock); 189 } 190 191 return r; 192 } 193 194 int 195 srvInit(void) 196 { 197 sbox.lock = vtLockAlloc(); 198 199 cliAddCmd("srv", cmdSrv); 200 201 return 1; 202 } 203