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->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) 293 { 294 isdir(c); 295 return devdirread(c, va, n, 0, 0, srvgen); 296 } 297 298 static long 299 srvwrite(Chan *c, void *va, long n, vlong) 300 { 301 Srv *sp; 302 Chan *c1; 303 int fd; 304 char buf[32]; 305 306 if(n >= sizeof buf) 307 error(Egreg); 308 memmove(buf, va, n); /* so we can NUL-terminate */ 309 buf[n] = 0; 310 fd = strtoul(buf, 0, 0); 311 312 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 313 314 qlock(&srvlk); 315 if(waserror()) { 316 qunlock(&srvlk); 317 cclose(c1); 318 nexterror(); 319 } 320 if(c1->flag & (CCEXEC|CRCLOSE)) 321 error("posted fd has remove-on-close or close-on-exec"); 322 if(c1->qid.type & QTAUTH) 323 error("cannot post auth file in srv"); 324 sp = srvlookup(nil, c->qid.path); 325 if(sp == 0) 326 error(Enonexist); 327 328 if(sp->chan) 329 error(Ebadusefd); 330 331 sp->chan = c1; 332 qunlock(&srvlk); 333 poperror(); 334 return n; 335 } 336 337 Dev srvdevtab = { 338 's', 339 "srv", 340 341 devreset, 342 srvinit, 343 devshutdown, 344 srvattach, 345 srvwalk, 346 srvstat, 347 srvopen, 348 srvcreate, 349 srvclose, 350 srvread, 351 devbread, 352 srvwrite, 353 devbwrite, 354 srvremove, 355 srvwstat, 356 }; 357