devsrv.c (5982B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "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 *name, Dirtab *dt, int i, 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->ref); 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 char *sname; 143 Srv *sp; 144 145 if(openmode(omode) != OWRITE) 146 error(Eperm); 147 148 if(omode & OCEXEC) /* can't happen */ 149 panic("someone broke namec"); 150 151 sp = smalloc(sizeof *sp); 152 sname = smalloc(strlen(name)+1); 153 154 qlock(&srvlk); 155 if(waserror()){ 156 free(sp); 157 free(sname); 158 qunlock(&srvlk); 159 nexterror(); 160 } 161 if(sp == nil || sname == nil) 162 error(Enomem); 163 if(srvlookup(name, -1)) 164 error(Eexist); 165 166 sp->path = qidpath++; 167 sp->link = srv; 168 strcpy(sname, name); 169 sp->name = sname; 170 c->qid.type = QTFILE; 171 c->qid.path = sp->path; 172 srv = sp; 173 qunlock(&srvlk); 174 poperror(); 175 176 kstrdup(&sp->owner, up->user); 177 sp->perm = perm&0777; 178 179 c->flag |= COPEN; 180 c->mode = OWRITE; 181 } 182 183 static void 184 srvremove(Chan *c) 185 { 186 Srv *sp, **l; 187 188 if(c->qid.type == QTDIR) 189 error(Eperm); 190 191 qlock(&srvlk); 192 if(waserror()){ 193 qunlock(&srvlk); 194 nexterror(); 195 } 196 l = &srv; 197 for(sp = *l; sp; sp = sp->link) { 198 if(sp->path == c->qid.path) 199 break; 200 201 l = &sp->link; 202 } 203 if(sp == 0) 204 error(Enonexist); 205 206 /* 207 * Only eve can remove system services. 208 * No one can remove #s/boot. 209 */ 210 if(strcmp(sp->owner, eve) == 0 && !iseve()) 211 error(Eperm); 212 if(strcmp(sp->name, "boot") == 0) 213 error(Eperm); 214 215 /* 216 * No removing personal services. 217 */ 218 if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve()) 219 error(Eperm); 220 221 *l = sp->link; 222 qunlock(&srvlk); 223 poperror(); 224 225 if(sp->chan) 226 cclose(sp->chan); 227 free(sp->name); 228 free(sp); 229 } 230 231 static int 232 srvwstat(Chan *c, uchar *dp, int n) 233 { 234 char *strs; 235 Dir d; 236 Srv *sp; 237 238 if(c->qid.type & QTDIR) 239 error(Eperm); 240 241 strs = nil; 242 qlock(&srvlk); 243 if(waserror()){ 244 qunlock(&srvlk); 245 free(strs); 246 nexterror(); 247 } 248 249 sp = srvlookup(nil, c->qid.path); 250 if(sp == 0) 251 error(Enonexist); 252 253 if(strcmp(sp->owner, up->user) != 0 && !iseve()) 254 error(Eperm); 255 256 strs = smalloc(n); 257 n = convM2D(dp, n, &d, strs); 258 if(n == 0) 259 error(Eshortstat); 260 if(d.mode != ~0UL) 261 sp->perm = d.mode & 0777; 262 if(d.uid && *d.uid) 263 kstrdup(&sp->owner, d.uid); 264 if(d.name && *d.name && strcmp(sp->name, d.name) != 0) { 265 if(strchr(d.name, '/') != nil) 266 error(Ebadchar); 267 kstrdup(&sp->name, d.name); 268 } 269 qunlock(&srvlk); 270 free(strs); 271 poperror(); 272 return n; 273 } 274 275 static void 276 srvclose(Chan *c) 277 { 278 /* 279 * in theory we need to override any changes in removability 280 * since open, but since all that's checked is the owner, 281 * which is immutable, all is well. 282 */ 283 if(c->flag & CRCLOSE){ 284 if(waserror()) 285 return; 286 srvremove(c); 287 poperror(); 288 } 289 } 290 291 static long 292 srvread(Chan *c, void *va, long n, vlong off) 293 { 294 isdir(c); 295 return devdirread(c, va, n, 0, 0, srvgen); 296 } 297 static void srvadd(Chan*, Chan*); 298 299 300 static long 301 srvwrite(Chan *c, void *va, long n, vlong off) 302 { 303 Chan *c1; 304 int fd; 305 char buf[32]; 306 307 if(n >= sizeof buf) 308 error(Egreg); 309 memmove(buf, va, n); /* so we can NUL-terminate */ 310 buf[n] = 0; 311 fd = strtoul(buf, 0, 0); 312 313 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 314 srvadd(c, c1); 315 return n; 316 } 317 318 // Plan 9 VX split srvadd out from srvwrite. 319 static void 320 srvadd(Chan *c, Chan *c1) 321 { 322 Srv *sp; 323 324 /* c1 already incref'ed */ 325 326 qlock(&srvlk); 327 if(waserror()) { 328 qunlock(&srvlk); 329 cclose(c1); 330 nexterror(); 331 } 332 if(c1->flag & (CCEXEC|CRCLOSE)) 333 error("posted fd has remove-on-close or close-on-exec"); 334 if(c1->qid.type & QTAUTH) 335 error("cannot post auth file in srv"); 336 sp = srvlookup(nil, c->qid.path); 337 if(sp == 0) 338 error(Enonexist); 339 340 if(sp->chan) 341 error(Ebadusefd); 342 343 sp->chan = c1; 344 qunlock(&srvlk); 345 poperror(); 346 } 347 348 Dev srvdevtab = { 349 's', 350 "srv", 351 352 devreset, 353 srvinit, 354 devshutdown, 355 srvattach, 356 srvwalk, 357 srvstat, 358 srvopen, 359 srvcreate, 360 srvclose, 361 srvread, 362 devbread, 363 srvwrite, 364 devbwrite, 365 srvremove, 366 srvwstat, 367 }; 368 369 // Plan 9 VX addition 370 void 371 ksrvadd(Chan *c, Chan *c1) 372 { 373 incref(&c1->ref); 374 srvadd(c, c1); 375 } 376