diff options
| author | forsyth <forsyth@vitanuova.com> | 2011-03-29 08:55:03 +0100 |
|---|---|---|
| committer | forsyth <forsyth@vitanuova.com> | 2011-03-29 08:55:03 +0100 |
| commit | 35a6f3e10aa63aa1ac127c14186949900fe25993 (patch) | |
| tree | fe00f91e4d847dd3f633c707457f89b4291402b4 /emu/port/devfs-posix.c | |
| parent | 3a78c580bfacbdc12a08507f98b0dfb3c9b78f94 (diff) | |
20110329-0852
Diffstat (limited to 'emu/port/devfs-posix.c')
| -rw-r--r-- | emu/port/devfs-posix.c | 205 |
1 files changed, 120 insertions, 85 deletions
diff --git a/emu/port/devfs-posix.c b/emu/port/devfs-posix.c index 7372f589..c4aa3d9a 100644 --- a/emu/port/devfs-posix.c +++ b/emu/port/devfs-posix.c @@ -10,6 +10,8 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/fcntl.h> +#include <sys/socket.h> +#include <sys/un.h> #include <utime.h> #include <dirent.h> #include <stdio.h> @@ -30,6 +32,7 @@ struct Fsinfo int fd; /* open files */ ulong offset; /* offset when reading directory */ int eod; /* end of directory */ + int issocket; QLock oq; /* mutex for offset */ char* spec; Cname* name; /* Unix's name for file */ @@ -81,8 +84,7 @@ static int fsomode(int); static void fsremove(Chan*); /* - * this crud is to compensate for invalid symbolic links; - * all you can do is delete them, and good riddance + * make invalid symbolic links visible; less confusing, and at least you can then delete them. */ static int xstat(char *f, struct stat *sb) @@ -104,28 +106,31 @@ Chan* fsattach(char *spec) { Chan *c; - struct stat stbuf; + struct stat st; static int devno; static Lock l; if(!emptystr(spec) && strcmp(spec, "*") != 0) error(Ebadspec); - if(stat(rootdir, &stbuf) < 0) + if(stat(rootdir, &st) < 0) oserror(); + if(!S_ISDIR(st.st_mode)) + error(Enotdir); c = devattach('U', spec); - c->qid = fsqid(&stbuf); + c->qid = fsqid(&st); c->aux = smalloc(sizeof(Fsinfo)); FS(c)->dir = nil; FS(c)->de = nil; FS(c)->fd = -1; - FS(c)->gid = stbuf.st_gid; - FS(c)->uid = stbuf.st_uid; - FS(c)->mode = stbuf.st_mode; + FS(c)->issocket = 0; + FS(c)->gid = st.st_gid; + FS(c)->uid = st.st_uid; + FS(c)->mode = st.st_mode; lock(&l); c->dev = devno++; unlock(&l); - if (!emptystr(spec)){ + if(!emptystr(spec)){ FS(c)->spec = "/"; FS(c)->name = newcname(FS(c)->spec); }else @@ -141,7 +146,7 @@ fswalk(Chan *c, Chan *nc, char **name, int nname) int j; volatile int alloc; Walkqid *wq; - struct stat stbuf; + struct stat st; char *n; Cname *next; Cname *volatile current; @@ -182,14 +187,14 @@ fswalk(Chan *c, Chan *nc, char **name, int nname) incref(&next->r); next = addelem(current, n); //print("** ufs walk '%s' -> %s [%s]\n", current->s, n, next->s); - if(xstat(next->s, &stbuf) < 0){ + if(xstat(next->s, &st) < 0){ cnameclose(next); if(j == 0) error(Enonexist); strcpy(up->env->errstr, Enonexist); break; } - nc->qid = fsqid(&stbuf); + nc->qid = fsqid(&st); cnameclose(current); current = next; } @@ -204,14 +209,16 @@ fswalk(Chan *c, Chan *nc, char **name, int nname) }else if(wq->clone){ nc->aux = smalloc(sizeof(Fsinfo)); nc->type = c->type; - if (nname) { - FS(nc)->gid = stbuf.st_gid; - FS(nc)->uid = stbuf.st_uid; - FS(nc)->mode = stbuf.st_mode; + if(nname > 0) { + FS(nc)->gid = st.st_gid; + FS(nc)->uid = st.st_uid; + FS(nc)->mode = st.st_mode; + FS(nc)->issocket = S_ISSOCK(st.st_mode); } else { FS(nc)->gid = FS(c)->gid; FS(nc)->uid = FS(c)->uid; FS(nc)->mode = FS(c)->mode; + FS(nc)->issocket = FS(c)->issocket; } FS(nc)->name = current; FS(nc)->spec = FS(c)->spec; @@ -226,20 +233,39 @@ fswalk(Chan *c, Chan *nc, char **name, int nname) static int fsstat(Chan *c, uchar *dp, int n) { - struct stat stbuf; + struct stat st; char *p; - if(xstat(FS(c)->name->s, &stbuf) < 0) + if(xstat(FS(c)->name->s, &st) < 0) oserror(); p = fslastelem(FS(c)->name); if(*p == 0) p = "/"; qlock(&idl); - n = fsdirconv(c, p, &stbuf, dp, n, 0); + n = fsdirconv(c, p, &st, dp, n, 0); qunlock(&idl); return n; } +static int +opensocket(char *path) +{ + int fd; + struct sockaddr_un su; + + memset(&su, 0, sizeof su); + su.sun_family = AF_UNIX; + if(strlen(path)+1 > sizeof su.sun_path) + error("unix socket name too long"); + strcpy(su.sun_path, path); + if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + if(connect(fd, (struct sockaddr*)&su, sizeof su) >= 0) + return fd; + close(fd); + return -1; +} + static Chan* fsopen(Chan *c, int mode) { @@ -277,14 +303,17 @@ fsopen(Chan *c, int mode) if(isdir) { FS(c)->dir = opendir(FS(c)->name->s); - if(FS(c)->dir == 0) + if(FS(c)->dir == nil) oserror(); FS(c)->eod = 0; } else { - if(mode & OTRUNC) - m |= O_TRUNC; - FS(c)->fd = open(FS(c)->name->s, m, 0666); + if(!FS(c)->issocket){ + if(mode & OTRUNC) + m |= O_TRUNC; + FS(c)->fd = open(FS(c)->name->s, m, 0666); + }else + FS(c)->fd = opensocket(FS(c)->name->s); if(FS(c)->fd < 0) oserror(); } @@ -299,7 +328,7 @@ static void fscreate(Chan *c, char *name, int mode, ulong perm) { int fd, m, o; - struct stat stbuf; + struct stat st; Cname *n; fsperm(c, 2); @@ -327,7 +356,7 @@ fscreate(Chan *c, char *name, int mode, ulong perm) oserror(); fchmod(fd, perm); fchown(fd, up->env->uid, FS(c)->gid); - if(fstat(fd, &stbuf) <0){ + if(fstat(fd, &st) <0){ close(fd); oserror(); } @@ -346,7 +375,7 @@ fscreate(Chan *c, char *name, int mode, ulong perm) oserror(); fchmod(fd, perm); fchown(fd, up->env->uid, FS(c)->gid); - if(fstat(fd, &stbuf) < 0){ + if(fstat(fd, &st) < 0){ close(fd); oserror(); } @@ -356,13 +385,14 @@ fscreate(Chan *c, char *name, int mode, ulong perm) FS(c)->name = n; poperror(); - c->qid = fsqid(&stbuf); - FS(c)->gid = stbuf.st_gid; - FS(c)->uid = stbuf.st_uid; - FS(c)->mode = stbuf.st_mode; + c->qid = fsqid(&st); + FS(c)->gid = st.st_gid; + FS(c)->uid = st.st_uid; + FS(c)->mode = st.st_mode; c->mode = openmode(mode); c->offset = 0; FS(c)->offset = 0; + FS(c)->issocket = 0; c->flag |= COPEN; } @@ -400,15 +430,16 @@ fsread(Chan *c, void *va, long n, vlong offset) poperror(); qunlock(&FS(c)->oq); }else{ - r = pread(FS(c)->fd, va, n, offset); - if(r < 0){ - if(errno == ESPIPE || errno == EPIPE){ - r = read(FS(c)->fd, va, n); - if(r >= 0) - return r; - } - oserror(); + if(!FS(c)->issocket){ + r = pread(FS(c)->fd, va, n, offset); + if(r >= 0) + return r; + if(errno != ESPIPE && errno != EPIPE) + oserror(); } + r = read(FS(c)->fd, va, n); + if(r < 0) + oserror(); } return r; } @@ -418,30 +449,33 @@ fswrite(Chan *c, void *va, long n, vlong offset) { long r; - r = pwrite(FS(c)->fd, va, n, offset); - if(r < 0 && (errno == ESPIPE || errno == EPIPE)){ - r = write(FS(c)->fd, va, n); - if(r < 0) + if(!FS(c)->issocket){ + r = pwrite(FS(c)->fd, va, n, offset); + if(r >= 0) + return r; + if(errno != ESPIPE && errno != EPIPE) oserror(); } + r = write(FS(c)->fd, va, n); + if(r < 0) + oserror(); return r; } static void fswchk(Cname *c) { - struct stat stbuf; + struct stat st; - if(stat(c->s, &stbuf) < 0) + if(stat(c->s, &st) < 0) oserror(); - if(stbuf.st_uid == up->env->uid) - stbuf.st_mode >>= 6; - else - if(stbuf.st_gid == up->env->gid || ingroup(up->env->uid, stbuf.st_gid)) - stbuf.st_mode >>= 3; + if(st.st_uid == up->env->uid) + st.st_mode >>= 6; + else if(st.st_gid == up->env->gid || ingroup(up->env->uid, st.st_gid)) + st.st_mode >>= 3; - if(stbuf.st_mode & S_IWOTH) + if(st.st_mode & S_IWOTH) return; error(Eperm); @@ -451,18 +485,20 @@ static void fsremove(Chan *c) { int n; - volatile struct { Cname *dir; } dir; + Cname *volatile dir; - dir.dir = fswalkpath(FS(c)->name, "..", 1); if(waserror()){ - if(dir.dir != nil) - cnameclose(dir.dir); fsfree(c); nexterror(); } - fswchk(dir.dir); - cnameclose(dir.dir); - dir.dir = nil; + dir = fswalkpath(FS(c)->name, "..", 1); + if(waserror()){ + cnameclose(dir); + nexterror(); + } + fswchk(dir); + cnameclose(dir); + poperror(); if(c->qid.type & QTDIR) n = rmdir(FS(c)->name->s); else @@ -478,16 +514,16 @@ fswstat(Chan *c, uchar *buf, int nb) { Dir *d; User *p; - volatile struct { Cname *ph; } ph; - struct stat stbuf; + Cname *volatile ph; + struct stat st; struct utimbuf utbuf; int tsync; if(FS(c)->fd >= 0){ - if(fstat(FS(c)->fd, &stbuf) < 0) + if(fstat(FS(c)->fd, &st) < 0) oserror(); }else{ - if(stat(FS(c)->name->s, &stbuf) < 0) + if(stat(FS(c)->name->s, &st) < 0) oserror(); } d = malloc(sizeof(*d)+nb); @@ -504,23 +540,23 @@ fswstat(Chan *c, uchar *buf, int nb) if(!emptystr(d->name) && strcmp(d->name, fslastelem(FS(c)->name)) != 0) { tsync = 0; validname(d->name, 0); - ph.ph = fswalkpath(FS(c)->name, "..", 1); + ph = fswalkpath(FS(c)->name, "..", 1); if(waserror()){ - cnameclose(ph.ph); + cnameclose(ph); nexterror(); } - fswchk(ph.ph); - ph.ph = fswalkpath(ph.ph, d->name, 0); - if(rename(FS(c)->name->s, ph.ph->s) < 0) + fswchk(ph); + ph = fswalkpath(ph, d->name, 0); + if(rename(FS(c)->name->s, ph->s) < 0) oserror(); cnameclose(FS(c)->name); poperror(); - FS(c)->name = ph.ph; + FS(c)->name = ph; } - if(d->mode != ~0 && (d->mode&0777) != (stbuf.st_mode&0777)) { + if(d->mode != ~0 && (d->mode&0777) != (st.st_mode&0777)) { tsync = 0; - if(up->env->uid != stbuf.st_uid) + if(up->env->uid != st.st_uid) error(Eowner); if(FS(c)->fd >= 0){ if(fchmod(FS(c)->fd, d->mode&0777) < 0) @@ -533,19 +569,19 @@ fswstat(Chan *c, uchar *buf, int nb) FS(c)->mode |= d->mode&0777; } - if(d->atime != ~0 && d->atime != stbuf.st_atime - || d->mtime != ~0 && d->mtime != stbuf.st_mtime) { + if(d->atime != ~0 && d->atime != st.st_atime || + d->mtime != ~0 && d->mtime != st.st_mtime) { tsync = 0; - if(up->env->uid != stbuf.st_uid) + if(up->env->uid != st.st_uid) error(Eowner); if(d->mtime != ~0) utbuf.modtime = d->mtime; else - utbuf.modtime = stbuf.st_mtime; + utbuf.modtime = st.st_mtime; if(d->atime != ~0) utbuf.actime = d->atime; else - utbuf.actime = stbuf.st_atime; + utbuf.actime = st.st_atime; if(utime(FS(c)->name->s, &utbuf) < 0) /* TO DO: futimes isn't portable */ oserror(); } @@ -560,14 +596,14 @@ fswstat(Chan *c, uchar *buf, int nb) p = name2user(gidmap, d->gid, newgname); if(p == 0) error(Eunknown); - if(p->id != stbuf.st_gid) { - if(up->env->uid != stbuf.st_uid) + if(p->id != st.st_gid) { + if(up->env->uid != st.st_uid) error(Eowner); if(FS(c)->fd >= 0){ - if(fchown(FS(c)->fd, stbuf.st_uid, p->id) < 0) + if(fchown(FS(c)->fd, st.st_uid, p->id) < 0) oserror(); }else{ - if(chown(FS(c)->name->s, stbuf.st_uid, p->id) < 0) + if(chown(FS(c)->name->s, st.st_uid, p->id) < 0) oserror(); } FS(c)->gid = p->id; @@ -691,8 +727,7 @@ fsperm(Chan *c, int mask) */ if(FS(c)->uid == up->env->uid) m >>= 6; - else - if(FS(c)->gid == up->env->gid || ingroup(up->env->uid, FS(c)->gid)) + else if(FS(c)->gid == up->env->gid || ingroup(up->env->uid, FS(c)->gid)) m >>= 3; m &= mask; @@ -747,7 +782,7 @@ fsdirread(Chan *c, uchar *va, int count, vlong offset) { int i; long n, r; - struct stat stbuf; + struct stat st; char path[MAXPATH], *ep; struct dirent *de; static uchar slop[8192]; @@ -770,7 +805,7 @@ fsdirread(Chan *c, uchar *va, int count, vlong offset) if(de->d_ino==0 || de->d_name[0]==0 || isdots(de->d_name)) continue; strecpy(ep, path+sizeof(path), de->d_name); - if(xstat(path, &stbuf) < 0) { + if(xstat(path, &st) < 0) { fprint(2, "dir: bad path %s\n", path); continue; } @@ -779,7 +814,7 @@ fsdirread(Chan *c, uchar *va, int count, vlong offset) qunlock(&idl); nexterror(); } - r = fsdirconv(c, de->d_name, &stbuf, slop, sizeof(slop), 1); + r = fsdirconv(c, de->d_name, &st, slop, sizeof(slop), 1); poperror(); qunlock(&idl); if(r <= 0) { @@ -814,11 +849,11 @@ fsdirread(Chan *c, uchar *va, int count, vlong offset) continue; strecpy(ep, path+sizeof(path), de->d_name); - if(xstat(path, &stbuf) < 0) { + if(xstat(path, &st) < 0) { fprint(2, "dir: bad path %s\n", path); continue; } - r = fsdirconv(c, de->d_name, &stbuf, va+i, count-i, 1); + r = fsdirconv(c, de->d_name, &st, va+i, count-i, 1); if(r <= 0){ FS(c)->de = de; break; |
