wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 8ed8e54507a5a49d15ffb76891334371726c0c3d
parent 418e341a18c45291f62f6bf5d426aa6bad25b675
Author: Anselm R. Garbe <garbeam@wmii.de>
Date:   Mon,  6 Feb 2006 18:43:03 +0100

began with wmiifs 9Pization (tricky parts will follow)


Diffstat:
cmd/Makefile | 2+-
cmd/wmiifs.c | 668++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
2 files changed, 370 insertions(+), 300 deletions(-)

diff --git a/cmd/Makefile b/cmd/Makefile @@ -28,7 +28,7 @@ SRC_warp = wmiiwarp.c OBJ_warp = ${SRC_warp:.c=.o} #all: wmiibar wmiimenu wmiir wmiifs wmiikeys wmiiplumb wmiiwarp -all: wmiibar wmiikeys wmiir wmiiplumb wmiiwarp +all: wmiifs wmiibar wmiikeys wmiir wmiiplumb wmiiwarp @echo built wmii commands .c.o: diff --git a/cmd/wmiifs.c b/cmd/wmiifs.c @@ -6,46 +6,37 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "wmii.h" -/* array indexes for file pointers */ -typedef enum { - F_CTL, - F_LAST -} FsIndexes; +/* + * filesystem specification + * / Droot + * /ctl Fctl command interface + * /foobar Dmount + */ -typedef struct Route Route; -struct Route { - File dest; - int src; +/* 8-bit qid.path.type */ +enum { + Droot, + Dmount, + Fctl }; -typedef struct Bind Bind; -struct Bind { - IXPClient *client; - Route route[MAX_CONN * MAX_OPEN_FILES]; - File *mount; - char *prefix; - Bind *next; +typedef struct Mount Mount; +struct Mount { + unsigned short id; + char wname[256]; + char address[256]; }; +Qid root_qid; static Display *dpy; -static IXPServer *ixps; -static char *sockfile = nil; -static File *files[F_LAST]; -static Bind *bindings = nil; - -static void quit(void *obj, char *arg); -static void bind(void *obj, char *arg); -static void unbind(void *obj, char *arg); - -static Action acttbl[] = { - {"quit", quit}, - {"unbind", unbind}, - {"bind", bind}, - {0, 0} -}; +static IXPServer srv; +static Mount **mount = nil; +static size_t mountsz = 0; +static size_t nmount = 0; static char version[] = "wmiifs - " VERSION ", (C)opyright MMIV-MMVI Anselm R. Garbe\n"; @@ -56,330 +47,393 @@ usage() exit(1); } -static void -quit(void *obj, char *arg) +static Mount * +mount_of_name(char *name) { - Bind *b; - while((b = bindings)) { - bindings = bindings->next; - if(b->mount) { - b->mount->content = nil; - ixp_remove(ixps, b->prefix); - if(ixps->errstr) - fprintf(stderr, "wmiifs: error on unbind %s: %s\n", - b->prefix, ixps->errstr); - } - free(b->prefix); - free(b); - } - bindings = nil; - ixps->runlevel = SHUTDOWN; + size_t i; + for(i = 0; i < nmount; i++) + if(!strncmp(mount[i]->wname, name, sizeof(mount[i]->wname))) + return mount[i]; + return nil; } -static void -do_unbind(Bind * bind) +static int +index_of_id(unsigned short id) { - Bind *b; - if(bind == bindings) - bindings = bind->next; - else { - for(b = bindings; b && b->next != bind; b = b->next); - b->next = bind->next; - } - /* free stuff */ - deinit_client(bind->client); - free(bind->prefix); - free(bind); + int i; + for(i = 0; i < nmount; i++) + if(mount[i]->id == id) + return i; + return -1; } -static void -unbind(void *obj, char *arg) -{ - Bind *b; - - for(b = bindings; b && strncmp(b->prefix, arg, strlen(b->prefix)); - b = b->next); +/* IXP stuff */ - if(!b) { - fprintf(stderr, "wmiifs: unbind: '%s' no such path\n", arg); - return; - } - do_unbind(b); +static unsigned long long +mkqpath(unsigned char type, unsigned short id) +{ + return ((unsigned long long) id << 8) | (unsigned long long) type; } -static void -bind(void *obj, char *arg) +static unsigned char +qpath_type(unsigned long long path) { - Bind *b, *new = nil; - char cmd[1024]; - char *sfile; - - if(!arg) - return; - cext_strlcpy(cmd, arg, sizeof(cmd)); - sfile = strchr(cmd, ' '); - if(!sfile) { - fprintf(stderr, - "wmiifs: bind: '%s' without socket argument, ignoring\n", - arg); - return; /* shortcut with empty argument */ - } - *sfile = 0; - sfile++; - if(*sfile == 0) { - fprintf(stderr, - "wmiifs: bind: '%s' without socket argument, ignoring\n", - arg); - return; /* shortcut with empty argument */ - } - new = cext_emallocz(sizeof(Bind)); - new->client = init_ixp_client(sfile); - - if(!new->client) { - fprintf(stderr, - "wmiifs: bind: cannot connect to server '%s', ignoring\n", - sfile); - free(new); - return; - } - new->prefix = strdup(cmd); - new->mount = ixp_create(ixps, new->prefix); - new->mount->content = new->mount; /* shall be a directory */ - - if(!bindings) - bindings = new; - else { - for(b = bindings; b && b->next; b = b->next); - b->next = new; - } + return path & 0xff; } -static void -handle_after_write(IXPServer * s, File * f) +static unsigned short +qpath_id(unsigned long long path) { - int i; - size_t len; - - for(i = 0; acttbl[i].name; i++) { - len = strlen(acttbl[i].name); - if(!strncmp(acttbl[i].name, (char *) f->content, len)) { - if(strlen(f->content) > len) { - acttbl[i].func(0, &((char *) f->content)[len + 1]); - } else { - acttbl[i].func(0, 0); - } - break; - } - } + return (path >> 8) & 0xffff; } -static Bind * -fd_to_bind(int fd, int *client_fd) +static char * +qid_to_name(Qid *qid) { - File *f = fd_to_file(ixps, fd); - unsigned int i; - Bind *b; - - if(!f) - return nil; - for(b = bindings; b; b = b->next) { - for(i = 0; i < MAX_CONN * MAX_OPEN_FILES; i++) { - if(&b->route[i].dest == f) { - *client_fd = b->route[i].src; - return b; - } - } - } - return nil; + unsigned char type = qpath_type(qid->path); + unsigned short id = qpath_id(qid->path); + int i; + + if(id && ((i = index_of_id(id)) == -1)) + return nil; + switch(type) { + case Droot: return "/"; break; + case Dmount: return mount[i]->wname; break; + case Fctl: return "ctl"; break; + default: return nil; break; + } } -static File * -fixp_create(IXPServer * s, char *path) +static int +name_to_type(char *name) { - Bind *b; - size_t len; + if(!name || !name[0] || !strncmp(name, "/", 2) || !strncmp(name, "..", 3)) + return Droot; + if(!strncmp(name, "ctl", 4)) + return Fctl; + if(mount_of_name(name)) + return Dmount; + return -1; +} - for(b = bindings; b && strncmp(b->prefix, path, strlen(b->prefix)); - b = b->next); +static int +mkqid(Qid *dir, char *wname, Qid *new, Bool iswalk) +{ + Mount *mnt; + int type = name_to_type(wname); + + if((dir->type != IXP_QTDIR) || (type == -1)) + return -1; + + new->dtype = qpath_type(dir->path); + new->version = 0; + switch(type) { + case Droot: + *new = root_qid; + break; + case Dmount: + if(!(mnt = mount_of_name(wname))) + return -1; + new->type = IXP_QTDIR; + new->path = mkqpath(type, mnt->id); + break; + default: + new->type = IXP_QTFILE; + new->path = mkqpath(type, 0); + break; + } + return 0; +} - if(!b) { - File *f = ixp_create(s, path); - return f; - } - /* route to b */ - len = strlen(b->prefix); - b->client->create(b->client, path[len] == 0 ? "/" : &path[len]); - if(b->client->errstr) { - if(!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } - return nil; +static char * +xwalk(IXPConn *c, Fcall *fcall) +{ + unsigned short nwqid = 0; + Qid dir = root_qid; + IXPMap *m; + + if(!(m = ixp_server_fid2map(c, fcall->fid))) + return Enofid; + if(fcall->fid != fcall->newfid && (ixp_server_fid2map(c, fcall->newfid))) + return Enofid; + if(fcall->nwname) { + dir = m->qid; + for(nwqid = 0; (nwqid < fcall->nwname) + && !mkqid(&dir, fcall->wname[nwqid], &fcall->wqid[nwqid], True); nwqid++) { + /*fprintf(stderr, "wname=%s nwqid=%d\n", fcall->wname[nwqid], nwqid);*/ + dir = fcall->wqid[nwqid]; + } + if(!nwqid) + return Enofile; + } + /* a fid will only be valid, if the walk was complete */ + if(nwqid == fcall->nwname) { + if(fcall->fid != fcall->newfid) { + m = cext_emallocz(sizeof(IXPMap)); + c->map = (IXPMap **)cext_array_attach((void **)c->map, + m, sizeof(IXPMap *), &c->mapsz); + } + m->qid = dir; + m->fid = fcall->newfid; + } + fcall->id = RWALK; + fcall->nwqid = nwqid; + ixp_server_respond_fcall(c, fcall); + return nil; } -static File * -fixp_open(IXPServer * s, char *path) +static char * +xopen(IXPConn *c, Fcall *fcall) { - Bind *b; - int fd; - size_t len; + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + + if(!m) + return Enofid; + if(!(fcall->mode | IXP_OREAD) && !(fcall->mode | IXP_OWRITE)) + return Enomode; + fcall->id = ROPEN; + fcall->qid = m->qid; + fcall->iounit = 2048; + ixp_server_respond_fcall(c, fcall); + return nil; +} - for(b = bindings; b && strncmp(b->prefix, path, strlen(b->prefix)); - b = b->next); +static unsigned int +mkstat(Stat *stat, Qid *dir, char *name, unsigned long long length, unsigned int mode) +{ + stat->mode = mode; + stat->atime = stat->mtime = time(0); + cext_strlcpy(stat->uid, getenv("USER"), sizeof(stat->uid)); + cext_strlcpy(stat->gid, getenv("USER"), sizeof(stat->gid)); + cext_strlcpy(stat->muid, getenv("USER"), sizeof(stat->muid)); + + cext_strlcpy(stat->name, name, sizeof(stat->name)); + stat->length = length; + mkqid(dir, name, &stat->qid, False); + return ixp_sizeof_stat(stat); +} - if(!b) { - File *f = ixp_open(s, path); - return f; - } - /* route to b */ - len = strlen(b->prefix); - fd = b->client->open(b->client, path[len] == 0 ? "/" : &path[len]); - if(b->client->errstr) { - set_error(s, b->client->errstr); - if(!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - return nil; - } - b->route[fd].src = fd; - return &b->route[fd].dest; +static unsigned int +type_to_stat(Stat *stat, char *name, Qid *dir) +{ + Mount *mnt; + int type = name_to_type(name); + + switch (type) { + case Droot: + return mkstat(stat, dir, name, 0, DMDIR | DMREAD | DMEXEC); + break; + case Fctl: + return mkstat(stat, dir, name, 0, DMWRITE); + break; + case Dmount: + if(!(mnt = mount_of_name(name))) + return -1; + return mkstat(stat, dir, name, 0, DMREAD | DMWRITE); + break; + } + return 0; } -static size_t -fixp_read(IXPServer * s, int fd, size_t offset, void *out_buf, - size_t out_buf_len) +static char * +xremove(IXPConn *c, Fcall *fcall) { - int cfd; - Bind *b = fd_to_bind(fd, &cfd); - size_t result; + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + unsigned short id = qpath_id(m->qid.path); + int i; + + if(!m) + return Enofid; + if(id && ((i = qpath_id(id)) == -1)) + return Enofile; + if((qpath_type(m->qid.path) == Dmount) && (i < nmount)) { + /* TODO: umount */ + fcall->id = RREMOVE; + ixp_server_respond_fcall(c, fcall); + return nil; + } + return Enoperm; +} - if(!b) { - result = ixp_read(s, fd, offset, out_buf, out_buf_len); - return result; - } - /* route to b */ - result = seek_read(b->client, cfd, offset, out_buf, out_buf_len); - if(b->client->errstr) { - set_error(s, b->client->errstr); - if(!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } - return result; +static char * +xread(IXPConn *c, Fcall *fcall) +{ + Stat stat; + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + unsigned short id; + unsigned char *p = fcall->data; + unsigned int len = 0; + int i; + + if(!m) + return Enofid; + id = qpath_id(m->qid.path); + if(id && ((i = index_of_id(id)) == -1)) + return Enofile; + + fcall->count = 0; + if(fcall->offset) { + switch (qpath_type(m->qid.path)) { + case Droot: + /* jump to offset */ + len = type_to_stat(&stat, "ctl", &m->qid); + for(i = 0; i < nmount; i++) { + len += type_to_stat(&stat, mount[i]->wname, &m->qid); + if(len <= fcall->offset) + continue; + break; + } + /* offset found, proceeding */ + for(; i < nmount; i++) { + len = type_to_stat(&stat, mount[i]->wname, &m->qid); + if(fcall->count + len > fcall->iounit) + break; + fcall->count += len; + p = ixp_enc_stat(p, &stat); + } + break; + default: + break; + } + } + else { + switch (qpath_type(m->qid.path)) { + case Droot: + fcall->count = type_to_stat(&stat, "ctl", &m->qid); + p = ixp_enc_stat(p, &stat); + for(i = 0; i < nmount; i++) { + len = type_to_stat(&stat, mount[i]->wname, &m->qid); + if(fcall->count + len > fcall->iounit) + break; + fcall->count += len; + p = ixp_enc_stat(p, &stat); + } + break; + case Dmount: + /* TODO: */ + break; + case Fctl: + return Enoperm; + break; + default: + return "invalid read"; + break; + } + } + fcall->id = RREAD; + ixp_server_respond_fcall(c, fcall); + return nil; } -static void -fixp_write(IXPServer * s, int fd, size_t offset, void *content, - size_t in_len) +static char * +xstat(IXPConn *c, Fcall *fcall) { - int cfd; - Bind *b = fd_to_bind(fd, &cfd); + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + char *name; + + if(!m) + return Enofid; + name = qid_to_name(&m->qid); + /*fprintf(stderr, "xstat: name=%s\n", name);*/ + if(!type_to_stat(&fcall->stat, name, &m->qid)) + return Enofile; + fcall->id = RSTAT; + ixp_server_respond_fcall(c, fcall); + return nil; +} - if(!b) { - ixp_write(s, fd, offset, content, in_len); - return; - } - /* route to b */ - seek_write(b->client, cfd, offset, content, in_len); - if(b->client->errstr) { - set_error(s, b->client->errstr); - if(!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } +static char * +xwrite(IXPConn *c, Fcall *fcall) +{ + char buf[256]; + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + + if(!m) + return Enofid; + switch (qpath_type(m->qid.path)) { + case Fctl: + if(fcall->count == 4) { + memcpy(buf, fcall->data, 4); + buf[4] = 0; + if(!strncmp(buf, "quit", 5)) { + srv.running = 0; + break; + } + } + return Enocommand; + break; + default: + return "invalid write"; + break; + } + fcall->id = RWRITE; + ixp_server_respond_fcall(c, fcall); + return nil; } static void -fixp_close(IXPServer * s, int fd) +do_fcall(IXPConn *c) { - int cfd; - Bind *b = fd_to_bind(fd, &cfd); - - if(!b) { - ixp_close(s, fd); - return; - } - /* route to b */ - b->client->close(b->client, cfd); - if(b->client->errstr) { - set_error(s, b->client->errstr); - if(!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } + static Fcall fcall; + unsigned int msize; + char *errstr; + + if((msize = ixp_server_receive_fcall(c, &fcall))) { + /*fprintf(stderr, "fcall=%d\n", fcall.id);*/ + switch(fcall.id) { + case TVERSION: errstr = wmii_ixp_version(c, &fcall); break; + case TATTACH: errstr = wmii_ixp_attach(c, &fcall); break; + case TWALK: errstr = xwalk(c, &fcall); break; + case TREMOVE: errstr = xremove(c, &fcall); break; + case TOPEN: errstr = xopen(c, &fcall); break; + case TREAD: errstr = xread(c, &fcall); break; + case TWRITE: errstr = xwrite(c, &fcall); break; + case TCLUNK: errstr = wmii_ixp_clunk(c, &fcall); break; + case TSTAT: errstr = xstat(c, &fcall); break; + default: errstr = Enofunc; break; + } + if(errstr) + ixp_server_respond_error(c, &fcall, errstr); + } } static void -fixp_remove(IXPServer * s, char *path) +new_ixp_conn(IXPConn *c) { - Bind *b; - size_t len; - - for(b = bindings; b && strncmp(b->prefix, path, strlen(b->prefix)); - b = b->next); - - if(!b) { - ixp_remove(s, path); - return; - } - /* route to b */ - len = strlen(b->prefix); - b->client->remove(b->client, path[len] == 0 ? "/" : &path[len]); - if(b->client->errstr) { - set_error(s, b->client->errstr); - if(!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } + int fd = ixp_accept_sock(c->fd); + + if(fd >= 0) + ixp_server_open_conn(c->srv, fd, do_fcall, ixp_server_close_conn); } static void -check_event(Connection * e) +check_x_event(IXPConn *c) { XEvent ev; - while(XPending(dpy)) { - /* - * wmiifs isn't interested in any X events, so just drop them - * all - */ + while(XPending(dpy)) XNextEvent(dpy, &ev); - } /* why check them? because X won't kill wmiifs when X dies */ } -static void -run() -{ - if(!(files[F_CTL] = ixp_create(ixps, "/ctl"))) { - perror("wmiifs: cannot connect IXP server"); - exit(1); - } - files[F_CTL]->after_write = handle_after_write; - - /* routing functions */ - ixps->create = fixp_create; - ixps->remove = fixp_remove; - ixps->open = fixp_open; - ixps->close = fixp_close; - ixps->read = fixp_read; - ixps->write = fixp_write; - - /* main event loop */ - run_server_with_fd_support(ixps, ConnectionNumber(dpy), - check_event, 0); - - deinit_server(ixps); -} +/* main */ int main(int argc, char *argv[]) { int i; + char *errstr; + char *address = nil; /* command line args */ for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { switch (argv[i][1]) { case 'v': - fprintf(stdout, "%s", version[0]); + fprintf(stdout, "%s", version); exit(0); break; - case 's': + case 'a': if(i + 1 < argc) - sockfile = argv[++i]; + address = argv[++i]; else usage(); break; @@ -389,20 +443,36 @@ main(int argc, char *argv[]) } } - if(!getenv("HOME")) { - fprintf(stderr, "%s", - "wmiifs: $HOME environment variable is not set\n"); - usage(); - } /* just for the case X crashes/gets quit */ dpy = XOpenDisplay(0); if(!dpy) { fprintf(stderr, "%s", "wmiifs: cannot open display\n"); exit(1); } - ixps = wmii_setup_server(sockfile); - run(); + i = ixp_create_sock(address, &errstr); + if(i < 0) { + fprintf(stderr, "wmiifs: fatal: %s\n", errstr); + exit(1); + } + + /* IXP server */ + ixp_server_open_conn(&srv, i, new_ixp_conn, ixp_server_close_conn); + root_qid.type = IXP_QTDIR; + root_qid.version = 0; + root_qid.path = mkqpath(Droot, 0); + + /* X server */ + ixp_server_open_conn(&srv, ConnectionNumber(dpy), check_x_event, nil); + + /* main loop */ + errstr = ixp_server_loop(&srv); + if(errstr) + fprintf(stderr, "wmiibar: fatal: %s\n", errstr); + + /* cleanup */ + ixp_server_close(&srv); + XCloseDisplay(dpy); - return 0; + return errstr ? 1 : 0; }