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 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 if(sp == nil || sname == nil) { 154 free(sp); 155 free(sname); 156 error(Enomem); 157 } 158 159 qlock(&srvlk); 160 if(waserror()){ 161 free(sp); 162 qunlock(&srvlk); 163 nexterror(); 164 } 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->name); 230 free(sp); 231 } 232 233 static int 234 srvwstat(Chan *c, uchar *dp, int n) 235 { 236 char *strs; 237 Dir d; 238 Srv *sp; 239 240 if(c->qid.type & QTDIR) 241 error(Eperm); 242 243 strs = nil; 244 qlock(&srvlk); 245 if(waserror()){ 246 qunlock(&srvlk); 247 free(strs); 248 nexterror(); 249 } 250 251 sp = srvlookup(nil, c->qid.path); 252 if(sp == 0) 253 error(Enonexist); 254 255 if(strcmp(sp->owner, up->user) != 0 && !iseve()) 256 error(Eperm); 257 258 strs = smalloc(n); 259 n = convM2D(dp, n, &d, strs); 260 if(n == 0) 261 error(Eshortstat); 262 if(d.mode != ~0UL) 263 sp->perm = d.mode & 0777; 264 if(d.uid && *d.uid) 265 kstrdup(&sp->owner, d.uid); 266 if(d.name && *d.name && strcmp(sp->name, d.name) != 0) { 267 if(strchr(d.name, '/') != nil) 268 error(Ebadchar); 269 kstrdup(&sp->name, d.name); 270 } 271 qunlock(&srvlk); 272 free(strs); 273 poperror(); 274 return n; 275 } 276 277 static void 278 srvclose(Chan *c) 279 { 280 /* 281 * in theory we need to override any changes in removability 282 * since open, but since all that's checked is the owner, 283 * which is immutable, all is well. 284 */ 285 if(c->flag & CRCLOSE){ 286 if(waserror()) 287 return; 288 srvremove(c); 289 poperror(); 290 } 291 } 292 293 static long 294 srvread(Chan *c, void *va, long n, vlong) 295 { 296 isdir(c); 297 return devdirread(c, va, n, 0, 0, srvgen); 298 } 299 300 static long 301 srvwrite(Chan *c, void *va, long n, vlong) 302 { 303 Srv *sp; 304 Chan *c1; 305 int fd; 306 char buf[32]; 307 308 if(n >= sizeof buf) 309 error(Egreg); 310 memmove(buf, va, n); /* so we can NUL-terminate */ 311 buf[n] = 0; 312 fd = strtoul(buf, 0, 0); 313 314 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 315 316 qlock(&srvlk); 317 if(waserror()) { 318 qunlock(&srvlk); 319 cclose(c1); 320 nexterror(); 321 } 322 if(c1->flag & (CCEXEC|CRCLOSE)) 323 error("posted fd has remove-on-close or close-on-exec"); 324 if(c1->qid.type & QTAUTH) 325 error("cannot post auth file in srv"); 326 sp = srvlookup(nil, c->qid.path); 327 if(sp == 0) 328 error(Enonexist); 329 330 if(sp->chan) 331 error(Ebadusefd); 332 333 sp->chan = c1; 334 qunlock(&srvlk); 335 poperror(); 336 return n; 337 } 338 339 Dev srvdevtab = { 340 's', 341 "srv", 342 343 devreset, 344 srvinit, 345 devshutdown, 346 srvattach, 347 srvwalk, 348 srvstat, 349 srvopen, 350 srvcreate, 351 srvclose, 352 srvread, 353 devbread, 354 srvwrite, 355 devbwrite, 356 srvremove, 357 srvwstat, 358 }; 359