mirror of
https://github.com/0intro/wmii
synced 2024-11-22 05:42:05 +03:00
reorganized, still liblitz there
This commit is contained in:
parent
b71f8a147e
commit
4a7273b827
2
Makefile
2
Makefile
@ -3,7 +3,7 @@
|
||||
|
||||
include config.mk
|
||||
|
||||
SUBDIRS = libcext liblitz libixp cmd
|
||||
SUBDIRS = liblitz
|
||||
|
||||
BIN = cmd/wm/wmii cmd/wm/wmiiwm cmd/wmiir
|
||||
|
||||
|
28
cmd/Makefile
28
cmd/Makefile
@ -1,28 +0,0 @@
|
||||
# window manager improved 2 utilities
|
||||
# (C)opyright MMIV-MMVI Anselm R. Garbe
|
||||
|
||||
include ../config.mk
|
||||
|
||||
CFLAGS += -I../liblitz -I../libixp -I../libcext
|
||||
LDFLAGS += -L../libixp -lixp -L../libcext -lcext
|
||||
X11LDFLAGS += -L../liblitz -llitz -L../libcext -lcext
|
||||
|
||||
SRC = wmiir.c
|
||||
ALLSRC = ${SRC}
|
||||
|
||||
all: ${ALLSRC:.c=}
|
||||
@echo built wmii commands
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
@${CC} -c ${CFLAGS} $<
|
||||
|
||||
${SRC:.c=}: ${SRC:.c=.o}
|
||||
@echo LD $@
|
||||
@${CC} -o $@ $@.o ${LDFLAGS}
|
||||
|
||||
# Solaris
|
||||
# @${CC} -o $* $*.o ${LDFLAGS} -lsocket
|
||||
|
||||
clean:
|
||||
rm -f ${ALLSRC:.c=} *.o
|
@ -1,84 +0,0 @@
|
||||
.TH WMIIMENU 1 wmii-4
|
||||
.SH NAME
|
||||
wmiimenu \- window manager improved 2 menu
|
||||
.SH SYNOPSIS
|
||||
.B wmiimenu
|
||||
.RB [ \-v ]
|
||||
.RB [ \-t
|
||||
.IR title ]
|
||||
.SH DESCRIPTION
|
||||
.SS Overview
|
||||
.B wmiimenu
|
||||
is a generic, highly customizable, and efficient menu for the X Window System,
|
||||
originally designed for
|
||||
.BR wmii (1).
|
||||
It supports arbitrary, user defined menu contents.
|
||||
.SS Options
|
||||
.TP
|
||||
.B \-v
|
||||
prints version information to stdout, then exits.
|
||||
.TP
|
||||
.BI \-t " title"
|
||||
displays
|
||||
.I title
|
||||
above the menu.
|
||||
.SS Usage
|
||||
.B wmiimenu
|
||||
reads a list of newline-separated items from stdin and creates a menu.
|
||||
When the user selects an item or enters any text and presses Enter, his choice
|
||||
is printed to stdout and
|
||||
.B wmiimenu
|
||||
terminates.
|
||||
.SS Keyboard Control
|
||||
.B wmiimenu
|
||||
is completely controlled by the keyboard. The following keys are recognized:
|
||||
.TP 2
|
||||
Any printable character
|
||||
appends the character to the text in the input field. This works as a filter:
|
||||
only items containing this text will be displayed.
|
||||
.TP 2
|
||||
Left/Right (Control-p/Control-n)
|
||||
select the previous/next item.
|
||||
.TP 2
|
||||
Tab (Control-i)
|
||||
copy the selected item to the input field.
|
||||
.TP 2
|
||||
Enter (Control-j)
|
||||
confirm selection and quit (print the selected item to stdout).
|
||||
.TP 2
|
||||
Shift-Enter (Shift-Control-j)
|
||||
confirm selection and quit (print the text in the input field to stdout).
|
||||
.TP 2
|
||||
Escape (Control-[)
|
||||
quit without selecting an item.
|
||||
.TP 2
|
||||
Backspace (Control-h)
|
||||
remove enough characters from the input field to change its filtering effect.
|
||||
.TP 2
|
||||
Control-u
|
||||
remove all characters from the input field.
|
||||
.SS Exit codes
|
||||
.B wmiimenu
|
||||
returns
|
||||
.B 0
|
||||
if Enter is pressed on termination,
|
||||
.B 1
|
||||
if Escape is pressed.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
WMII_FONT
|
||||
The X11 font used to display each item in the menu.
|
||||
.br
|
||||
Default: fixed
|
||||
.TP
|
||||
WMII_NORMCOLORS
|
||||
The foreground, background, and border colors of a label. Syntactically, three blank-separated color values of the form #RRGGBB are expected.
|
||||
.br
|
||||
Default: #222222 #eeeeee #666666
|
||||
.TP
|
||||
WMII_SELCOLORS
|
||||
Like WMII_NORMCOLORS, but for the selected label.
|
||||
.br
|
||||
Default: #ffffff #335577 #447799
|
||||
.SH SEE ALSO
|
||||
.BR wmii (1)
|
86
cmd/wmiir.1
86
cmd/wmiir.1
@ -1,86 +0,0 @@
|
||||
.TH WMIIR 1 wmii-4
|
||||
.SH NAME
|
||||
wmiir \- window manager improved 2 remote
|
||||
.SH SYNOPSIS
|
||||
.B wmiir
|
||||
.RB [ \-a
|
||||
.IR address ]
|
||||
.I action
|
||||
.I file
|
||||
.br
|
||||
.B wmiir
|
||||
.B \-v
|
||||
.SH DESCRIPTION
|
||||
.SS Overview
|
||||
.B wmiir
|
||||
is a client to access the filesystem of
|
||||
.BR wmiiwm (1)
|
||||
from the command line or from shell
|
||||
scripts. It can be used to configure
|
||||
.BR wmii (1).
|
||||
.SS Options
|
||||
.TP
|
||||
.BI \-a " address"
|
||||
Lets you specify the address to which
|
||||
.B wmiir
|
||||
will establish a connection. If this option is not supplied, and the
|
||||
environment variable WMII_ADDRESS is set,
|
||||
.B wmiir
|
||||
will use this value as its address. Currently, the address can only be a
|
||||
unix socket file or a tcp socket. The syntax for
|
||||
.I address
|
||||
is taken (along with many other profound ideas) from the Plan 9 operating
|
||||
system and has the form
|
||||
.BR unix!/path/to/socket
|
||||
for unix socket files, and
|
||||
.BR tcp!hostname!port
|
||||
for tcp sockets.
|
||||
.TP
|
||||
.B \-v
|
||||
Prints version information to stdout, then exits.
|
||||
.TP
|
||||
The syntax of the actions is as follows:
|
||||
.TP
|
||||
.B write
|
||||
Writes the supplied data from stdin to
|
||||
.IR file,
|
||||
overwriting any previous data. The data to be written is arbitrary
|
||||
and only gains meaning (and restrictions) when it is interpreted by
|
||||
.BR wmiiwm (1).
|
||||
See
|
||||
.B EXAMPLES
|
||||
below.
|
||||
.TP
|
||||
.B create
|
||||
Creates file or directory but does not write any data. If the file exists,
|
||||
nothing is done.
|
||||
.TP
|
||||
.B read
|
||||
Reads file or directory contents
|
||||
.TP
|
||||
.B remove
|
||||
Removes file or directory tree
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
WMII_ADDRESS
|
||||
See above.
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
.B wmiir read /
|
||||
This prints the root directory of the wmii filesystem. For more information
|
||||
about the contents of this filesystem, see
|
||||
.BR wmiiwm (1).
|
||||
.TP
|
||||
.B echo -n quit | wmiir write /ctl
|
||||
Write 'quit' to the main control file of the wmii filesystem, effectively
|
||||
leaving wmii.
|
||||
.TP
|
||||
.B echo -n view 2 | wmiir write /ctl
|
||||
Bring into view all clients tagged '2'. To learn about clients and
|
||||
tags, see
|
||||
.BR wmiiwm (1).
|
||||
.SH SEE ALSO
|
||||
.BR wmii (1),
|
||||
.BR wmiiwm (1)
|
||||
|
||||
http://www.cs.bell-labs.com/sys/man/5/INDEX.html
|
324
cmd/wmiir.c
324
cmd/wmiir.c
@ -1,324 +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 <time.h>
|
||||
|
||||
#include <ixp.h>
|
||||
|
||||
static IXPClient c = { 0 };
|
||||
|
||||
static char version[] = "wmiir - " VERSION ", (C)opyright MMIV-MMVI Anselm R. Garbe\n";
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "%s",
|
||||
"usage: wmiir [-a <address>] [-v] create | read | ls [-l] | remove | write <file>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
write_data(unsigned int fid)
|
||||
{
|
||||
void *data = cext_emallocz(c.ofcall.iounit);
|
||||
unsigned long long offset = 0;
|
||||
unsigned int len = 0;
|
||||
|
||||
while((len = read(0, data, c.ofcall.iounit)) > 0) {
|
||||
if(ixp_client_write(&c, fid, offset, len, data) != len) {
|
||||
fprintf(stderr, "wmiir: cannot write file: %s\n", c.errstr);
|
||||
break;
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
if(offset == 0) /* do an explicit empty write when no writing has been done yet */
|
||||
if(ixp_client_write(&c, fid, offset, 0, 0) != 0)
|
||||
fprintf(stderr, "wmiir: cannot write file: %s\n", c.errstr);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static int
|
||||
xcreate(char *file)
|
||||
{
|
||||
unsigned int fid;
|
||||
char *p = strrchr(file, '/');
|
||||
|
||||
if(!p)
|
||||
p = 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;
|
||||
}
|
||||
p++;
|
||||
if(ixp_client_create(&c, fid, p, IXP_DMWRITE, IXP_OWRITE) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot create file '%s': %s\n", p, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
if(!(c.ofcall.qid.type&P9DMDIR))
|
||||
write_data(fid);
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
xwrite(char *file, unsigned char mode)
|
||||
{
|
||||
/* open */
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
if(ixp_client_walkopen(&c, fid, file, mode) == -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_stat(const void *s1, const void *s2)
|
||||
{
|
||||
Stat *st1 = (Stat *)s1;
|
||||
Stat *st2 = (Stat *)s2;
|
||||
return strcmp(st1->name, st2->name);
|
||||
}
|
||||
|
||||
static void
|
||||
setrwx(long m, char *s)
|
||||
{
|
||||
static char *modes[] =
|
||||
{
|
||||
"---",
|
||||
"--x",
|
||||
"-w-",
|
||||
"-wx",
|
||||
"r--",
|
||||
"r-x",
|
||||
"rw-",
|
||||
"rwx",
|
||||
};
|
||||
strncpy(s, modes[m], 3);
|
||||
}
|
||||
|
||||
static char *
|
||||
str_of_mode(unsigned int mode)
|
||||
{
|
||||
static char buf[16];
|
||||
|
||||
if(mode & IXP_DMDIR)
|
||||
buf[0]='d';
|
||||
else
|
||||
buf[0]='-';
|
||||
|
||||
buf[1]='-';
|
||||
setrwx((mode >> 6) & 7, &buf[2]);
|
||||
setrwx((mode >> 3) & 7, &buf[5]);
|
||||
setrwx((mode >> 0) & 7, &buf[8]);
|
||||
buf[11] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *
|
||||
str_of_time(unsigned int val)
|
||||
{
|
||||
static char buf[32];
|
||||
time_t t = (time_t)(int)val;
|
||||
char *tstr = ctime(&t);
|
||||
cext_strlcpy(buf, tstr ? tstr : "in v a l id ", sizeof(buf));
|
||||
buf[strlen(buf) - 1] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
print_stat(Stat *s, int details)
|
||||
{
|
||||
if(details)
|
||||
fprintf(stdout, "%s %s %s %5llu %s %s\n", str_of_mode(s->mode),
|
||||
s->uid, s->gid, s->length, str_of_time(s->mtime), s->name);
|
||||
else {
|
||||
if(s->mode & IXP_DMDIR)
|
||||
fprintf(stdout, "%s/\n", s->name);
|
||||
else
|
||||
fprintf(stdout, "%s\n", s->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xls(void *result, unsigned int msize, int details)
|
||||
{
|
||||
unsigned int n = 0, i = 0;
|
||||
unsigned char *p = result;
|
||||
Stat *dir;
|
||||
static Stat stat;
|
||||
|
||||
do {
|
||||
ixp_unpack_stat(&p, nil, &stat);
|
||||
n++;
|
||||
}
|
||||
while(p - (unsigned char*)result < msize);
|
||||
dir = (Stat *)cext_emallocz(sizeof(Stat) * n);
|
||||
p = result;
|
||||
do {
|
||||
ixp_unpack_stat(&p, nil, &dir[i++]);
|
||||
}
|
||||
while(p - (unsigned char*)result < msize);
|
||||
qsort(dir, n, sizeof(Stat), comp_stat);
|
||||
for(i = 0; i < n; i++)
|
||||
print_stat(&dir[i], details);
|
||||
free(dir);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int
|
||||
xdir(char *file, int details)
|
||||
{
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
/* XXX: buffer overflow */
|
||||
Stat *s = cext_emallocz(sizeof(Stat));
|
||||
unsigned char *buf;
|
||||
int count;
|
||||
static unsigned char result[IXP_MAX_MSG];
|
||||
void *data = nil;
|
||||
unsigned long long offset = 0;
|
||||
|
||||
if(ixp_client_stat(&c, fid, file) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot stat file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
buf = c.ofcall.stat;
|
||||
ixp_unpack_stat(&buf, nil, s);
|
||||
if(!(s->mode & IXP_DMDIR)) {
|
||||
print_stat(s, details);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* directory */
|
||||
if(ixp_client_open(&c, fid, IXP_OREAD) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot open directory '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
while((count = ixp_client_read(&c, fid, offset, result, IXP_MAX_MSG)) > 0) {
|
||||
data = cext_erealloc(data, offset + count);
|
||||
memcpy(data + offset, result, count);
|
||||
offset += count;
|
||||
}
|
||||
if(count == -1) {
|
||||
fprintf(stderr, "wmiir: cannot read directory '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
if(data)
|
||||
xls(data, offset + count, details);
|
||||
return ixp_client_close(&c, fid);
|
||||
}
|
||||
|
||||
static int
|
||||
xread(char *file)
|
||||
{
|
||||
unsigned int fid = c.root_fid << 2;
|
||||
int count;
|
||||
static unsigned char result[IXP_MAX_MSG];
|
||||
unsigned long long offset = 0;
|
||||
|
||||
if(ixp_client_walkopen(&c, fid, file, IXP_OREAD) == -1) {
|
||||
fprintf(stderr, "wmiir: cannot open file '%s': %s\n", file, c.errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while((count = ixp_client_read(&c, fid, offset, result, IXP_MAX_MSG)) > 0) {
|
||||
write(1, result, count);
|
||||
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;
|
||||
|
||||
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 ret = 0, i = 0, details = 0;
|
||||
char *cmd, *file, *address = getenv("WMII_ADDRESS");
|
||||
|
||||
/* command line args */
|
||||
if(argc < 2)
|
||||
usage();
|
||||
|
||||
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
|
||||
switch (argv[i][1]) {
|
||||
case 'v':
|
||||
fprintf(stdout, "%s", version);
|
||||
exit(0);
|
||||
break;
|
||||
case 'a':
|
||||
if(i + 1 < argc)
|
||||
address = argv[++i];
|
||||
else
|
||||
usage();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd = argv[argc - 2];
|
||||
file = argv[argc - 1];
|
||||
if((details = !strncmp(cmd, "-l", 3))) {
|
||||
if(argc < 3)
|
||||
usage();
|
||||
if(strncmp(argv[argc - 3], "ls", 3))
|
||||
usage();
|
||||
cmd = argv[argc - 3];
|
||||
}
|
||||
|
||||
if(!address) {
|
||||
fprintf(stderr, "%s", "wmiir: error: $WMII_ADDRESS not set\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
if(ixp_client_dial(&c, address, getpid()) == -1) {
|
||||
fprintf(stderr, "wmiir: %s\n", c.errstr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!strncmp(cmd, "create", 7))
|
||||
ret = xcreate(file);
|
||||
else if(!strncmp(cmd, "ls", 3))
|
||||
ret = xdir(file, details);
|
||||
else if(!strncmp(cmd, "read", 5))
|
||||
ret = xread(file);
|
||||
else if(!strncmp(cmd, "remove", 7))
|
||||
ret = xremove(file);
|
||||
else if(!strncmp(cmd, "write", 6))
|
||||
ret = xwrite(file, IXP_OWRITE);
|
||||
else
|
||||
usage();
|
||||
|
||||
/* close socket */
|
||||
ixp_client_hangup(&c);
|
||||
|
||||
return ret;
|
||||
}
|
25
doc/Makefile
25
doc/Makefile
@ -1,25 +0,0 @@
|
||||
# window manager improved 2 user guide
|
||||
l2h_opts=-local_icons -scalable_fonts -split +1 -subdir -show_section_numbers -address "<br>Last update: $(shell date) by $$USER@$$HOSTNAME"
|
||||
|
||||
SRC = guide_en.tex wmii.tex
|
||||
DVI = ${SRC:.tex=.dvi}
|
||||
PDF = ${SRC:.tex=.pdf}
|
||||
PS = ${SRC:.tex=.ps}
|
||||
HTML = ${SRC:.tex=.html}
|
||||
|
||||
.SUFFIXES: .tex .dvi .pdf .ps .html
|
||||
|
||||
all: ${DVI} ${PDF} #${PS} ${HTML}
|
||||
.tex.dvi:
|
||||
latex -interaction=batchmode $<
|
||||
latex -interaction=batchmode $<
|
||||
.tex.pdf:
|
||||
pdflatex $<
|
||||
pdflatex $<
|
||||
.dvi.ps:
|
||||
dvips -o $@ $<
|
||||
.tex.html:
|
||||
latex2html ${l2h_opts} $<
|
||||
clean:
|
||||
rm -f *.pdf *.ps *.dvi *.log *.aux *.out *.toc
|
||||
rm -rf guide_en
|
1005
doc/guide_en.tex
1005
doc/guide_en.tex
File diff suppressed because it is too large
Load Diff
83
doc/wmii.tex
83
doc/wmii.tex
@ -1,83 +0,0 @@
|
||||
% (C)opyright 2005 by Anselm R. Garbe
|
||||
\documentclass{article} \usepackage{times} \begin{document}
|
||||
|
||||
\title{Improved GUI concepts for experienced users}
|
||||
|
||||
\author{Anselm R. Garbe\\ \small garbeam at gmail dot com}
|
||||
|
||||
\maketitle \thispagestyle{empty}
|
||||
|
||||
\begin{abstract}
|
||||
This article presents the motivation and concepts of the dynamic
|
||||
window manager wmii and the graphical toolkit liblitz for the
|
||||
\it{X Window System}.
|
||||
\end{abstract}
|
||||
|
||||
|
||||
%-------------------------------------------------------------------------
|
||||
\section{Motivation}
|
||||
|
||||
Most common graphical user interfaces are designed after the WIMP\cite{wimp}
|
||||
paradigm, which has dominated the desktop environment
|
||||
landscape since late 1980s. While research has been done on alternative
|
||||
user interfaces, often the focus targeted more in ease of use and low
|
||||
learning curves for new computer users rather than in efficiency and
|
||||
power of abstraction.
|
||||
|
||||
The main reason has been the economical success of computers
|
||||
in the normal consumer market, which consists of unexperienced users mainly.
|
||||
Our motivation is to change this situation and to provide a graphical
|
||||
user interface for experienced users, though we know that this market is
|
||||
a niche.
|
||||
|
||||
There has been done rarly research in the non-wimp GUI landscape for years.
|
||||
Back in 80s and early 90s there has been some research in
|
||||
this area for the Plan 9\cite{plan9} operating system at Bell Labs.
|
||||
Most recent research has been done by individuals only, like Tuomo Valkonen with
|
||||
his Ion\cite{ion} project and Lars Bernhardsson with his
|
||||
LarsWM\cite{larswm} project.
|
||||
|
||||
The approaches found in the Plan 9 operating system are interesting, because
|
||||
on the one hand they cancelled the Unix tradition to work in Teletype emulators
|
||||
and on the other hand, they didn't followed the WIMP paradigm propagated by Apple,
|
||||
IBM or Microsoft. This makes Plan 9 the most unique approach compared to the
|
||||
classical WIMP world.
|
||||
|
||||
The main aspects of an improved GUI consists of two things, a powerful
|
||||
window management approach and a sane and simple widget set which fits well
|
||||
into this window management approach.
|
||||
|
||||
In the area of improved window management concepts there has been done more
|
||||
research, thus there appeared several different approaches. But the area
|
||||
of improved widget sets which form powerful applications with a simple widget
|
||||
set has been ignored for long time. Instead, the WIMP world introduced many
|
||||
widgets which seem to focus on eye-candy, like progress bars, but don't
|
||||
fix the essential problems with WIMP toolkits.
|
||||
|
||||
|
||||
|
||||
\section{Future}
|
||||
|
||||
|
||||
\section*{Acknowlegdements} Following people provided useful feedback or several
|
||||
grammar fixes to this article:
|
||||
\begin{itemize}
|
||||
\item Frank Boehme (1st version of this article)
|
||||
\item Tuncer M zayamut Ayaz (1st version of this article)
|
||||
\end{itemize}
|
||||
|
||||
\begin{thebibliography}{99}
|
||||
\bibitem{wimp} Ashley George Taylor, WIMP Interfaces, CS6751 Topic Report: Winter '97
|
||||
\bibitem{x} X Window System - http://www.freedesktop.org
|
||||
\bibitem{plan9} plan9 operating system - http://cm.bell-labs.com/plan9dist/
|
||||
\bibitem{acme} Rob Pike, Acme: A User Interface for Programmers -
|
||||
http://www.cs.bell-labs.com/sys/doc/acme/acme.html
|
||||
\bibitem{rat} Ratpoison window manager - http://www.nongnu.org/ratpoison/
|
||||
\bibitem{evil} evilwm window manager - http://evilwm.sf.net
|
||||
\bibitem{ion} Ion window manager - http://modeemi.cs.tut.fi/~tuomov/ion/
|
||||
\bibitem{larswm} LarsWM window manager - http://www.fnurt.net/larswm/
|
||||
\bibitem{vi} Vi Improved (VIM) - http://www.vim.org
|
||||
\bibitem{9p} 9P protocol - http://www.cs.bell-labs.com/sys/man/5/INDEX.html
|
||||
\end{thebibliography}
|
||||
|
||||
\end{document}
|
@ -1,28 +0,0 @@
|
||||
# libcext - c extensions for wmii project
|
||||
# (C)opyright MMIV-MMVI Anselm R. Garbe
|
||||
|
||||
include ../config.mk
|
||||
|
||||
SRC = assert.c malloc.c strlcat.c strlcpy.c tokenize.c \
|
||||
trim.c
|
||||
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
.PREFIXES = .c .o
|
||||
|
||||
all: libcext.a
|
||||
@echo built libcext
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
@${CC} -c ${CFLAGS} $<
|
||||
|
||||
$(OBJ): cext.h
|
||||
|
||||
libcext.a: ${OBJ}
|
||||
@echo AR $@
|
||||
@${AR} $@ ${OBJ}
|
||||
@${RANLIB} $@
|
||||
|
||||
clean:
|
||||
rm -f libcext.a *.o
|
@ -1,10 +0,0 @@
|
||||
/* Public Domain */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void
|
||||
cext_failed_assert(char *a, char *file, int line)
|
||||
{
|
||||
fprintf(stderr, "Assertion \"%s\" failed at %s:%d\n", a, file, line);
|
||||
abort();
|
||||
}
|
@ -1,38 +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 (void *)0
|
||||
#endif
|
||||
|
||||
/* asprintf.c */
|
||||
extern int cext_asprintf(char **str, char const *fmt, ...);
|
||||
|
||||
/* malloc.c */
|
||||
extern void *cext_emallocz(unsigned int size);
|
||||
extern void *cext_emalloc(unsigned int size);
|
||||
extern void *cext_erealloc(void *ptr, unsigned int size);
|
||||
extern char *cext_estrdup(const char *str);
|
||||
|
||||
/* strlcat.c */
|
||||
extern unsigned int cext_strlcat(char *dst, const char *src, unsigned int siz);
|
||||
|
||||
/* strlcpy.c */
|
||||
extern unsigned int cext_strlcpy(char *dst, const char *src, unsigned int siz);
|
||||
|
||||
/* tokenize.c */
|
||||
extern unsigned int cext_tokenize(char **result, unsigned int reslen, char *str, char delim);
|
||||
|
||||
/* trim.c */
|
||||
extern void cext_trim(char *str, const char *chars);
|
||||
|
||||
/* assert.c */
|
||||
#define cext_assert(a) do { \
|
||||
if(!(a)) \
|
||||
cext_failed_assert(#a, __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
extern void cext_failed_assert(char *a, char *file, int line);
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cext.h"
|
||||
|
||||
static void
|
||||
bad_malloc(unsigned int size)
|
||||
{
|
||||
fprintf(stderr, "fatal: could not malloc() %d bytes\n",
|
||||
(int) size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void *
|
||||
cext_emallocz(unsigned int size)
|
||||
{
|
||||
void *res = calloc(1, size);
|
||||
if(!res)
|
||||
bad_malloc(size);
|
||||
return res;
|
||||
}
|
||||
|
||||
void *
|
||||
cext_emalloc(unsigned int size)
|
||||
{
|
||||
void *res = malloc(size);
|
||||
if(!res)
|
||||
bad_malloc(size);
|
||||
return res;
|
||||
}
|
||||
|
||||
void *
|
||||
cext_erealloc(void *ptr, unsigned int size)
|
||||
{
|
||||
void *res = realloc(ptr, size);
|
||||
if(!res)
|
||||
bad_malloc(size);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
cext_estrdup(const char *str)
|
||||
{
|
||||
void *res = strdup(str);
|
||||
if(!res)
|
||||
bad_malloc(strlen(str));
|
||||
return res;
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cext.h"
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
unsigned int
|
||||
cext_strlcat(char *dst, const char *src, unsigned int siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register unsigned int n = siz;
|
||||
unsigned int dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while(n-- != 0 && *d != 0)
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if(n == 0)
|
||||
return (dlen + strlen(s));
|
||||
while(*s != 0) {
|
||||
if(n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = 0;
|
||||
|
||||
return (dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "cext.h"
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
unsigned int
|
||||
cext_strlcpy(char *dst, const char *src, unsigned int siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register unsigned int n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if(n != 0 && --n != 0) {
|
||||
do {
|
||||
if((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while(--n != 0);
|
||||
}
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if(n == 0) {
|
||||
if(siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while(*s++);
|
||||
}
|
||||
return (s - src - 1); /* count does not include NUL */
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cext.h"
|
||||
|
||||
unsigned int
|
||||
cext_tokenize(char **result, unsigned int reslen, char *str, char delim)
|
||||
{
|
||||
char *p, *n;
|
||||
unsigned int i = 0;
|
||||
|
||||
if(!str)
|
||||
return 0;
|
||||
for(n = str; *n == delim; n++);
|
||||
p = n;
|
||||
for(i = 0; *n != 0;) {
|
||||
if(i == reslen)
|
||||
return i;
|
||||
if(*n == delim) {
|
||||
*n = 0;
|
||||
if(strlen(p))
|
||||
result[i++] = p;
|
||||
p = ++n;
|
||||
} else
|
||||
n++;
|
||||
}
|
||||
if((i < reslen) && (p < n) && strlen(p))
|
||||
result[i++] = p;
|
||||
return i; /* number of tokens */
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) MMVI Anselm R. Garbe <arg@suckless.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "cext.h"
|
||||
|
||||
/*
|
||||
* Removes all characters in chars from str.
|
||||
*/
|
||||
void
|
||||
cext_trim(char *str, const char *chars)
|
||||
{
|
||||
const char *cp;
|
||||
char *sp, *sn;
|
||||
|
||||
for(cp = chars; *cp; cp++) {
|
||||
for(sp = sn = str; *sn; sn++) {
|
||||
if(*sn != *cp)
|
||||
*(sp++) = *sn;
|
||||
}
|
||||
*sp = 0;
|
||||
}
|
||||
}
|
@ -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 intmap.c request.c
|
||||
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: libixp.a
|
||||
@echo built libixp
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
@${CC} -c ${CFLAGS} $<
|
||||
|
||||
libixp.a: ${OBJ}
|
||||
@echo AR $@
|
||||
@${AR} $@ ${OBJ}
|
||||
@${RANLIB} $@
|
||||
|
||||
clean:
|
||||
rm -f libixp.a *.o
|
220
libixp/client.c
220
libixp/client.c
@ -1,220 +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 "ixp.h"
|
||||
|
||||
int
|
||||
ixp_client_do_fcall(IXPClient *c)
|
||||
{
|
||||
static unsigned char msg[IXP_MAX_MSG];
|
||||
unsigned int msize = ixp_fcall2msg(msg, &c->ifcall, 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_msg2fcall(&c->ofcall, msg, IXP_MAX_MSG))) {
|
||||
c->errstr = "received bad message";
|
||||
return -1;
|
||||
}
|
||||
if(c->ofcall.type == RERROR) {
|
||||
c->errstr = c->ofcall.ename;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_dial(IXPClient *c, char *sockfile, unsigned int rootfid)
|
||||
{
|
||||
|
||||
if((c->fd = ixp_connect_sock(sockfile)) < 0) {
|
||||
c->errstr = "cannot connect server";
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->ifcall.type = TVERSION;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.msize = IXP_MAX_MSG;
|
||||
c->ifcall.version = IXP_VERSION;
|
||||
if(ixp_client_do_fcall(c) == -1) {
|
||||
fprintf(stderr, "error: %s\n", c->errstr);
|
||||
ixp_client_hangup(c);
|
||||
return -1;
|
||||
}
|
||||
if(strncmp(c->ofcall.version, IXP_VERSION, strlen(IXP_VERSION))) {
|
||||
fprintf(stderr, "error: %s\n", c->errstr);
|
||||
c->errstr = "9P versions differ";
|
||||
ixp_client_hangup(c);
|
||||
return -1; /* we cannot handle this version */
|
||||
}
|
||||
free(c->ofcall.version);
|
||||
c->root_fid = rootfid;
|
||||
|
||||
c->ifcall.type = TATTACH;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = c->root_fid;
|
||||
c->ifcall.afid = IXP_NOFID;
|
||||
c->ifcall.uname = getenv("USER");
|
||||
c->ifcall.aname = "";
|
||||
if(ixp_client_do_fcall(c) == -1) {
|
||||
fprintf(stderr, "error: %s\n", c->errstr);
|
||||
ixp_client_hangup(c);
|
||||
return -1;
|
||||
}
|
||||
c->root_qid = c->ofcall.qid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_remove(IXPClient *c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
c->ifcall.type = TREMOVE;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = newfid;
|
||||
|
||||
return ixp_client_do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_create(IXPClient *c, unsigned int dirfid, char *name,
|
||||
unsigned int perm, unsigned char mode)
|
||||
{
|
||||
c->ifcall.type = TCREATE;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = dirfid;
|
||||
c->ifcall.name = name;
|
||||
c->ifcall.perm = perm;
|
||||
c->ifcall.mode = mode;
|
||||
return ixp_client_do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_walk(IXPClient *c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
unsigned int i;
|
||||
char *wname[IXP_MAX_WELEM];
|
||||
|
||||
c->ifcall.type = TWALK;
|
||||
c->ifcall.fid = c->root_fid;
|
||||
c->ifcall.newfid = newfid;
|
||||
if(filepath) {
|
||||
c->ifcall.name = filepath;
|
||||
c->ifcall.nwname =
|
||||
cext_tokenize(wname, IXP_MAX_WELEM, c->ifcall.name, '/');
|
||||
for(i = 0; i < c->ifcall.nwname; i++)
|
||||
c->ifcall.wname[i] = wname[i];
|
||||
}
|
||||
return ixp_client_do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_stat(IXPClient *c, unsigned int newfid, char *filepath)
|
||||
{
|
||||
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
|
||||
c->ifcall.type = TSTAT;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = newfid;
|
||||
return ixp_client_do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_open(IXPClient *c, unsigned int newfid, unsigned char mode)
|
||||
{
|
||||
|
||||
c->ifcall.type = TOPEN;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = newfid;
|
||||
c->ifcall.mode = mode;
|
||||
return ixp_client_do_fcall(c);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_walkopen(IXPClient *c, unsigned int newfid, char *filepath,
|
||||
unsigned char mode)
|
||||
{
|
||||
|
||||
if(ixp_client_walk(c, newfid, filepath) == -1)
|
||||
return -1;
|
||||
return ixp_client_open(c, newfid, mode);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_read(IXPClient *c, unsigned int fid, unsigned long long offset,
|
||||
void *result, unsigned int res_len)
|
||||
{
|
||||
unsigned int bytes = c->ofcall.iounit;
|
||||
|
||||
c->ifcall.type = TREAD;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = fid;
|
||||
c->ifcall.offset = offset;
|
||||
c->ifcall.count = res_len < bytes ? res_len : bytes;
|
||||
if(ixp_client_do_fcall(c) == -1)
|
||||
return -1;
|
||||
memcpy(result, c->ofcall.data, c->ofcall.count);
|
||||
free(c->ofcall.data);
|
||||
|
||||
return c->ofcall.count;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_write(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset, unsigned int count,
|
||||
unsigned char *data)
|
||||
{
|
||||
|
||||
if(count > c->ofcall.iounit) {
|
||||
c->errstr = "iounit exceeded";
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->ifcall.type = TWRITE;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = fid;
|
||||
c->ifcall.offset = offset;
|
||||
c->ifcall.count = count;
|
||||
c->ifcall.data = (void *)data;
|
||||
if(ixp_client_do_fcall(c) == -1)
|
||||
return -1;
|
||||
|
||||
return c->ofcall.count;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_client_close(IXPClient *c, unsigned int fid)
|
||||
{
|
||||
|
||||
c->ifcall.type = TCLUNK;
|
||||
c->ifcall.tag = IXP_NOTAG;
|
||||
c->ifcall.fid = fid;
|
||||
return ixp_client_do_fcall(c);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_client_hangup(IXPClient *c)
|
||||
{
|
||||
/* session finished, now shutdown */
|
||||
if(c->fd) {
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
}
|
||||
}
|
236
libixp/convert.c
236
libixp/convert.c
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ixp.h"
|
||||
|
||||
/* packode/unpackode stuff */
|
||||
|
||||
void
|
||||
ixp_pack_u8(unsigned char **msg, int *msize, unsigned char val)
|
||||
{
|
||||
if(!msize || (*msize -= 1) >= 0)
|
||||
*(*msg)++ = val;
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_u8(unsigned char **msg, int *msize, unsigned char *val)
|
||||
{
|
||||
if(!msize || (*msize -= 1) >= 0)
|
||||
*val = *(*msg)++;
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_u16(unsigned char **msg, int *msize, unsigned short val)
|
||||
{
|
||||
if(!msize || (*msize -= 2) >= 0) {
|
||||
*(*msg)++ = val;
|
||||
*(*msg)++ = val >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_u16(unsigned char **msg, int *msize, unsigned short *val)
|
||||
{
|
||||
if(!msize || (*msize -= 2) >= 0) {
|
||||
*val = *(*msg)++;
|
||||
*val |= *(*msg)++ << 8;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_u32(unsigned char **msg, int *msize, unsigned int val)
|
||||
{
|
||||
if(!msize || (*msize -= 4) >= 0) {
|
||||
*(*msg)++ = val;
|
||||
*(*msg)++ = val >> 8;
|
||||
*(*msg)++ = val >> 16;
|
||||
*(*msg)++ = val >> 24;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_u32(unsigned char **msg, int *msize, unsigned int *val)
|
||||
{
|
||||
if(!msize || (*msize -= 4) >= 0) {
|
||||
*val = *(*msg)++;
|
||||
*val |= *(*msg)++ << 8;
|
||||
*val |= *(*msg)++ << 16;
|
||||
*val |= *(*msg)++ << 24;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_u64(unsigned char **msg, int *msize, unsigned long long val)
|
||||
{
|
||||
if(!msize || (*msize -= 8) >= 0) {
|
||||
*(*msg)++ = val;
|
||||
*(*msg)++ = val >> 8;
|
||||
*(*msg)++ = val >> 16;
|
||||
*(*msg)++ = val >> 24;
|
||||
*(*msg)++ = val >> 32;
|
||||
*(*msg)++ = val >> 40;
|
||||
*(*msg)++ = val >> 48;
|
||||
*(*msg)++ = val >> 56;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_u64(unsigned char **msg, int *msize, unsigned long long *val)
|
||||
{
|
||||
if(!msize || (*msize -= 8) >= 0) {
|
||||
*val |= *(*msg)++;
|
||||
*val |= *(*msg)++ << 8;
|
||||
*val |= *(*msg)++ << 16;
|
||||
*val |= *(*msg)++ << 24;
|
||||
*val |= (unsigned long long)*(*msg)++ << 32;
|
||||
*val |= (unsigned long long)*(*msg)++ << 40;
|
||||
*val |= (unsigned long long)*(*msg)++ << 48;
|
||||
*val |= (unsigned long long)*(*msg)++ << 56;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_string(unsigned char **msg, int *msize, const char *s)
|
||||
{
|
||||
unsigned short len = s ? strlen(s) : 0;
|
||||
ixp_pack_u16(msg, msize, len);
|
||||
if(s)
|
||||
ixp_pack_data(msg, msize, (void *)s, len);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_strings(unsigned char **msg, int *msize, unsigned short n, char **strings) {
|
||||
unsigned char *s = *msg;
|
||||
unsigned int i, size = 0;
|
||||
unsigned short len;
|
||||
for(i=0; i<n; i++) {
|
||||
ixp_unpack_u16(&s, msize, &len);
|
||||
s += len;
|
||||
size += len + 1; /* for '\0' */
|
||||
}
|
||||
if(!size) {
|
||||
/* So we don't try to free some random value */
|
||||
*strings = nil;
|
||||
return;
|
||||
}
|
||||
s = cext_emalloc(size);
|
||||
for(i=0; i < n; i++) {
|
||||
ixp_unpack_u16(msg, msize, &len);
|
||||
if(!msize || (*msize -= len) < 0)
|
||||
return;
|
||||
|
||||
memcpy(s, *msg, len);
|
||||
s[len] = '\0';
|
||||
strings[i] = (char *)s;
|
||||
*msg += len;
|
||||
s += len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_string(unsigned char **msg, int *msize, char **string, unsigned short *len)
|
||||
{
|
||||
ixp_unpack_u16(msg, msize, len);
|
||||
*string = nil;
|
||||
if (!msize || (*msize -= *len) >= 0) {
|
||||
*string = cext_emalloc(*len+1);
|
||||
if(*len)
|
||||
memcpy(*string, *msg, *len);
|
||||
(*string)[*len] = 0;
|
||||
*msg += *len;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_data(unsigned char **msg, int *msize, unsigned char *data, unsigned int datalen)
|
||||
{
|
||||
if(!msize || (*msize -= datalen) >= 0) {
|
||||
memcpy(*msg, data, datalen);
|
||||
*msg += datalen;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_data(unsigned char **msg, int *msize, unsigned char **data, unsigned int datalen)
|
||||
{
|
||||
if(!msize || (*msize -= datalen) >= 0) {
|
||||
*data = cext_emallocz(datalen);
|
||||
memcpy(*data, *msg, datalen);
|
||||
*msg += datalen;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_prefix(unsigned char *msg, unsigned int size, unsigned char id,
|
||||
unsigned short tag)
|
||||
{
|
||||
ixp_pack_u32(&msg, 0, size);
|
||||
ixp_pack_u8(&msg, 0, id);
|
||||
ixp_pack_u16(&msg, 0, tag);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_prefix(unsigned char **msg, unsigned int *size, unsigned char *id,
|
||||
unsigned short *tag)
|
||||
{
|
||||
int msize;
|
||||
ixp_unpack_u32(msg, nil, size);
|
||||
msize = *size;
|
||||
ixp_unpack_u8(msg, &msize, id);
|
||||
ixp_unpack_u16(msg, &msize, tag);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_qid(unsigned char **msg, int *msize, Qid * qid)
|
||||
{
|
||||
ixp_pack_u8(msg, msize, qid->type);
|
||||
ixp_pack_u32(msg, msize, qid->version);
|
||||
ixp_pack_u64(msg, msize, qid->path);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_qid(unsigned char **msg, int *msize, Qid * qid)
|
||||
{
|
||||
ixp_unpack_u8(msg, msize, &qid->type);
|
||||
ixp_unpack_u32(msg, msize, &qid->version);
|
||||
ixp_unpack_u64(msg, msize, &qid->path);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_pack_stat(unsigned char **msg, int *msize, Stat * stat)
|
||||
{
|
||||
ixp_pack_u16(msg, msize, ixp_sizeof_stat(stat) - sizeof(unsigned short));
|
||||
ixp_pack_u16(msg, msize, stat->type);
|
||||
ixp_pack_u32(msg, msize, stat->dev);
|
||||
ixp_pack_qid(msg, msize, &stat->qid);
|
||||
ixp_pack_u32(msg, msize, stat->mode);
|
||||
ixp_pack_u32(msg, msize, stat->atime);
|
||||
ixp_pack_u32(msg, msize, stat->mtime);
|
||||
ixp_pack_u64(msg, msize, stat->length);
|
||||
ixp_pack_string(msg, msize, stat->name);
|
||||
ixp_pack_string(msg, msize, stat->uid);
|
||||
ixp_pack_string(msg, msize, stat->gid);
|
||||
ixp_pack_string(msg, msize, stat->muid);
|
||||
}
|
||||
|
||||
void
|
||||
ixp_unpack_stat(unsigned char **msg, int *msize, Stat * stat)
|
||||
{
|
||||
unsigned short dummy;
|
||||
*msg += sizeof(unsigned short);
|
||||
ixp_unpack_u16(msg, msize, &stat->type);
|
||||
ixp_unpack_u32(msg, msize, &stat->dev);
|
||||
ixp_unpack_qid(msg, msize, &stat->qid);
|
||||
ixp_unpack_u32(msg, msize, &stat->mode);
|
||||
ixp_unpack_u32(msg, msize, &stat->atime);
|
||||
ixp_unpack_u32(msg, msize, &stat->mtime);
|
||||
ixp_unpack_u64(msg, msize, &stat->length);
|
||||
ixp_unpack_string(msg, msize, &stat->name, &dummy);
|
||||
ixp_unpack_string(msg, msize, &stat->uid, &dummy);
|
||||
ixp_unpack_string(msg, msize, &stat->gid, &dummy);
|
||||
ixp_unpack_string(msg, msize, &stat->muid, &dummy);
|
||||
}
|
144
libixp/intmap.c
144
libixp/intmap.c
@ -1,144 +0,0 @@
|
||||
/* This file is derived from src/lib9p/intmap.c from plan9port */
|
||||
/* See LICENCE.p9p for terms of use */
|
||||
#include <stdlib.h>
|
||||
#include "ixp.h"
|
||||
#define USED(v) if(v){}else{}
|
||||
|
||||
struct Intlist {
|
||||
unsigned long id;
|
||||
void* aux;
|
||||
Intlist* link;
|
||||
unsigned int ref;
|
||||
};
|
||||
|
||||
static unsigned long
|
||||
hashid(Intmap *map, unsigned long id)
|
||||
{
|
||||
return id%map->nhash;
|
||||
}
|
||||
|
||||
static void
|
||||
nop(void *v)
|
||||
{
|
||||
USED(v);
|
||||
}
|
||||
|
||||
void
|
||||
initmap(Intmap *m, unsigned long nhash, void *hash)
|
||||
{
|
||||
m->nhash = nhash;
|
||||
m->hash = hash;
|
||||
}
|
||||
|
||||
static Intlist**
|
||||
llookup(Intmap *map, unsigned long id)
|
||||
{
|
||||
Intlist **lf;
|
||||
|
||||
for(lf=&map->hash[hashid(map, id)]; *lf; lf=&(*lf)->link)
|
||||
if((*lf)->id == id)
|
||||
break;
|
||||
return lf;
|
||||
}
|
||||
|
||||
void
|
||||
freemap(Intmap *map, void (*destroy)(void*))
|
||||
{
|
||||
int i;
|
||||
Intlist *p, *nlink;
|
||||
|
||||
if(destroy == nil)
|
||||
destroy = nop;
|
||||
for(i=0; i<map->nhash; i++){
|
||||
for(p=map->hash[i]; p; p=nlink){
|
||||
nlink = p->link;
|
||||
destroy(p->aux);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
execmap(Intmap *map, void (*run)(void*))
|
||||
{
|
||||
int i;
|
||||
Intlist *p, *nlink;
|
||||
|
||||
for(i=0; i<map->nhash; i++){
|
||||
for(p=map->hash[i]; p; p=nlink){
|
||||
nlink = p->link;
|
||||
run(p->aux);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
lookupkey(Intmap *map, unsigned long id)
|
||||
{
|
||||
Intlist *f;
|
||||
void *v;
|
||||
|
||||
if((f = *llookup(map, id)))
|
||||
v = f->aux;
|
||||
else
|
||||
v = nil;
|
||||
return v;
|
||||
}
|
||||
|
||||
void*
|
||||
insertkey(Intmap *map, unsigned long id, void *v)
|
||||
{
|
||||
Intlist *f;
|
||||
void *ov;
|
||||
unsigned long h;
|
||||
|
||||
if((f = *llookup(map, id))){
|
||||
/* no decrement for ov because we're returning it */
|
||||
ov = f->aux;
|
||||
f->aux = v;
|
||||
}else{
|
||||
f = cext_emallocz(sizeof(*f));
|
||||
f->id = id;
|
||||
f->aux = v;
|
||||
h = hashid(map, id);
|
||||
f->link = map->hash[h];
|
||||
map->hash[h] = f;
|
||||
ov = nil;
|
||||
}
|
||||
return ov;
|
||||
}
|
||||
|
||||
int
|
||||
caninsertkey(Intmap *map, unsigned long id, void *v)
|
||||
{
|
||||
Intlist *f;
|
||||
int rv;
|
||||
unsigned long h;
|
||||
|
||||
if(*llookup(map, id))
|
||||
rv = 0;
|
||||
else{
|
||||
f = cext_emallocz(sizeof *f);
|
||||
f->id = id;
|
||||
f->aux = v;
|
||||
h = hashid(map, id);
|
||||
f->link = map->hash[h];
|
||||
map->hash[h] = f;
|
||||
rv = 1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void*
|
||||
deletekey(Intmap *map, unsigned long id)
|
||||
{
|
||||
Intlist **lf, *f;
|
||||
void *ov;
|
||||
|
||||
if((f = *(lf = llookup(map, id)))){
|
||||
ov = f->aux;
|
||||
*lf = f->link;
|
||||
free(f);
|
||||
}else
|
||||
ov = nil;
|
||||
return ov;
|
||||
}
|
369
libixp/ixp.h
369
libixp/ixp.h
@ -1,369 +0,0 @@
|
||||
/*
|
||||
*(C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
*See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cext.h>
|
||||
|
||||
#define IXP_VERSION "9P2000"
|
||||
#define IXP_NOTAG (unsigned short)~0U /*Dummy tag */
|
||||
#define IXP_NOFID (unsigned int)~0 /*No auth */
|
||||
|
||||
enum { IXP_MAX_VERSION = 32,
|
||||
IXP_MAX_ERROR = 128,
|
||||
IXP_MAX_CACHE = 32,
|
||||
IXP_MAX_MSG = 8192,
|
||||
IXP_MAX_FLEN = 128,
|
||||
IXP_MAX_ULEN = 32,
|
||||
IXP_MAX_WELEM = 16 };
|
||||
|
||||
/* 9P message types */
|
||||
enum { TVERSION = 100,
|
||||
RVERSION,
|
||||
TAUTH = 102,
|
||||
RAUTH,
|
||||
TATTACH = 104,
|
||||
RATTACH,
|
||||
TERROR = 106, /* illegal */
|
||||
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 */
|
||||
enum { IXP_DMDIR = 0x80000000, /* mode bit for directories */
|
||||
IXP_DMAPPEND = 0x40000000, /* mode bit for append only files */
|
||||
IXP_DMEXCL = 0x20000000, /* mode bit for exclusive use files */
|
||||
IXP_DMMOUNT = 0x10000000, /* mode bit for mounted channel */
|
||||
IXP_DMAUTH = 0x08000000, /* mode bit for authentication file */
|
||||
IXP_DMTMP = 0x04000000, /* mode bit for non-backed-up file */
|
||||
IXP_DMREAD = 0x4<<6, /* mode bit for read permission */
|
||||
IXP_DMWRITE = 0x2<<6, /* mode bit for write permission */
|
||||
IXP_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,
|
||||
};
|
||||
|
||||
/* from libc.h in p9p */
|
||||
enum { P9OREAD = 0, /* open for read */
|
||||
P9OWRITE = 1, /* write */
|
||||
P9ORDWR = 2, /* read and write */
|
||||
P9OEXEC = 3, /* execute, == read but check execute permission */
|
||||
P9OTRUNC = 16, /* or'ed in (except for exec), truncate file first */
|
||||
P9OCEXEC = 32, /* or'ed in, close on exec */
|
||||
P9ORCLOSE = 64, /* or'ed in, remove on close */
|
||||
P9ODIRECT = 128, /* or'ed in, direct access */
|
||||
P9ONONBLOCK = 256, /* or'ed in, non-blocking call */
|
||||
P9OEXCL = 0x1000, /* or'ed in, exclusive use (create only) */
|
||||
P9OLOCK = 0x2000, /* or'ed in, lock after opening */
|
||||
P9OAPPEND = 0x4000 /* or'ed in, append only */
|
||||
};
|
||||
|
||||
/* bits in Qid.type */
|
||||
enum { P9QTDIR = 0x80, /* type bit for directories */
|
||||
P9QTAPPEND = 0x40, /* type bit for append only files */
|
||||
P9QTEXCL = 0x20, /* type bit for exclusive use files */
|
||||
P9QTMOUNT = 0x10, /* type bit for mounted channel */
|
||||
P9QTAUTH = 0x08, /* type bit for authentication file */
|
||||
P9QTTMP = 0x04, /* type bit for non-backed-up file */
|
||||
P9QTSYMLINK = 0x02, /* type bit for symbolic link */
|
||||
P9QTFILE = 0x00 /* type bits for plain file */
|
||||
};
|
||||
|
||||
/* bits in Dir.mode */
|
||||
#define P9DMDIR 0x80000000 /* mode bit for directories */
|
||||
#define P9DMAPPEND 0x40000000 /* mode bit for append only files */
|
||||
#define P9DMEXCL 0x20000000 /* mode bit for exclusive use files */
|
||||
#define P9DMMOUNT 0x10000000 /* mode bit for mounted channel */
|
||||
#define P9DMAUTH 0x08000000 /* mode bit for authentication file */
|
||||
#define P9DMTMP 0x04000000 /* mode bit for non-backed-up file */
|
||||
#define P9DMSYMLINK 0x02000000 /* mode bit for symbolic link (Unix, 9P2000.u) */
|
||||
#define P9DMDEVICE 0x00800000 /* mode bit for device file (Unix, 9P2000.u) */
|
||||
#define P9DMNAMEDPIPE 0x00200000 /* mode bit for named pipe (Unix, 9P2000.u) */
|
||||
#define P9DMSOCKET 0x00100000 /* mode bit for socket (Unix, 9P2000.u) */
|
||||
#define P9DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */
|
||||
#define P9DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */
|
||||
|
||||
enum { P9DMREAD = 0x4, /* mode bit for read permission */
|
||||
P9DMWRITE = 0x2, /* mode bit for write permission */
|
||||
P9DMEXEC = 0x1 /* mode bit for execute permission */
|
||||
};
|
||||
|
||||
|
||||
typedef struct Qid Qid;
|
||||
struct Qid {
|
||||
unsigned char type;
|
||||
unsigned int version;
|
||||
unsigned long long path;
|
||||
/* internal use only */
|
||||
unsigned char dir_type;
|
||||
};
|
||||
|
||||
/* stat structure */
|
||||
typedef struct Stat {
|
||||
unsigned short type;
|
||||
unsigned int dev;
|
||||
Qid qid;
|
||||
unsigned int mode;
|
||||
unsigned int atime;
|
||||
unsigned int mtime;
|
||||
unsigned long long length;
|
||||
char *name;
|
||||
char *uid;
|
||||
char *gid;
|
||||
char *muid;
|
||||
} Stat;
|
||||
|
||||
/* from fcall(3) in plan9port */
|
||||
typedef struct Fcall {
|
||||
unsigned char type;
|
||||
unsigned short tag;
|
||||
unsigned int fid;
|
||||
union {
|
||||
struct { /* Tversion, Rversion */
|
||||
unsigned int msize;
|
||||
char *version;
|
||||
};
|
||||
struct { /* Tflush */
|
||||
unsigned short oldtag;
|
||||
};
|
||||
struct { /* Rerror */
|
||||
char *ename;
|
||||
};
|
||||
struct { /* Ropen, Rcreate */
|
||||
Qid qid; /* +Rattach */
|
||||
unsigned int iounit;
|
||||
};
|
||||
struct { /* Rauth */
|
||||
Qid aqid;
|
||||
};
|
||||
struct { /* Tauth, Tattach */
|
||||
unsigned int afid;
|
||||
char *uname;
|
||||
char *aname;
|
||||
};
|
||||
struct { /* Tcreate */
|
||||
unsigned int perm;
|
||||
char *name;
|
||||
unsigned char mode; /* +Topen */
|
||||
};
|
||||
struct { /* Twalk */
|
||||
unsigned int newfid;
|
||||
unsigned short nwname;
|
||||
char *wname[IXP_MAX_WELEM];
|
||||
};
|
||||
struct { /* Rwalk */
|
||||
unsigned short nwqid;
|
||||
Qid wqid[IXP_MAX_WELEM];
|
||||
};
|
||||
struct { /* Twrite */
|
||||
unsigned long long offset; /* +Tread */
|
||||
/* +Rread */
|
||||
unsigned int count; /* +Tread */
|
||||
char *data;
|
||||
};
|
||||
struct { /* Twstat, Rstat */
|
||||
unsigned short nstat;
|
||||
unsigned char *stat;
|
||||
};
|
||||
};
|
||||
} Fcall;
|
||||
|
||||
typedef struct IXPServer IXPServer;
|
||||
typedef struct IXPConn IXPConn;
|
||||
typedef struct Intmap Intmap;
|
||||
|
||||
typedef struct Intlist Intlist;
|
||||
struct Intmap {
|
||||
unsigned long nhash;
|
||||
Intlist **hash;
|
||||
};
|
||||
|
||||
struct IXPConn {
|
||||
IXPServer *srv;
|
||||
void *aux;
|
||||
int fd;
|
||||
void (*read) (IXPConn *);
|
||||
void (*close) (IXPConn *);
|
||||
char closed;
|
||||
|
||||
/* Implementation details */
|
||||
/* do not use */
|
||||
IXPConn *next;
|
||||
};
|
||||
|
||||
struct IXPServer {
|
||||
int running;
|
||||
IXPConn *conn;
|
||||
int maxfd;
|
||||
fd_set rd;
|
||||
};
|
||||
|
||||
typedef struct IXPClient {
|
||||
int fd;
|
||||
unsigned int root_fid;
|
||||
Qid root_qid;
|
||||
Fcall ifcall;
|
||||
Fcall ofcall;
|
||||
char *errstr;
|
||||
} IXPClient;
|
||||
|
||||
typedef struct P9Conn P9Conn;
|
||||
typedef struct Fid {
|
||||
P9Conn *conn;
|
||||
Intmap *map;
|
||||
char *uid;
|
||||
void *aux;
|
||||
unsigned long fid;
|
||||
Qid qid;
|
||||
signed char omode;
|
||||
} Fid;
|
||||
|
||||
typedef struct P9Req P9Req;
|
||||
struct P9Req {
|
||||
P9Conn *conn;
|
||||
Fid *fid;
|
||||
Fid *newfid;
|
||||
P9Req *oldreq;
|
||||
Fcall ifcall;
|
||||
Fcall ofcall;
|
||||
void *aux;
|
||||
};
|
||||
|
||||
typedef struct P9Srv {
|
||||
void (*attach)(P9Req *r);
|
||||
void (*clunk)(P9Req *r);
|
||||
void (*create)(P9Req *r);
|
||||
void (*flush)(P9Req *r);
|
||||
void (*open)(P9Req *r);
|
||||
void (*read)(P9Req *r);
|
||||
void (*remove)(P9Req *r);
|
||||
void (*stat)(P9Req *r);
|
||||
void (*walk)(P9Req *r);
|
||||
void (*write)(P9Req *r);
|
||||
void (*freefid)(Fid *f);
|
||||
} P9Srv;
|
||||
|
||||
/* client.c */
|
||||
extern int ixp_client_dial(IXPClient *c, char *address, unsigned int rootfid);
|
||||
extern void ixp_client_hangup(IXPClient *c);
|
||||
extern int ixp_client_remove(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
extern int ixp_client_create(IXPClient *c, unsigned int dirfid, char *name,
|
||||
unsigned int perm, unsigned char mode);
|
||||
extern int ixp_client_walk(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
extern int ixp_client_stat(IXPClient *c, unsigned int newfid, char *filepath);
|
||||
extern int ixp_client_walkopen(IXPClient *c, unsigned int newfid, char *filepath,
|
||||
unsigned char mode);
|
||||
extern int ixp_client_open(IXPClient *c, unsigned int newfid, unsigned char mode);
|
||||
extern int ixp_client_read(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset, void *result,
|
||||
unsigned int res_len);
|
||||
extern int ixp_client_write(IXPClient *c, unsigned int fid,
|
||||
unsigned long long offset,
|
||||
unsigned int count, unsigned char *data);
|
||||
extern int ixp_client_close(IXPClient *c, unsigned int fid);
|
||||
extern int ixp_client_do_fcall(IXPClient * c);
|
||||
|
||||
/* convert.c */
|
||||
extern void ixp_pack_u8(unsigned char **msg, int *msize, unsigned char val);
|
||||
extern void ixp_unpack_u8(unsigned char **msg, int *msize, unsigned char *val);
|
||||
extern void ixp_pack_u16(unsigned char **msg, int *msize, unsigned short val);
|
||||
extern void ixp_unpack_u16(unsigned char **msg, int *msize, unsigned short *val);
|
||||
extern void ixp_pack_u32(unsigned char **msg, int *msize, unsigned int val);
|
||||
extern void ixp_unpack_u32(unsigned char **msg, int *msize, unsigned int *val);
|
||||
extern void ixp_pack_u64(unsigned char **msg, int *msize, unsigned long long val);
|
||||
extern void ixp_unpack_u64(unsigned char **msg, int *msize, unsigned long long *val);
|
||||
extern void ixp_pack_string(unsigned char **msg, int *msize, const char *s);
|
||||
extern void ixp_unpack_strings(unsigned char **msg, int *msize, unsigned short n, char **strings);
|
||||
extern void ixp_unpack_string(unsigned char **msg, int *msize, char **string, unsigned short *len);
|
||||
extern void ixp_pack_data(unsigned char **msg, int *msize, unsigned char *data,
|
||||
unsigned int datalen);
|
||||
extern void ixp_unpack_data(unsigned char **msg, int *msize, unsigned char **data,
|
||||
unsigned int datalen);
|
||||
extern void ixp_pack_prefix(unsigned char *msg, unsigned int size,
|
||||
unsigned char id, unsigned short tag);
|
||||
extern void ixp_unpack_prefix(unsigned char **msg, unsigned int *size,
|
||||
unsigned char *id, unsigned short *tag);
|
||||
extern void ixp_pack_qid(unsigned char **msg, int *msize, Qid *qid);
|
||||
extern void ixp_unpack_qid(unsigned char **msg, int *msize, Qid *qid);
|
||||
extern void ixp_pack_stat(unsigned char **msg, int *msize, Stat *stat);
|
||||
extern void ixp_unpack_stat(unsigned char **msg, int *msize, Stat *stat);
|
||||
|
||||
/* request.c */
|
||||
extern void respond(P9Req *r, char *error);
|
||||
extern void serve_9pcon(IXPConn *c);
|
||||
|
||||
/* intmap.c */
|
||||
extern void initmap(Intmap *m, unsigned long nhash, void *hash);
|
||||
extern void incref_map(Intmap *m);
|
||||
extern void decref_map(Intmap *m);
|
||||
extern void freemap(Intmap *map, void (*destroy)(void*));
|
||||
extern void execmap(Intmap *map, void (*destroy)(void*));
|
||||
extern void* lookupkey(Intmap *map, unsigned long id);
|
||||
extern void* insertkey(Intmap *map, unsigned long id, void *v);
|
||||
extern int caninsertkey(Intmap *map, unsigned long id, void *v);
|
||||
extern void* deletekey(Intmap *map, unsigned long id);
|
||||
|
||||
/* message.c */
|
||||
extern unsigned short ixp_sizeof_stat(Stat *stat);
|
||||
extern unsigned int ixp_fcall2msg(void *msg, Fcall *fcall, unsigned int msglen);
|
||||
extern unsigned int ixp_msg2fcall(Fcall *call, void *msg, unsigned int msglen);
|
||||
|
||||
/* server.c */
|
||||
extern IXPConn *ixp_server_open_conn(IXPServer *s, int fd, void *aux,
|
||||
void (*read)(IXPConn *c), void (*close)(IXPConn *c));
|
||||
extern void ixp_server_close_conn(IXPConn *c);
|
||||
extern char *ixp_server_loop(IXPServer *s);
|
||||
extern unsigned int ixp_server_receive_fcall(IXPConn *c, Fcall *fcall);
|
||||
extern int ixp_server_respond_fcall(IXPConn *c, Fcall *fcall);
|
||||
extern int ixp_server_respond_error(IXPConn *c, Fcall *fcall, char *errstr);
|
||||
extern void ixp_server_close(IXPServer *s);
|
||||
|
||||
/* socket.c */
|
||||
extern int ixp_connect_sock(char *address);
|
||||
extern int ixp_create_sock(char *address, char **errstr);
|
||||
|
||||
/* transport.c */
|
||||
extern unsigned int ixp_send_message(int fd, void *msg, unsigned int msize, char **errstr);
|
||||
extern unsigned int ixp_recv_message(int fd, void *msg, unsigned int msglen, char **errstr);
|
243
libixp/message.c
243
libixp/message.c
@ -1,243 +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_fcall2msg(void *msg, Fcall *fcall, unsigned int msglen)
|
||||
{
|
||||
unsigned int i = sizeof(unsigned char) +
|
||||
sizeof(unsigned short) + sizeof(unsigned int);
|
||||
int msize = msglen - i;
|
||||
unsigned char *p = msg + i;
|
||||
|
||||
switch (fcall->type) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
ixp_pack_u32(&p, &msize, fcall->msize);
|
||||
ixp_pack_string(&p, &msize, fcall->version);
|
||||
break;
|
||||
case TAUTH:
|
||||
ixp_pack_u32(&p, &msize, fcall->afid);
|
||||
ixp_pack_string(&p, &msize, fcall->uname);
|
||||
ixp_pack_string(&p, &msize, fcall->aname);
|
||||
break;
|
||||
case RAUTH:
|
||||
ixp_pack_qid(&p, &msize, &fcall->aqid);
|
||||
break;
|
||||
case RATTACH:
|
||||
ixp_pack_qid(&p, &msize, &fcall->qid);
|
||||
break;
|
||||
case TATTACH:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_u32(&p, &msize, fcall->afid);
|
||||
ixp_pack_string(&p, &msize, fcall->uname);
|
||||
ixp_pack_string(&p, &msize, fcall->aname);
|
||||
break;
|
||||
case RERROR:
|
||||
ixp_pack_string(&p, &msize, fcall->ename);
|
||||
break;
|
||||
case TFLUSH:
|
||||
ixp_pack_u16(&p, &msize, fcall->oldtag);
|
||||
break;
|
||||
case TWALK:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_u32(&p, &msize, fcall->newfid);
|
||||
ixp_pack_u16(&p, &msize, fcall->nwname);
|
||||
for(i = 0; i < fcall->nwname; i++)
|
||||
ixp_pack_string(&p, &msize, fcall->wname[i]);
|
||||
break;
|
||||
case RWALK:
|
||||
ixp_pack_u16(&p, &msize, fcall->nwqid);
|
||||
for(i = 0; i < fcall->nwqid; i++)
|
||||
ixp_pack_qid(&p, &msize, &fcall->wqid[i]);
|
||||
break;
|
||||
case TOPEN:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_u8(&p, &msize, fcall->mode);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
ixp_pack_qid(&p, &msize, &fcall->qid);
|
||||
ixp_pack_u32(&p, &msize, fcall->iounit);
|
||||
break;
|
||||
case TCREATE:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_string(&p, &msize, fcall->name);
|
||||
ixp_pack_u32(&p, &msize, fcall->perm);
|
||||
ixp_pack_u8(&p, &msize, fcall->mode);
|
||||
break;
|
||||
case TREAD:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_u64(&p, &msize, fcall->offset);
|
||||
ixp_pack_u32(&p, &msize, fcall->count);
|
||||
break;
|
||||
case RREAD:
|
||||
ixp_pack_u32(&p, &msize, fcall->count);
|
||||
ixp_pack_data(&p, &msize, (unsigned char *)fcall->data, fcall->count);
|
||||
break;
|
||||
case TWRITE:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_u64(&p, &msize, fcall->offset);
|
||||
ixp_pack_u32(&p, &msize, fcall->count);
|
||||
ixp_pack_data(&p, &msize, (unsigned char *)fcall->data, fcall->count);
|
||||
break;
|
||||
case RWRITE:
|
||||
ixp_pack_u32(&p, &msize, fcall->count);
|
||||
break;
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
break;
|
||||
case RSTAT:
|
||||
ixp_pack_u16(&p, &msize, fcall->nstat);
|
||||
ixp_pack_data(&p, &msize, fcall->stat, fcall->nstat);
|
||||
break;
|
||||
case TWSTAT:
|
||||
ixp_pack_u32(&p, &msize, fcall->fid);
|
||||
ixp_pack_u16(&p, &msize, fcall->nstat);
|
||||
ixp_pack_data(&p, &msize, fcall->stat, fcall->nstat);
|
||||
break;
|
||||
}
|
||||
|
||||
if(msize < 0)
|
||||
return 0;
|
||||
|
||||
msize = msglen - msize;
|
||||
ixp_pack_prefix(msg, msize, fcall->type, fcall->tag);
|
||||
return msize;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ixp_msg2fcall(Fcall *fcall, void *msg, unsigned int msglen)
|
||||
{
|
||||
int msize;
|
||||
unsigned int i, tsize;
|
||||
unsigned short len;
|
||||
unsigned char *p = msg;
|
||||
ixp_unpack_prefix(&p, (unsigned int *)&msize, &fcall->type, &fcall->tag);
|
||||
tsize = msize;
|
||||
|
||||
if(msize > msglen) /* bad message */
|
||||
return 0;
|
||||
switch (fcall->type) {
|
||||
case TVERSION:
|
||||
case RVERSION:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->msize);
|
||||
ixp_unpack_string(&p, &msize, &fcall->version, &len);
|
||||
break;
|
||||
case TAUTH:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->afid);
|
||||
ixp_unpack_string(&p, &msize, &fcall->uname, &len);
|
||||
ixp_unpack_string(&p, &msize, &fcall->aname, &len);
|
||||
break;
|
||||
case RAUTH:
|
||||
ixp_unpack_qid(&p, &msize, &fcall->aqid);
|
||||
break;
|
||||
case RATTACH:
|
||||
ixp_unpack_qid(&p, &msize, &fcall->qid);
|
||||
break;
|
||||
case TATTACH:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_u32(&p, &msize, &fcall->afid);
|
||||
ixp_unpack_string(&p, &msize, &fcall->uname, &len);
|
||||
ixp_unpack_string(&p, &msize, &fcall->aname, &len);
|
||||
break;
|
||||
case RERROR:
|
||||
ixp_unpack_string(&p, &msize, &fcall->ename, &len);
|
||||
break;
|
||||
case TFLUSH:
|
||||
ixp_unpack_u16(&p, &msize, &fcall->oldtag);
|
||||
break;
|
||||
case TWALK:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_u32(&p, &msize, &fcall->newfid);
|
||||
ixp_unpack_u16(&p, &msize, &fcall->nwname);
|
||||
ixp_unpack_strings(&p, &msize, fcall->nwname, fcall->wname);
|
||||
break;
|
||||
case RWALK:
|
||||
ixp_unpack_u16(&p, &msize, &fcall->nwqid);
|
||||
for(i = 0; i < fcall->nwqid; i++)
|
||||
ixp_unpack_qid(&p, &msize, &fcall->wqid[i]);
|
||||
break;
|
||||
case TOPEN:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_u8(&p, &msize, &fcall->mode);
|
||||
break;
|
||||
case ROPEN:
|
||||
case RCREATE:
|
||||
ixp_unpack_qid(&p, &msize, &fcall->qid);
|
||||
ixp_unpack_u32(&p, &msize, &fcall->iounit);
|
||||
break;
|
||||
case TCREATE:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_string(&p, &msize, &fcall->name, &len);
|
||||
ixp_unpack_u32(&p, &msize, &fcall->perm);
|
||||
ixp_unpack_u8(&p, &msize, &fcall->mode);
|
||||
break;
|
||||
case TREAD:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_u64(&p, &msize, &fcall->offset);
|
||||
ixp_unpack_u32(&p, &msize, &fcall->count);
|
||||
break;
|
||||
case RREAD:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->count);
|
||||
ixp_unpack_data(&p, &msize, (void *)&fcall->data, fcall->count);
|
||||
break;
|
||||
case TWRITE:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_u64(&p, &msize, &fcall->offset);
|
||||
ixp_unpack_u32(&p, &msize, &fcall->count);
|
||||
ixp_unpack_data(&p, &msize, (void *)&fcall->data, fcall->count);
|
||||
break;
|
||||
case RWRITE:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->count);
|
||||
break;
|
||||
case TCLUNK:
|
||||
case TREMOVE:
|
||||
case TSTAT:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
break;
|
||||
case RSTAT:
|
||||
ixp_unpack_u16(&p, &msize, &len);
|
||||
ixp_unpack_data(&p, &msize, &fcall->stat, len);
|
||||
break;
|
||||
case TWSTAT:
|
||||
ixp_unpack_u32(&p, &msize, &fcall->fid);
|
||||
ixp_unpack_u16(&p, &msize, &len);
|
||||
ixp_unpack_data(&p, &msize, &fcall->stat, len);
|
||||
break;
|
||||
}
|
||||
|
||||
if(msize > 0)
|
||||
return tsize;
|
||||
return 0;
|
||||
}
|
394
libixp/request.c
394
libixp/request.c
@ -1,394 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMVI Kris Maglione <fbsdaemon at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include "ixp.h"
|
||||
|
||||
static void ixp_handle_req(P9Req *r);
|
||||
|
||||
/* We use string literals rather than arrays here because
|
||||
* they're allocated in a readonly section */
|
||||
static char
|
||||
*Eduptag = "tag in use",
|
||||
*Edupfid = "fid in use",
|
||||
*Enofunc = "function not implemented",
|
||||
*Ebotch = "9P protocol botch",
|
||||
*Enofile = "file does not exist",
|
||||
*Enofid = "fid does not exist",
|
||||
*Enotag = "tag does not exist",
|
||||
*Enotdir = "not a directory",
|
||||
*Einterrupted = "interrupted",
|
||||
*Eisdir = "cannot perform operation on a directory";
|
||||
|
||||
enum { TAG_BUCKETS = 64,
|
||||
FID_BUCKETS = 64 };
|
||||
|
||||
struct P9Conn {
|
||||
Intmap tagmap;
|
||||
void *taghash[TAG_BUCKETS];
|
||||
Intmap fidmap;
|
||||
void *fidhash[FID_BUCKETS];
|
||||
P9Srv *srv;
|
||||
IXPConn *conn;
|
||||
unsigned int msize;
|
||||
unsigned char *buf;
|
||||
unsigned int ref;
|
||||
};
|
||||
|
||||
static void
|
||||
free_p9conn(P9Conn *pc) {
|
||||
free(pc->buf);
|
||||
free(pc);
|
||||
}
|
||||
|
||||
static void *
|
||||
createfid(Intmap *map, int fid, P9Conn *pc) {
|
||||
Fid *f = cext_emallocz(sizeof(Fid));
|
||||
f->fid = fid;
|
||||
f->omode = -1;
|
||||
f->map = map;
|
||||
f->conn = pc;
|
||||
if(caninsertkey(map, fid, f))
|
||||
return f;
|
||||
free(f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static int
|
||||
destroyfid(P9Conn *pc, unsigned long fid) {
|
||||
Fid *f;
|
||||
if(!(f = deletekey(&pc->fidmap, fid)))
|
||||
return 0;
|
||||
if(pc->srv->freefid)
|
||||
pc->srv->freefid(f);
|
||||
free(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ixp_server_handle_fcall(IXPConn *c)
|
||||
{
|
||||
Fcall fcall = {0};
|
||||
P9Conn *pc = c->aux;
|
||||
P9Req *req;
|
||||
unsigned int msize;
|
||||
char *errstr = nil;
|
||||
|
||||
if(!(msize = ixp_recv_message(c->fd, pc->buf, pc->msize, &errstr)))
|
||||
goto Fail;
|
||||
if(!(msize = ixp_msg2fcall(&fcall, pc->buf, IXP_MAX_MSG)))
|
||||
goto Fail;
|
||||
|
||||
req = cext_emallocz(sizeof(P9Req));
|
||||
req->conn = pc;
|
||||
req->ifcall = fcall;
|
||||
pc->conn = c;
|
||||
|
||||
if(lookupkey(&pc->tagmap, fcall.tag))
|
||||
return respond(req, Eduptag);
|
||||
|
||||
insertkey(&pc->tagmap, fcall.tag, req);
|
||||
return ixp_handle_req(req);
|
||||
|
||||
Fail:
|
||||
ixp_server_close_conn(c);
|
||||
}
|
||||
|
||||
static void
|
||||
ixp_handle_req(P9Req *r)
|
||||
{
|
||||
P9Conn *pc = r->conn;
|
||||
P9Srv *srv = pc->srv;
|
||||
|
||||
switch(r->ifcall.type) {
|
||||
default:
|
||||
respond(r, Enofunc);
|
||||
break;
|
||||
case TVERSION:
|
||||
if(!strncmp(r->ifcall.version, "9P", 3)) {
|
||||
r->ofcall.version = "9P";
|
||||
}else
|
||||
if(!strncmp(r->ifcall.version, "9P2000", 7)) {
|
||||
r->ofcall.version = "9P2000";
|
||||
}else{
|
||||
r->ofcall.version = "unknown";
|
||||
}
|
||||
r->ofcall.msize = r->ifcall.msize;
|
||||
respond(r, nil);
|
||||
break;
|
||||
case TATTACH:
|
||||
if(!(r->fid = createfid(&pc->fidmap, r->ifcall.fid, pc)))
|
||||
return respond(r, Edupfid);
|
||||
/* attach is a required function */
|
||||
srv->attach(r);
|
||||
break;
|
||||
case TCLUNK:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if(!srv->clunk)
|
||||
return respond(r, nil);
|
||||
srv->clunk(r);
|
||||
break;
|
||||
case TFLUSH:
|
||||
if(!(r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag)))
|
||||
return respond(r, Enotag);
|
||||
if(!srv->flush)
|
||||
return respond(r, Enofunc);
|
||||
srv->flush(r);
|
||||
break;
|
||||
case TCREATE:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if(r->fid->omode != -1)
|
||||
return respond(r, Ebotch);
|
||||
if(!(r->fid->qid.type&P9QTDIR))
|
||||
return respond(r, Enotdir);
|
||||
if(!pc->srv->create)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->create(r);
|
||||
break;
|
||||
case TOPEN:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if((r->fid->qid.type&P9QTDIR) && (r->ifcall.mode|P9ORCLOSE) != (P9OREAD|P9ORCLOSE))
|
||||
return respond(r, Eisdir);
|
||||
r->ofcall.qid = r->fid->qid;
|
||||
if(!pc->srv->open)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->open(r);
|
||||
break;
|
||||
case TREAD:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if(r->fid->omode == -1 || r->fid->omode == P9OWRITE)
|
||||
return respond(r, Ebotch);
|
||||
if(!pc->srv->read)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->read(r);
|
||||
break;
|
||||
case TREMOVE:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if(!pc->srv->remove)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->remove(r);
|
||||
break;
|
||||
case TSTAT:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if(!pc->srv->stat)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->stat(r);
|
||||
break;
|
||||
case TWALK:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if(r->fid->omode != -1)
|
||||
return respond(r, "cannot walk from an open fid");
|
||||
if(r->ifcall.nwname && !(r->fid->qid.type&P9QTDIR))
|
||||
return respond(r, Enotdir);
|
||||
if((r->ifcall.fid != r->ifcall.newfid)) {
|
||||
if(!(r->newfid = createfid(&pc->fidmap, r->ifcall.newfid, pc)))
|
||||
return respond(r, Edupfid);
|
||||
}else
|
||||
r->newfid = r->fid;
|
||||
if(!pc->srv->walk)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->walk(r);
|
||||
break;
|
||||
case TWRITE:
|
||||
if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid)))
|
||||
return respond(r, Enofid);
|
||||
if((r->fid->omode&3) != P9OWRITE && (r->fid->omode&3) != P9ORDWR)
|
||||
return respond(r, "write on fid not opened for writing");
|
||||
if(!pc->srv->write)
|
||||
return respond(r, Enofunc);
|
||||
pc->srv->write(r);
|
||||
break;
|
||||
/* Still to be implemented: flush, wstat, auth */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
respond(P9Req *r, char *error) {
|
||||
P9Conn *pc = r->conn;
|
||||
switch(r->ifcall.type) {
|
||||
default:
|
||||
if(!error)
|
||||
cext_assert(!"Respond called on unsupported fcall type");
|
||||
break;
|
||||
case TVERSION:
|
||||
cext_assert(!error);
|
||||
free(r->ifcall.version);
|
||||
pc->msize = (r->ofcall.msize < IXP_MAX_MSG) ? r->ofcall.msize : IXP_MAX_MSG;
|
||||
free(pc->buf);
|
||||
pc->buf = cext_emallocz(r->ofcall.msize);
|
||||
break;
|
||||
case TATTACH:
|
||||
if(error)
|
||||
destroyfid(pc, r->fid->fid);
|
||||
free(r->ifcall.uname);
|
||||
free(r->ifcall.aname);
|
||||
break;
|
||||
case TOPEN:
|
||||
case TCREATE:
|
||||
if(!error) {
|
||||
r->fid->omode = r->ifcall.mode;
|
||||
r->fid->qid = r->ofcall.qid;
|
||||
}
|
||||
free(r->ifcall.name);
|
||||
r->ofcall.iounit = pc->msize - sizeof(unsigned long);
|
||||
break;
|
||||
case TWALK:
|
||||
if(error || r->ofcall.nwqid < r->ifcall.nwname) {
|
||||
if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
|
||||
destroyfid(pc, r->newfid->fid);
|
||||
if(!error && r->ofcall.nwqid == 0)
|
||||
error = Enofile;
|
||||
}else{
|
||||
if(r->ofcall.nwqid == 0)
|
||||
r->newfid->qid = r->fid->qid;
|
||||
else
|
||||
r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
|
||||
}
|
||||
free(*r->ifcall.wname);
|
||||
break;
|
||||
case TWRITE:
|
||||
free(r->ifcall.data);
|
||||
break;
|
||||
case TREMOVE:
|
||||
if(r->fid)
|
||||
destroyfid(pc, r->fid->fid);
|
||||
break;
|
||||
case TCLUNK:
|
||||
if(r->fid)
|
||||
destroyfid(pc, r->fid->fid);
|
||||
if(!pc->conn && r->ifcall.tag == IXP_NOTAG)
|
||||
pc->ref--;
|
||||
break;
|
||||
case TFLUSH:
|
||||
if((r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag)))
|
||||
respond(r->oldreq, Einterrupted);
|
||||
if(!pc->conn && r->ifcall.tag == IXP_NOTAG)
|
||||
pc->ref--;
|
||||
break;
|
||||
case TREAD:
|
||||
case TSTAT:
|
||||
break;
|
||||
/* Still to be implemented: flush, wstat, auth */
|
||||
}
|
||||
|
||||
r->ofcall.tag = r->ifcall.tag;
|
||||
if(!error)
|
||||
r->ofcall.type = r->ifcall.type + 1;
|
||||
else {
|
||||
r->ofcall.type = RERROR;
|
||||
r->ofcall.ename = error;
|
||||
}
|
||||
|
||||
if(pc->conn)
|
||||
ixp_server_respond_fcall(pc->conn, &r->ofcall);
|
||||
|
||||
switch(r->ofcall.type) {
|
||||
case RSTAT:
|
||||
free(r->ofcall.stat);
|
||||
break;
|
||||
case RREAD:
|
||||
free(r->ofcall.data);
|
||||
break;
|
||||
}
|
||||
|
||||
deletekey(&pc->tagmap, r->ifcall.tag);;
|
||||
free(r);
|
||||
|
||||
if(!pc->conn && pc->ref == 0)
|
||||
free_p9conn(pc);
|
||||
}
|
||||
|
||||
/* Pending request cleanup */
|
||||
static void
|
||||
ixp_void_request(void *t) {
|
||||
P9Req *r, *tr;
|
||||
P9Conn *pc;
|
||||
|
||||
r = t;
|
||||
pc = r->conn;
|
||||
|
||||
tr = cext_emallocz(sizeof(P9Req));
|
||||
tr->conn = pc;
|
||||
tr->ifcall.type = TFLUSH;
|
||||
tr->ifcall.tag = IXP_NOTAG;
|
||||
tr->ifcall.oldtag = r->ifcall.tag;
|
||||
ixp_handle_req(tr);
|
||||
}
|
||||
|
||||
/* Open FID cleanup */
|
||||
static void
|
||||
ixp_void_fid(void *t) {
|
||||
P9Conn *pc;
|
||||
P9Req *tr;
|
||||
Fid *f;
|
||||
|
||||
f = t;
|
||||
pc = f->conn;
|
||||
|
||||
tr = cext_emallocz(sizeof(P9Req));
|
||||
tr->fid = f;
|
||||
tr->conn = pc;
|
||||
tr->ifcall.type = TCLUNK;
|
||||
tr->ifcall.tag = IXP_NOTAG;
|
||||
tr->ifcall.fid = f->fid;
|
||||
ixp_handle_req(tr);
|
||||
}
|
||||
|
||||
static void
|
||||
ixp_p9conn_incref(void *r) {
|
||||
P9Conn *pc = *(P9Conn **)r;
|
||||
pc->ref++;
|
||||
}
|
||||
|
||||
/* To cleanup a connction, we increase the ref count for
|
||||
* each open FID and pending request and generate clunk and
|
||||
* flush requests. As each request is responded to and each
|
||||
* FID is clunked, we decrease the ref count. When the ref
|
||||
* count is 0, we free the P9Conn and its buf. The IXPConn
|
||||
* is taken care of in server.c */
|
||||
static void
|
||||
ixp_cleanup_conn(IXPConn *c) {
|
||||
P9Conn *pc = c->aux;
|
||||
pc->conn = nil;
|
||||
pc->ref = 1;
|
||||
execmap(&pc->tagmap, ixp_p9conn_incref);
|
||||
execmap(&pc->fidmap, ixp_p9conn_incref);
|
||||
if(pc->ref > 1) {
|
||||
execmap(&pc->tagmap, ixp_void_request);
|
||||
execmap(&pc->fidmap, ixp_void_fid);
|
||||
}
|
||||
if(--pc->ref == 0)
|
||||
free_p9conn(pc);
|
||||
}
|
||||
|
||||
/* Handle incoming 9P connections */
|
||||
void
|
||||
serve_9pcon(IXPConn *c) {
|
||||
int fd = accept(c->fd, nil, nil);
|
||||
if(fd < 0)
|
||||
return;
|
||||
|
||||
P9Conn *pc = cext_emallocz(sizeof(P9Conn));
|
||||
pc->srv = c->aux;
|
||||
|
||||
/* XXX */
|
||||
pc->msize = 1024;
|
||||
pc->buf = cext_emallocz(pc->msize);
|
||||
|
||||
initmap(&pc->tagmap, TAG_BUCKETS, &pc->taghash);
|
||||
initmap(&pc->fidmap, FID_BUCKETS, &pc->fidhash);
|
||||
|
||||
ixp_server_open_conn(c->srv, fd, pc, ixp_server_handle_fcall, ixp_cleanup_conn);
|
||||
}
|
130
libixp/server.c
130
libixp/server.c
@ -1,130 +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"
|
||||
|
||||
static unsigned char *msg[IXP_MAX_MSG];
|
||||
|
||||
IXPConn *
|
||||
ixp_server_open_conn(IXPServer *s, int fd, void *aux,
|
||||
void (*read)(IXPConn *c), void (*close)(IXPConn *c))
|
||||
{
|
||||
IXPConn *c = cext_emallocz(sizeof(IXPConn));
|
||||
c->fd = fd;
|
||||
c->aux = aux;
|
||||
c->srv = s;
|
||||
c->read = read;
|
||||
c->close = close;
|
||||
c->next = s->conn;
|
||||
s->conn = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
ixp_server_close_conn(IXPConn *c)
|
||||
{
|
||||
IXPServer *s = c->srv;
|
||||
IXPConn **tc;
|
||||
for(tc=&s->conn; *tc && *tc != c; tc=&(*tc)->next);
|
||||
cext_assert(*tc == c);
|
||||
*tc = c->next;
|
||||
c->closed = 1;
|
||||
if(c->close)
|
||||
c->close(c);
|
||||
else
|
||||
shutdown(c->fd, SHUT_RDWR);
|
||||
close(c->fd);
|
||||
free(c);
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_select(IXPServer *s)
|
||||
{
|
||||
IXPConn **c;
|
||||
FD_ZERO(&s->rd);
|
||||
for(c=&s->conn; *c; *c && (c=&(*c)->next)) {
|
||||
if(s->maxfd < (*c)->fd)
|
||||
s->maxfd = (*c)->fd;
|
||||
if((*c)->read)
|
||||
FD_SET((*c)->fd, &s->rd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_conns(IXPServer *s)
|
||||
{
|
||||
IXPConn *c, *n;
|
||||
for((c=s->conn) && (n=c->next); c; (c=n) && (n=c->next))
|
||||
if(FD_ISSET(c->fd, &s->rd) && c->read)
|
||||
c->read(c);
|
||||
}
|
||||
|
||||
char *
|
||||
ixp_server_loop(IXPServer *s)
|
||||
{
|
||||
int r;
|
||||
s->running = 1;
|
||||
|
||||
/* main loop */
|
||||
while(s->running) {
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ixp_server_receive_fcall(IXPConn *c, Fcall *fcall)
|
||||
{
|
||||
unsigned int msize;
|
||||
char *errstr = 0;
|
||||
if(!(msize = ixp_recv_message(c->fd, msg, IXP_MAX_MSG, &errstr))) {
|
||||
ixp_server_close_conn(c);
|
||||
return 0;
|
||||
}
|
||||
return ixp_msg2fcall(fcall, msg, IXP_MAX_MSG);
|
||||
}
|
||||
|
||||
int
|
||||
ixp_server_respond_fcall(IXPConn *c, Fcall *fcall)
|
||||
{
|
||||
char *errstr;
|
||||
unsigned int msize = ixp_fcall2msg(msg, fcall, IXP_MAX_MSG);
|
||||
if(c->closed)
|
||||
return 0;
|
||||
if(ixp_send_message(c->fd, msg, msize, &errstr) != msize) {
|
||||
ixp_server_close_conn(c);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ixp_server_close(IXPServer *s)
|
||||
{
|
||||
IXPConn *c, *next;
|
||||
for(c=s->conn; c; c=next) {
|
||||
next=c->next;
|
||||
ixp_server_close_conn(c);
|
||||
}
|
||||
}
|
200
libixp/socket.c
200
libixp/socket.c
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ixp.h"
|
||||
|
||||
static int
|
||||
connect_unix_sock(char *address)
|
||||
{
|
||||
int fd = 0;
|
||||
struct sockaddr_un addr = { 0 };
|
||||
socklen_t su_len;
|
||||
|
||||
/* init */
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, address, sizeof(addr.sun_path));
|
||||
su_len = sizeof(struct sockaddr) + strlen(addr.sun_path);
|
||||
|
||||
if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
if(connect(fd, (struct sockaddr *) &addr, su_len)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_inet_sock(char *host)
|
||||
{
|
||||
int fd = 0;
|
||||
struct sockaddr_in addr = { 0 };
|
||||
struct hostent *hp;
|
||||
char *port = strrchr(host, '!');
|
||||
unsigned int prt;
|
||||
|
||||
if(!port)
|
||||
return -1;
|
||||
*port = 0;
|
||||
port++;
|
||||
if(sscanf(port, "%d", &prt) != 1)
|
||||
return -1;
|
||||
|
||||
/* init */
|
||||
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
hp = gethostbyname(host);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(prt);
|
||||
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
|
||||
|
||||
if(connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in))) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_connect_sock(char *address)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if((p = strchr(address, '!'))) {
|
||||
*p = 0;
|
||||
p++;
|
||||
|
||||
if(!strncmp(address, "unix", 5))
|
||||
return connect_unix_sock(p);
|
||||
else if(!strncmp(address, "tcp", 4))
|
||||
return connect_inet_sock(p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
create_inet_sock(char *host, char **errstr)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr = { 0 };
|
||||
struct hostent *hp;
|
||||
char *port = strrchr(host, '!');
|
||||
unsigned int prt;
|
||||
|
||||
if(!port) {
|
||||
*errstr = "no port provided in address";
|
||||
return -1;
|
||||
}
|
||||
*port = 0;
|
||||
port++;
|
||||
if(sscanf(port, "%d", &prt) != 1) {
|
||||
*errstr = "invalid port number";
|
||||
return -1;
|
||||
}
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
*errstr = "cannot open socket";
|
||||
return -1;
|
||||
}
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(prt);
|
||||
|
||||
if(!strncmp(host, "*", 2))
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else if((hp = gethostbyname(host)))
|
||||
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
|
||||
else {
|
||||
*errstr = "cannot translate hostname to an address";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
|
||||
*errstr = "cannot bind socket";
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(listen(fd, IXP_MAX_CACHE) < 0) {
|
||||
*errstr = "cannot listen on socket";
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
create_unix_sock(char *file, char **errstr)
|
||||
{
|
||||
int fd;
|
||||
int yes = 1;
|
||||
struct sockaddr_un addr = { 0 };
|
||||
socklen_t su_len;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
*errstr = "cannot open socket";
|
||||
return -1;
|
||||
}
|
||||
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &yes, sizeof(yes)) < 0) {
|
||||
*errstr = "cannot set socket options";
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, file, sizeof(addr.sun_path));
|
||||
su_len = sizeof(struct sockaddr) + strlen(addr.sun_path);
|
||||
|
||||
unlink(file); /* remove old socket, if any */
|
||||
if(bind(fd, (struct sockaddr *) &addr, su_len) < 0) {
|
||||
*errstr = "cannot bind socket";
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
chmod(file, S_IRWXU);
|
||||
|
||||
if(listen(fd, IXP_MAX_CACHE) < 0) {
|
||||
*errstr = "cannot listen on socket";
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
ixp_create_sock(char *address, char **errstr)
|
||||
{
|
||||
char *p = strchr(address, '!');
|
||||
char *addr, *type;
|
||||
|
||||
if(!p) {
|
||||
*errstr = "no socket type defined";
|
||||
return -1;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
addr = &p[1];
|
||||
type = address; /* unix, inet */
|
||||
|
||||
if(!strncmp(type, "unix", 5))
|
||||
return create_unix_sock(addr, errstr);
|
||||
else if(!strncmp(type, "tcp", 4))
|
||||
return create_inet_sock(addr, errstr);
|
||||
else
|
||||
*errstr = "unkown socket type";
|
||||
return -1;
|
||||
}
|
@ -1,77 +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 <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"
|
||||
|
||||
unsigned int
|
||||
ixp_send_message(int fd, void *msg, unsigned int msize, char **errstr)
|
||||
{
|
||||
unsigned int num = 0;
|
||||
int r;
|
||||
|
||||
/* send message */
|
||||
while(num < msize) {
|
||||
r = write(fd, msg + num, msize - num);
|
||||
if(r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if(r < 1) {
|
||||
*errstr = "broken pipe";
|
||||
return 0;
|
||||
}
|
||||
num += r;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ixp_recv_data(int fd, void *msg, unsigned int msize, char **errstr)
|
||||
{
|
||||
unsigned int num = 0;
|
||||
int r = 0;
|
||||
|
||||
/* receive data */
|
||||
while(num < msize) {
|
||||
r = read(fd, msg + num, msize - num);
|
||||
if(r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if(r < 1) {
|
||||
*errstr = "broken pipe";
|
||||
return 0;
|
||||
}
|
||||
num += r;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ixp_recv_message(int fd, void *msg, unsigned int msglen, char **errstr)
|
||||
{
|
||||
unsigned int msize;
|
||||
|
||||
/* receive header */
|
||||
if(ixp_recv_data(fd, msg, sizeof(unsigned int), errstr) !=
|
||||
sizeof(unsigned int))
|
||||
return 0;
|
||||
ixp_unpack_u32((void *)&msg, nil, &msize);
|
||||
if(msize > msglen) {
|
||||
*errstr = "invalid message header";
|
||||
return 0;
|
||||
}
|
||||
/* receive message */
|
||||
if(ixp_recv_data(fd, msg, msize - sizeof(unsigned int), errstr)
|
||||
!= msize - sizeof(unsigned int))
|
||||
return 0;
|
||||
return msize;
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cext.h>
|
||||
#include "blitz.h"
|
||||
|
||||
void
|
||||
@ -30,7 +29,7 @@ blitz_draw_label(BlitzBrush *b, char *text)
|
||||
return;
|
||||
|
||||
shortened = 0;
|
||||
cext_strlcpy(buf, text, sizeof(buf));
|
||||
strncpy(buf, text, sizeof(buf));
|
||||
len = strlen(buf);
|
||||
gcv.foreground = b->color.fg;
|
||||
gcv.background = b->color.bg;
|
||||
|
@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <cext.h>
|
||||
|
||||
#include "blitz.h"
|
||||
|
||||
@ -14,7 +13,7 @@ xloadcolor(Blitz *blitz, char *colstr)
|
||||
XColor color;
|
||||
char col[8];
|
||||
|
||||
cext_strlcpy(col, colstr, sizeof(col));
|
||||
strncpy(col, colstr, sizeof(col));
|
||||
col[7] = 0;
|
||||
XAllocNamedColor(blitz->dpy,
|
||||
DefaultColormap(blitz->dpy, blitz->screen), col, &color, &color);
|
||||
|
@ -7,8 +7,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <cext.h>
|
||||
|
||||
#include "blitz.h"
|
||||
|
||||
unsigned int
|
||||
@ -16,7 +14,7 @@ blitz_textwidth_l(BlitzFont *font, char *text, unsigned int len)
|
||||
{
|
||||
if(font->set) {
|
||||
XRectangle r;
|
||||
XmbTextExtents(font->set, text, len, nil, &r);
|
||||
XmbTextExtents(font->set, text, len, NULL, &r);
|
||||
return r.width;
|
||||
}
|
||||
return XTextWidth(font->xfont, text, len);
|
||||
@ -32,7 +30,7 @@ void
|
||||
blitz_loadfont(Blitz *blitz, BlitzFont *font)
|
||||
{
|
||||
char *fontname = font->fontstr;
|
||||
char **missing = nil, *def = "?";
|
||||
char **missing = NULL, *def = "?";
|
||||
int n;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
@ -45,7 +43,7 @@ blitz_loadfont(Blitz *blitz, BlitzFont *font)
|
||||
XFreeStringList(missing);
|
||||
if(font->set) {
|
||||
XFreeFontSet(blitz->dpy, font->set);
|
||||
font->set = nil;
|
||||
font->set = NULL;
|
||||
}
|
||||
}
|
||||
if(font->set) {
|
||||
@ -68,7 +66,7 @@ blitz_loadfont(Blitz *blitz, BlitzFont *font)
|
||||
else {
|
||||
if(font->xfont)
|
||||
XFreeFont(blitz->dpy, font->xfont);
|
||||
font->xfont = nil;
|
||||
font->xfont = NULL;
|
||||
font->xfont = XLoadQueryFont(blitz->dpy, fontname);
|
||||
if (!font->xfont) {
|
||||
fontname = "fixed";
|
||||
|
@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Heavy access test of wmiiwm's fs
|
||||
|
||||
dump_fs() {
|
||||
echo $1
|
||||
wmiir read $1|wmiir write $1;
|
||||
for i in `wmiir read $1|awk '{print $10}'`
|
||||
do
|
||||
if test $i != "event"
|
||||
then
|
||||
dump_fs $1/$i
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
while true
|
||||
do
|
||||
dump_fs /
|
||||
done
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Loading…
Reference in New Issue
Block a user