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