1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 9 typedef struct Srv Srv; 10 struct Srv 11 { 12 char *name; 13 char *owner; 14 ulong perm; 15 Chan *chan; 16 Srv *link; 17 ulong path; 18 }; 19 20 static QLock srvlk; 21 static Srv *srv; 22 static int qidpath; 23 24 static int 25 srvgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) 26 { 27 Srv *sp; 28 Qid q; 29 30 if(s == DEVDOTDOT){ 31 devdir(c, c->qid, "#s", 0, eve, 0555, dp); 32 return 1; 33 } 34 35 qlock(&srvlk); 36 for(sp = srv; sp && s; sp = sp->link) 37 s--; 38 39 if(sp == 0) { 40 qunlock(&srvlk); 41 return -1; 42 } 43 44 mkqid(&q, sp->path, 0, QTFILE); 45 /* make sure name string continues to exist after we release lock */ 46 kstrcpy(up->genbuf, sp->name, sizeof up->genbuf); 47 devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp); 48 qunlock(&srvlk); 49 return 1; 50 } 51 52 static void 53 srvinit(void) 54 { 55 qidpath = 1; 56 } 57 58 static Chan* 59 srvattach(char *spec) 60 { 61 return devattach('s', spec); 62 } 63 64 static Walkqid* 65 srvwalk(Chan *c, Chan *nc, char **name, int nname) 66 { 67 return devwalk(c, nc, name, nname, 0, 0, srvgen); 68 } 69 70 static Srv* 71 srvlookup(char *name, ulong qidpath) 72 { 73 Srv *sp; 74 for(sp = srv; sp; sp = sp->link) 75 if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0)) 76 return sp; 77 return nil; 78 } 79 80 static int 81 srvstat(Chan *c, uchar *db, int n) 82 { 83 return devstat(c, db, n, 0, 0, srvgen); 84 } 85 86 char* 87 srvname(Chan *c) 88 { 89 Srv *sp; 90 char *s; 91 92 for(sp = srv; sp; sp = sp->link) 93 if(sp->chan == c){ 94 s = smalloc(3+strlen(sp->name)+1); 95 sprint(s, "#s/%s", sp->name); 96 return s; 97 } 98 return nil; 99 } 100 101 static Chan* 102 srvopen(Chan *c, int omode) 103 { 104 Srv *sp; 105 106 if(c->qid.type == QTDIR){ 107 if(omode & ORCLOSE) 108 error(Eperm); 109 if(omode != OREAD) 110 error(Eisdir); 111 c->mode = omode; 112 c->flag |= COPEN; 113 c->offset = 0; 114 return c; 115 } 116 qlock(&srvlk); 117 if(waserror()){ 118 qunlock(&srvlk); 119 nexterror(); 120 } 121 122 sp = srvlookup(nil, c->qid.path); 123 if(sp == 0 || sp->chan == 0) 124 error(Eshutdown); 125 126 if(omode&OTRUNC) 127 error("srv file already exists"); 128 if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR) 129 error(Eperm); 130 devpermcheck(sp->owner, sp->perm, omode); 131 132 cclose(c); 133 incref(sp->chan); 134 qunlock(&srvlk); 135 poperror(); 136 return sp->chan; 137 } 138 139 static void 140 srvcreate(Chan *c, char *name, int omode, ulong perm) 141 { 142 Srv *sp; 143 144 if(openmode(omode) != OWRITE) 145 error(Eperm); 146 147 if(omode & OCEXEC) /* can't happen */ 148 panic("someone broke namec"); 149 150 sp = malloc(sizeof(Srv)); 151 if(sp == 0) 152 error(Enomem); 153 154 qlock(&srvlk); 155 if(waserror()){ 156 free(sp); 157 qunlock(&srvlk); 158 nexterror(); 159 } 160 if(srvlookup(name, -1)) 161 error(Eexist); 162 163 sp->path = qidpath++; 164 sp->link = srv; 165 c->qid.type = QTFILE; 166 c->qid.path = sp->path; 167 srv = sp; 168 qunlock(&srvlk); 169 poperror(); 170 171 sp->name = smalloc(strlen(name)+1); 172 strcpy(sp->name, name); 173 kstrdup(&sp->owner, up->user); 174 sp->perm = perm&0777; 175 176 c->flag |= COPEN; 177 c->mode = OWRITE; 178 } 179 180 static void 181 srvremove(Chan *c) 182 { 183 Srv *sp, **l; 184 185 if(c->qid.type == QTDIR) 186 error(Eperm); 187 188 qlock(&srvlk); 189 if(waserror()){ 190 qunlock(&srvlk); 191 nexterror(); 192 } 193 l = &srv; 194 for(sp = *l; sp; sp = sp->link) { 195 if(sp->path == c->qid.path) 196 break; 197 198 l = &sp->link; 199 } 200 if(sp == 0) 201 error(Enonexist); 202 203 if(strcmp(sp->name, "boot") == 0) 204 error(Eperm); 205 206 *l = sp->link; 207 qunlock(&srvlk); 208 poperror(); 209 210 if(sp->chan) 211 cclose(sp->chan); 212 if(sp->name){ 213 free(sp->name); 214 sp->name = nil; 215 } 216 free(sp); 217 } 218 219 static int 220 srvwstat(Chan *c, uchar *dp, int n) 221 { 222 Dir d; 223 Srv *sp; 224 225 if(c->qid.type & QTDIR) 226 error(Eperm); 227 228 qlock(&srvlk); 229 if(waserror()){ 230 qunlock(&srvlk); 231 nexterror(); 232 } 233 234 sp = srvlookup(nil, c->qid.path); 235 if(sp == 0) 236 error(Enonexist); 237 238 if(strcmp(sp->owner, up->user) && !iseve()) 239 error(Eperm); 240 241 n = convM2D(dp, n, &d, nil); 242 if(n == 0) 243 error (Eshortstat); 244 if(d.mode != ~0UL) 245 sp->perm = d.mode & 0777; 246 if(d.uid && *d.uid) 247 kstrdup(&sp->owner, d.uid); 248 249 qunlock(&srvlk); 250 poperror(); 251 return n; 252 } 253 254 static void 255 srvclose(Chan *c) 256 { 257 /* 258 * in theory we need to override any changes in removability 259 * since open, but since all that's checked is the owner, 260 * which is immutable, all is well. 261 */ 262 if(c->flag & CRCLOSE){ 263 if(waserror()) 264 return; 265 srvremove(c); 266 poperror(); 267 } 268 } 269 270 static long 271 srvread(Chan *c, void *va, long n, vlong) 272 { 273 isdir(c); 274 return devdirread(c, va, n, 0, 0, srvgen); 275 } 276 277 static long 278 srvwrite(Chan *c, void *va, long n, vlong) 279 { 280 Srv *sp; 281 Chan *c1; 282 int fd; 283 char buf[32]; 284 285 if(n >= sizeof buf) 286 error(Egreg); 287 memmove(buf, va, n); /* so we can NUL-terminate */ 288 buf[n] = 0; 289 fd = strtoul(buf, 0, 0); 290 291 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 292 293 qlock(&srvlk); 294 if(waserror()) { 295 qunlock(&srvlk); 296 cclose(c1); 297 nexterror(); 298 } 299 if(c1->flag & (CCEXEC|CRCLOSE)) 300 error("posted fd has remove-on-close or close-on-exec"); 301 if(c1->qid.type & QTAUTH) 302 error("can't post auth file in srv"); 303 sp = srvlookup(nil, c->qid.path); 304 if(sp == 0) 305 error(Enonexist); 306 307 if(sp->chan) 308 error(Ebadusefd); 309 310 sp->chan = c1; 311 qunlock(&srvlk); 312 poperror(); 313 return n; 314 } 315 316 Dev srvdevtab = { 317 's', 318 "srv", 319 320 devreset, 321 srvinit, 322 devshutdown, 323 srvattach, 324 srvwalk, 325 srvstat, 326 srvopen, 327 srvcreate, 328 srvclose, 329 srvread, 330 devbread, 331 srvwrite, 332 devbwrite, 333 srvremove, 334 srvwstat, 335 }; 336