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)); 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 c->qid.type = QTFILE; 166 c->qid.path = sp->path; 167 srv = sp; 168 qunlock(&srvlk); 169 poperror(); 170 171 sp->name = smalloc(strlen(name)+1); 172 strcpy(sp->name, name); 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 if(strcmp(sp->name, "boot") == 0) 204 error(Eperm); 205 206 *l = sp->link; 207 qunlock(&srvlk); 208 poperror(); 209 210 if(sp->chan) 211 cclose(sp->chan); 212 if(sp->name){ 213 free(sp->name); 214 sp->name = nil; 215 } 216 free(sp); 217 } 218 219 static int 220 srvwstat(Chan *c, uchar *dp, int n) 221 { 222 Dir d; 223 Srv *sp; 224 225 if(c->qid.type & QTDIR) 226 error(Eperm); 227 228 qlock(&srvlk); 229 if(waserror()){ 230 qunlock(&srvlk); 231 nexterror(); 232 } 233 234 sp = srvlookup(nil, c->qid.path); 235 if(sp == 0) 236 error(Enonexist); 237 238 if(strcmp(sp->owner, up->user) && !iseve()) 239 error(Eperm); 240 241 n = convM2D(dp, n, &d, nil); 242 if(n == 0) 243 error (Eshortstat); 244 if(d.mode != ~0UL) 245 sp->perm = d.mode & 0777; 246 247 qunlock(&srvlk); 248 poperror(); 249 return n; 250 } 251 252 static void 253 srvclose(Chan *c) 254 { 255 /* 256 * in theory we need to override any changes in removability 257 * since open, but since all that's checked is the owner, 258 * which is immutable, all is well. 259 */ 260 if(c->flag & CRCLOSE){ 261 if(waserror()) 262 return; 263 srvremove(c); 264 poperror(); 265 } 266 } 267 268 static long 269 srvread(Chan *c, void *va, long n, vlong) 270 { 271 isdir(c); 272 return devdirread(c, va, n, 0, 0, srvgen); 273 } 274 275 static long 276 srvwrite(Chan *c, void *va, long n, vlong) 277 { 278 Srv *sp; 279 Chan *c1; 280 int fd; 281 char buf[32]; 282 283 if(n >= sizeof buf) 284 error(Egreg); 285 memmove(buf, va, n); /* so we can NUL-terminate */ 286 buf[n] = 0; 287 fd = strtoul(buf, 0, 0); 288 289 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 290 291 qlock(&srvlk); 292 if(waserror()) { 293 qunlock(&srvlk); 294 cclose(c1); 295 nexterror(); 296 } 297 if(c1->flag & (CCEXEC|CRCLOSE)) 298 error("posted fd has remove-on-close or close-on-exec"); 299 if(c1->qid.type & QTAUTH) 300 error("can't post auth file in srv"); 301 sp = srvlookup(nil, c->qid.path); 302 if(sp == 0) 303 error(Enonexist); 304 305 if(sp->chan) 306 error(Ebadusefd); 307 308 sp->chan = c1; 309 qunlock(&srvlk); 310 poperror(); 311 return n; 312 } 313 314 Dev srvdevtab = { 315 's', 316 "srv", 317 318 devreset, 319 srvinit, 320 devshutdown, 321 srvattach, 322 srvwalk, 323 srvstat, 324 srvopen, 325 srvcreate, 326 srvclose, 327 srvread, 328 devbread, 329 srvwrite, 330 devbwrite, 331 srvremove, 332 srvwstat, 333 }; 334