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