mirror of
https://github.com/0intro/wmii
synced 2024-11-25 23:30:24 +03:00
removed old libixp crap, now several things are broken and will settle after a while
This commit is contained in:
parent
f137735249
commit
df407fd8cd
2
Makefile
2
Makefile
@ -3,7 +3,7 @@
|
||||
|
||||
include config.mk
|
||||
|
||||
SUBDIRS = libcext liblitz libixp libixp2 libwmii cmd
|
||||
SUBDIRS = libcext liblitz libixp libwmii cmd
|
||||
|
||||
BIN = cmd/wm/wmii cmd/wm/wmiiwm cmd/wmiibar cmd/wmiifs \
|
||||
cmd/wmiikeys cmd/wmiimenu cmd/wmiiplumb cmd/wmiir cmd/wmiir2 cmd/wmiiwarp
|
||||
|
22
cmd/Makefile
22
cmd/Makefile
@ -5,9 +5,7 @@ include ../config.mk
|
||||
|
||||
CFLAGS += -I../liblitz -I../libixp -I../libwmii -I../libcext
|
||||
LDFLAGS += -L../liblitz -llitz -L../libixp -lixp \
|
||||
-L../libwmii -lwmii -L../libcext -lcext
|
||||
LDFLAGS2 += ${LIBS} -L../liblitz -llitz -L../libixp2 -lixp \
|
||||
-L../libwmii -lwmii -L../libcext -lcext
|
||||
-L../libwmii -lwmii -L../libcext -lcext
|
||||
|
||||
SRC_bar = wmiibar.c
|
||||
OBJ_bar = ${SRC_bar:.c=.o}
|
||||
@ -15,9 +13,6 @@ OBJ_bar = ${SRC_bar:.c=.o}
|
||||
SRC_menu = wmiimenu.c
|
||||
OBJ_menu = ${SRC_menu:.c=.o}
|
||||
|
||||
SRC_r2 = wmiir2.c
|
||||
OBJ_r2 = ${SRC_r2:.c=.o}
|
||||
|
||||
SRC_r = wmiir.c
|
||||
OBJ_r = ${SRC_r:.c=.o}
|
||||
|
||||
@ -33,7 +28,8 @@ OBJ_plumb = ${SRC_plumb:.c=.o}
|
||||
SRC_warp = wmiiwarp.c
|
||||
OBJ_warp = ${SRC_warp:.c=.o}
|
||||
|
||||
all: wmiibar wmiimenu wmiir wmiir2 wmiifs wmiikeys wmiiplumb wmiiwarp
|
||||
#all: wmiibar wmiimenu wmiir wmiifs wmiikeys wmiiplumb wmiiwarp
|
||||
all: wmiibar wmiir wmiiplumb wmiiwarp
|
||||
@echo built wmii commands
|
||||
|
||||
.c.o:
|
||||
@ -42,9 +38,9 @@ all: wmiibar wmiimenu wmiir wmiir2 wmiifs wmiikeys wmiiplumb wmiiwarp
|
||||
|
||||
wmiibar: ${OBJ_bar}
|
||||
@echo LD $@
|
||||
@${CC} -o $@ ${OBJ_bar} ${LDFLAGS2}
|
||||
@${CC} -o $@ ${OBJ_bar} ${LDFLAGS}
|
||||
# Solaris
|
||||
# @${CC} -o $@ ${OBJ_bar2} ${LDFLAGS2} -lsocket
|
||||
# @${CC} -o $@ ${OBJ_bar} ${LDFLAGS} -lsocket
|
||||
|
||||
wmiimenu: ${OBJ_menu}
|
||||
@echo LD $@
|
||||
@ -52,14 +48,6 @@ wmiimenu: ${OBJ_menu}
|
||||
# Solaris
|
||||
# @${CC} -o $@ ${OBJ_menu} ${LDFLAGS} -lsocket
|
||||
|
||||
wmiir2: ${OBJ_r2}
|
||||
@echo LD $@
|
||||
@${CC} -o $@ ${OBJ_r2} -g -static -L${PREFIX}/lib -L/usr/lib -lc \
|
||||
-L../libixp2 -lixp -L../libcext -lcext
|
||||
# Solaris
|
||||
# @${CC} -o $@ ${OBJ_r2} -g -static -L${PREFIX}/lib -L/usr/lib -lc \
|
||||
# -L../libixp2 -lixp -L../libcext -lcext -lsocket
|
||||
|
||||
wmiir: ${OBJ_r}
|
||||
@echo LD $@
|
||||
@${CC} -o $@ ${OBJ_r} -g -static -L${PREFIX}/lib -L/usr/lib -lc \
|
||||
|
@ -291,7 +291,7 @@ draw_client(Client *c)
|
||||
XRectangle notch;
|
||||
|
||||
d.drawable = c->frame.win;
|
||||
d.font = font;
|
||||
d.xfont = xfont;
|
||||
d.gc = c->frame.gc;
|
||||
|
||||
if(c == sel_client()) {
|
||||
@ -476,7 +476,7 @@ unsigned int
|
||||
tab_height(Client * c)
|
||||
{
|
||||
if(blitz_strtonum(c->file[C_TAB]->content, 0, 1))
|
||||
return font->ascent + font->descent + 4;
|
||||
return xfont->ascent + xfont->descent + 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
12
cmd/wm/wm.c
12
cmd/wm/wm.c
@ -8,7 +8,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/cursorxfont.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xatom.h>
|
||||
@ -177,7 +177,7 @@ draw_pager()
|
||||
th = ((double) tw / rect.width) * rect.height;
|
||||
d.drawable = transient;
|
||||
d.gc = gc_transient;
|
||||
d.font = font;
|
||||
d.xfont = xfont;
|
||||
i = 0;
|
||||
for(ir = 0; ir < rows; ir++) {
|
||||
for(ic = 0; ic < cols; ic++) {
|
||||
@ -563,8 +563,8 @@ handle_after_write(IXPServer * s, File * f)
|
||||
&color_xor, &color_xor);
|
||||
XSetForeground(dpy, gc_xor, color_xor.pixel);
|
||||
} else if(f == def[WM_FONT]) {
|
||||
XFreeFont(dpy, font);
|
||||
font = blitz_getfont(dpy, def[WM_FONT]->content);
|
||||
XFreeFont(dpy, xfont);
|
||||
xfont = blitz_getxfont(dpy, def[WM_FONT]->content);
|
||||
}
|
||||
check_event(0);
|
||||
}
|
||||
@ -625,7 +625,7 @@ init_default()
|
||||
BLITZ_NORM_FG_COLOR);
|
||||
def[WM_NORM_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/default/nstyle/bordercolor",
|
||||
BLITZ_NORM_BORDER_COLOR);
|
||||
def[WM_FONT] = wmii_create_ixpfile(ixps, "/default/font", BLITZ_FONT);
|
||||
def[WM_FONT] = wmii_create_ixpfile(ixps, "/default/xfont", BLITZ_FONT);
|
||||
def[WM_FONT]->after_write = handle_after_write;
|
||||
def[WM_SNAP_VALUE] = wmii_create_ixpfile(ixps, "/default/snapvalue", "20"); /* 0..1000 */
|
||||
def[WM_BORDER] = wmii_create_ixpfile(ixps, "/default/border", "1");
|
||||
@ -803,7 +803,7 @@ main(int argc, char *argv[])
|
||||
init_atoms();
|
||||
init_cursors();
|
||||
init_default();
|
||||
font = blitz_getfont(dpy, def[WM_FONT]->content);
|
||||
xfont = blitz_getxfont(dpy, def[WM_FONT]->content);
|
||||
wmii_init_lock_modifiers(dpy, &valid_mask, &num_lock_mask);
|
||||
init_screen();
|
||||
scan_wins();
|
||||
|
74
cmd/wm/wm.h
74
cmd/wm/wm.h
@ -9,56 +9,6 @@
|
||||
|
||||
#include "wmii.h"
|
||||
|
||||
/* array indexes of page file pointers */
|
||||
enum {
|
||||
P_PREFIX,
|
||||
P_NAME,
|
||||
P_CLIENT_PREFIX,
|
||||
P_SEL_PREFIX,
|
||||
P_CTL,
|
||||
P_LAST
|
||||
};
|
||||
|
||||
/* array indexes of frame file pointers */
|
||||
enum {
|
||||
C_PREFIX,
|
||||
C_NAME,
|
||||
C_GEOMETRY,
|
||||
C_BORDER,
|
||||
C_TAB,
|
||||
C_HANDLE_INC,
|
||||
C_CTL,
|
||||
C_LAST
|
||||
};
|
||||
|
||||
/* array indexes of wm file pointers */
|
||||
enum {
|
||||
WM_CTL,
|
||||
WM_TRANS_COLOR,
|
||||
WM_COLUMN_GEOMETRY,
|
||||
WM_SEL_BG_COLOR,
|
||||
WM_SEL_BORDER_COLOR,
|
||||
WM_SEL_FG_COLOR,
|
||||
WM_NORM_BG_COLOR,
|
||||
WM_NORM_BORDER_COLOR,
|
||||
WM_NORM_FG_COLOR,
|
||||
WM_FONT,
|
||||
WM_BORDER,
|
||||
WM_TAB,
|
||||
WM_HANDLE_INC,
|
||||
WM_SNAP_VALUE,
|
||||
WM_DETACHED_PREFIX,
|
||||
WM_SEL_PAGE,
|
||||
WM_EVENT_PAGE_UPDATE,
|
||||
WM_EVENT_CLIENT_UPDATE,
|
||||
WM_EVENT_B1PRESS,
|
||||
WM_EVENT_B2PRESS,
|
||||
WM_EVENT_B3PRESS,
|
||||
WM_EVENT_B4PRESS,
|
||||
WM_EVENT_B5PRESS,
|
||||
WM_LAST
|
||||
};
|
||||
|
||||
/* array indexes of EWMH window properties */
|
||||
/* TODO: set / react */
|
||||
enum {
|
||||
@ -96,7 +46,6 @@ struct Page {
|
||||
size_t sel_column;
|
||||
Bool is_column;
|
||||
XRectangle rect_column;
|
||||
File *file[P_LAST];
|
||||
};
|
||||
|
||||
struct Client {
|
||||
@ -104,6 +53,7 @@ struct Client {
|
||||
int proto;
|
||||
unsigned int border;
|
||||
unsigned int ignore_unmap;
|
||||
Bool handle_inc;
|
||||
Bool destroyed;
|
||||
Bool maximized;
|
||||
Bool attached;
|
||||
@ -119,8 +69,8 @@ struct Client {
|
||||
XRectangle revert;
|
||||
GC gc;
|
||||
Cursor cursor;
|
||||
Bool title;
|
||||
} frame;
|
||||
File *file[C_LAST];
|
||||
};
|
||||
|
||||
/* global variables */
|
||||
@ -140,11 +90,22 @@ int screen;
|
||||
Window root;
|
||||
Window transient; /* pager / attach */
|
||||
XRectangle rect;
|
||||
XFontStruct *font;
|
||||
XFontStruct *xfont;
|
||||
XColor color_xor;
|
||||
GC gc_xor;
|
||||
GC gc_transient;
|
||||
|
||||
/* default values */
|
||||
typedef struct {
|
||||
char xorcolor[24];
|
||||
char selcolor[24];
|
||||
char normcolor[24];
|
||||
char font[24];
|
||||
unsigned int border;
|
||||
unsigned int title;
|
||||
unsigned int snap;
|
||||
} Default def;
|
||||
|
||||
Atom wm_state; /* TODO: Maybe replace with wm_atoms[WM_ATOM_COUNT]? */
|
||||
Atom wm_change_state;
|
||||
Atom wm_protocols;
|
||||
@ -165,9 +126,6 @@ Cursor ne_cursor;
|
||||
Cursor sw_cursor;
|
||||
Cursor se_cursor;
|
||||
|
||||
/* default file pointers */
|
||||
File *def[WM_LAST];
|
||||
|
||||
unsigned int valid_mask, num_lock_mask;
|
||||
|
||||
|
||||
@ -222,12 +180,14 @@ void select_column(Client *c, char *arg);
|
||||
void new_column(Page *p);
|
||||
|
||||
/* wm.c */
|
||||
/*
|
||||
void invoke_wm_event(File * f);
|
||||
void run_action(File * f, void *obj, Action * acttbl);
|
||||
*/
|
||||
void scan_wins();
|
||||
Client *win_to_client(Window w);
|
||||
int win_proto(Window w);
|
||||
int win_state(Window w);
|
||||
void handle_after_write(IXPServer * s, File * f);
|
||||
/*void handle_after_write(IXPServer * s, File * f);*/
|
||||
void detach(Client * f, int client_destroyed);
|
||||
void set_client_state(Client * c, int state);
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <X11/Xutil.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../libixp2/ixp.h"
|
||||
#include "ixp.h"
|
||||
#include "blitz.h"
|
||||
|
||||
/*
|
||||
|
373
cmd/wmiir.c
373
cmd/wmiir.c
@ -6,11 +6,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "ixp.h"
|
||||
|
||||
static IXPClient *c;
|
||||
static int exit_code = 0;
|
||||
#include <cext.h>
|
||||
|
||||
static IXPClient c = { 0 };
|
||||
|
||||
static char *version[] = {
|
||||
"wmiir - window manager improved remote - " VERSION "\n"
|
||||
@ -21,211 +24,213 @@ static void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "%s",
|
||||
"usage: wmiir [-s <socket file>] [-v] <action> <action_arg> [...]\n"
|
||||
" -s socket file (default: $WMIIR_SOCKET)\n"
|
||||
" -f read actions from stdin\n"
|
||||
"usage: wmiir [-a <server address>] [-v] <command>\n"
|
||||
" -a server address (default: $WMIIR_ADDRESS)\n"
|
||||
" -v version info\n"
|
||||
"actions:\n"
|
||||
" create <file> [<content>] -- creates and optionally writes content to a file\n"
|
||||
" write <file> <content> -- writes content to a file\n"
|
||||
" read <directory/file> -- reads file or directory contents\n"
|
||||
" remove <directory/file> -- removes file or directory, use with care!\n");
|
||||
"valid commands:\n"
|
||||
" create <file> -- creates file and writes data from stdin to file\n"
|
||||
" read <file/dir> -- prints file/directory contents\n"
|
||||
" write <file> -- writes data from stdin to file\n"
|
||||
" remove <file> -- removes file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
perform(char *action, char *file, char *content)
|
||||
write_data(unsigned int fid)
|
||||
{
|
||||
size_t out_len = 0;
|
||||
char output[2050];
|
||||
int crt, fd = -1;
|
||||
void *data = cext_emallocz(c.fcall.iounit);
|
||||
unsigned long long offset = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if(!action)
|
||||
return;
|
||||
while((len = read(0, data, c.fcall.iounit)) > 0) {
|
||||
fprintf(stderr, "read=%d, bufsz=%d\n", len, c.fcall.iounit);
|
||||
if(ixp_client_write
|
||||
(&c, fid, offset, len, data) != len) {
|
||||
fprintf(stderr, "wmiir: cannot write file: %s\n", c.errstr);
|
||||
break;
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
crt = !strncmp(action, "create", 7);
|
||||
if(!strncmp(action, "write", 6) || crt) {
|
||||
if(!file)
|
||||
return;
|
||||
/* create file first */
|
||||
if(crt) {
|
||||
c->create(c, file);
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: create %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!content)
|
||||
return;
|
||||
fd = c->open(c, file);
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: open %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
return;
|
||||
}
|
||||
c->write(c, fd, content, strlen(content));
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: write %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
if(!strncmp(c->errstr, DEAD_SERVER, strlen(DEAD_SERVER) + 1))
|
||||
return;
|
||||
}
|
||||
} else if(!strncmp(action, "read", 5)) {
|
||||
if(!file)
|
||||
return;
|
||||
fd = c->open(c, file);
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: open %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
return;
|
||||
}
|
||||
do {
|
||||
out_len = c->read(c, fd, output, 2048);
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: read %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
if(!strncmp
|
||||
(c->errstr, DEAD_SERVER, strlen(DEAD_SERVER) + 1))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
output[out_len] = 0;
|
||||
fprintf(stdout, "%s", output);
|
||||
}
|
||||
while(out_len == 2048);
|
||||
fprintf(stdout, "%s", "\n");
|
||||
} else if(!strncmp(action, "remove", 7)) {
|
||||
if(!file)
|
||||
return;
|
||||
c->remove(c, file);
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: remove %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
return;
|
||||
}
|
||||
static int
|
||||
xcreate(char *file)
|
||||
{
|
||||
unsigned int fid;
|
||||
char *p = strrchr(file, '/');
|
||||
|
||||
fid = c.root_fid << 2;
|
||||
/* walk to bottom-most directory */
|
||||
*p = 0;
|
||||
if(ixp_client_walk(&c, fid, file) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot walk to '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
if(fd != -1) {
|
||||
c->close(c, fd);
|
||||
if(c->errstr) {
|
||||
fprintf(stderr, "wmiir: error: close %s: %s\n", file,
|
||||
c->errstr);
|
||||
exit_code = 1;
|
||||
return;
|
||||
}
|
||||
/* create */
|
||||
p++;
|
||||
if(ixp_client_create(&c, fid, p, (unsigned int) 0xff, IXP_OWRITE) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot create file '%s': %s\n", p, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
write_data(fid);
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
xwrite(char *file)
|
||||
{
|
||||
|
||||
/* open */
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
if(ixp_client_open(&c, fid, file, IXP_OWRITE) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot open file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
write_data(fid);
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
comp(const void *s1, const void *s2)
|
||||
{
|
||||
return strcmp(*(char **)s1, *(char **)s2);
|
||||
}
|
||||
|
||||
static void
|
||||
xls(void *result, unsigned int msize)
|
||||
{
|
||||
size_t n = 0, j = 0;
|
||||
char buf[IXP_MAX_FLEN];
|
||||
void *p = result;
|
||||
char **dir;
|
||||
static Stat stat, zerostat = { 0 };
|
||||
do {
|
||||
p = ixp_dec_stat(p, &stat);
|
||||
n++;
|
||||
}
|
||||
while(p - result < msize);
|
||||
dir = (char **)cext_emallocz(sizeof(char *) * n);
|
||||
p = result;
|
||||
do {
|
||||
p = ixp_dec_stat(p, &stat);
|
||||
if(stat.qid.type == IXP_QTDIR)
|
||||
snprintf(buf, sizeof(buf), "%s/", stat.name);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s", stat.name);
|
||||
dir[j++] = cext_estrdup(buf);
|
||||
stat = zerostat;
|
||||
}
|
||||
while(p - result < msize);
|
||||
qsort(dir, n, sizeof(char *), comp);
|
||||
for(j = 0; j < n; j++) {
|
||||
fprintf(stdout, "%s\n", dir[j]);
|
||||
free(dir[j]);
|
||||
}
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static int
|
||||
xread(char *file)
|
||||
{
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
int count, is_directory = 0;
|
||||
static unsigned char result[IXP_MAX_MSG];
|
||||
unsigned long long offset = 0;
|
||||
|
||||
/* open */
|
||||
if(ixp_client_open(&c, fid, file, IXP_OREAD) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot open file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
is_directory = !c.fcall.nwqid || (c.fcall.qid.type == IXP_QTDIR);
|
||||
|
||||
/* read */
|
||||
while((count = ixp_client_read(&c, fid, offset, result, IXP_MAX_MSG)) > 0) {
|
||||
if(is_directory)
|
||||
xls(result, count);
|
||||
else {
|
||||
unsigned int i;
|
||||
for(i = 0; i < count; i++)
|
||||
fputc(result[i], stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
if(count == -1) {
|
||||
fprintf(stderr, "wmiir: cannot read file/directory '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
xremove(char *file)
|
||||
{
|
||||
unsigned int fid;
|
||||
|
||||
/* remove */
|
||||
fid = c.root_fid << 2;
|
||||
if(ixp_client_remove(&c, fid, file) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot remove file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i = 0, read_stdin = 0;
|
||||
char line[4096], *p;
|
||||
char *sockfile = getenv("WMIIR_SOCKET");
|
||||
int i = 0;
|
||||
char *cmd, *file, *sockfile = getenv("WMIIR_ADDRESS");
|
||||
|
||||
/* command line args */
|
||||
if(argc > 1) {
|
||||
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
|
||||
switch (argv[i][1]) {
|
||||
case 'v':
|
||||
fprintf(stderr, "%s", version[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 's':
|
||||
if(i + 1 < argc) {
|
||||
sockfile = argv[++i];
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
read_stdin = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if((argc <= 1) || (!read_stdin && (i + 1) >= argc)) {
|
||||
fprintf(stderr, "%s", "wmiir: arguments: ");
|
||||
for(i = 1; i < argc; i++)
|
||||
fprintf(stderr, "%s, ", argv[i]);
|
||||
fprintf(stderr, "%s", "\n");
|
||||
usage();
|
||||
}
|
||||
if(argc < 2)
|
||||
usage();
|
||||
|
||||
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
|
||||
switch (argv[i][1]) {
|
||||
case 'v':
|
||||
fprintf(stderr, "%s", version[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'a':
|
||||
if(i + 1 < argc)
|
||||
sockfile = argv[++i];
|
||||
else
|
||||
usage();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd = argv[argc - 2];
|
||||
file = argv[argc - 1];
|
||||
|
||||
if(!sockfile) {
|
||||
fprintf(stderr, "%s",
|
||||
"wmiir: error: WMIIR_SOCKET environment not set\n");
|
||||
fprintf(stderr, "%s", "wmiir: error: $WMIIR_ADDRESS not set\n");
|
||||
usage();
|
||||
}
|
||||
/* open socket */
|
||||
if(!(c = init_ixp_client(sockfile))) {
|
||||
fprintf(stderr, "wmiir: cannot connect to server '%s'\n",
|
||||
sockfile);
|
||||
if(ixp_client_init(&c, sockfile) == -1) {
|
||||
fprintf(stderr, "wmiir: %s\n", c.errstr);
|
||||
exit(1);
|
||||
}
|
||||
if(read_stdin) {
|
||||
/* simple shell */
|
||||
char *action, *file, *content;
|
||||
while(fgets(line, 4096, stdin)) {
|
||||
p = line;
|
||||
while(*p != 0 && (*p == ' ' || *p == '\t'))
|
||||
p++;
|
||||
if(*p == 0)
|
||||
continue; /* empty line */
|
||||
if(strncmp(p, "create ", 7) &&
|
||||
strncmp(p, "write ", 6) &&
|
||||
strncmp(p, "read ", 5) && strncmp(p, "remove ", 7))
|
||||
continue;
|
||||
|
||||
action = p;
|
||||
while(*p != 0 && *p != ' ' && *p != '\t' && *p != '\n')
|
||||
p++;
|
||||
if(*p == 0 || *p == '\n')
|
||||
continue; /* ignore bogus command */
|
||||
*p = 0;
|
||||
p++;
|
||||
while(*p != 0 && (*p == ' ' || *p == '\t'))
|
||||
p++;
|
||||
if(*p == 0)
|
||||
continue; /* ignore bogus command */
|
||||
file = p;
|
||||
while(*p != 0 && *p != ' ' && *p != '\t' && *p != '\n')
|
||||
p++;
|
||||
if(*p == 0 || *p == '\n') {
|
||||
content = 0;
|
||||
*p = 0;
|
||||
} else {
|
||||
*p = 0;
|
||||
p++;
|
||||
content = p;
|
||||
}
|
||||
if(file[0] == 0)
|
||||
continue;
|
||||
if(content) {
|
||||
static size_t len;
|
||||
if((len = strlen(content)))
|
||||
content[len - 1] = 0;
|
||||
}
|
||||
perform(action, file, content);
|
||||
if(c->errstr)
|
||||
fprintf(stderr, "wmiir: error: read %s: %s\n", file,
|
||||
c->errstr);
|
||||
}
|
||||
} else {
|
||||
perform(argv[i], argv[i + 1], (i + 2) < argc ? argv[i + 2] : 0);
|
||||
}
|
||||
if(!strncmp(cmd, "create", 7))
|
||||
xcreate(file);
|
||||
else if(!strncmp(cmd, "write", 6))
|
||||
xwrite(file);
|
||||
else if(!strncmp(cmd, "read", 5))
|
||||
xread(file);
|
||||
else if(!strncmp(cmd, "remove", 7))
|
||||
xremove(file);
|
||||
else
|
||||
usage();
|
||||
|
||||
if(c->errstr) {
|
||||
deinit_client(c);
|
||||
exit_code = 1;
|
||||
}
|
||||
return exit_code;
|
||||
/* close socket */
|
||||
ixp_client_deinit(&c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
236
cmd/wmiir2.c
236
cmd/wmiir2.c
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "../libixp2/ixp.h"
|
||||
|
||||
#include <cext.h>
|
||||
|
||||
static IXPClient c = { 0 };
|
||||
|
||||
static char *version[] = {
|
||||
"wmiir - window manager improved remote - " VERSION "\n"
|
||||
" (C)opyright MMIV-MMVI Anselm R. Garbe\n", 0
|
||||
};
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "%s",
|
||||
"usage: wmiir [-a <server address>] [-v] <command>\n"
|
||||
" -a server address (default: $WMIIR_ADDRESS)\n"
|
||||
" -v version info\n"
|
||||
"valid commands:\n"
|
||||
" create <file> -- creates file and writes data from stdin to file\n"
|
||||
" read <file/dir> -- prints file/directory contents\n"
|
||||
" write <file> -- writes data from stdin to file\n"
|
||||
" remove <file> -- removes file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
write_data(unsigned int fid)
|
||||
{
|
||||
void *data = cext_emallocz(c.fcall.iounit);
|
||||
unsigned long long offset = 0;
|
||||
size_t len = 0;
|
||||
|
||||
while((len = read(0, data, c.fcall.iounit)) > 0) {
|
||||
fprintf(stderr, "read=%d, bufsz=%d\n", len, c.fcall.iounit);
|
||||
if(ixp_client_write
|
||||
(&c, fid, offset, len, data) != len) {
|
||||
fprintf(stderr, "wmiir: cannot write file: %s\n", c.errstr);
|
||||
break;
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
static int
|
||||
xcreate(char *file)
|
||||
{
|
||||
unsigned int fid;
|
||||
char *p = strrchr(file, '/');
|
||||
|
||||
fid = c.root_fid << 2;
|
||||
/* walk to bottom-most directory */
|
||||
*p = 0;
|
||||
if(ixp_client_walk(&c, fid, file) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot walk to '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
/* create */
|
||||
p++;
|
||||
if(ixp_client_create(&c, fid, p, (unsigned int) 0xff, IXP_OWRITE) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot create file '%s': %s\n", p, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
write_data(fid);
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
xwrite(char *file)
|
||||
{
|
||||
|
||||
/* open */
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
if(ixp_client_open(&c, fid, file, IXP_OWRITE) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot open file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
write_data(fid);
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
comp(const void *s1, const void *s2)
|
||||
{
|
||||
return strcmp(*(char **)s1, *(char **)s2);
|
||||
}
|
||||
|
||||
static void
|
||||
xls(void *result, unsigned int msize)
|
||||
{
|
||||
size_t n = 0, j = 0;
|
||||
char buf[IXP_MAX_FLEN];
|
||||
void *p = result;
|
||||
char **dir;
|
||||
static Stat stat, zerostat = { 0 };
|
||||
do {
|
||||
p = ixp_dec_stat(p, &stat);
|
||||
n++;
|
||||
}
|
||||
while(p - result < msize);
|
||||
dir = (char **)cext_emallocz(sizeof(char *) * n);
|
||||
p = result;
|
||||
do {
|
||||
p = ixp_dec_stat(p, &stat);
|
||||
if(stat.qid.type == IXP_QTDIR)
|
||||
snprintf(buf, sizeof(buf), "%s/", stat.name);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s", stat.name);
|
||||
dir[j++] = cext_estrdup(buf);
|
||||
stat = zerostat;
|
||||
}
|
||||
while(p - result < msize);
|
||||
qsort(dir, n, sizeof(char *), comp);
|
||||
for(j = 0; j < n; j++) {
|
||||
fprintf(stdout, "%s\n", dir[j]);
|
||||
free(dir[j]);
|
||||
}
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static int
|
||||
xread(char *file)
|
||||
{
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
int count, is_directory = 0;
|
||||
static unsigned char result[IXP_MAX_MSG];
|
||||
unsigned long long offset = 0;
|
||||
|
||||
/* open */
|
||||
if(ixp_client_open(&c, fid, file, IXP_OREAD) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot open file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
is_directory = !c.fcall.nwqid || (c.fcall.qid.type == IXP_QTDIR);
|
||||
|
||||
/* read */
|
||||
while((count = ixp_client_read(&c, fid, offset, result, IXP_MAX_MSG)) > 0) {
|
||||
if(is_directory)
|
||||
xls(result, count);
|
||||
else {
|
||||
unsigned int i;
|
||||
for(i = 0; i < count; i++)
|
||||
fputc(result[i], stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
offset += count;
|
||||
}
|
||||
if(count == -1) {
|
||||
fprintf(stderr, "wmiir: cannot read file/directory '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
xremove(char *file)
|
||||
{
|
||||
unsigned int fid;
|
||||
|
||||
/* remove */
|
||||
fid = c.root_fid << 2;
|
||||
if(ixp_client_remove(&c, fid, file) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot remove file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i = 0;
|
||||
char *cmd, *file, *sockfile = getenv("WMIIR_ADDRESS");
|
||||
|
||||
/* command line args */
|
||||
if(argc < 2)
|
||||
usage();
|
||||
|
||||
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
|
||||
switch (argv[i][1]) {
|
||||
case 'v':
|
||||
fprintf(stderr, "%s", version[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'a':
|
||||
if(i + 1 < argc)
|
||||
sockfile = argv[++i];
|
||||
else
|
||||
usage();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd = argv[argc - 2];
|
||||
file = argv[argc - 1];
|
||||
|
||||
if(!sockfile) {
|
||||
fprintf(stderr, "%s", "wmiir: error: $WMIIR_ADDRESS not set\n");
|
||||
usage();
|
||||
}
|
||||
/* open socket */
|
||||
if(ixp_client_init(&c, sockfile) == -1) {
|
||||
fprintf(stderr, "wmiir: %s\n", c.errstr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!strncmp(cmd, "create", 7))
|
||||
xcreate(file);
|
||||
else if(!strncmp(cmd, "write", 6))
|
||||
xwrite(file);
|
||||
else if(!strncmp(cmd, "read", 5))
|
||||
xread(file);
|
||||
else if(!strncmp(cmd, "remove", 7))
|
||||
xremove(file);
|
||||
else
|
||||
usage();
|
||||
|
||||
/* close socket */
|
||||
ixp_client_deinit(&c);
|
||||
|
||||
return 0;
|
||||
}
|
@ -4,14 +4,13 @@
|
||||
include ../config.mk
|
||||
|
||||
CFLAGS += -I ../libcext
|
||||
LDFLAGS += -L../libcext -lcext
|
||||
|
||||
SRC = client.c message.c ramfs.c server.c
|
||||
SRC = client.c convert.c message.c server.c socket.c transport.c
|
||||
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: libixp
|
||||
@echo built libixp
|
||||
@echo built libixp2
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
|
400
libixp/client.c
400
libixp/client.c
@ -3,288 +3,192 @@
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cext.h"
|
||||
#include "ixp.h"
|
||||
|
||||
#include <cext.h>
|
||||
static unsigned char msg[IXP_MAX_MSG];
|
||||
|
||||
static size_t offsets[MAX_CONN * MAX_OPEN_FILES][2]; /* set of possible fd's */
|
||||
|
||||
static void check_error(IXPClient * c, void *msg)
|
||||
static int
|
||||
do_fcall(IXPClient * c)
|
||||
{
|
||||
ResHeader h;
|
||||
|
||||
if (c->errstr)
|
||||
free(c->errstr);
|
||||
c->errstr = 0;
|
||||
|
||||
memcpy(&h, msg, sizeof(ResHeader));
|
||||
if (h.res == RERROR)
|
||||
c->errstr = strdup((char *) msg + sizeof(ResHeader));
|
||||
unsigned int msize = ixp_fcall_to_msg(&c->fcall, msg, IXP_MAX_MSG);
|
||||
c->errstr = 0;
|
||||
if(ixp_send_message(c->fd, msg, msize, &c->errstr) != msize)
|
||||
return -1;
|
||||
if(!ixp_recv_message(c->fd, msg, IXP_MAX_MSG, &c->errstr))
|
||||
return -1;
|
||||
if(!(msize = ixp_msg_to_fcall(msg, IXP_MAX_MSG, &c->fcall))) {
|
||||
c->errstr = "received bad message";
|
||||
return -1;
|
||||
}
|
||||
if(c->fcall.id == RERROR) {
|
||||
c->errstr = c->fcall.errstr;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_dead_server(IXPClient * c)
|
||||
int
|
||||
ixp_client_init(IXPClient * c, char *sockfile)
|
||||
{
|
||||
if (c->errstr)
|
||||
free(c->errstr);
|
||||
c->errstr = strdup(DEAD_SERVER);
|
||||
if (c->fd) {
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
}
|
||||
c->fd = -1;
|
||||
if((c->fd = ixp_connect_sock(sockfile)) < 0) {
|
||||
c->errstr = "cannot connect server";
|
||||
return -1;
|
||||
}
|
||||
/* version */
|
||||
c->fcall.id = TVERSION;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.maxmsg = IXP_MAX_MSG;
|
||||
cext_strlcpy(c->fcall.version, IXP_VERSION, sizeof(c->fcall.version));
|
||||
if(do_fcall(c) == -1) {
|
||||
ixp_client_deinit(c);
|
||||
return -1;
|
||||
}
|
||||
if(strncmp(c->fcall.version, IXP_VERSION, strlen(IXP_VERSION))) {
|
||||
c->errstr = "9P versions differ";
|
||||
ixp_client_deinit(c);
|
||||
return -1; /* we cannot handle this version */
|
||||
}
|
||||
c->root_fid = getpid();
|
||||
|
||||
/* attach */
|
||||
c->fcall.id = TATTACH;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = c->root_fid;
|
||||
c->fcall.afid = IXP_NOFID;
|
||||
cext_strlcpy(c->fcall.uname, getenv("USER"), sizeof(c->fcall.uname));
|
||||
c->fcall.aname[0] = 0;
|
||||
if(do_fcall(c) == -1) {
|
||||
ixp_client_deinit(c);
|
||||
return -1;
|
||||
}
|
||||
c->root_qid = c->fcall.qid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *poll_server(IXPClient * c, void *request, size_t req_len,
|
||||
size_t * out_len)
|
||||
int
|
||||
ixp_client_remove(IXPClient * c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
size_t num = 0;
|
||||
void *result = 0;
|
||||
int r, header = 0;
|
||||
|
||||
if (c->errstr)
|
||||
free(c->errstr);
|
||||
c->errstr = 0;
|
||||
|
||||
/* first send request */
|
||||
while (num < req_len) {
|
||||
FD_ZERO(&c->wr);
|
||||
FD_SET(c->fd, &c->wr);
|
||||
r = select(c->fd + 1, 0, &c->wr, 0, 0);
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (r < 0) {
|
||||
perror("ixp: client: select");
|
||||
if (result)
|
||||
free(result);
|
||||
handle_dead_server(c);
|
||||
return 0;
|
||||
} else if (r > 0) {
|
||||
if (!header) {
|
||||
/* write header first */
|
||||
r = write(c->fd, &req_len, sizeof(size_t));
|
||||
if (r != sizeof(size_t)) {
|
||||
if (result)
|
||||
free(result);
|
||||
handle_dead_server(c);
|
||||
return 0;
|
||||
}
|
||||
header = 1;
|
||||
}
|
||||
r = write(c->fd, ((char *) request) + num, req_len - num);
|
||||
if (r < 1) {
|
||||
perror("ixp: client: write");
|
||||
if (result)
|
||||
free(result);
|
||||
handle_dead_server(c);
|
||||
return 0;
|
||||
}
|
||||
num += r;
|
||||
}
|
||||
}
|
||||
free(request); /* cleanup */
|
||||
|
||||
num = 0;
|
||||
header = 0;
|
||||
/* now wait for response */
|
||||
do {
|
||||
FD_ZERO(&c->rd);
|
||||
FD_SET(c->fd, &c->rd);
|
||||
r = select(c->fd + 1, &c->rd, 0, 0, 0);
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (r < 0) {
|
||||
perror("ixp: client: select");
|
||||
if (result)
|
||||
free(result);
|
||||
handle_dead_server(c);
|
||||
return 0;
|
||||
} else if (r > 0) {
|
||||
if (!header) {
|
||||
r = read(c->fd, out_len, sizeof(size_t));
|
||||
if (r != sizeof(size_t)) {
|
||||
if (result)
|
||||
free(result);
|
||||
handle_dead_server(c);
|
||||
return 0;
|
||||
}
|
||||
result = cext_emallocz(*out_len);
|
||||
header = 1;
|
||||
}
|
||||
r = read(c->fd, ((char *) result) + num, *out_len - num);
|
||||
if (r < 1) {
|
||||
perror("ixp: client: read");
|
||||
if (result)
|
||||
free(result);
|
||||
handle_dead_server(c);
|
||||
return 0;
|
||||
}
|
||||
num += r;
|
||||
}
|
||||
}
|
||||
while (num != *out_len);
|
||||
|
||||
/* error checking */
|
||||
if (result)
|
||||
check_error(c, result);
|
||||
if (c->errstr) {
|
||||
free(result);
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
/* remove */
|
||||
c->fcall.id = TREMOVE;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = newfid;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
static void cixp_create(IXPClient * c, char *path)
|
||||
int
|
||||
ixp_client_create(IXPClient * c, unsigned int dirfid, char *name,
|
||||
unsigned int perm, unsigned char mode)
|
||||
{
|
||||
ResHeader h;
|
||||
size_t req_len, res_len;
|
||||
void *req = tcreate_message(path, &req_len);
|
||||
void *result = poll_server(c, req, req_len, &res_len);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
memcpy(&h, result, sizeof(ResHeader));
|
||||
free(result);
|
||||
/* create */
|
||||
c->fcall.id = TCREATE;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = dirfid;
|
||||
cext_strlcpy(c->fcall.name, name, sizeof(c->fcall.name));
|
||||
c->fcall.perm = perm;
|
||||
c->fcall.mode = mode;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
static int cixp_open(IXPClient * c, char *path)
|
||||
int
|
||||
ixp_client_walk(IXPClient * c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
ResHeader h;
|
||||
size_t req_len, res_len;
|
||||
void *req = topen_message(path, &req_len);
|
||||
void *result = poll_server(c, req, req_len, &res_len);
|
||||
|
||||
if (!result)
|
||||
return -1;
|
||||
memcpy(&h, result, sizeof(ResHeader));
|
||||
free(result);
|
||||
offsets[h.fd][0] = offsets[h.fd][1] = 0;
|
||||
return h.fd;
|
||||
unsigned int i;
|
||||
char *wname[IXP_MAX_WELEM];
|
||||
/* walk */
|
||||
c->fcall.id = TWALK;
|
||||
c->fcall.fid = c->root_fid;
|
||||
c->fcall.newfid = newfid;
|
||||
if(filepath) {
|
||||
cext_strlcpy(c->fcall.name, filepath, sizeof(c->fcall.name));
|
||||
c->fcall.nwname =
|
||||
cext_tokenize(wname, IXP_MAX_WELEM, c->fcall.name, '/');
|
||||
for(i = 0; i < c->fcall.nwname; i++)
|
||||
cext_strlcpy(c->fcall.wname[i], wname[i], sizeof(c->fcall.wname[i]));
|
||||
}
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
static size_t
|
||||
cixp_read(IXPClient * c, int fd, void *out_buf, size_t out_buf_len)
|
||||
int
|
||||
ixp_client_open(IXPClient * c, unsigned int newfid, char *filepath,
|
||||
unsigned char mode)
|
||||
{
|
||||
size_t len;
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
|
||||
len = seek_read(c, fd, offsets[fd][0], out_buf, out_buf_len);
|
||||
if (c->errstr)
|
||||
return 0;
|
||||
if (len == out_buf_len)
|
||||
offsets[fd][0] += len;
|
||||
return len;
|
||||
/* open */
|
||||
c->fcall.id = TOPEN;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = newfid;
|
||||
c->fcall.mode = mode;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
size_t
|
||||
seek_read(IXPClient * c, int fd, size_t offset,
|
||||
void *out_buf, size_t out_buf_len)
|
||||
int
|
||||
ixp_client_read(IXPClient * c, unsigned int fid, unsigned long long offset,
|
||||
void *result, unsigned int res_len)
|
||||
{
|
||||
ResHeader h;
|
||||
size_t req_len, res_len;
|
||||
void *req = tread_message(fd, offset, out_buf_len, &req_len);
|
||||
void *result = poll_server(c, req, req_len, &res_len);
|
||||
unsigned int bytes = c->fcall.iounit;
|
||||
|
||||
if (!result)
|
||||
return -1;
|
||||
memcpy(&h, result, sizeof(ResHeader));
|
||||
memcpy(out_buf, ((char *) result) + sizeof(ResHeader), h.buf_len);
|
||||
free(result);
|
||||
return h.buf_len;
|
||||
/* read */
|
||||
c->fcall.id = TREAD;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = fid;
|
||||
c->fcall.offset = offset;
|
||||
c->fcall.count = res_len < bytes ? res_len : bytes;
|
||||
if(do_fcall(c) == -1)
|
||||
return -1;
|
||||
memcpy(result, c->fcall.data, c->fcall.count);
|
||||
return c->fcall.count;
|
||||
}
|
||||
|
||||
static void cixp_write(IXPClient * c, int fd, void *content, size_t in_len)
|
||||
int
|
||||
ixp_client_write(IXPClient * c, unsigned int fid,
|
||||
unsigned long long offset, unsigned int count,
|
||||
unsigned char *data)
|
||||
{
|
||||
seek_write(c, fd, offsets[fd][1], content, in_len);
|
||||
if (!c->errstr)
|
||||
offsets[fd][1] += in_len;
|
||||
if(count > c->fcall.iounit)
|
||||
{
|
||||
c->errstr = "iounit exceeded";
|
||||
return -1;
|
||||
}
|
||||
/* write */
|
||||
c->fcall.id = TWRITE;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = fid;
|
||||
c->fcall.offset = offset;
|
||||
c->fcall.count = count;
|
||||
memcpy(c->fcall.data, data, count);
|
||||
if(do_fcall(c) == -1)
|
||||
return -1;
|
||||
return c->fcall.count;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_close(IXPClient * c, unsigned int fid)
|
||||
{
|
||||
/* clunk */
|
||||
c->fcall.id = TCLUNK;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = fid;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
void
|
||||
seek_write(IXPClient * c, int fd, size_t offset, void *content,
|
||||
size_t in_len)
|
||||
ixp_client_deinit(IXPClient * c)
|
||||
{
|
||||
ResHeader h;
|
||||
size_t req_len, res_len;
|
||||
void *req = twrite_message(fd, offset, content, in_len, &req_len);
|
||||
void *result = poll_server(c, req, req_len, &res_len);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
memcpy(&h, result, sizeof(ResHeader));
|
||||
free(result);
|
||||
}
|
||||
|
||||
static void cixp_close(IXPClient * c, int fd)
|
||||
{
|
||||
ResHeader h;
|
||||
size_t req_len, res_len;
|
||||
void *req = tclose_message(fd, &req_len);
|
||||
void *result = poll_server(c, req, req_len, &res_len);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
memcpy(&h, result, sizeof(ResHeader));
|
||||
free(result);
|
||||
offsets[fd][0] = offsets[fd][1] = 0;
|
||||
}
|
||||
|
||||
static void cixp_remove(IXPClient * c, char *path)
|
||||
{
|
||||
ResHeader h;
|
||||
size_t req_len, res_len;
|
||||
void *req = tremove_message(path, &req_len);
|
||||
void *result = poll_server(c, req, req_len, &res_len);
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
memcpy(&h, result, sizeof(ResHeader));
|
||||
free(result);
|
||||
}
|
||||
|
||||
IXPClient *init_ixp_client(char *sockfile)
|
||||
{
|
||||
struct sockaddr_un addr = { 0 };
|
||||
socklen_t su_len;
|
||||
|
||||
/* init */
|
||||
IXPClient *c = (IXPClient *) cext_emallocz(sizeof(IXPClient));
|
||||
c->create = cixp_create;
|
||||
c->open = cixp_open;
|
||||
c->read = cixp_read;
|
||||
c->write = cixp_write;
|
||||
c->close = cixp_close;
|
||||
c->remove = cixp_remove;
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, sockfile, sizeof(addr.sun_path));
|
||||
su_len = sizeof(struct sockaddr) + strlen(addr.sun_path);
|
||||
|
||||
if ((c->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
free(c);
|
||||
return 0;
|
||||
}
|
||||
if (connect(c->fd, (struct sockaddr *) &addr, su_len)) {
|
||||
close(c->fd);
|
||||
free(c);
|
||||
return 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void deinit_client(IXPClient * c)
|
||||
{
|
||||
if (c->fd) {
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
}
|
||||
c->fd = -1;
|
||||
free(c);
|
||||
/* session finished, now shutdown */
|
||||
if(c->fd) {
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
}
|
||||
}
|
||||
|
415
libixp/ixp.h
415
libixp/ixp.h
@ -1,172 +1,289 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*(C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
*See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_CONN 32
|
||||
#define MAX_OPEN_FILES 16
|
||||
#define DEAD_SERVER "server closed connection unexpectedly"
|
||||
#define MAX_SEEN_SHUTDOWN 3
|
||||
#ifndef nil
|
||||
#define nil 0
|
||||
#endif
|
||||
|
||||
#define xMAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
#define IXP_VERSION "9P2000"
|
||||
#define IXP_MAX_VERSION 32
|
||||
#define IXP_MAX_ERROR 128
|
||||
#define IXP_MAX_CACHE 32
|
||||
#define IXP_MAX_MSG 8192
|
||||
#define IXP_MAX_FLEN 128
|
||||
#define IXP_MAX_ULEN 32
|
||||
#define IXP_MAX_STAT 64
|
||||
#define IXP_MAX_WELEM 16 /*MAXWELEM */
|
||||
#define IXP_MAX_TFUNCS 14
|
||||
|
||||
/* 9P message types */
|
||||
|
||||
/*
|
||||
size[4] Tversion tag[2] msize[4] version[s]
|
||||
size[4] Rversion tag[2] msize[4] version[s]
|
||||
size[4] Tauth tag[2] afid[4] uname[s] aname[s]
|
||||
size[4] Rauth tag[2] aqid[13]
|
||||
size[4] Rerror tag[2] ename[s]
|
||||
size[4] Tflush tag[2] oldtag[2]
|
||||
size[4] Rflush tag[2]
|
||||
size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s]
|
||||
size[4] Rattach tag[2] qid[13]
|
||||
size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
|
||||
size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13])
|
||||
size[4] Topen tag[2] fid[4] mode[1]
|
||||
size[4] Ropen tag[2] qid[13] iounit[4]
|
||||
size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1]
|
||||
size[4] Rcreate tag[2] qid[13] iounit[4]
|
||||
size[4] Tread tag[2] fid[4] offset[8] count[4]
|
||||
size[4] Rread tag[2] count[4] data[count]
|
||||
size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]
|
||||
size[4] Rwrite tag[2] count[4]
|
||||
size[4] Tclunk tag[2] fid[4]
|
||||
size[4] Rclunk tag[2]
|
||||
size[4] Tremove tag[2] fid[4]
|
||||
size[4] Rremove tag[2]
|
||||
size[4] Tstat tag[2] fid[4]
|
||||
size[4] Rstat tag[2] stat[n]
|
||||
size[4] Twstat tag[2] fid[4] stat[n]
|
||||
size[4] Rwstat tag[2]
|
||||
|
||||
stat[n]:
|
||||
size[2] total byte count of the following data
|
||||
type[2] for kernel use
|
||||
dev[4] for kernel use
|
||||
qid.type[1] the type of the file (directory, etc.),
|
||||
represented as a bit vector corresponding to the high 8 bits of the file's mode word.
|
||||
qid.vers[4] version number for given path
|
||||
qid.path[8] the file server's unique identification for the file
|
||||
mode[4] permissions and flags
|
||||
atime[4] last access time
|
||||
mtime[4] last modification time
|
||||
length[8] length of file in bytes
|
||||
name[ s ] file name; must be / if the file is the root directory of the server
|
||||
uid[ s ] owner name
|
||||
gid[ s ] group name
|
||||
muid[ s ]
|
||||
*/
|
||||
|
||||
/*9P message types */
|
||||
enum {
|
||||
TVERSION = 100,
|
||||
RVERSION,
|
||||
TAUTH = 102,
|
||||
RAUTH,
|
||||
TATTACH = 104,
|
||||
RATTACH,
|
||||
TERROR = 106,
|
||||
RERROR,
|
||||
TFLUSH = 108,
|
||||
RFLUSH,
|
||||
TWALK = 110,
|
||||
RWALK,
|
||||
TOPEN = 112,
|
||||
ROPEN,
|
||||
TCREATE = 114,
|
||||
RCREATE,
|
||||
TREAD = 116,
|
||||
RREAD,
|
||||
TWRITE = 118,
|
||||
RWRITE,
|
||||
TCLUNK = 120,
|
||||
RCLUNK,
|
||||
TREMOVE = 122,
|
||||
RREMOVE,
|
||||
TSTAT = 124,
|
||||
RSTAT,
|
||||
TWSTAT = 126,
|
||||
RWSTAT,
|
||||
TVERSION = 100,
|
||||
RVERSION,
|
||||
TAUTH = 102,
|
||||
RAUTH,
|
||||
TATTACH = 104,
|
||||
RATTACH,
|
||||
TERROR = 106,
|
||||
RERROR,
|
||||
TFLUSH = 108,
|
||||
RFLUSH,
|
||||
TWALK = 110,
|
||||
RWALK,
|
||||
TOPEN = 112,
|
||||
ROPEN,
|
||||
TCREATE = 114,
|
||||
RCREATE,
|
||||
TREAD = 116,
|
||||
RREAD,
|
||||
TWRITE = 118,
|
||||
RWRITE,
|
||||
TCLUNK = 120,
|
||||
RCLUNK,
|
||||
TREMOVE = 122,
|
||||
RREMOVE,
|
||||
TSTAT = 124,
|
||||
RSTAT,
|
||||
TWSTAT = 126,
|
||||
RWSTAT,
|
||||
};
|
||||
|
||||
typedef struct ResHeader ResHeader;
|
||||
typedef struct ReqHeader ReqHeader;
|
||||
typedef struct Connection Connection;
|
||||
typedef struct File File;
|
||||
typedef struct IXPClient IXPClient;
|
||||
/*borrowed from libc.h of Plan 9 */
|
||||
#define DMDIR 0x80000000 /*mode bit for directories */
|
||||
#define DMAPPEND 0x40000000 /*mode bit for append only files */
|
||||
#define DMEXCL 0x20000000 /*mode bit for exclusive use files */
|
||||
#define DMMOUNT 0x10000000 /*mode bit for mounted channel */
|
||||
#define DMAUTH 0x08000000 /*mode bit for authentication file */
|
||||
#define DMTMP 0x04000000 /*mode bit for non-backed-up file */
|
||||
|
||||
#define DMREAD 0x4<<6 /*mode bit for read permission */
|
||||
#define DMWRITE 0x2<<6 /*mode bit for write permission */
|
||||
#define DMEXEC 0x1<<6 /*mode bit for execute permission */
|
||||
|
||||
/*modes */
|
||||
enum {
|
||||
IXP_OREAD = 0x00,
|
||||
IXP_OWRITE = 0x01,
|
||||
IXP_ORDWR = 0x02,
|
||||
IXP_OEXEC = 0x03,
|
||||
IXP_OEXCL = 0x04,
|
||||
IXP_OTRUNC = 0x10,
|
||||
IXP_OREXEC = 0x20,
|
||||
IXP_ORCLOSE = 0x40,
|
||||
IXP_OAPPEND = 0x80,
|
||||
};
|
||||
|
||||
/*qid.types */
|
||||
enum {
|
||||
IXP_QTDIR = 0x80,
|
||||
IXP_QTAPPEND = 0x40,
|
||||
IXP_QTEXCL = 0x20,
|
||||
IXP_QTMOUNT = 0x10,
|
||||
IXP_QTAUTH = 0x08,
|
||||
IXP_QTTMP = 0x04,
|
||||
IXP_QTSYMLINK = 0x02,
|
||||
IXP_QTLINK = 0x01,
|
||||
IXP_QTFILE = 0x00,
|
||||
};
|
||||
|
||||
#define IXP_NOTAG (unsigned short)~0U /*Dummy tag */
|
||||
#define IXP_NOFID (unsigned int)~0 /*No auth */
|
||||
|
||||
typedef struct {
|
||||
unsigned char type;
|
||||
unsigned int version;
|
||||
unsigned long long path;
|
||||
} Qid;
|
||||
|
||||
/*stat structure */
|
||||
typedef struct {
|
||||
unsigned short type;
|
||||
unsigned int dev;
|
||||
Qid qid;
|
||||
unsigned int mode;
|
||||
unsigned int atime;
|
||||
unsigned int mtime;
|
||||
unsigned long long length;
|
||||
char name[IXP_MAX_FLEN];
|
||||
char uid[IXP_MAX_ULEN];
|
||||
char gid[IXP_MAX_ULEN];
|
||||
char muid[IXP_MAX_ULEN];
|
||||
} Stat;
|
||||
|
||||
typedef struct {
|
||||
unsigned char id;
|
||||
unsigned short tag;
|
||||
unsigned int fid;
|
||||
unsigned int maxmsg; /*Tversion, Rversion */
|
||||
char version[IXP_MAX_VERSION]; /*Tversion, Rversion */
|
||||
unsigned short oldtag; /*Tflush */
|
||||
char errstr[IXP_MAX_ERROR]; /*Rerror */
|
||||
Qid qid; /*Rattach, Ropen, Rcreate */
|
||||
unsigned int iounit; /*Ropen, Rcreate */
|
||||
Qid aqid; /*Rauth */
|
||||
unsigned int afid; /*Tauth, Tattach */
|
||||
char uname[IXP_MAX_ULEN]; /*Tauth, Tattach */
|
||||
char aname[IXP_MAX_FLEN]; /*Tauth, Tattach */
|
||||
unsigned int perm; /*Tcreate */
|
||||
char name[IXP_MAX_FLEN]; /*Tcreate */
|
||||
unsigned char mode; /*Tcreate, Topen */
|
||||
unsigned int newfid; /*Twalk */
|
||||
unsigned short nwname; /*Twalk */
|
||||
char wname[IXP_MAX_WELEM][IXP_MAX_FLEN]; /*Twalk */
|
||||
unsigned short nwqid; /*Rwalk */
|
||||
Qid wqid[IXP_MAX_WELEM]; /*Rwalk */
|
||||
unsigned long long offset; /*Tread, Twrite */
|
||||
unsigned int count; /*Tread, Twrite, Rread */
|
||||
Stat stat; /*Rstat */
|
||||
unsigned short nstat; /*Twstat, Rstat */
|
||||
unsigned char data[IXP_MAX_MSG]; /*Twrite, Rread, Twstat,
|
||||
*Rstat */
|
||||
} Fcall;
|
||||
|
||||
typedef struct IXPServer IXPServer;
|
||||
typedef int IXPRequest;
|
||||
typedef int IXPResponse;
|
||||
typedef enum {
|
||||
HALT, SHUTDOWN, RUNNING
|
||||
} IXPRunlevel;
|
||||
typedef struct IXPConn IXPConn;
|
||||
typedef struct IXPMap IXPMap;
|
||||
|
||||
struct ReqHeader {
|
||||
IXPRequest req;
|
||||
int fd;
|
||||
size_t offset;
|
||||
size_t buf_len;
|
||||
struct IXPMap {
|
||||
unsigned int fid;
|
||||
Qid qid;
|
||||
};
|
||||
|
||||
struct ResHeader {
|
||||
IXPResponse res;
|
||||
int fd;
|
||||
size_t buf_len;
|
||||
};
|
||||
|
||||
/** Definition of a connection to IXP */
|
||||
struct Connection {
|
||||
IXPServer *s; /* !< server for this connection */
|
||||
int index; /* !< index inside server */
|
||||
int fd; /* !< file descriptor */
|
||||
int mode; /* 0 for reading, 1 for writing */
|
||||
int header;
|
||||
void *data;
|
||||
size_t len;
|
||||
size_t remain;
|
||||
void (*read) (Connection *);
|
||||
void (*write) (Connection *);
|
||||
File *files[MAX_OPEN_FILES];
|
||||
int seen[MAX_OPEN_FILES];
|
||||
};
|
||||
|
||||
struct File {
|
||||
char *name;
|
||||
void *content;
|
||||
size_t size;
|
||||
int bind;
|
||||
File *parent;
|
||||
File *next;
|
||||
/* introduced IXPServer in signature for IXPServer->errstr */
|
||||
void (*after_write) (IXPServer * s, File *);
|
||||
void (*before_read) (IXPServer * s, File *);
|
||||
};
|
||||
|
||||
struct IXPClient {
|
||||
int fd;
|
||||
fd_set rd, wr;
|
||||
char *errstr; /* 0 if succes, CHECK AFTER EACH of following
|
||||
* operations */
|
||||
/* returns fd if path exists */
|
||||
void (*create) (IXPClient *, char *path);
|
||||
void (*remove) (IXPClient *, char *path);
|
||||
int (*open) (IXPClient *, char *path);
|
||||
void (*close) (IXPClient *, int fd);
|
||||
size_t(*read) (IXPClient *, int fd, void *out_buf, size_t out_buf_len);
|
||||
void (*write) (IXPClient *, int fd, void *content, size_t in_len);
|
||||
struct IXPConn {
|
||||
int fd;
|
||||
void (*read) (IXPServer *, IXPConn *);
|
||||
void (*close) (IXPServer *, IXPConn *);
|
||||
IXPMap **map;
|
||||
size_t mapsz;
|
||||
Fcall *fcall;
|
||||
Fcall **pend;
|
||||
size_t pendsz;
|
||||
};
|
||||
|
||||
struct IXPServer {
|
||||
char *sockfile;
|
||||
IXPRunlevel runlevel;
|
||||
Connection conn[MAX_CONN];
|
||||
fd_set rd, wr; /* socks to wakeup while select() */
|
||||
int nfds; /* number of file descriptors */
|
||||
File *root;
|
||||
char *errstr; /* 0 if succes, CHECK AFTER EACH of following
|
||||
* operations */
|
||||
File *(*create) (IXPServer *, char *);
|
||||
File *(*open) (IXPServer *, char *);
|
||||
size_t(*read) (IXPServer *, int, size_t, void *, size_t);
|
||||
void (*write) (IXPServer *, int, size_t, void *, size_t);
|
||||
void (*close) (IXPServer *, int);
|
||||
void (*remove) (IXPServer *, char *);
|
||||
int running;
|
||||
IXPConn **conn;
|
||||
size_t connsz;
|
||||
int maxfd;
|
||||
fd_set rd;
|
||||
};
|
||||
|
||||
/* client.c, implements client stub functions for fs access */
|
||||
IXPClient *init_ixp_client(char *sockfile);
|
||||
void deinit_client(IXPClient * c);
|
||||
size_t seek_read(IXPClient * c, int fd, size_t offset, void *out_buf, size_t out_buf_len);
|
||||
void seek_write(IXPClient * c, int fd, size_t offset, void *content, size_t in_len);
|
||||
typedef struct {
|
||||
int fd;
|
||||
unsigned int root_fid;
|
||||
Qid root_qid;
|
||||
Fcall fcall;
|
||||
char *errstr;
|
||||
} IXPClient;
|
||||
|
||||
/* client.c */
|
||||
int ixp_client_init(IXPClient *c, char *address);
|
||||
void ixp_client_deinit(IXPClient *c);
|
||||
int ixp_client_remove(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
int ixp_client_create(IXPClient *c, unsigned int dirfid, char *name,
|
||||
unsigned int perm, unsigned char mode);
|
||||
int ixp_client_walk(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
int ixp_client_open(IXPClient *c, unsigned int newfid, char *filepath,
|
||||
unsigned char mode);
|
||||
int ixp_client_read(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset, void *result,
|
||||
unsigned int res_len);
|
||||
int ixp_client_write(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset,
|
||||
unsigned int count, unsigned char *data);
|
||||
int ixp_client_close(IXPClient *c, unsigned int fid);
|
||||
|
||||
/* convert.c */
|
||||
void *ixp_enc_u8(unsigned char *msg, unsigned char val);
|
||||
void *ixp_dec_u8(unsigned char *msg, unsigned char *val);
|
||||
void *ixp_enc_u16(unsigned char *msg, unsigned short val);
|
||||
void *ixp_dec_u16(unsigned char *msg, unsigned short *val);
|
||||
void *ixp_enc_u32(unsigned char *msg, unsigned int val);
|
||||
void *ixp_dec_u32(unsigned char *msg, unsigned int *val);
|
||||
void *ixp_enc_u64(unsigned char *msg, unsigned long long val);
|
||||
void *ixp_dec_u64(unsigned char *msg, unsigned long long *val);
|
||||
void *ixp_enc_string(unsigned char *msg, const char *s);
|
||||
void *ixp_dec_string(unsigned char *msg, char *string,
|
||||
unsigned short stringlen, unsigned short *len);
|
||||
void *ixp_enc_data(unsigned char *msg, unsigned char *data,
|
||||
unsigned int datalen);
|
||||
void *ixp_dec_data(unsigned char *msg, unsigned char *data,
|
||||
unsigned int datalen);
|
||||
void *ixp_enc_prefix(unsigned char *msg, unsigned int size,
|
||||
unsigned char id, unsigned short tag);
|
||||
void *ixp_dec_prefix(unsigned char *msg, unsigned int *size,
|
||||
unsigned char *id, unsigned short *tag);
|
||||
void *ixp_enc_qid(unsigned char *msg, Qid *qid);
|
||||
void *ixp_dec_qid(unsigned char *msg, Qid *qid);
|
||||
void *ixp_enc_stat(unsigned char *msg, Stat *stat);
|
||||
void *ixp_dec_stat(unsigned char *msg, Stat *stat);
|
||||
|
||||
/* message.c */
|
||||
void *tcreate_message(char *path, size_t * msg_len);
|
||||
void *topen_message(char *path, size_t * msg_len);
|
||||
void *tread_message(int fd, size_t offset, size_t buf_len, size_t * msg_len);
|
||||
void *twrite_message(int fd, size_t offset, void *msg, size_t in_len, size_t * msg_len);
|
||||
void *tclose_message(int fd, size_t * msg_len);
|
||||
void *tremove_message(char *path, size_t * msg_len);
|
||||
void *rcreate_message(size_t * msg_len);
|
||||
void *ropen_message(int fd, size_t * msg_len);
|
||||
void *rread_message(void *content, size_t content_len, size_t * msg_len);
|
||||
void *rwrite_message(size_t * msg_len);
|
||||
void *rclose_message(size_t * msg_len);
|
||||
void *rremove_message(size_t * msg_len);
|
||||
void *rerror_message(char *errstr, size_t * msg_len);
|
||||
unsigned short ixp_sizeof_stat(Stat *stat);
|
||||
unsigned int ixp_fcall_to_msg(Fcall *fcall, void *msg, unsigned int msglen);
|
||||
unsigned int ixp_msg_to_fcall(void *msg, unsigned int msglen, Fcall *fcall);
|
||||
|
||||
/* ramfs.c */
|
||||
int is_directory(File * f);
|
||||
File *ixp_walk(IXPServer * s, char *path);
|
||||
File *ixp_create(IXPServer * s, char *path);
|
||||
File *ixp_open(IXPServer * s, char *path);
|
||||
size_t ixp_read(IXPServer * s, int fd, size_t offset, void *out_buf, size_t out_buf_len);
|
||||
void ixp_write(IXPServer * s, int fd, size_t offset, void *content, size_t in_len);
|
||||
void ixp_close(IXPServer * s, int fd);
|
||||
void ixp_remove(IXPServer * s, char *path);
|
||||
void ixp_remove_file(IXPServer * s, File * f);
|
||||
/* server.c */
|
||||
char *ixp_server_loop(IXPServer *s);
|
||||
IXPMap *ixp_server_fid2map(IXPConn *c, unsigned int fid);
|
||||
|
||||
/* server.c, uses fs directly for manipulation */
|
||||
IXPServer *init_server(char *sockfile, void (*cleanup) (void));
|
||||
void deinit_server(IXPServer * s);
|
||||
File *fd_to_file(IXPServer * s, int fd);
|
||||
void run_server(IXPServer * s);
|
||||
void run_server_with_fd_support(IXPServer * s, int fd, void (*fd_read) (Connection *), /* callback for read on fd */
|
||||
void (*fd_write) (Connection *)); /* callback for write on fd */
|
||||
void set_error(IXPServer * s, char *errstr);
|
||||
/* socket.c */
|
||||
int ixp_connect_sock(char *address);
|
||||
int ixp_accept_sock(int fd);
|
||||
int ixp_create_sock(char *address, char **errstr);
|
||||
|
||||
/* transport.c */
|
||||
unsigned int ixp_send_message(int fd, void *msg, unsigned int msize, char **errstr);
|
||||
unsigned int ixp_recv_message(int fd, void *msg, unsigned int msglen, char **errstr);
|
||||
|
439
libixp/message.c
439
libixp/message.c
@ -3,170 +3,315 @@
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ixp.h"
|
||||
|
||||
#include <cext.h>
|
||||
#define IXP_QIDSZ (sizeof(unsigned char) + sizeof(unsigned int)\
|
||||
+ sizeof(unsigned long long))
|
||||
|
||||
void *tcreate_message(char *path, size_t * msg_len)
|
||||
static unsigned short
|
||||
sizeof_string(const char *s)
|
||||
{
|
||||
char *msg;
|
||||
ReqHeader h;
|
||||
*msg_len = sizeof(ReqHeader) + strlen(path) + 1;
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.req = TCREATE;
|
||||
memcpy(msg, &h, sizeof(ReqHeader));
|
||||
memcpy(msg + sizeof(ReqHeader), path, strlen(path) + 1);
|
||||
return msg;
|
||||
return sizeof(unsigned short) + strlen(s);
|
||||
}
|
||||
|
||||
void *topen_message(char *path, size_t * msg_len)
|
||||
unsigned short
|
||||
ixp_sizeof_stat(Stat * stat)
|
||||
{
|
||||
char *msg;
|
||||
ReqHeader h;
|
||||
*msg_len = sizeof(ReqHeader) + strlen(path) + 1;
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.req = TOPEN;
|
||||
memcpy(msg, &h, sizeof(ReqHeader));
|
||||
memcpy(msg + sizeof(ReqHeader), path, strlen(path) + 1);
|
||||
return msg;
|
||||
return IXP_QIDSZ
|
||||
+ 2 * sizeof(unsigned short)
|
||||
+ 4 * sizeof(unsigned int)
|
||||
+ sizeof(unsigned long long)
|
||||
+ sizeof_string(stat->name)
|
||||
+ sizeof_string(stat->uid)
|
||||
+ sizeof_string(stat->gid)
|
||||
+ sizeof_string(stat->muid);
|
||||
}
|
||||
|
||||
void *tread_message(int fd, size_t offset, size_t buf_len,
|
||||
size_t * msg_len)
|
||||
unsigned int
|
||||
ixp_fcall_to_msg(Fcall * fcall, void *msg, unsigned int msglen)
|
||||
{
|
||||
char *msg;
|
||||
ReqHeader h;
|
||||
*msg_len = sizeof(ReqHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.req = TREAD;
|
||||
h.fd = fd;
|
||||
h.offset = offset;
|
||||
h.buf_len = buf_len;
|
||||
memcpy(msg, &h, sizeof(ReqHeader));
|
||||
return msg;
|
||||
unsigned int i, msize =
|
||||
sizeof(unsigned char) + sizeof(unsigned short) +
|
||||
sizeof(unsigned int);
|
||||
void *p = msg;
|
||||
|
||||
switch (fcall->id) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
msize += sizeof(unsigned int) + sizeof_string(fcall->version);
|
||||
break;
|
||||
case TAUTH:
|
||||
msize +=
|
||||
sizeof(unsigned int) + sizeof_string(fcall->uname) +
|
||||
sizeof_string(fcall->aname);
|
||||
break;
|
||||
case RAUTH:
|
||||
case RATTACH:
|
||||
msize += IXP_QIDSZ;
|
||||
break;
|
||||
case TATTACH:
|
||||
msize +=
|
||||
2 * sizeof(unsigned int) + sizeof_string(fcall->uname) +
|
||||
sizeof_string(fcall->aname);
|
||||
break;
|
||||
case RERROR:
|
||||
msize += sizeof_string(fcall->errstr);
|
||||
break;
|
||||
case RWRITE:
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
msize += sizeof(unsigned int);
|
||||
break;
|
||||
case TWALK:
|
||||
msize += sizeof(unsigned short) + 2 * sizeof(unsigned int);
|
||||
for(i = 0; i < fcall->nwname; i++)
|
||||
msize += sizeof_string(fcall->wname[i]);
|
||||
break;
|
||||
case TFLUSH:
|
||||
msize += sizeof(unsigned short);
|
||||
break;
|
||||
case RWALK:
|
||||
msize += sizeof(unsigned short) + fcall->nwqid * IXP_QIDSZ;
|
||||
break;
|
||||
case TOPEN:
|
||||
msize += sizeof(unsigned int) + sizeof(unsigned char);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
msize += IXP_QIDSZ + sizeof(unsigned int);
|
||||
break;
|
||||
case TCREATE:
|
||||
msize +=
|
||||
sizeof(unsigned char) + 2 * sizeof(unsigned int) +
|
||||
sizeof_string(fcall->name);
|
||||
break;
|
||||
case TREAD:
|
||||
msize += 2 * sizeof(unsigned int) + sizeof(unsigned long long);
|
||||
break;
|
||||
case RREAD:
|
||||
msize += sizeof(unsigned int) + fcall->count;
|
||||
break;
|
||||
case TWRITE:
|
||||
msize +=
|
||||
2 * sizeof(unsigned int) + sizeof(unsigned long long) +
|
||||
fcall->count;
|
||||
break;
|
||||
case RSTAT:
|
||||
msize += sizeof(unsigned short) + ixp_sizeof_stat(&fcall->stat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
msize += sizeof(unsigned int) + sizeof(unsigned short) + ixp_sizeof_stat(&fcall->stat);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(msize > msglen)
|
||||
return 0;
|
||||
p = ixp_enc_prefix(p, msize, fcall->id, fcall->tag);
|
||||
|
||||
switch (fcall->id) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
p = ixp_enc_u32(p, fcall->maxmsg);
|
||||
p = ixp_enc_string(p, fcall->version);
|
||||
break;
|
||||
case TAUTH:
|
||||
p = ixp_enc_u32(p, fcall->afid);
|
||||
p = ixp_enc_string(p, fcall->uname);
|
||||
p = ixp_enc_string(p, fcall->aname);
|
||||
break;
|
||||
case RAUTH:
|
||||
p = ixp_enc_qid(p, &fcall->aqid);
|
||||
break;
|
||||
case RATTACH:
|
||||
p = ixp_enc_qid(p, &fcall->qid);
|
||||
break;
|
||||
case TATTACH:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u32(p, fcall->afid);
|
||||
p = ixp_enc_string(p, fcall->uname);
|
||||
p = ixp_enc_string(p, fcall->aname);
|
||||
break;
|
||||
case RERROR:
|
||||
p = ixp_enc_string(p, fcall->errstr);
|
||||
break;
|
||||
case TFLUSH:
|
||||
p = ixp_enc_u16(p, fcall->oldtag);
|
||||
break;
|
||||
case TWALK:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u32(p, fcall->newfid);
|
||||
p = ixp_enc_u16(p, fcall->nwname);
|
||||
for(i = 0; i < fcall->nwname; i++)
|
||||
p = ixp_enc_string(p, fcall->wname[i]);
|
||||
break;
|
||||
case RWALK:
|
||||
p = ixp_enc_u16(p, fcall->nwqid);
|
||||
for(i = 0; i < fcall->nwqid; i++)
|
||||
p = ixp_enc_qid(p, &fcall->wqid[i]);
|
||||
break;
|
||||
case TOPEN:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u8(p, fcall->mode);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
p = ixp_enc_qid(p, &fcall->qid);
|
||||
p = ixp_enc_u32(p, fcall->iounit);
|
||||
break;
|
||||
case TCREATE:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_string(p, fcall->name);
|
||||
p = ixp_enc_u32(p, fcall->perm);
|
||||
p = ixp_enc_u8(p, fcall->mode);
|
||||
break;
|
||||
case TREAD:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u64(p, fcall->offset);
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
break;
|
||||
case RREAD:
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
p = ixp_enc_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case TWRITE:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u64(p, fcall->offset);
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
p = ixp_enc_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case RWRITE:
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
break;
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
break;
|
||||
case RSTAT:
|
||||
p = ixp_enc_u16(p, ixp_sizeof_stat(&fcall->stat));
|
||||
p = ixp_enc_stat(p, &fcall->stat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u16(p, ixp_sizeof_stat(&fcall->stat));
|
||||
p = ixp_enc_stat(p, &fcall->stat);
|
||||
break;
|
||||
}
|
||||
|
||||
if(msg + msize == p)
|
||||
return msize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *twrite_message(int fd, size_t offset, void *content,
|
||||
size_t content_len, size_t * msg_len)
|
||||
unsigned int
|
||||
ixp_msg_to_fcall(void *msg, unsigned int msglen, Fcall * fcall)
|
||||
{
|
||||
char *msg;
|
||||
ReqHeader h;
|
||||
*msg_len = sizeof(ReqHeader) + content_len;
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.req = TWRITE;
|
||||
h.fd = fd;
|
||||
h.offset = offset;
|
||||
h.buf_len = content_len;
|
||||
memcpy(msg, &h, sizeof(ReqHeader));
|
||||
memcpy(msg + sizeof(ReqHeader), content, content_len);
|
||||
return msg;
|
||||
}
|
||||
unsigned int i, msize;
|
||||
unsigned short len;
|
||||
void *p = ixp_dec_prefix(msg, &msize, &fcall->id, &fcall->tag);
|
||||
|
||||
void *tclose_message(int fd, size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ReqHeader h;
|
||||
*msg_len = sizeof(ReqHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.req = TCLUNK;
|
||||
h.fd = fd;
|
||||
memcpy(msg, &h, sizeof(ReqHeader));
|
||||
return msg;
|
||||
}
|
||||
if(msize > msglen) /* bad message */
|
||||
return 0;
|
||||
|
||||
void *tremove_message(char *path, size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ReqHeader h;
|
||||
*msg_len = sizeof(ReqHeader) + strlen(path) + 1;
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.req = TREMOVE;
|
||||
memcpy(msg, &h, sizeof(ReqHeader));
|
||||
memcpy(msg + sizeof(ReqHeader), path, strlen(path) + 1);
|
||||
return msg;
|
||||
}
|
||||
switch (fcall->id) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
p = ixp_dec_u32(p, &fcall->maxmsg);
|
||||
p = ixp_dec_string(p, fcall->version, sizeof(fcall->version), &len);
|
||||
break;
|
||||
case TAUTH:
|
||||
p = ixp_dec_u32(p, &fcall->afid);
|
||||
p = ixp_dec_string(p, fcall->uname, sizeof(fcall->uname), &len);
|
||||
p = ixp_dec_string(p, fcall->aname, sizeof(fcall->aname), &len);
|
||||
break;
|
||||
case RAUTH:
|
||||
p = ixp_dec_qid(p, &fcall->aqid);
|
||||
break;
|
||||
case RATTACH:
|
||||
p = ixp_dec_qid(p, &fcall->qid);
|
||||
break;
|
||||
case TATTACH:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u32(p, &fcall->afid);
|
||||
p = ixp_dec_string(p, fcall->uname, sizeof(fcall->uname), &len);
|
||||
p = ixp_dec_string(p, fcall->aname, sizeof(fcall->aname), &len);
|
||||
break;
|
||||
case RERROR:
|
||||
p = ixp_dec_string(p, fcall->errstr, sizeof(fcall->errstr), &len);
|
||||
break;
|
||||
case TFLUSH:
|
||||
p = ixp_dec_u16(p, &fcall->oldtag);
|
||||
break;
|
||||
case TWALK:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u32(p, &fcall->newfid);
|
||||
p = ixp_dec_u16(p, &fcall->nwname);
|
||||
for(i = 0; i < fcall->nwname; i++) {
|
||||
|
||||
void *rcreate_message(size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = RCREATE;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
return msg;
|
||||
}
|
||||
p = ixp_dec_string(p, fcall->wname[i], IXP_MAX_FLEN, &len);
|
||||
}
|
||||
break;
|
||||
case RWALK:
|
||||
p = ixp_dec_u16(p, &fcall->nwqid);
|
||||
for(i = 0; i < fcall->nwqid; i++)
|
||||
p = ixp_dec_qid(p, &fcall->wqid[i]);
|
||||
break;
|
||||
case TOPEN:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u8(p, &fcall->mode);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
p = ixp_dec_qid(p, &fcall->qid);
|
||||
p = ixp_dec_u32(p, &fcall->iounit);
|
||||
break;
|
||||
case TCREATE:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_string(p, fcall->name, sizeof(fcall->name), &len);
|
||||
p = ixp_dec_u32(p, &fcall->perm);
|
||||
p = ixp_dec_u8(p, &fcall->mode);
|
||||
break;
|
||||
case TREAD:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u64(p, &fcall->offset);
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
break;
|
||||
case RREAD:
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
p = ixp_dec_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case TWRITE:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u64(p, &fcall->offset);
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
p = ixp_dec_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case RWRITE:
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
break;
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
break;
|
||||
case RSTAT:
|
||||
p = ixp_dec_u16(p, &len);
|
||||
p = ixp_dec_stat(p, &fcall->stat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u16(p, &len);
|
||||
p = ixp_dec_stat(p, &fcall->stat);
|
||||
break;
|
||||
}
|
||||
|
||||
void *ropen_message(int fd, size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = ROPEN;
|
||||
h.fd = fd;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
return msg;
|
||||
}
|
||||
|
||||
void *rread_message(void *content, size_t content_len, size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader) + content_len;
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = RREAD;
|
||||
h.buf_len = content_len;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
memmove(msg + sizeof(ResHeader), content, content_len);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void *rwrite_message(size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = RWRITE;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
return msg;
|
||||
}
|
||||
|
||||
void *rclose_message(size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = RCLUNK;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
return msg;
|
||||
}
|
||||
|
||||
void *rremove_message(size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader);
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = RREMOVE;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
return msg;
|
||||
}
|
||||
|
||||
void *rerror_message(char *errstr, size_t * msg_len)
|
||||
{
|
||||
char *msg;
|
||||
size_t len = strlen(errstr) + 1;
|
||||
ResHeader h;
|
||||
*msg_len = sizeof(ResHeader) + len;
|
||||
msg = cext_emallocz(*msg_len);
|
||||
h.res = RERROR;
|
||||
memcpy(msg, &h, sizeof(ResHeader));
|
||||
memmove(msg + sizeof(ResHeader), errstr, len);
|
||||
return msg;
|
||||
if(msg + msize == p)
|
||||
return msize;
|
||||
return 0;
|
||||
}
|
||||
|
297
libixp/ramfs.c
297
libixp/ramfs.c
@ -1,297 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ixp.h"
|
||||
|
||||
#include <cext.h>
|
||||
|
||||
int is_directory(File * f)
|
||||
{
|
||||
return !f->size && f->content;
|
||||
}
|
||||
|
||||
File *ixp_create(IXPServer * s, char *path)
|
||||
{
|
||||
File *f, *p;
|
||||
char *buf = strdup(path);
|
||||
char *tok, *tok_ptr;
|
||||
|
||||
if (!path)
|
||||
return 0;
|
||||
|
||||
/* cannot create a directory with empty name */
|
||||
if (buf[strlen(buf) - 1] == '/')
|
||||
return 0;
|
||||
tok = strtok_r(buf, "/", &tok_ptr);
|
||||
p = s->root;
|
||||
f = p->content;
|
||||
/* first determine the path as it exists already */
|
||||
while (f && tok) {
|
||||
if (!strcmp(f->name, tok)) {
|
||||
tok = strtok_r(0, "/", &tok_ptr);
|
||||
p = f;
|
||||
if (tok && is_directory(f))
|
||||
f = f->content;
|
||||
else
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
f = f->next;
|
||||
}
|
||||
if (p->size && tok) {
|
||||
free(buf);
|
||||
return 0; /* cannot create subdirectory, if file has
|
||||
* content */
|
||||
}
|
||||
/* only create missing parts, if file is directory */
|
||||
while (tok) {
|
||||
f = (File *) cext_emallocz(sizeof(File));
|
||||
f->name = strdup(tok);
|
||||
f->parent = p;
|
||||
if (p->content) {
|
||||
p = p->content;
|
||||
while (p->next) {
|
||||
p = p->next;
|
||||
}
|
||||
p->next = f;
|
||||
} else {
|
||||
p->content = f;
|
||||
}
|
||||
p = f;
|
||||
tok = strtok_r(0, "/", &tok_ptr);
|
||||
}
|
||||
free(buf);
|
||||
return f;
|
||||
}
|
||||
|
||||
static int comp_file_name(const void *f1, const void *f2)
|
||||
{
|
||||
File *f = (File *) f1;
|
||||
File *p = (File *) f2;
|
||||
return strcmp(*(char **) f->name, *(char **) p->name);
|
||||
}
|
||||
|
||||
static char *xls(File * f)
|
||||
{
|
||||
File *p;
|
||||
char *result = 0;
|
||||
size_t size = 1; /* for \n */
|
||||
int num = 0, i;
|
||||
File **tmp;
|
||||
|
||||
for (p = f; p; p = p->next)
|
||||
num++;
|
||||
tmp = cext_emallocz(sizeof(File *) * num);
|
||||
i = 0;
|
||||
for (p = f; p; p = p->next) {
|
||||
size += strlen(p->name) + 1;
|
||||
if (is_directory(p))
|
||||
size++;
|
||||
tmp[i++] = p;
|
||||
}
|
||||
qsort(tmp, num, sizeof(File *), comp_file_name);
|
||||
result = cext_emallocz(size);
|
||||
for (i = 0; i < num; i++) {
|
||||
strncat(result, tmp[i]->name, size);
|
||||
if (is_directory(tmp[i]))
|
||||
strncat(result, "/\n", size);
|
||||
else
|
||||
strncat(result, "\n", size);
|
||||
}
|
||||
free(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
File *ixp_open(IXPServer * s, char *path)
|
||||
{
|
||||
File *f;
|
||||
|
||||
f = ixp_walk(s, path);
|
||||
if (!f) {
|
||||
set_error(s, "file does not exist");
|
||||
return nil;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void ixp_close(IXPServer * s, int fd)
|
||||
{
|
||||
File *f = fd_to_file(s, fd);
|
||||
if (!f)
|
||||
set_error(s, "invalid file descriptor");
|
||||
}
|
||||
|
||||
size_t
|
||||
ixp_read(IXPServer * s, int fd, size_t offset, void *out_buf,
|
||||
size_t out_buf_len)
|
||||
{
|
||||
File *f = fd_to_file(s, fd);
|
||||
void *result = 0;
|
||||
size_t len = 0, res_len = 0;
|
||||
|
||||
if (!f) {
|
||||
set_error(s, "invalid file descriptor");
|
||||
return 0;
|
||||
}
|
||||
/* callback */
|
||||
if (f->before_read)
|
||||
f->before_read(s, f);
|
||||
if (is_directory(f)) {
|
||||
result = xls(f->content);
|
||||
res_len = strlen(result);
|
||||
} else if (f->size) {
|
||||
result = f->content;
|
||||
res_len = f->size;
|
||||
}
|
||||
if (offset > res_len) {
|
||||
set_error(s, "invalid offset when reading file");
|
||||
if (is_directory(f))
|
||||
free(result);
|
||||
return 0;
|
||||
}
|
||||
if (result) {
|
||||
len = res_len - offset;
|
||||
if (len > out_buf_len)
|
||||
len = out_buf_len;
|
||||
memcpy(out_buf, (char *) result + offset, len);
|
||||
if (is_directory(f))
|
||||
free(result);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
ixp_write(IXPServer * s, int fd, size_t offset, void *content,
|
||||
size_t in_len)
|
||||
{
|
||||
File *f = fd_to_file(s, fd);
|
||||
|
||||
if (!f) {
|
||||
set_error(s, "invalid file descriptor");
|
||||
return;
|
||||
}
|
||||
if (is_directory(f)) {
|
||||
/* we cannot write to directories */
|
||||
set_error(s, "cannot write to a directory");
|
||||
return;
|
||||
}
|
||||
if (in_len) {
|
||||
/* offset 0 flushes the file */
|
||||
if (!offset || (offset + in_len > f->size)) {
|
||||
f->content = realloc(f->content, offset + in_len + 1);
|
||||
f->size = offset + in_len;
|
||||
}
|
||||
memcpy((char *) f->content + offset, content, in_len);
|
||||
/* internal EOF character */
|
||||
((char *) f->content)[f->size] = 0;
|
||||
} else if (!offset) {
|
||||
/* blank file */
|
||||
if (f->content)
|
||||
free(f->content);
|
||||
f->content = 0;
|
||||
f->size = 0;
|
||||
}
|
||||
/* callback */
|
||||
if (f->after_write)
|
||||
f->after_write(s, f);
|
||||
}
|
||||
|
||||
static void xremove(IXPServer * s, File * f)
|
||||
{
|
||||
if (!f)
|
||||
return;
|
||||
if (f->next) {
|
||||
xremove(s, f->next);
|
||||
if (s->errstr)
|
||||
return;
|
||||
}
|
||||
if (!f->bind && is_directory(f)) {
|
||||
xremove(s, f->content);
|
||||
if (s->errstr)
|
||||
return;
|
||||
}
|
||||
if (f->content && f->size) {
|
||||
free(f->content);
|
||||
}
|
||||
if (f != s->root) {
|
||||
if (f->name) {
|
||||
free(f->name);
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
|
||||
void ixp_remove_file(IXPServer * s, File * f)
|
||||
{
|
||||
File *p, *n;
|
||||
set_error(s, 0);
|
||||
if (!f) {
|
||||
set_error(s, "file does not exist");
|
||||
return;
|
||||
}
|
||||
/* detach */
|
||||
p = f->parent;
|
||||
n = f->next;
|
||||
f->next = 0;
|
||||
if (p) {
|
||||
if (p->content == f)
|
||||
p->content = n;
|
||||
else {
|
||||
p = p->content;
|
||||
while (p && (p->next != f))
|
||||
p = p->next;
|
||||
if (p)
|
||||
p->next = n;
|
||||
}
|
||||
}
|
||||
/* remove now */
|
||||
xremove(s, f);
|
||||
}
|
||||
|
||||
|
||||
void ixp_remove(IXPServer * s, char *path)
|
||||
{
|
||||
ixp_remove_file(s, ixp_walk(s, path));
|
||||
}
|
||||
|
||||
File *ixp_walk(IXPServer * s, char *path)
|
||||
{
|
||||
File *f = 0;
|
||||
File *n;
|
||||
char *buf;
|
||||
char *tok, *tok_ptr;
|
||||
|
||||
if (!path) {
|
||||
return 0;
|
||||
}
|
||||
buf = strdup(path);
|
||||
|
||||
tok = strtok_r(buf, "/", &tok_ptr);
|
||||
f = s->root->content;
|
||||
if (!tok && buf[0] == '/') {
|
||||
f = s->root;
|
||||
}
|
||||
while (f && tok) {
|
||||
n = f->next;
|
||||
if (!strcmp(f->name, tok)) {
|
||||
tok = strtok_r(0, "/", &tok_ptr);
|
||||
if (tok && f->size)
|
||||
return 0;
|
||||
if (!tok)
|
||||
break;
|
||||
f = f->content;
|
||||
continue;
|
||||
}
|
||||
f = n;
|
||||
}
|
||||
if (f && (path[strlen(path) - 1] == '/') && !is_directory(f))
|
||||
f = 0;
|
||||
free(buf);
|
||||
return f;
|
||||
}
|
459
libixp/server.c
459
libixp/server.c
@ -5,434 +5,69 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ixp.h"
|
||||
#include "cext.h"
|
||||
|
||||
#include <cext.h>
|
||||
|
||||
static Connection zero_conn = { 0 };
|
||||
static int user_fd = -1;
|
||||
|
||||
void set_error(IXPServer * s, char *errstr)
|
||||
static void
|
||||
prepare_select(IXPServer *s)
|
||||
{
|
||||
if (s->errstr)
|
||||
free(s->errstr);
|
||||
if (errstr)
|
||||
s->errstr = strdup(errstr);
|
||||
else
|
||||
s->errstr = 0;
|
||||
int i;
|
||||
FD_ZERO(&s->rd);
|
||||
for(i = 0; (i < s->connsz) && s->conn[i]; i++) {
|
||||
if(s->maxfd < s->conn[i]->fd)
|
||||
s->maxfd = s->conn[i]->fd;
|
||||
if(s->conn[i]->read)
|
||||
FD_SET(s->conn[i]->fd, &s->rd);
|
||||
}
|
||||
}
|
||||
|
||||
File *fd_to_file(IXPServer * s, int fd)
|
||||
static void
|
||||
handle_conns(IXPServer *s)
|
||||
{
|
||||
int cidx = fd / MAX_CONN;
|
||||
int fidx = fd - (cidx * MAX_CONN);
|
||||
|
||||
return s->conn[cidx].files[fidx];
|
||||
int i;
|
||||
for(i = 0; (i < s->connsz) && s->conn[i]; i++)
|
||||
if(FD_ISSET(s->conn[i]->fd, &s->rd) && s->conn[i]->read)
|
||||
/* call read handler */
|
||||
s->conn[i]->read(s, s->conn[i]);
|
||||
}
|
||||
|
||||
static void handle_ixp_create(Connection * c)
|
||||
char *
|
||||
ixp_server_loop(IXPServer *s)
|
||||
{
|
||||
c->s->create(c->s, ((char *) c->data) + sizeof(ReqHeader));
|
||||
free(c->data);
|
||||
c->data = c->s->errstr ?
|
||||
rerror_message(c->s->errstr, &c->len) : rcreate_message(&c->len);
|
||||
c->remain = c->len;
|
||||
int r;
|
||||
s->running = 1;
|
||||
|
||||
/* main loop */
|
||||
while(s->running && s->conn) {
|
||||
|
||||
prepare_select(s);
|
||||
|
||||
r = select(s->maxfd + 1, &s->rd, 0, 0, 0);
|
||||
if(r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if(r < 0)
|
||||
return "fatal select error";
|
||||
else if(r > 0)
|
||||
handle_conns(s);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void handle_ixp_open(Connection * c)
|
||||
IXPMap *
|
||||
ixp_server_fid2map(IXPConn *c, unsigned int fid)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* seek next free slot */
|
||||
for (i = 0; (i < MAX_OPEN_FILES) && c->files[i]; i++);
|
||||
if (i == MAX_OPEN_FILES) {
|
||||
fprintf(stderr, "%s",
|
||||
"ixp: server: maximum of open files, try again later.\n");
|
||||
free(c->data);
|
||||
c->data =
|
||||
rerror_message("maximum open files reached, close files first",
|
||||
&c->len);
|
||||
c->remain = c->len;
|
||||
return;
|
||||
}
|
||||
c->files[i] = c->s->open(c->s, ((char *) c->data) + sizeof(ReqHeader));
|
||||
c->seen[i] = MAX_SEEN_SHUTDOWN;
|
||||
free(c->data);
|
||||
c->data = c->s->errstr ?
|
||||
rerror_message(c->s->errstr,
|
||||
&c->len) : ropen_message(i + MAX_CONN * c->index,
|
||||
&c->len);
|
||||
c->remain = c->len;
|
||||
}
|
||||
|
||||
static void handle_ixp_read(Connection * c, ReqHeader * h)
|
||||
{
|
||||
void *data = 0;
|
||||
size_t out_len;
|
||||
|
||||
data = cext_emallocz(h->buf_len);
|
||||
out_len = c->s->read(c->s, h->fd, h->offset, data, h->buf_len);
|
||||
free(c->data);
|
||||
if (c->s->errstr)
|
||||
c->data = rerror_message(c->s->errstr, &c->len);
|
||||
else
|
||||
c->data = rread_message(data, out_len, &c->len);
|
||||
c->remain = c->len;
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void handle_ixp_write(Connection * c, ReqHeader * h)
|
||||
{
|
||||
c->s->write(c->s, h->fd, h->offset,
|
||||
((char *) c->data) + sizeof(ReqHeader), h->buf_len);
|
||||
free(c->data);
|
||||
if (c->s->errstr)
|
||||
c->data = rerror_message(c->s->errstr, &c->len);
|
||||
else
|
||||
c->data = rwrite_message(&c->len);
|
||||
c->remain = c->len;
|
||||
}
|
||||
|
||||
static void handle_ixp_close(Connection * c, ReqHeader * h)
|
||||
{
|
||||
int fidx = h->fd - (c->index * MAX_CONN);
|
||||
|
||||
c->s->close(c->s, h->fd);
|
||||
c->files[fidx] = 0;
|
||||
free(c->data);
|
||||
if (c->s->errstr)
|
||||
c->data = rerror_message(c->s->errstr, &c->len);
|
||||
else
|
||||
c->data = rclose_message(&c->len);
|
||||
c->remain = c->len;
|
||||
}
|
||||
|
||||
static void handle_ixp_remove(Connection * c)
|
||||
{
|
||||
c->s->remove(c->s, ((char *) c->data) + sizeof(ReqHeader));
|
||||
free(c->data);
|
||||
c->data = c->s->errstr ?
|
||||
rerror_message(c->s->errstr, &c->len) : rremove_message(&c->len);
|
||||
c->remain = c->len;
|
||||
}
|
||||
|
||||
static void check_ixp_request(Connection * c)
|
||||
{
|
||||
ReqHeader h;
|
||||
/* check pending request */
|
||||
if (c->s->errstr)
|
||||
set_error(c->s, 0);
|
||||
memcpy(&h, c->data, sizeof(ReqHeader));
|
||||
switch (h.req) {
|
||||
case TCREATE:
|
||||
handle_ixp_create(c);
|
||||
break;
|
||||
case TREMOVE:
|
||||
handle_ixp_remove(c);
|
||||
break;
|
||||
case TOPEN:
|
||||
handle_ixp_open(c);
|
||||
break;
|
||||
case TCLUNK:
|
||||
handle_ixp_close(c, &h);
|
||||
break;
|
||||
case TREAD:
|
||||
handle_ixp_read(c, &h);
|
||||
break;
|
||||
case TWRITE:
|
||||
handle_ixp_write(c, &h);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s", "ixp: server: invalid request\n");
|
||||
free(c->data);
|
||||
c->len = c->remain = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_conns(IXPServer * s)
|
||||
{
|
||||
int i;
|
||||
|
||||
FD_ZERO(&s->rd);
|
||||
FD_ZERO(&s->wr);
|
||||
for (i = 0; i < MAX_CONN; i++) {
|
||||
if (s->conn[i].fd >= 0) {
|
||||
s->nfds = xMAX(s->nfds, s->conn[i].fd);
|
||||
if (s->conn[i].read && !s->conn[i].mode
|
||||
&& (!s->conn[i].len || s->conn[i].remain)) {
|
||||
FD_SET(s->conn[i].fd, &s->rd);
|
||||
}
|
||||
if (s->conn[i].write && s->conn[i].mode && s->conn[i].remain) {
|
||||
FD_SET(s->conn[i].fd, &s->wr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void close_conn(Connection * c)
|
||||
{
|
||||
int i;
|
||||
/* shutdown connection and cleanup open files */
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
c->fd = -1;
|
||||
c->mode = 0;
|
||||
for (i = 0; i < MAX_OPEN_FILES; i++) {
|
||||
if (c->files[i])
|
||||
c->files[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_conn(Connection * c)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
if (!c->header) {
|
||||
r = read(c->fd, &c->len, sizeof(size_t));
|
||||
if (r != sizeof(size_t)) {
|
||||
close_conn(c);
|
||||
return;
|
||||
}
|
||||
c->remain = c->len;
|
||||
c->data = cext_emallocz(c->len);
|
||||
c->header = 1;
|
||||
}
|
||||
r = read(c->fd, ((char *) c->data) + c->len - c->remain, c->remain);
|
||||
if (r < 1) {
|
||||
close_conn(c);
|
||||
return;
|
||||
}
|
||||
c->remain -= r;
|
||||
|
||||
if (c->remain == 0) {
|
||||
/* check IXP request */
|
||||
c->mode = 1; /* next mode is response */
|
||||
check_ixp_request(c);
|
||||
c->header = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_conn(Connection * c)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
if (!c->header) {
|
||||
r = write(c->fd, &c->len, sizeof(size_t));
|
||||
if (r != sizeof(size_t)) {
|
||||
close_conn(c);
|
||||
}
|
||||
c->header = 1;
|
||||
}
|
||||
r = write(c->fd, ((char *) c->data) + c->len - c->remain, c->remain);
|
||||
if (r < 1) {
|
||||
close_conn(c);
|
||||
return;
|
||||
}
|
||||
c->remain -= r;
|
||||
|
||||
if (c->remain == 0) {
|
||||
c->len = 0;
|
||||
c->mode = 0;
|
||||
c->header = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void new_conn(Connection * c)
|
||||
{
|
||||
int r, i;
|
||||
socklen_t l;
|
||||
struct sockaddr_un name = { 0 };
|
||||
|
||||
l = sizeof(name);
|
||||
if ((r = accept(c->fd, (struct sockaddr *) &name, &l)) < 0) {
|
||||
perror("ixp: server: cannot accept connection");
|
||||
return;
|
||||
}
|
||||
if (c->s->runlevel == SHUTDOWN) {
|
||||
fprintf(stderr, "%s",
|
||||
"ixp: server: connection refused, server is shutting down.\n");
|
||||
close(r);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < MAX_CONN; i++) {
|
||||
if (c->s->conn[i].fd == -1) { /* free connection */
|
||||
c->s->conn[i] = zero_conn;
|
||||
c->s->conn[i].s = c->s;
|
||||
c->s->conn[i].index = i;
|
||||
c->s->conn[i].fd = r;
|
||||
c->s->conn[i].read = read_conn;
|
||||
c->s->conn[i].write = write_conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == MAX_CONN) {
|
||||
fprintf(stderr, "%s",
|
||||
"ixp: server: connection refused, try again later.\n");
|
||||
close(r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int check_open_files(Connection * c)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_OPEN_FILES; i++) {
|
||||
if (c->files[i] && c->seen[i]) {
|
||||
c->seen[i]--;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_socks(IXPServer * s)
|
||||
{
|
||||
int i, now = 1;
|
||||
for (i = 0; i < MAX_CONN; i++) {
|
||||
if (s->conn[i].fd >= 0) {
|
||||
if (FD_ISSET(s->conn[i].fd, &s->rd) && s->conn[i].read) {
|
||||
/* call back read handler */
|
||||
s->conn[i].read(&s->conn[i]);
|
||||
} else if (FD_ISSET(s->conn[i].fd, &s->wr) && s->conn[i].write) {
|
||||
/* call back write handler */
|
||||
s->conn[i].write(&s->conn[i]);
|
||||
}
|
||||
/*
|
||||
* don't shutdown, if there're remaining bits or if
|
||||
* still responses are sent or still opened files
|
||||
*/
|
||||
if ((s->runlevel == SHUTDOWN)
|
||||
&& (check_open_files(&s->conn[i])
|
||||
|| (s->conn[i].remain > 0)
|
||||
|| s->conn[i].mode))
|
||||
now = 0;
|
||||
}
|
||||
}
|
||||
if ((s->runlevel == SHUTDOWN) && now)
|
||||
s->runlevel = HALT; /* real stop */
|
||||
}
|
||||
|
||||
IXPServer *init_server(char *sockfile, void (*cleanup) (void))
|
||||
{
|
||||
int i;
|
||||
struct sockaddr_un addr = { 0 };
|
||||
int yes = 1;
|
||||
socklen_t su_len;
|
||||
IXPServer *s;
|
||||
|
||||
/* init */
|
||||
s = (IXPServer *) cext_emallocz(sizeof(IXPServer));
|
||||
s->sockfile = sockfile;
|
||||
s->root = (File *) cext_emallocz(sizeof(File));
|
||||
s->runlevel = HALT; /* initially server is not running */
|
||||
s->create = ixp_create;
|
||||
s->remove = ixp_remove;
|
||||
s->open = ixp_open;
|
||||
s->close = ixp_close;
|
||||
s->read = ixp_read;
|
||||
s->write = ixp_write;
|
||||
s->root->name = strdup("");
|
||||
for (i = 0; i < MAX_CONN; i++) {
|
||||
s->conn[i].s = s;
|
||||
s->conn[i].fd = -1;
|
||||
s->conn[i].index = i;
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if ((s->conn[0].fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror("ixp: server: socket");
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
if (setsockopt(s->conn[0].fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &yes, sizeof(yes)) < 0) {
|
||||
perror("ixp: server: setsockopt");
|
||||
close(s->conn[0].fd);
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, sockfile, sizeof(addr.sun_path));
|
||||
su_len = sizeof(struct sockaddr) + strlen(addr.sun_path);
|
||||
|
||||
if (bind(s->conn[0].fd, (struct sockaddr *) &addr, su_len) < 0) {
|
||||
perror("ixp: server: cannot bind socket");
|
||||
close(s->conn[0].fd);
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
chmod(sockfile, S_IRWXU);
|
||||
|
||||
if (listen(s->conn[0].fd, MAX_CONN) < 0) {
|
||||
perror("ixp: server: cannot listen on socket");
|
||||
close(s->conn[0].fd);
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
s->conn[0].read = new_conn;
|
||||
|
||||
/* register to cleanup function, to unlink sockfile */
|
||||
if (cleanup)
|
||||
atexit(cleanup);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
run_server_with_fd_support(IXPServer * s, int fd,
|
||||
void (*fd_read) (Connection *),
|
||||
void (*fd_write) (Connection *))
|
||||
{
|
||||
s->conn[1] = zero_conn;
|
||||
s->conn[1].index = 1;
|
||||
s->conn[1].s = s;
|
||||
s->conn[1].fd = user_fd = fd;
|
||||
s->conn[1].read = fd_read;
|
||||
s->conn[1].write = fd_write;
|
||||
run_server(s);
|
||||
}
|
||||
|
||||
void run_server(IXPServer * s)
|
||||
{
|
||||
int r, i;
|
||||
s->runlevel = RUNNING;
|
||||
|
||||
/* main loop */
|
||||
while (s->runlevel != HALT) {
|
||||
|
||||
update_conns(s);
|
||||
|
||||
r = select(s->nfds + 1, &s->rd, &s->wr, 0, 0);
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (r < 0) {
|
||||
perror("ixp: server: select");
|
||||
break; /* allow cleanups in IXP using app */
|
||||
} else if (r > 0) {
|
||||
handle_socks(s);
|
||||
}
|
||||
}
|
||||
/* shut down server */
|
||||
for (i = MAX_CONN - 1; i >= 0; i--) {
|
||||
if (s->conn[i].fd >= 0 && s->conn[i].fd != user_fd) {
|
||||
close(s->conn[i].fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deinit_server(IXPServer * s)
|
||||
{
|
||||
unlink(s->sockfile);
|
||||
ixp_remove(s, "/");
|
||||
free(s);
|
||||
size_t i;
|
||||
for(i = 0; (i < c->mapsz) && c->map[i]; i++)
|
||||
if(c->map[i]->fid == fid)
|
||||
return c->map[i];
|
||||
return nil;
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
# libixp - lib ixp protocol
|
||||
# (C)opyright MMIV-MMVI Anselm R. Garbe
|
||||
|
||||
include ../config.mk
|
||||
|
||||
CFLAGS += -I ../libcext
|
||||
|
||||
SRC = client.c convert.c message.c server.c socket.c transport.c
|
||||
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: libixp
|
||||
@echo built libixp2
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
@${CC} -c ${CFLAGS} $<
|
||||
|
||||
libixp: ${OBJ}
|
||||
@echo AR $@.a
|
||||
@${AR} $@.a ${OBJ}
|
||||
@${RANLIB} $@.a
|
||||
|
||||
clean:
|
||||
rm -f libixp.a *.o
|
194
libixp2/client.c
194
libixp2/client.c
@ -1,194 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cext.h"
|
||||
#include "ixp.h"
|
||||
|
||||
static unsigned char msg[IXP_MAX_MSG];
|
||||
|
||||
static int
|
||||
do_fcall(IXPClient * c)
|
||||
{
|
||||
unsigned int msize = ixp_fcall_to_msg(&c->fcall, msg, IXP_MAX_MSG);
|
||||
c->errstr = 0;
|
||||
if(ixp_send_message(c->fd, msg, msize, &c->errstr) != msize)
|
||||
return -1;
|
||||
if(!ixp_recv_message(c->fd, msg, IXP_MAX_MSG, &c->errstr))
|
||||
return -1;
|
||||
if(!(msize = ixp_msg_to_fcall(msg, IXP_MAX_MSG, &c->fcall))) {
|
||||
c->errstr = "received bad message";
|
||||
return -1;
|
||||
}
|
||||
if(c->fcall.id == RERROR) {
|
||||
c->errstr = c->fcall.errstr;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_init(IXPClient * c, char *sockfile)
|
||||
{
|
||||
if((c->fd = ixp_connect_sock(sockfile)) < 0) {
|
||||
c->errstr = "cannot connect server";
|
||||
return -1;
|
||||
}
|
||||
/* version */
|
||||
c->fcall.id = TVERSION;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.maxmsg = IXP_MAX_MSG;
|
||||
cext_strlcpy(c->fcall.version, IXP_VERSION, sizeof(c->fcall.version));
|
||||
if(do_fcall(c) == -1) {
|
||||
ixp_client_deinit(c);
|
||||
return -1;
|
||||
}
|
||||
if(strncmp(c->fcall.version, IXP_VERSION, strlen(IXP_VERSION))) {
|
||||
c->errstr = "9P versions differ";
|
||||
ixp_client_deinit(c);
|
||||
return -1; /* we cannot handle this version */
|
||||
}
|
||||
c->root_fid = getpid();
|
||||
|
||||
/* attach */
|
||||
c->fcall.id = TATTACH;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = c->root_fid;
|
||||
c->fcall.afid = IXP_NOFID;
|
||||
cext_strlcpy(c->fcall.uname, getenv("USER"), sizeof(c->fcall.uname));
|
||||
c->fcall.aname[0] = 0;
|
||||
if(do_fcall(c) == -1) {
|
||||
ixp_client_deinit(c);
|
||||
return -1;
|
||||
}
|
||||
c->root_qid = c->fcall.qid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_remove(IXPClient * c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
/* remove */
|
||||
c->fcall.id = TREMOVE;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = newfid;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_create(IXPClient * c, unsigned int dirfid, char *name,
|
||||
unsigned int perm, unsigned char mode)
|
||||
{
|
||||
/* create */
|
||||
c->fcall.id = TCREATE;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = dirfid;
|
||||
cext_strlcpy(c->fcall.name, name, sizeof(c->fcall.name));
|
||||
c->fcall.perm = perm;
|
||||
c->fcall.mode = mode;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_walk(IXPClient * c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
unsigned int i;
|
||||
char *wname[IXP_MAX_WELEM];
|
||||
/* walk */
|
||||
c->fcall.id = TWALK;
|
||||
c->fcall.fid = c->root_fid;
|
||||
c->fcall.newfid = newfid;
|
||||
if(filepath) {
|
||||
cext_strlcpy(c->fcall.name, filepath, sizeof(c->fcall.name));
|
||||
c->fcall.nwname =
|
||||
cext_tokenize(wname, IXP_MAX_WELEM, c->fcall.name, '/');
|
||||
for(i = 0; i < c->fcall.nwname; i++)
|
||||
cext_strlcpy(c->fcall.wname[i], wname[i], sizeof(c->fcall.wname[i]));
|
||||
}
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_open(IXPClient * c, unsigned int newfid, char *filepath,
|
||||
unsigned char mode)
|
||||
{
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
|
||||
/* open */
|
||||
c->fcall.id = TOPEN;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = newfid;
|
||||
c->fcall.mode = mode;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_read(IXPClient * c, unsigned int fid, unsigned long long offset,
|
||||
void *result, unsigned int res_len)
|
||||
{
|
||||
unsigned int bytes = c->fcall.iounit;
|
||||
|
||||
/* read */
|
||||
c->fcall.id = TREAD;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = fid;
|
||||
c->fcall.offset = offset;
|
||||
c->fcall.count = res_len < bytes ? res_len : bytes;
|
||||
if(do_fcall(c) == -1)
|
||||
return -1;
|
||||
memcpy(result, c->fcall.data, c->fcall.count);
|
||||
return c->fcall.count;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_write(IXPClient * c, unsigned int fid,
|
||||
unsigned long long offset, unsigned int count,
|
||||
unsigned char *data)
|
||||
{
|
||||
if(count > c->fcall.iounit)
|
||||
{
|
||||
c->errstr = "iounit exceeded";
|
||||
return -1;
|
||||
}
|
||||
/* write */
|
||||
c->fcall.id = TWRITE;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = fid;
|
||||
c->fcall.offset = offset;
|
||||
c->fcall.count = count;
|
||||
memcpy(c->fcall.data, data, count);
|
||||
if(do_fcall(c) == -1)
|
||||
return -1;
|
||||
return c->fcall.count;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_close(IXPClient * c, unsigned int fid)
|
||||
{
|
||||
/* clunk */
|
||||
c->fcall.id = TCLUNK;
|
||||
c->fcall.tag = IXP_NOTAG;
|
||||
c->fcall.fid = fid;
|
||||
return do_fcall(c);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_client_deinit(IXPClient * c)
|
||||
{
|
||||
/* session finished, now shutdown */
|
||||
if(c->fd) {
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
}
|
||||
}
|
289
libixp2/ixp.h
289
libixp2/ixp.h
@ -1,289 +0,0 @@
|
||||
/*
|
||||
*(C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
*See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef nil
|
||||
#define nil 0
|
||||
#endif
|
||||
|
||||
#define IXP_VERSION "9P2000"
|
||||
#define IXP_MAX_VERSION 32
|
||||
#define IXP_MAX_ERROR 128
|
||||
#define IXP_MAX_CACHE 32
|
||||
#define IXP_MAX_MSG 8192
|
||||
#define IXP_MAX_FLEN 128
|
||||
#define IXP_MAX_ULEN 32
|
||||
#define IXP_MAX_STAT 64
|
||||
#define IXP_MAX_WELEM 16 /*MAXWELEM */
|
||||
#define IXP_MAX_TFUNCS 14
|
||||
|
||||
|
||||
/*
|
||||
size[4] Tversion tag[2] msize[4] version[s]
|
||||
size[4] Rversion tag[2] msize[4] version[s]
|
||||
size[4] Tauth tag[2] afid[4] uname[s] aname[s]
|
||||
size[4] Rauth tag[2] aqid[13]
|
||||
size[4] Rerror tag[2] ename[s]
|
||||
size[4] Tflush tag[2] oldtag[2]
|
||||
size[4] Rflush tag[2]
|
||||
size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s]
|
||||
size[4] Rattach tag[2] qid[13]
|
||||
size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
|
||||
size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13])
|
||||
size[4] Topen tag[2] fid[4] mode[1]
|
||||
size[4] Ropen tag[2] qid[13] iounit[4]
|
||||
size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1]
|
||||
size[4] Rcreate tag[2] qid[13] iounit[4]
|
||||
size[4] Tread tag[2] fid[4] offset[8] count[4]
|
||||
size[4] Rread tag[2] count[4] data[count]
|
||||
size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]
|
||||
size[4] Rwrite tag[2] count[4]
|
||||
size[4] Tclunk tag[2] fid[4]
|
||||
size[4] Rclunk tag[2]
|
||||
size[4] Tremove tag[2] fid[4]
|
||||
size[4] Rremove tag[2]
|
||||
size[4] Tstat tag[2] fid[4]
|
||||
size[4] Rstat tag[2] stat[n]
|
||||
size[4] Twstat tag[2] fid[4] stat[n]
|
||||
size[4] Rwstat tag[2]
|
||||
|
||||
stat[n]:
|
||||
size[2] total byte count of the following data
|
||||
type[2] for kernel use
|
||||
dev[4] for kernel use
|
||||
qid.type[1] the type of the file (directory, etc.),
|
||||
represented as a bit vector corresponding to the high 8 bits of the file's mode word.
|
||||
qid.vers[4] version number for given path
|
||||
qid.path[8] the file server's unique identification for the file
|
||||
mode[4] permissions and flags
|
||||
atime[4] last access time
|
||||
mtime[4] last modification time
|
||||
length[8] length of file in bytes
|
||||
name[ s ] file name; must be / if the file is the root directory of the server
|
||||
uid[ s ] owner name
|
||||
gid[ s ] group name
|
||||
muid[ s ]
|
||||
*/
|
||||
|
||||
/*9P message types */
|
||||
enum {
|
||||
TVERSION = 100,
|
||||
RVERSION,
|
||||
TAUTH = 102,
|
||||
RAUTH,
|
||||
TATTACH = 104,
|
||||
RATTACH,
|
||||
TERROR = 106,
|
||||
RERROR,
|
||||
TFLUSH = 108,
|
||||
RFLUSH,
|
||||
TWALK = 110,
|
||||
RWALK,
|
||||
TOPEN = 112,
|
||||
ROPEN,
|
||||
TCREATE = 114,
|
||||
RCREATE,
|
||||
TREAD = 116,
|
||||
RREAD,
|
||||
TWRITE = 118,
|
||||
RWRITE,
|
||||
TCLUNK = 120,
|
||||
RCLUNK,
|
||||
TREMOVE = 122,
|
||||
RREMOVE,
|
||||
TSTAT = 124,
|
||||
RSTAT,
|
||||
TWSTAT = 126,
|
||||
RWSTAT,
|
||||
};
|
||||
|
||||
/*borrowed from libc.h of Plan 9 */
|
||||
#define DMDIR 0x80000000 /*mode bit for directories */
|
||||
#define DMAPPEND 0x40000000 /*mode bit for append only files */
|
||||
#define DMEXCL 0x20000000 /*mode bit for exclusive use files */
|
||||
#define DMMOUNT 0x10000000 /*mode bit for mounted channel */
|
||||
#define DMAUTH 0x08000000 /*mode bit for authentication file */
|
||||
#define DMTMP 0x04000000 /*mode bit for non-backed-up file */
|
||||
|
||||
#define DMREAD 0x4<<6 /*mode bit for read permission */
|
||||
#define DMWRITE 0x2<<6 /*mode bit for write permission */
|
||||
#define DMEXEC 0x1<<6 /*mode bit for execute permission */
|
||||
|
||||
/*modes */
|
||||
enum {
|
||||
IXP_OREAD = 0x00,
|
||||
IXP_OWRITE = 0x01,
|
||||
IXP_ORDWR = 0x02,
|
||||
IXP_OEXEC = 0x03,
|
||||
IXP_OEXCL = 0x04,
|
||||
IXP_OTRUNC = 0x10,
|
||||
IXP_OREXEC = 0x20,
|
||||
IXP_ORCLOSE = 0x40,
|
||||
IXP_OAPPEND = 0x80,
|
||||
};
|
||||
|
||||
/*qid.types */
|
||||
enum {
|
||||
IXP_QTDIR = 0x80,
|
||||
IXP_QTAPPEND = 0x40,
|
||||
IXP_QTEXCL = 0x20,
|
||||
IXP_QTMOUNT = 0x10,
|
||||
IXP_QTAUTH = 0x08,
|
||||
IXP_QTTMP = 0x04,
|
||||
IXP_QTSYMLINK = 0x02,
|
||||
IXP_QTLINK = 0x01,
|
||||
IXP_QTFILE = 0x00,
|
||||
};
|
||||
|
||||
#define IXP_NOTAG (unsigned short)~0U /*Dummy tag */
|
||||
#define IXP_NOFID (unsigned int)~0 /*No auth */
|
||||
|
||||
typedef struct {
|
||||
unsigned char type;
|
||||
unsigned int version;
|
||||
unsigned long long path;
|
||||
} Qid;
|
||||
|
||||
/*stat structure */
|
||||
typedef struct {
|
||||
unsigned short type;
|
||||
unsigned int dev;
|
||||
Qid qid;
|
||||
unsigned int mode;
|
||||
unsigned int atime;
|
||||
unsigned int mtime;
|
||||
unsigned long long length;
|
||||
char name[IXP_MAX_FLEN];
|
||||
char uid[IXP_MAX_ULEN];
|
||||
char gid[IXP_MAX_ULEN];
|
||||
char muid[IXP_MAX_ULEN];
|
||||
} Stat;
|
||||
|
||||
typedef struct {
|
||||
unsigned char id;
|
||||
unsigned short tag;
|
||||
unsigned int fid;
|
||||
unsigned int maxmsg; /*Tversion, Rversion */
|
||||
char version[IXP_MAX_VERSION]; /*Tversion, Rversion */
|
||||
unsigned short oldtag; /*Tflush */
|
||||
char errstr[IXP_MAX_ERROR]; /*Rerror */
|
||||
Qid qid; /*Rattach, Ropen, Rcreate */
|
||||
unsigned int iounit; /*Ropen, Rcreate */
|
||||
Qid aqid; /*Rauth */
|
||||
unsigned int afid; /*Tauth, Tattach */
|
||||
char uname[IXP_MAX_ULEN]; /*Tauth, Tattach */
|
||||
char aname[IXP_MAX_FLEN]; /*Tauth, Tattach */
|
||||
unsigned int perm; /*Tcreate */
|
||||
char name[IXP_MAX_FLEN]; /*Tcreate */
|
||||
unsigned char mode; /*Tcreate, Topen */
|
||||
unsigned int newfid; /*Twalk */
|
||||
unsigned short nwname; /*Twalk */
|
||||
char wname[IXP_MAX_WELEM][IXP_MAX_FLEN]; /*Twalk */
|
||||
unsigned short nwqid; /*Rwalk */
|
||||
Qid wqid[IXP_MAX_WELEM]; /*Rwalk */
|
||||
unsigned long long offset; /*Tread, Twrite */
|
||||
unsigned int count; /*Tread, Twrite, Rread */
|
||||
Stat stat; /*Rstat */
|
||||
unsigned short nstat; /*Twstat, Rstat */
|
||||
unsigned char data[IXP_MAX_MSG]; /*Twrite, Rread, Twstat,
|
||||
*Rstat */
|
||||
} Fcall;
|
||||
|
||||
typedef struct IXPServer IXPServer;
|
||||
typedef struct IXPConn IXPConn;
|
||||
typedef struct IXPMap IXPMap;
|
||||
|
||||
struct IXPMap {
|
||||
unsigned int fid;
|
||||
Qid qid;
|
||||
};
|
||||
|
||||
struct IXPConn {
|
||||
int fd;
|
||||
void (*read) (IXPServer *, IXPConn *);
|
||||
void (*close) (IXPServer *, IXPConn *);
|
||||
IXPMap **map;
|
||||
size_t mapsz;
|
||||
Fcall *fcall;
|
||||
Fcall **pend;
|
||||
size_t pendsz;
|
||||
};
|
||||
|
||||
struct IXPServer {
|
||||
int running;
|
||||
IXPConn **conn;
|
||||
size_t connsz;
|
||||
int maxfd;
|
||||
fd_set rd;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
unsigned int root_fid;
|
||||
Qid root_qid;
|
||||
Fcall fcall;
|
||||
char *errstr;
|
||||
} IXPClient;
|
||||
|
||||
/* client.c */
|
||||
int ixp_client_init(IXPClient *c, char *address);
|
||||
void ixp_client_deinit(IXPClient *c);
|
||||
int ixp_client_remove(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
int ixp_client_create(IXPClient *c, unsigned int dirfid, char *name,
|
||||
unsigned int perm, unsigned char mode);
|
||||
int ixp_client_walk(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
int ixp_client_open(IXPClient *c, unsigned int newfid, char *filepath,
|
||||
unsigned char mode);
|
||||
int ixp_client_read(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset, void *result,
|
||||
unsigned int res_len);
|
||||
int ixp_client_write(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset,
|
||||
unsigned int count, unsigned char *data);
|
||||
int ixp_client_close(IXPClient *c, unsigned int fid);
|
||||
|
||||
/* convert.c */
|
||||
void *ixp_enc_u8(unsigned char *msg, unsigned char val);
|
||||
void *ixp_dec_u8(unsigned char *msg, unsigned char *val);
|
||||
void *ixp_enc_u16(unsigned char *msg, unsigned short val);
|
||||
void *ixp_dec_u16(unsigned char *msg, unsigned short *val);
|
||||
void *ixp_enc_u32(unsigned char *msg, unsigned int val);
|
||||
void *ixp_dec_u32(unsigned char *msg, unsigned int *val);
|
||||
void *ixp_enc_u64(unsigned char *msg, unsigned long long val);
|
||||
void *ixp_dec_u64(unsigned char *msg, unsigned long long *val);
|
||||
void *ixp_enc_string(unsigned char *msg, const char *s);
|
||||
void *ixp_dec_string(unsigned char *msg, char *string,
|
||||
unsigned short stringlen, unsigned short *len);
|
||||
void *ixp_enc_data(unsigned char *msg, unsigned char *data,
|
||||
unsigned int datalen);
|
||||
void *ixp_dec_data(unsigned char *msg, unsigned char *data,
|
||||
unsigned int datalen);
|
||||
void *ixp_enc_prefix(unsigned char *msg, unsigned int size,
|
||||
unsigned char id, unsigned short tag);
|
||||
void *ixp_dec_prefix(unsigned char *msg, unsigned int *size,
|
||||
unsigned char *id, unsigned short *tag);
|
||||
void *ixp_enc_qid(unsigned char *msg, Qid *qid);
|
||||
void *ixp_dec_qid(unsigned char *msg, Qid *qid);
|
||||
void *ixp_enc_stat(unsigned char *msg, Stat *stat);
|
||||
void *ixp_dec_stat(unsigned char *msg, Stat *stat);
|
||||
|
||||
/* message.c */
|
||||
unsigned short ixp_sizeof_stat(Stat *stat);
|
||||
unsigned int ixp_fcall_to_msg(Fcall *fcall, void *msg, unsigned int msglen);
|
||||
unsigned int ixp_msg_to_fcall(void *msg, unsigned int msglen, Fcall *fcall);
|
||||
|
||||
/* server.c */
|
||||
char *ixp_server_loop(IXPServer *s);
|
||||
IXPMap *ixp_server_fid2map(IXPConn *c, unsigned int fid);
|
||||
|
||||
/* socket.c */
|
||||
int ixp_connect_sock(char *address);
|
||||
int ixp_accept_sock(int fd);
|
||||
int ixp_create_sock(char *address, char **errstr);
|
||||
|
||||
/* transport.c */
|
||||
unsigned int ixp_send_message(int fd, void *msg, unsigned int msize, char **errstr);
|
||||
unsigned int ixp_recv_message(int fd, void *msg, unsigned int msglen, char **errstr);
|
@ -1,317 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ixp.h"
|
||||
|
||||
#define IXP_QIDSZ (sizeof(unsigned char) + sizeof(unsigned int)\
|
||||
+ sizeof(unsigned long long))
|
||||
|
||||
static unsigned short
|
||||
sizeof_string(const char *s)
|
||||
{
|
||||
return sizeof(unsigned short) + strlen(s);
|
||||
}
|
||||
|
||||
unsigned short
|
||||
ixp_sizeof_stat(Stat * stat)
|
||||
{
|
||||
return IXP_QIDSZ
|
||||
+ 2 * sizeof(unsigned short)
|
||||
+ 4 * sizeof(unsigned int)
|
||||
+ sizeof(unsigned long long)
|
||||
+ sizeof_string(stat->name)
|
||||
+ sizeof_string(stat->uid)
|
||||
+ sizeof_string(stat->gid)
|
||||
+ sizeof_string(stat->muid);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ixp_fcall_to_msg(Fcall * fcall, void *msg, unsigned int msglen)
|
||||
{
|
||||
unsigned int i, msize =
|
||||
sizeof(unsigned char) + sizeof(unsigned short) +
|
||||
sizeof(unsigned int);
|
||||
void *p = msg;
|
||||
|
||||
switch (fcall->id) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
msize += sizeof(unsigned int) + sizeof_string(fcall->version);
|
||||
break;
|
||||
case TAUTH:
|
||||
msize +=
|
||||
sizeof(unsigned int) + sizeof_string(fcall->uname) +
|
||||
sizeof_string(fcall->aname);
|
||||
break;
|
||||
case RAUTH:
|
||||
case RATTACH:
|
||||
msize += IXP_QIDSZ;
|
||||
break;
|
||||
case TATTACH:
|
||||
msize +=
|
||||
2 * sizeof(unsigned int) + sizeof_string(fcall->uname) +
|
||||
sizeof_string(fcall->aname);
|
||||
break;
|
||||
case RERROR:
|
||||
msize += sizeof_string(fcall->errstr);
|
||||
break;
|
||||
case RWRITE:
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
msize += sizeof(unsigned int);
|
||||
break;
|
||||
case TWALK:
|
||||
msize += sizeof(unsigned short) + 2 * sizeof(unsigned int);
|
||||
for(i = 0; i < fcall->nwname; i++)
|
||||
msize += sizeof_string(fcall->wname[i]);
|
||||
break;
|
||||
case TFLUSH:
|
||||
msize += sizeof(unsigned short);
|
||||
break;
|
||||
case RWALK:
|
||||
msize += sizeof(unsigned short) + fcall->nwqid * IXP_QIDSZ;
|
||||
break;
|
||||
case TOPEN:
|
||||
msize += sizeof(unsigned int) + sizeof(unsigned char);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
msize += IXP_QIDSZ + sizeof(unsigned int);
|
||||
break;
|
||||
case TCREATE:
|
||||
msize +=
|
||||
sizeof(unsigned char) + 2 * sizeof(unsigned int) +
|
||||
sizeof_string(fcall->name);
|
||||
break;
|
||||
case TREAD:
|
||||
msize += 2 * sizeof(unsigned int) + sizeof(unsigned long long);
|
||||
break;
|
||||
case RREAD:
|
||||
msize += sizeof(unsigned int) + fcall->count;
|
||||
break;
|
||||
case TWRITE:
|
||||
msize +=
|
||||
2 * sizeof(unsigned int) + sizeof(unsigned long long) +
|
||||
fcall->count;
|
||||
break;
|
||||
case RSTAT:
|
||||
msize += sizeof(unsigned short) + ixp_sizeof_stat(&fcall->stat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
msize += sizeof(unsigned int) + sizeof(unsigned short) + ixp_sizeof_stat(&fcall->stat);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(msize > msglen)
|
||||
return 0;
|
||||
p = ixp_enc_prefix(p, msize, fcall->id, fcall->tag);
|
||||
|
||||
switch (fcall->id) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
p = ixp_enc_u32(p, fcall->maxmsg);
|
||||
p = ixp_enc_string(p, fcall->version);
|
||||
break;
|
||||
case TAUTH:
|
||||
p = ixp_enc_u32(p, fcall->afid);
|
||||
p = ixp_enc_string(p, fcall->uname);
|
||||
p = ixp_enc_string(p, fcall->aname);
|
||||
break;
|
||||
case RAUTH:
|
||||
p = ixp_enc_qid(p, &fcall->aqid);
|
||||
break;
|
||||
case RATTACH:
|
||||
p = ixp_enc_qid(p, &fcall->qid);
|
||||
break;
|
||||
case TATTACH:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u32(p, fcall->afid);
|
||||
p = ixp_enc_string(p, fcall->uname);
|
||||
p = ixp_enc_string(p, fcall->aname);
|
||||
break;
|
||||
case RERROR:
|
||||
p = ixp_enc_string(p, fcall->errstr);
|
||||
break;
|
||||
case TFLUSH:
|
||||
p = ixp_enc_u16(p, fcall->oldtag);
|
||||
break;
|
||||
case TWALK:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u32(p, fcall->newfid);
|
||||
p = ixp_enc_u16(p, fcall->nwname);
|
||||
for(i = 0; i < fcall->nwname; i++)
|
||||
p = ixp_enc_string(p, fcall->wname[i]);
|
||||
break;
|
||||
case RWALK:
|
||||
p = ixp_enc_u16(p, fcall->nwqid);
|
||||
for(i = 0; i < fcall->nwqid; i++)
|
||||
p = ixp_enc_qid(p, &fcall->wqid[i]);
|
||||
break;
|
||||
case TOPEN:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u8(p, fcall->mode);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
p = ixp_enc_qid(p, &fcall->qid);
|
||||
p = ixp_enc_u32(p, fcall->iounit);
|
||||
break;
|
||||
case TCREATE:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_string(p, fcall->name);
|
||||
p = ixp_enc_u32(p, fcall->perm);
|
||||
p = ixp_enc_u8(p, fcall->mode);
|
||||
break;
|
||||
case TREAD:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u64(p, fcall->offset);
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
break;
|
||||
case RREAD:
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
p = ixp_enc_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case TWRITE:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u64(p, fcall->offset);
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
p = ixp_enc_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case RWRITE:
|
||||
p = ixp_enc_u32(p, fcall->count);
|
||||
break;
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
break;
|
||||
case RSTAT:
|
||||
p = ixp_enc_u16(p, ixp_sizeof_stat(&fcall->stat));
|
||||
p = ixp_enc_stat(p, &fcall->stat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
p = ixp_enc_u32(p, fcall->fid);
|
||||
p = ixp_enc_u16(p, ixp_sizeof_stat(&fcall->stat));
|
||||
p = ixp_enc_stat(p, &fcall->stat);
|
||||
break;
|
||||
}
|
||||
|
||||
if(msg + msize == p)
|
||||
return msize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ixp_msg_to_fcall(void *msg, unsigned int msglen, Fcall * fcall)
|
||||
{
|
||||
unsigned int i, msize;
|
||||
unsigned short len;
|
||||
void *p = ixp_dec_prefix(msg, &msize, &fcall->id, &fcall->tag);
|
||||
|
||||
if(msize > msglen) /* bad message */
|
||||
return 0;
|
||||
|
||||
switch (fcall->id) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
p = ixp_dec_u32(p, &fcall->maxmsg);
|
||||
p = ixp_dec_string(p, fcall->version, sizeof(fcall->version), &len);
|
||||
break;
|
||||
case TAUTH:
|
||||
p = ixp_dec_u32(p, &fcall->afid);
|
||||
p = ixp_dec_string(p, fcall->uname, sizeof(fcall->uname), &len);
|
||||
p = ixp_dec_string(p, fcall->aname, sizeof(fcall->aname), &len);
|
||||
break;
|
||||
case RAUTH:
|
||||
p = ixp_dec_qid(p, &fcall->aqid);
|
||||
break;
|
||||
case RATTACH:
|
||||
p = ixp_dec_qid(p, &fcall->qid);
|
||||
break;
|
||||
case TATTACH:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u32(p, &fcall->afid);
|
||||
p = ixp_dec_string(p, fcall->uname, sizeof(fcall->uname), &len);
|
||||
p = ixp_dec_string(p, fcall->aname, sizeof(fcall->aname), &len);
|
||||
break;
|
||||
case RERROR:
|
||||
p = ixp_dec_string(p, fcall->errstr, sizeof(fcall->errstr), &len);
|
||||
break;
|
||||
case TFLUSH:
|
||||
p = ixp_dec_u16(p, &fcall->oldtag);
|
||||
break;
|
||||
case TWALK:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u32(p, &fcall->newfid);
|
||||
p = ixp_dec_u16(p, &fcall->nwname);
|
||||
for(i = 0; i < fcall->nwname; i++) {
|
||||
|
||||
p = ixp_dec_string(p, fcall->wname[i], IXP_MAX_FLEN, &len);
|
||||
}
|
||||
break;
|
||||
case RWALK:
|
||||
p = ixp_dec_u16(p, &fcall->nwqid);
|
||||
for(i = 0; i < fcall->nwqid; i++)
|
||||
p = ixp_dec_qid(p, &fcall->wqid[i]);
|
||||
break;
|
||||
case TOPEN:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u8(p, &fcall->mode);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
p = ixp_dec_qid(p, &fcall->qid);
|
||||
p = ixp_dec_u32(p, &fcall->iounit);
|
||||
break;
|
||||
case TCREATE:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_string(p, fcall->name, sizeof(fcall->name), &len);
|
||||
p = ixp_dec_u32(p, &fcall->perm);
|
||||
p = ixp_dec_u8(p, &fcall->mode);
|
||||
break;
|
||||
case TREAD:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u64(p, &fcall->offset);
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
break;
|
||||
case RREAD:
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
p = ixp_dec_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case TWRITE:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u64(p, &fcall->offset);
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
p = ixp_dec_data(p, fcall->data, fcall->count);
|
||||
break;
|
||||
case RWRITE:
|
||||
p = ixp_dec_u32(p, &fcall->count);
|
||||
break;
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
break;
|
||||
case RSTAT:
|
||||
p = ixp_dec_u16(p, &len);
|
||||
p = ixp_dec_stat(p, &fcall->stat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
p = ixp_dec_u32(p, &fcall->fid);
|
||||
p = ixp_dec_u16(p, &len);
|
||||
p = ixp_dec_stat(p, &fcall->stat);
|
||||
break;
|
||||
}
|
||||
|
||||
if(msg + msize == p)
|
||||
return msize;
|
||||
return 0;
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ixp.h"
|
||||
#include "cext.h"
|
||||
|
||||
static void
|
||||
prepare_select(IXPServer *s)
|
||||
{
|
||||
int i;
|
||||
FD_ZERO(&s->rd);
|
||||
for(i = 0; (i < s->connsz) && s->conn[i]; i++) {
|
||||
if(s->maxfd < s->conn[i]->fd)
|
||||
s->maxfd = s->conn[i]->fd;
|
||||
if(s->conn[i]->read)
|
||||
FD_SET(s->conn[i]->fd, &s->rd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_conns(IXPServer *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; (i < s->connsz) && s->conn[i]; i++)
|
||||
if(FD_ISSET(s->conn[i]->fd, &s->rd) && s->conn[i]->read)
|
||||
/* call read handler */
|
||||
s->conn[i]->read(s, s->conn[i]);
|
||||
}
|
||||
|
||||
char *
|
||||
ixp_server_loop(IXPServer *s)
|
||||
{
|
||||
int r;
|
||||
s->running = 1;
|
||||
|
||||
/* main loop */
|
||||
while(s->running && s->conn) {
|
||||
|
||||
prepare_select(s);
|
||||
|
||||
r = select(s->maxfd + 1, &s->rd, 0, 0, 0);
|
||||
if(r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if(r < 0)
|
||||
return "fatal select error";
|
||||
else if(r > 0)
|
||||
handle_conns(s);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
IXPMap *
|
||||
ixp_server_fid2map(IXPConn *c, unsigned int fid)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; (i < c->mapsz) && c->map[i]; i++)
|
||||
if(c->map[i]->fid == fid)
|
||||
return c->map[i];
|
||||
return nil;
|
||||
}
|
@ -6,7 +6,7 @@ include ../config.mk
|
||||
CFLAGS += -I../liblitz -I../libixp -I../libcext
|
||||
LDFLAGS += -L../liblitz -llitz -L../libixp -lixp -L../libcext -lcext
|
||||
|
||||
SRC = ixputil.c spawn.c wm.c
|
||||
SRC = spawn.c wm.c
|
||||
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "wmii.h"
|
||||
|
||||
static pid_t mypid;
|
||||
static char *mysockfile;
|
||||
|
||||
File *
|
||||
wmii_create_ixpfile(IXPServer * s, char *key, char *val)
|
||||
{
|
||||
File *f = ixp_create(s, key);
|
||||
if(f && !is_directory(f)) {
|
||||
size_t l = val ? strlen(val) : 0;
|
||||
f->content = l ? strdup(val) : 0;
|
||||
f->size = l;
|
||||
return f;
|
||||
}
|
||||
/* forbidden, file is directory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
wmii_get_ixppath(File * f, char *path, size_t size)
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
buf[0] = 0;
|
||||
if(path)
|
||||
cext_strlcpy(buf, path, sizeof(buf));
|
||||
snprintf(path, size, "%s/", f->name);
|
||||
if(buf[0] != 0)
|
||||
cext_strlcat(path, buf, size);
|
||||
if(f->parent)
|
||||
wmii_get_ixppath(f->parent, path, size);
|
||||
}
|
||||
|
||||
void
|
||||
wmii_move_ixpfile(File * f, File * to_parent)
|
||||
{
|
||||
File *p = f->parent;
|
||||
File *fil = p->content;
|
||||
|
||||
/* detach */
|
||||
if(p->content == f)
|
||||
p->content = fil->next;
|
||||
else {
|
||||
while(fil->next != f)
|
||||
fil = fil->next;
|
||||
fil->next = f->next;
|
||||
}
|
||||
f->next = 0;
|
||||
|
||||
|
||||
/* attach */
|
||||
if(!to_parent->content)
|
||||
to_parent->content = f;
|
||||
else {
|
||||
for(fil = to_parent->content; fil->next; fil = fil->next);
|
||||
fil->next = f;
|
||||
}
|
||||
f->parent = to_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
exit_cleanup()
|
||||
{
|
||||
if(mypid == getpid())
|
||||
unlink(mysockfile);
|
||||
}
|
||||
|
||||
IXPServer *
|
||||
wmii_setup_server(char *sockfile)
|
||||
{
|
||||
IXPServer *s;
|
||||
|
||||
if(!sockfile) {
|
||||
fprintf(stderr, "%s\n", "libwmii: no socket file provided");
|
||||
exit(1);
|
||||
}
|
||||
mysockfile = sockfile;
|
||||
mypid = getpid();
|
||||
s = init_server(sockfile, exit_cleanup);
|
||||
if(!s) {
|
||||
perror("libwmii: cannot initialize IXP server");
|
||||
exit(1);
|
||||
}
|
||||
return s;
|
||||
}
|
@ -16,12 +16,6 @@ struct Action {
|
||||
void (*func) (void *obj, char *);
|
||||
};
|
||||
|
||||
/* ixputil.c */
|
||||
File *wmii_create_ixpfile(IXPServer * s, char *key, char *val);
|
||||
void wmii_get_ixppath(File * f, char *path, size_t size);
|
||||
void wmii_move_ixpfile(File * f, File * to_parent);
|
||||
IXPServer *wmii_setup_server(char *sockfile);
|
||||
|
||||
/* spawn.c */
|
||||
void wmii_spawn(void *dpy, char *cmd);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user