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 int size; 90 Srv *sp; 91 char *s; 92 93 for(sp = srv; sp; sp = sp->link) 94 if(sp->chan == c){ 95 size = 3+strlen(sp->name)+1; 96 s = smalloc(size); 97 snprint(s, size, "#s/%s", sp->name); 98 return s; 99 } 100 return nil; 101 } 102 103 static Chan* 104 srvopen(Chan *c, int omode) 105 { 106 Srv *sp; 107 108 if(c->qid.type == QTDIR){ 109 if(omode & ORCLOSE) 110 error(Eperm); 111 if(omode != OREAD) 112 error(Eisdir); 113 c->mode = omode; 114 c->flag |= COPEN; 115 c->offset = 0; 116 return c; 117 } 118 qlock(&srvlk); 119 if(waserror()){ 120 qunlock(&srvlk); 121 nexterror(); 122 } 123 124 sp = srvlookup(nil, c->qid.path); 125 if(sp == 0 || sp->chan == 0) 126 error(Eshutdown); 127 128 if(omode&OTRUNC) 129 error("srv file already exists"); 130 if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR) 131 error(Eperm); 132 devpermcheck(sp->owner, sp->perm, omode); 133 134 cclose(c); 135 incref(sp->chan); 136 qunlock(&srvlk); 137 poperror(); 138 return sp->chan; 139 } 140 141 static void 142 srvcreate(Chan *c, char *name, int omode, ulong perm) 143 { 144 char *sname; 145 Srv *sp; 146 147 if(openmode(omode) != OWRITE) 148 error(Eperm); 149 150 if(omode & OCEXEC) /* can't happen */ 151 panic("someone broke namec"); 152 153 sp = smalloc(sizeof *sp); 154 sname = smalloc(strlen(name)+1); 155 156 qlock(&srvlk); 157 if(waserror()){ 158 free(sp); 159 free(sname); 160 qunlock(&srvlk); 161 nexterror(); 162 } 163 if(sp == nil || sname == nil) 164 error(Enomem); 165 if(srvlookup(name, -1)) 166 error(Eexist); 167 168 sp->path = qidpath++; 169 sp->link = srv; 170 strcpy(sname, name); 171 sp->name = sname; 172 c->qid.type = QTFILE; 173 c->qid.path = sp->path; 174 srv = sp; 175 qunlock(&srvlk); 176 poperror(); 177 178 kstrdup(&sp->owner, up->user); 179 sp->perm = perm&0777; 180 181 c->flag |= COPEN; 182 c->mode = OWRITE; 183 } 184 185 static void 186 srvremove(Chan *c) 187 { 188 Srv *sp, **l; 189 190 if(c->qid.type == QTDIR) 191 error(Eperm); 192 193 qlock(&srvlk); 194 if(waserror()){ 195 qunlock(&srvlk); 196 nexterror(); 197 } 198 l = &srv; 199 for(sp = *l; sp; sp = sp->link) { 200 if(sp->path == c->qid.path) 201 break; 202 203 l = &sp->link; 204 } 205 if(sp == 0) 206 error(Enonexist); 207 208 /* 209 * Only eve can remove system services. 210 * No one can remove #s/boot. 211 */ 212 if(strcmp(sp->owner, eve) == 0 && !iseve()) 213 error(Eperm); 214 if(strcmp(sp->name, "boot") == 0) 215 error(Eperm); 216 217 /* 218 * No removing personal services. 219 */ 220 if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve()) 221 error(Eperm); 222 223 *l = sp->link; 224 qunlock(&srvlk); 225 poperror(); 226 227 if(sp->chan) 228 cclose(sp->chan); 229 free(sp->owner); 230 free(sp->name); 231 free(sp); 232 } 233 234 static int 235 srvwstat(Chan *c, uchar *dp, int n) 236 { 237 char *strs; 238 Dir d; 239 Srv *sp; 240 241 if(c->qid.type & QTDIR) 242 error(Eperm); 243 244 strs = nil; 245 qlock(&srvlk); 246 if(waserror()){ 247 qunlock(&srvlk); 248 free(strs); 249 nexterror(); 250 } 251 252 sp = srvlookup(nil, c->qid.path); 253 if(sp == 0) 254 error(Enonexist); 255 256 if(strcmp(sp->owner, up->user) != 0 && !iseve()) 257 error(Eperm); 258 259 strs = smalloc(n); 260 n = convM2D(dp, n, &d, strs); 261 if(n == 0) 262 error(Eshortstat); 263 if(d.mode != ~0UL) 264 sp->perm = d.mode & 0777; 265 if(d.uid && *d.uid) 266 kstrdup(&sp->owner, d.uid); 267 if(d.name && *d.name && strcmp(sp->name, d.name) != 0) { 268 if(strchr(d.name, '/') != nil) 269 error(Ebadchar); 270 kstrdup(&sp->name, d.name); 271 } 272 qunlock(&srvlk); 273 free(strs); 274 poperror(); 275 return n; 276 } 277 278 static void 279 srvclose(Chan *c) 280 { 281 /* 282 * in theory we need to override any changes in removability 283 * since open, but since all that's checked is the owner, 284 * which is immutable, all is well. 285 */ 286 if(c->flag & CRCLOSE){ 287 if(waserror()) 288 return; 289 srvremove(c); 290 poperror(); 291 } 292 } 293 294 static long 295 srvread(Chan *c, void *va, long n, vlong) 296 { 297 isdir(c); 298 return devdirread(c, va, n, 0, 0, srvgen); 299 } 300 301 static long 302 srvwrite(Chan *c, void *va, long n, vlong) 303 { 304 Srv *sp; 305 Chan *c1; 306 int fd; 307 char buf[32]; 308 309 if(n >= sizeof buf) 310 error(Egreg); 311 memmove(buf, va, n); /* so we can NUL-terminate */ 312 buf[n] = 0; 313 fd = strtoul(buf, 0, 0); 314 315 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 316 317 qlock(&srvlk); 318 if(waserror()) { 319 qunlock(&srvlk); 320 cclose(c1); 321 nexterror(); 322 } 323 if(c1->flag & (CCEXEC|CRCLOSE)) 324 error("posted fd has remove-on-close or close-on-exec"); 325 if(c1->qid.type & QTAUTH) 326 error("cannot post auth file in srv"); 327 sp = srvlookup(nil, c->qid.path); 328 if(sp == 0) 329 error(Enonexist); 330 331 if(sp->chan) 332 error(Ebadusefd); 333 334 sp->chan = c1; 335 qunlock(&srvlk); 336 poperror(); 337 return n; 338 } 339 340 Dev srvdevtab = { 341 's', 342 "srv", 343 344 devreset, 345 srvinit, 346 devshutdown, 347 srvattach, 348 srvwalk, 349 srvstat, 350 srvopen, 351 srvcreate, 352 srvclose, 353 srvread, 354 devbread, 355 srvwrite, 356 devbwrite, 357 srvremove, 358 srvwstat, 359 }; 360