wmii

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

commit bf0b4012b486def636ee37c76dc770a36aba8a99
parent df407fd8cde2c2a9c19969fb40328f94ff1b048e
Author: Anselm R. Garbe <garbeam@wmii.de>
Date:   Mon, 30 Jan 2006 20:43:32 +0200

added fs spec to cmd/wm, removed old ixp dependencies from wm.h, added fs.c framework


Diffstat:
cmd/wm/fs.c | 761+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiibar.c | 2+-
2 files changed, 762 insertions(+), 1 deletion(-)

diff --git a/cmd/wm/fs.c b/cmd/wm/fs.c @@ -0,0 +1,761 @@ +/* + * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> +#include <sys/socket.h> + +#include "ixp.h" +#include "blitz.h" + +/* + * filesystem specification + * / Droot + * /default/ Ddefault + * /default/font Ffont <xlib font name> + * /default/selcolor Fcolor3 <#RRGGBB> <#RRGGBB> <#RRGGBB> + * /default/normcolor Fcolor3 <#RRGGBB> <#RRGGBB> <#RRGGBB> + * /default/transcolor Fcolor <#RRGGBB> + * /default/border Fuint 0..n + * /default/title Fbool 0, 1 + * /default/snap Fuint 0..n + * /event Fevent + * /ctl Fctl command interface (root) + * /new/ Dpage returns new page + * /sel/ Dpage sel page + * /1/ Dpage page + * /1/ctl Fctl command interface (page) + * /1/float/ Dfloat + * /1/float/sel/ Dclient + * /1/float/1/ Dclient + * /1/float/1/border Fuint 0..n + * /1/float/1/title Fbool 0, 1 + * /1/float/1/name Fname name of client + * /1/float/1/ctl Fctl command interface (client) + * /1/col/ Dcolroot + * /1/col/sel/ Dcol + * /1/col/1/ Dcol + * /1/col/1/sel/ Dclient + * /1/col/1/1/ Dclient + * /1/col/1/1/border Fuint 0..n + * /1/col/1/1/title Fbool 0, 1 + * /1/col/1/1/name Fname name of client + * /1/col/1/1/ctl Fctl command interface (client) + * /1/col/1/ctl Fctl command interface (col) + */ + +/* 8-bit qid.path.type */ +enum { + Droot, + Ddefault, + Dpage, + Dfloat, + Dcolroot, + Dcol, + Ffont, + Fcolor3, + Fcolor, + Fuint, + Fbool, + Fevent, + Fctl, + Fname +}; + +static char E9pversion[] = "9P version not supported"; +static char Enoperm[] = "permission denied"; +static char Enofid[] = "fid not assigned"; +static char Enofile[] = "file not found"; +static char Enomode[] = "mode not supported"; +static char Enofunc[] = "function not supported"; + +static unsigned char *msg[IXP_MAX_MSG]; +char *errstr = 0; +static size_t nitem = 0; +static size_t itemsz = 0; +static size_t iexpand = 0; +static Item **item = 0; +static char *address = nil; +static pid_t mypid = 0; +static IXPServer srv = { 0 }; +static Qid root_qid; +static Display *dpy; +static int screen_num; +static char *font = nil; +static XFontStruct *xfont; +static GC gc; +static Window win; +static XRectangle brect, rect; +static Pixmap pmap; + +static void do_pend_fcall(char *event); + +/* IXP stuff */ + +static unsigned long long +mkqpath(unsigned char type, unsigned short item) +{ + return ((unsigned long long) item << 8) | (unsigned long long) type; +} + +static unsigned char +qpath_type(unsigned long long path) +{ + return path & 0xff; +} + +static unsigned short +qpath_item(unsigned long long path) +{ + return (path >> 8) & 0xffff; +} + +static char * +qid_to_name(Qid *qid) +{ + unsigned char type = qpath_type(qid->path); + unsigned short i = qpath_item(qid->path); + static char buf[32]; + + switch(type) { + case Droot: return "/"; break; + case Ditem: + if(i == nitem) + return "new"; + snprintf(buf, sizeof(buf), "%u", i); + return buf; + break; + case Fctl: return "ctl"; break; + case Ffont: return "font"; break; + case Fexpand: return "expand"; break; + case Fdata: return "data"; break; + case Fevent: return "event"; break; + case Fcolor: return "color"; break; + default: return nil; break; + } +} + +static int +name_to_type(char *name) +{ + const char *err; + unsigned int i; + if(!name || !name[0] || !strncmp(name, "/", 2) || !strncmp(name, "..", 3)) + return Droot; + if(!strncmp(name, "new", 4)) + return Ditem; + if(!strncmp(name, "ctl", 4)) + return Fctl; + if(!strncmp(name, "font", 5)) + return Ffont; + if(!strncmp(name, "expand", 7)) + return Fexpand; + if(!strncmp(name, "data", 5)) + return Fdata; + if(!strncmp(name, "event", 6)) + return Fevent; + if(!strncmp(name, "color", 6)) + return Fcolor; + i = (unsigned short) cext_strtonum(name, 1, 0xffff, &err); + if(!err && (i <= nitem)) + return Ditem; + return -1; +} + +static int +mkqid(Qid *dir, char *wname, Qid *new) +{ + const char *err; + int type = name_to_type(wname); + unsigned short i = qpath_item(dir->path); + + if((dir->type != IXP_QTDIR) || (type == -1)) + return -1; + + new->version = 0; + switch(type) { + case Droot: + new->type = IXP_QTDIR; + *new = root_qid; + break; + case Ditem: + new->type = IXP_QTDIR; + if(!strncmp(wname, "new", 4)) + new->path = mkqpath(Ditem, nitem); + else { + unsigned short i = cext_strtonum(wname, 1, 0xffff, &err); + if(err || (i >= nitem)) + return -1; + new->path = mkqpath(Ditem, i); + } + break; + case Fdata: /* note, Fdata needs to be before Fcolor, fallthrough */ + if(!i) + return -1; + case Fcolor: + if(i > nitem) + return -1; + default: + new->type = IXP_QTFILE; + new->path = mkqpath(type, i); + break; + } + return 0; +} + +static int +xversion(IXPConn *c) +{ + if(strncmp(c->fcall->version, IXP_VERSION, strlen(IXP_VERSION))) { + errstr = E9pversion; + return -1; + } else if(c->fcall->maxmsg > IXP_MAX_MSG) + c->fcall->maxmsg = IXP_MAX_MSG; + c->fcall->id = RVERSION; + return 0; +} + +static int +xattach(IXPConn *c) +{ + IXPMap *new = cext_emallocz(sizeof(IXPMap)); + new->qid = root_qid; + new->fid = c->fcall->fid; + c->map = (IXPMap **)cext_array_attach((void **)c->map, new, + sizeof(IXPMap *), &c->mapsz); + c->fcall->id = RATTACH; + c->fcall->qid = root_qid; + return 0; +} + +static int +xwalk(IXPConn *c) +{ + unsigned short nwqid = 0; + Qid dir = root_qid; + IXPMap *m; + + if(!(m = ixp_server_fid2map(c, c->fcall->fid))) { + errstr = Enofid; + return -1; + } + if(c->fcall->fid != c->fcall->newfid + && (ixp_server_fid2map(c, c->fcall->newfid))) { + errstr = Enofid; + return -1; + } + if(c->fcall->nwname) { + dir = m->qid; + for(nwqid = 0; (nwqid < c->fcall->nwname) + && !mkqid(&dir, c->fcall->wname[nwqid], &c->fcall->wqid[nwqid]); nwqid++) + dir = c->fcall->wqid[nwqid]; + if(!nwqid) { + errstr = Enofile; + return -1; + } + } + /* a fid will only be valid, if the walk was complete */ + if(nwqid == c->fcall->nwname) { + if(c->fcall->fid != c->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 = c->fcall->newfid; + } + c->fcall->id = RWALK; + c->fcall->nwqid = nwqid; + return 0; +} + +static int +xopen(IXPConn *c) +{ + IXPMap *m = ixp_server_fid2map(c, c->fcall->fid); + + if(!m) { + errstr = Enofid; + return -1; + } + if(!(c->fcall->mode | IXP_OREAD) && !(c->fcall->mode | IXP_OWRITE)) { + errstr = Enomode; + return -1; + } + c->fcall->id = ROPEN; + c->fcall->qid = m->qid; + c->fcall->iounit = 256; + return 0; +} + +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); + return ixp_sizeof_stat(stat); +} + +static unsigned int +type_to_stat(Stat *stat, char *name, unsigned short i) +{ + int type = name_to_type(name); + Qid dir = {IXP_QTDIR, 0, mkqpath(Ditem, i)}; + char buf[16]; + + switch (type) { + case Droot: + case Ditem: + return mkstat(stat, &root_qid, name, 0, DMDIR | DMREAD | DMEXEC); + break; + case Fctl: + return mkstat(stat, &root_qid, name, 0, DMWRITE); + break; + case Fevent: + return mkstat(stat, &root_qid, name, 0, DMREAD); + break; + case Ffont: + return mkstat(stat, &root_qid, name, strlen(font), + DMREAD | DMWRITE); + break; + case Fexpand: + snprintf(buf, sizeof(buf), "%u", iexpand); + return mkstat(stat, &root_qid, name, strlen(buf), DMREAD | DMWRITE); + break; + case Fdata: + if(i == nitem) + i = 0; + return mkstat(stat, &dir, name, strlen(item[i]->data), + DMREAD | DMWRITE); + break; + case Fcolor: + if(i == nitem) + i = 0; + return mkstat(stat, &dir, name, strlen(item[i]->color), + DMREAD | DMWRITE); + break; + default: + errstr = "invalid stat"; + break; + } + return 0; +} + +static int +xremove(IXPConn *c) +{ + IXPMap *m = ixp_server_fid2map(c, c->fcall->fid); + unsigned short i; + + if(!m) { + errstr = Enofid; + return -1; + } + i = qpath_item(m->qid.path); + if((qpath_type(m->qid.path) == Ditem) && i && (i < nitem)) { + Item *it = item[i]; + detach_item(it); + free(it); + c->fcall->id = RREMOVE; + if(iexpand >= nitem) + iexpand = 0; + draw(); + return 0; + } + errstr = Enoperm; + return -1; +} + +static int +xread(IXPConn *c) +{ + Stat stat; + IXPMap *m = ixp_server_fid2map(c, c->fcall->fid); + unsigned char *p = c->fcall->data; + unsigned short i; + unsigned int len; + char buf[32]; + + if(!m) { + errstr = Enofid; + return -1; + } + i = qpath_item(m->qid.path); + + c->fcall->count = 0; + if(c->fcall->offset) { + switch (qpath_type(m->qid.path)) { + case Droot: + /* jump to offset */ + len = type_to_stat(&stat, "ctl", 0); + len += type_to_stat(&stat, "font", 0); + len += type_to_stat(&stat, "color", 0); + len += type_to_stat(&stat, "new", 0); + len += type_to_stat(&stat, "event", 0); + for(i = 1; i < nitem; i++) { + snprintf(buf, sizeof(buf), "%u", i); + len += type_to_stat(&stat, buf, i); + if(len <= c->fcall->offset) + continue; + else + break; + } + /* offset found, proceeding */ + for(; i < nitem; i++) { + snprintf(buf, sizeof(buf), "%u", i); + len = type_to_stat(&stat, buf, i); + if(c->fcall->count + len > c->fcall->iounit) + break; + c->fcall->count += len; + p = ixp_enc_stat(p, &stat); + } + break; + case Fevent: + return 1; + break; + default: + break; + } + } + else { + switch (qpath_type(m->qid.path)) { + case Droot: + c->fcall->count = type_to_stat(&stat, "ctl", 0); + p = ixp_enc_stat(p, &stat); + c->fcall->count += type_to_stat(&stat, "font", 0); + p = ixp_enc_stat(p, &stat); + c->fcall->count += type_to_stat(&stat, "color", 0); + p = ixp_enc_stat(p, &stat); + c->fcall->count += type_to_stat(&stat, "new", 0); + p = ixp_enc_stat(p, &stat); + c->fcall->count += type_to_stat(&stat, "event", 0); + p = ixp_enc_stat(p, &stat); + for(i = 1; i < nitem; i++) { + snprintf(buf, sizeof(buf), "%u", i); + len = type_to_stat(&stat, buf, i); + if(c->fcall->count + len > c->fcall->iounit) + break; + c->fcall->count += len; + p = ixp_enc_stat(p, &stat); + } + break; + case Ditem: + if(i > nitem) + goto error_xread; + if(i == nitem) + new_item(); + c->fcall->count = type_to_stat(&stat, "color", i); + p = ixp_enc_stat(p, &stat); + c->fcall->count += type_to_stat(&stat, "data", i); + p = ixp_enc_stat(p, &stat); + break; + case Fctl: + errstr = Enoperm; + return -1; + break; + case Ffont: + if((c->fcall->count = strlen(font))) + memcpy(p, font, c->fcall->count); + break; + case Fexpand: + snprintf(buf, sizeof(buf), "%u", iexpand); + c->fcall->count = strlen(buf); + memcpy(p, buf, c->fcall->count); + break; + case Fevent: + return 1; + break; + case Fdata: + if(i == nitem) + new_item(); + if(i >= nitem) + goto error_xread; + if((c->fcall->count = strlen(item[i]->data))) + memcpy(p, item[i]->data, c->fcall->count); + break; + case Fcolor: + if(i == nitem) + new_item(); + if(i >= nitem) + goto error_xread; + if((c->fcall->count = strlen(item[i]->color))) + memcpy(p, item[i]->color, c->fcall->count); + break; + default: + error_xread: + if(!errstr) + errstr = "invalid read"; + return -1; + break; + } + } + c->fcall->id = RREAD; + return 0; +} + +static int +xstat(IXPConn *c) +{ + IXPMap *m = ixp_server_fid2map(c, c->fcall->fid); + char *name; + + if(!m) { + errstr = Enofid; + return -1; + } + + name = qid_to_name(&m->qid); + if(!type_to_stat(&c->fcall->stat, name, qpath_item(m->qid.path))) + return -1; + c->fcall->id = RSTAT; + return 0; +} + +static int +xwrite(IXPConn *c) +{ + char buf[256]; + IXPMap *m = ixp_server_fid2map(c, c->fcall->fid); + unsigned short i; + + if(!m) { + errstr = Enofid; + return -1; + } + + i = qpath_item(m->qid.path); + switch (qpath_type(m->qid.path)) { + case Fctl: + if(c->fcall->count == 4) { + memcpy(buf, c->fcall->data, 4); + buf[4] = 0; + if(!strncmp(buf, "quit", 5)) { + srv.running = 0; + break; + } + } + errstr = "command not supported"; + return -1; + break; + case Ffont: + if(font) + free(font); + font = cext_emallocz(c->fcall->count + 1); + memcpy(font, c->fcall->data, c->fcall->count); + xfont = blitz_getfont(dpy, font); + update_geometry(); + break; + case Fexpand: + { + const char *err; + if(c->fcall->count && c->fcall->count < 16) { + memcpy(buf, c->fcall->data, c->fcall->count); + buf[c->fcall->count] = 0; + i = (unsigned short) cext_strtonum(buf, 1, 0xffff, &err); + if(i < nitem) { + iexpand = i; + draw(); + break; + } + } + } + errstr = "item not found"; + return -1; + break; + case Fdata: + { + unsigned int len = c->fcall->count; + if(i == nitem) + new_item(); + if(!i || (i >= nitem)) + goto error_xwrite; + if(len >= sizeof(item[i]->data)) + len = sizeof(item[i]->data) - 1; + memcpy(item[i]->data, c->fcall->data, len); + item[i]->data[len] = 0; + draw(); + } + break; + case Fcolor: + if(i == nitem) + new_item(); + if((i >= nitem) || (c->fcall->count != 24) + || (c->fcall->data[0] != '#') || (c->fcall->data[8] != '#') + || (c->fcall->data[16] != '#')) + { + errstr = "wrong color format"; + goto error_xwrite; + } + memcpy(item[i]->color, c->fcall->data, c->fcall->count); + item[i]->color[c->fcall->count] = 0; + update_color(item[i]); + draw(); + break; + default: +error_xwrite: + if(!errstr) + errstr = "invalid write"; + return -1; + break; + } + c->fcall->id = RWRITE; + return 0; +} + +static int +xclunk(IXPConn *c) +{ + IXPMap *m = ixp_server_fid2map(c, c->fcall->fid); + + if(!m) { + errstr = Enofid; + return -1; + } + cext_array_detach((void **)c->map, m, &c->mapsz); + free(m); + c->fcall->id = RCLUNK; + return 0; +} + +static void +close_ixp_conn(IXPServer *s, IXPConn *c) +{ + size_t i; + cext_array_detach((void **)s->conn, c, &s->connsz); + if(c->map) { + for(i = 0; (i < c->mapsz) && c->map[i]; i++) + free(c->map[i]); + free(c->map); + } + if(c->pend) { + for(i = 0; (i < c->pendsz) && c->pend[i]; i++) + free(c->pend[i]); + free(c->pend); + } + shutdown(c->fd, SHUT_RDWR); + close(c->fd); + free(c); +} + +static void +do_fcall(IXPServer *s, IXPConn *c) +{ + unsigned int msize; + int ret = -1; + errstr = 0; + if(!(msize = ixp_recv_message(c->fd, msg, IXP_MAX_MSG, &errstr))) { + close_ixp_conn(s, c); + return; + } + if(!c->fcall) + c->fcall = cext_emallocz(sizeof(Fcall)); + if((msize = ixp_msg_to_fcall(msg, IXP_MAX_MSG, c->fcall))) { + switch(c->fcall->id) { + case TVERSION: ret = xversion(c); break; + case TATTACH: ret = xattach(c); break; + case TWALK: ret = xwalk(c); break; + case TREMOVE: ret = xremove(c); break; + case TOPEN: ret = xopen(c); break; + case TREAD: ret = xread(c); break; + case TWRITE: ret = xwrite(c); break; + case TCLUNK: ret = xclunk(c); break; + case TSTAT: ret = xstat(c); break; + default: + break; + } + } + if(ret == -1) { + if(!errstr) + errstr = Enofunc; + c->fcall->id = RERROR; + cext_strlcpy(c->fcall->errstr, errstr, sizeof(c->fcall->errstr)); + } + else if(ret == 1) { + c->pend = (Fcall **)cext_array_attach((void **)c->pend, c->fcall, sizeof(Fcall *), &c->pendsz); + c->fcall = nil; + return; /* response asynchroneously */ + } + msize = ixp_fcall_to_msg(c->fcall, msg, IXP_MAX_MSG); + if(ixp_send_message(c->fd, msg, msize, &errstr) != msize) + close_ixp_conn(s, c); +} + +static Fcall * +pending(IXPConn *c, unsigned char id) +{ + size_t i; + for(i = 0; (i < c->pendsz) && c->pend[i]; i++) + if(c->pend[i]->id == id) + return c->pend[i]; + return nil; +} + +static void +do_pend_fcall(char *event) +{ + size_t i; + Fcall *fcall; + for(i = 0; (i < srv.connsz) && srv.conn[i]; i++) { + IXPConn *c = srv.conn[i]; + /* all pending TREADs are on /event, so no qid checking necessary */ + while((fcall = pending(c, TREAD))) { + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + unsigned char *p = fcall->data; + unsigned int msize; + + if(!m) { + errstr = Enofid; + fcall->id = RERROR; + } + else if(qpath_type(m->qid.path) == Fevent) { + fcall->count = strlen(event); + memcpy(p, event, fcall->count); + fcall->id = RREAD; + } + msize = ixp_fcall_to_msg(fcall, msg, IXP_MAX_MSG); + /* remove pending request */ + cext_array_detach((void **)c->pend, fcall, &c->pendsz); + free(fcall); + if(ixp_send_message(c->fd, msg, msize, &errstr) != msize) { + close_ixp_conn(&srv, c); + break; + } + } + } +} + +static void +new_ixp_conn(IXPServer *s, IXPConn *c) +{ + IXPConn *new; + int fd = ixp_accept_sock(c->fd); + + if(fd >= 0) { + new = cext_emallocz(sizeof(IXPConn)); + new->fd = fd; + new->read = do_fcall; + new->close = close_ixp_conn; + s->conn = (IXPConn **)cext_array_attach((void **)s->conn, new, + sizeof(IXPConn *), &s->connsz); + } +} diff --git a/cmd/wmiibar.c b/cmd/wmiibar.c @@ -29,7 +29,7 @@ * /event Fevent * /expand Fexpand id of expandable label * /ctl Fctl command interface - * /new Dnew returns content of new item + * /new/ Ditem * /1/ Ditem * /1/data Fdata <arbitrary data which gets displayed> * /1/color Fcolor <#RRGGBB> <#RRGGBB> <#RRGGBB>