libixp

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

commit b7bfd010155bef9f052d67b31844590dde225683
parent f46e453181e8fe692a9cca3ab627cef4a235f6af
Author: Kris Maglione <jg@suckless.org>
Date:   Mon, 26 Mar 2007 00:49:25 -0400

New tree layout and make system. New API. New client and ixpc code.

Diffstat:
LICENSE | 22----------------------
LICENSE.p9p | 251-------------------------------------------------------------------------------
Makefile | 100++++++-------------------------------------------------------------------------
README | 14--------------
client.c | 195-------------------------------------------------------------------------------
cmd/Makefile | 9+++++++++
cmd/ixpc.c | 334+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
config.mk | 42++++++++++++++++++++----------------------
convert.c | 225-------------------------------------------------------------------------------
fcall.h | 54------------------------------------------------------
fcall.h.nounion | 41-----------------------------------------
include/Makefile | 6++++++
include/ixp.h | 319+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
intmap.c | 135-------------------------------------------------------------------------------
ixp.h | 325-------------------------------------------------------------------------------
ixpc.1 | 92-------------------------------------------------------------------------------
ixpc.c | 300-------------------------------------------------------------------------------
libixp/LICENSE | 22++++++++++++++++++++++
libixp/LICENSE.p9p | 251+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/Makefile | 22++++++++++++++++++++++
libixp/README | 14++++++++++++++
libixp/client.c | 398+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/convert.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/fcall.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/fcall.h.nounion | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/intmap.c | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/message.c | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/request.c | 461+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/server.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/socket.c | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/transport.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/util.c | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/Makefile | 8++++++++
man/ixpc.1 | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
message.c | 239-------------------------------------------------------------------------------
mk/common.mk | 18++++++++++++++++++
mk/dir.mk | 25+++++++++++++++++++++++++
mk/hdr.mk | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mk/ixp.mk | 1+
mk/lib.mk | 24++++++++++++++++++++++++
mk/man.mk | 7+++++++
mk/many.mk | 18++++++++++++++++++
mk/one.mk | 22++++++++++++++++++++++
request.c | 435-------------------------------------------------------------------------------
server.c | 121-------------------------------------------------------------------------------
socket.c | 187-------------------------------------------------------------------------------
transport.c | 71-----------------------------------------------------------------------
util.c | 147-------------------------------------------------------------------------------
util/compile | 20++++++++++++++++++++
util/link | 31+++++++++++++++++++++++++++++++
50 files changed, 3381 insertions(+), 2969 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -1,22 +0,0 @@ -MIT/X Consortium License - -(C)opyright MMV-MMVI Anselm R. Garbe <garbeam@gmail.com> -(C)opyright MMVI Kris Maglione <bsdaemon at comcast dot net> - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/LICENSE.p9p b/LICENSE.p9p @@ -1,251 +0,0 @@ -The bulk of this software is derived from Plan 9 and is thus distributed -under the Lucent Public License, Version 1.02, reproduced below. - -There are a few exceptions: libutf, libfmt, and libregexp are distributed -under simpler BSD-like boilerplates. See the LICENSE files in those -directories. There are other exceptions, also marked with LICENSE files -in their directories. - -The bitmap fonts in the font/luc, font/lucm, font/lucsans, and font/pelm -directory are copyright B&H Inc. and distributed under more restricted -terms under agreement with B&H. See the NOTICE file in those directories. - -=================================================================== - -Lucent Public License Version 1.02 - -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC -LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE -PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - - a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original - Program, and - b. in the case of each Contributor, - - i. changes to the Program, and - ii. additions to the Program; - - where such changes and/or additions to the Program were added to the - Program by such Contributor itself or anyone acting on such - Contributor's behalf, and the Contributor explicitly consents, in - accordance with Section 3C, to characterization of the changes and/or - additions as Contributions. - -"Contributor" means LUCENT and any other entity that has Contributed a -Contribution to the Program. - -"Distributor" means a Recipient that distributes the Program, -modifications to the Program, or any part thereof. - -"Licensed Patents" mean patent claims licensable by a Contributor -which are necessarily infringed by the use or sale of its Contribution -alone or when combined with the Program. - -"Original Program" means the original version of the software -accompanying this Agreement as released by LUCENT, including source -code, object code and documentation, if any. - -"Program" means the Original Program and Contributions or any part -thereof - -"Recipient" means anyone who receives the Program under this -Agreement, including all Contributors. - -2. GRANT OF RIGHTS - - a. Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free copyright - license to reproduce, prepare derivative works of, publicly display, - publicly perform, distribute and sublicense the Contribution of such - Contributor, if any, and such derivative works, in source code and - object code form. - - b. Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free patent - license under Licensed Patents to make, use, sell, offer to sell, - import and otherwise transfer the Contribution of such Contributor, if - any, in source code and object code form. The patent license granted - by a Contributor shall also apply to the combination of the - Contribution of that Contributor and the Program if, at the time the - Contribution is added by the Contributor, such addition of the - Contribution causes such combination to be covered by the Licensed - Patents. The patent license granted by a Contributor shall not apply - to (i) any other combinations which include the Contribution, nor to - (ii) Contributions of other Contributors. No hardware per se is - licensed hereunder. - - c. Recipient understands that although each Contributor grants the - licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. Each - Contributor disclaims any liability to Recipient for claims brought by - any other entity based on infringement of intellectual property rights - or otherwise. As a condition to exercising the rights and licenses - granted hereunder, each Recipient hereby assumes sole responsibility - to secure any other intellectual property rights needed, if any. For - example, if a third party patent license is required to allow - Recipient to distribute the Program, it is Recipient's responsibility - to acquire that license before distributing the Program. - - d. Each Contributor represents that to its knowledge it has sufficient - copyright rights in its Contribution, if any, to grant the copyright - license set forth in this Agreement. - -3. REQUIREMENTS - -A. Distributor may choose to distribute the Program in any form under -this Agreement or under its own license agreement, provided that: - - a. it complies with the terms and conditions of this Agreement; - - b. if the Program is distributed in source code or other tangible - form, a copy of this Agreement or Distributor's own license agreement - is included with each copy of the Program; and - - c. if distributed under Distributor's own license agreement, such - license agreement: - - i. effectively disclaims on behalf of all Contributors all warranties - and conditions, express and implied, including warranties or - conditions of title and non-infringement, and implied warranties or - conditions of merchantability and fitness for a particular purpose; - ii. effectively excludes on behalf of all Contributors all liability - for damages, including direct, indirect, special, incidental and - consequential damages, such as lost profits; and - iii. states that any provisions which differ from this Agreement are - offered by that Contributor alone and not by any other party. - -B. Each Distributor must include the following in a conspicuous - location in the Program: - - Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights - Reserved. - -C. In addition, each Contributor must identify itself as the -originator of its Contribution in a manner that reasonably allows -subsequent Recipients to identify the originator of the Contribution. -Also, each Contributor must agree that the additions and/or changes -are intended to be a Contribution. Once a Contribution is contributed, -it may not thereafter be revoked. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain -responsibilities with respect to end users, business partners and the -like. While this license is intended to facilitate the commercial use -of the Program, the Distributor who includes the Program in a -commercial product offering should do so in a manner which does not -create potential liability for Contributors. Therefore, if a -Distributor includes the Program in a commercial product offering, -such Distributor ("Commercial Distributor") hereby agrees to defend -and indemnify every Contributor ("Indemnified Contributor") against -any losses, damages and costs (collectively"Losses") arising from -claims, lawsuits and other legal actions brought by a third party -against the Indemnified Contributor to the extent caused by the acts -or omissions of such Commercial Distributor in connection with its -distribution of the Program in a commercial product offering. The -obligations in this section do not apply to any claims or Losses -relating to any actual or alleged intellectual property infringement. -In order to qualify, an Indemnified Contributor must: a) promptly -notify the Commercial Distributor in writing of such claim, and b) -allow the Commercial Distributor to control, and cooperate with the -Commercial Distributor in, the defense and any related settlement -negotiations. The Indemnified Contributor may participate in any such -claim at its own expense. - -For example, a Distributor might include the Program in a commercial -product offering, Product X. That Distributor is then a Commercial -Distributor. If that Commercial Distributor then makes performance -claims, or offers warranties related to Product X, those performance -claims and warranties are such Commercial Distributor's responsibility -alone. Under this section, the Commercial Distributor would have to -defend claims against the Contributors related to those performance -claims and warranties, and if a court requires any Contributor to pay -any damages as a result, the Commercial Distributor must pay those -damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS -PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY -WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY -OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely -responsible for determining the appropriateness of using and -distributing the Program and assumes all risks associated with its -exercise of rights under this Agreement, including but not limited to -the risks and costs of program errors, compliance with applicable -laws, damage to or loss of data, programs or equipment, and -unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR -ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING -WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR -DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. EXPORT CONTROL - -Recipient agrees that Recipient alone is responsible for compliance -with the United States export administration regulations (and the -export control laws and regulation of any other countries). - -8. GENERAL - -If any provision of this Agreement is invalid or unenforceable under -applicable law, it shall not affect the validity or enforceability of -the remainder of the terms of this Agreement, and without further -action by the parties hereto, such provision shall be reformed to the -minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against a Contributor with -respect to a patent applicable to software (including a cross-claim or -counterclaim in a lawsuit), then any patent licenses granted by that -Contributor to such Recipient under this Agreement shall terminate as -of the date such litigation is filed. In addition, if Recipient -institutes patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Program -itself (excluding combinations of the Program with other software or -hardware) infringes such Recipient's patent(s), then such Recipient's -rights granted under Section 2(b) shall terminate as of the date such -litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it -fails to comply with any of the material terms or conditions of this -Agreement and does not cure such failure in a reasonable period of -time after becoming aware of such noncompliance. If all Recipient's -rights under this Agreement terminate, Recipient agrees to cease use -and distribution of the Program as soon as reasonably practicable. -However, Recipient's obligations under this Agreement and any licenses -granted by Recipient relating to the Program shall continue and -survive. - -LUCENT may publish new versions (including revisions) of this -Agreement from time to time. Each new version of the Agreement will be -given a distinguishing version number. The Program (including -Contributions) may always be distributed subject to the version of the -Agreement under which it was received. In addition, after a new -version of the Agreement is published, Contributor may elect to -distribute the Program (including its Contributions) under the new -version. No one other than LUCENT has the right to modify this -Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, -Recipient receives no rights or licenses to the intellectual property -of any Contributor under this Agreement, whether expressly, by -implication, estoppel or otherwise. All rights in the Program not -expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and -the intellectual property laws of the United States of America. No -party to this Agreement will bring a legal action under this Agreement -more than one year after the cause of action arose. Each party waives -its rights to a jury trial in any resulting litigation. - diff --git a/Makefile b/Makefile @@ -1,95 +1,9 @@ -# libixp - simple 9P client-/server-library -# (C)opyright MMIV-MMVII Anselm R. Garbe +ROOT=. +include ${ROOT}/mk/hdr.mk -include config.mk +DIRS = libixp \ + cmd \ + include \ + man -SRC = client.c convert.c intmap.c message.c request.c server.c socket.c \ - transport.c util.c -SRCIXPC = ixpc.c -OBJ = ${SRC:.c=.o} -OBJIXPC = ${SRCIXPC:.c=.o} ${OBJ} - -#all: options libixp.a libixp.so ixpc -all: options libixp.a ixpc - -options: - @echo libixp build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" - @echo "SOFLAGS = ${SOFLAGS}" - @echo "LD = ${LD}" - -.c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< - -${OBJ}: config.mk ixp.h ixp_fcall.h - -ixp_fcall.h: fcall.h fcall.h.nounion config.mk - @cat fcall.h${FCALL_H_VERSION} > ixp_fcall.h - -libixp.a: ${OBJ} - @echo AR $@ - @${AR} $@ ${OBJ} - @${RANLIB} $@ - -libixp.so: ${OBJ} - @echo LD $@ - @${LD} ${SOFLAGS} -o $@ ${OBJ} - -ixpc: ${OBJIXPC} - @echo LD $@ - @${LD} -o $@ ${OBJIXPC} ${LDFLAGS} -lixp - -clean: - @echo cleaning - @rm -f ixpc libixp.a libixp.so ${OBJ} ${OBJIXPC} libixp-${VERSION}.tar.gz - -dist: clean - @echo creating dist tarball - @mkdir -p libixp-${VERSION} - @cp -R LICENSE LICENSE.p9p Makefile README config.mk ixp.h fcall.h fcall.h.nounion ixpc.1 ${SRC} ${SRCIXPC} libixp-${VERSION} - @tar -cf libixp-${VERSION}.tar libixp-${VERSION} - @gzip libixp-${VERSION}.tar - @rm -rf libixp-${VERSION} - -install: all - @echo installing header to ${DESTDIR}${PREFIX}/include - @mkdir -p ${DESTDIR}${PREFIX}/include - @cp -f ixp.h ${DESTDIR}${PREFIX}/include - @chmod 644 ${DESTDIR}${PREFIX}/include/ixp.h - @cp -f ixp_fcall.h ${DESTDIR}${PREFIX}/include - @chmod 644 ${DESTDIR}${PREFIX}/include/ixp_fcall.h - @echo installing library to ${DESTDIR}${PREFIX}/lib - @mkdir -p ${DESTDIR}${PREFIX}/lib - @cp -f libixp.a ${DESTDIR}${PREFIX}/lib - @chmod 644 ${DESTDIR}${PREFIX}/lib/libixp.a -# @cp -f libixp.so ${DESTDIR}${PREFIX}/lib/libixp.so.${VERSION} -# @chmod 755 ${DESTDIR}${PREFIX}/lib/libixp.so.${VERSION} -# @ln -s libixp.so.${VERSION} ${DESTDIR}${PREFIX}/lib/libixp.so - @echo installing ixpc to ${DESTDIR}${PREFIX}/bin - @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f ixpc ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/ixpc - @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 - @mkdir -p ${DESTDIR}${MANPREFIX}/man1 - @sed 's/VERSION/${VERSION}/g' < ixpc.1 > ${DESTDIR}${MANPREFIX}/man1/ixpc.1 - @chmod 644 ${DESTDIR}${MANPREFIX}/man1/ixpc.1 - -uninstall: - @echo removing header file from ${DESTDIR}${PREFIX}/include - @rm -f ${DESTDIR}${PREFIX}/include/ixp.h - @rm -f ${DESTDIR}${PREFIX}/include/ixp_fcall.h - - @echo removing library file from ${DESTDIR}${PREFIX}/lib - @rm -f ${DESTDIR}${PREFIX}/lib/libixp.a - @echo removing shared object file from ${DESTDIR}${PREFIX}/lib -# @rm -f ${DESTDIR}${PREFIX}/lib/libixp.so -# @rm -f ${DESTDIR}${PREFIX}/lib/libixp.so.${VERSION} - @echo removing ipx client from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/ixpc - @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 - @rm -f ${DESTDIR}${MANPREFIX}/man1/ixpc.1 - -.PHONY: all options clean dist install uninstall +include ${ROOT}/mk/dir.mk diff --git a/README b/README @@ -1,14 +0,0 @@ -libixp - simple 9P client-/server-library -========================================= -libixp is an extremly simple 9P stand-alone library. - - -Installation ------------- -Edit config.mk to match your local setup. libixp is installed into -/usr/local by default. - -Afterwards enter the following command to build and install libixp -(if necessary as root): - - $ make clean install diff --git a/client.c b/client.c @@ -1,195 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -int -ixp_client_do_fcall(IXPClient *c) { - static uchar msg[IXP_MAX_MSG]; - uint 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, uint 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, uint 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, uint dirfid, char *name, - uint perm, uchar 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, uint newfid, char *filepath) { - int i; - char *wname[IXP_MAX_WELEM], *fp; - - c->ifcall.type = TWALK; - c->ifcall.fid = c->root_fid; - c->ifcall.newfid = newfid; - if(filepath) { - // c->ifcall.name = filepath; // tcreate overlaps with twalk !!! - fp = ixp_estrdup(filepath); - c->ifcall.nwname = ixp_tokenize(wname, IXP_MAX_WELEM, fp, '/'); // was "c->ifcall.name" - for(i = 0; i < c->ifcall.nwname; i++) - c->ifcall.wname[i] = wname[i]; - } - i = ixp_client_do_fcall(c); - free(fp); - return i; -} - -int -ixp_client_stat(IXPClient *c, uint 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, uint newfid, uchar 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, uint newfid, char *filepath, - uchar mode) -{ - if(ixp_client_walk(c, newfid, filepath) == -1) - return -1; - return ixp_client_open(c, newfid, mode); -} - -int -ixp_client_read(IXPClient *c, uint fid, uvlong offset, - void *result, uint res_len) -{ - uint 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, uint fid, - uvlong offset, uint count, - uchar *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, uint 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); - } -} diff --git a/cmd/Makefile b/cmd/Makefile @@ -0,0 +1,9 @@ +ROOT=.. +include ${ROOT}/mk/hdr.mk +include ${ROOT}/mk/ixp.mk + +TARG = ixpc +OBJ = ixpc +LIB = ${ROOT}/libixp/libixp.a + +include ${ROOT}/mk/one.mk diff --git a/cmd/ixpc.c b/cmd/ixpc.c @@ -0,0 +1,334 @@ +/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include "ixp.h" + +char *argv0; +#define ARGBEGIN int _argi, _argtmp, _inargv=0; char *_argv; \ + if(!argv0)argv0=ARGF(); _inargv=1; \ + while(argc && argv[0][0] == '-') { \ + _argi=1; _argv=*argv++; argc++; \ + while(_argv[_argi]) switch(_argv[_argi++]) +#define ARGEND }_inargv=0;USED(_argtmp);USED(_argv);USED(_argi) +#define ARGF() ((_inargv && _argv[_argi]) ? \ + (_argtmp=_argi, _argi=strlen(_argv), _argv+_argtmp) \ + : ((argc > 0) ? (argc--, *argv++) : ((char*)0))) +#define EARGF(f) ((_inargv && _argv[_argi]) ? \ + (_argtmp=_argi, _argi=strlen(_argv), _argv+_argtmp) \ + : ((argc > 0) ? (argc--, *argv++) : ((f), (char*)0))) +#define USED(x) if(x){}else +#define SET(x) ((x)=0) + +static IxpClient *client; + +static void +usage() { + ixp_eprint("usage: ixpc [-a <address>] {create | read | ls [-l] | remove | write} <file>\n" + " ixpc [-a <address>] xwrite <file> <data>\n" + " ixpc -v\n"); +} + +/* Utility Functions */ +static void +write_data(IxpCFid *fid) { + void *buf; + uint len; + + buf = ixp_emalloc(fid->iounit);; + while((len = read(0, buf, fid->iounit)) > 0) + if(ixp_write(fid, buf, len) != len) + ixp_eprint("ixpc: cannot write file: %s\n", errstr); + /* do an explicit empty write when no writing has been done yet */ + if(fid->offset == 0) + if(ixp_write(fid, buf, 0) != 0) + ixp_eprint("ixpc: cannot write file: %s\n", errstr); + free(buf); +} + +static int +comp_stat(const void *s1, const void *s2) { + Stat *st1, *st2; + + st1 = (Stat*)s1; + 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(uint mode) { + static char buf[16]; + + buf[0]='-'; + if(mode & P9_DMDIR) + buf[0]='d'; + 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(uint val) { + static char buf[32]; + + ctime_r((time_t*)&val, 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&P9_DMDIR) && strcmp(s->name, "/")) + fprintf(stdout, "%s/\n", s->name); + else + fprintf(stdout, "%s\n", s->name); + } +} + +/* Service Functions */ +static int +xwrite(int argc, char *argv[]) { + IxpCFid *fid; + char *file; + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + file = EARGF(usage()); + fid = ixp_open(client, file, P9_OWRITE); + if(fid == nil) + ixp_eprint("ixpc: error: Can't open file '%s': %s\n", file, errstr); + + write_data(fid); + return 0; +} + +static int +xawrite(int argc, char *argv[]) { + IxpCFid *fid; + char *file, *buf, *arg; + int nbuf, mbuf, len; + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + file = EARGF(usage()); + fid = ixp_open(client, file, P9_OWRITE); + if(fid == nil) + ixp_eprint("ixpc: error: Can't open file '%s': %s\n", file, errstr); + + nbuf = 0; + mbuf = 128; + buf = ixp_emalloc(mbuf); + while(argc) { + arg = ARGF(); + len = strlen(arg); + if(nbuf + len > mbuf) { + mbuf <<= 1; + buf = ixp_erealloc(buf, mbuf); + } + memcpy(buf+nbuf, arg, len); + nbuf += len; + if(argc) + buf[nbuf++] = ' '; + } + + if(ixp_write(fid, buf, nbuf) == -1) + ixp_eprint("ixpc: cannot write file '%s': %s\n", file, errstr); + return 0; +} + +static int +xcreate(int argc, char *argv[]) { + IxpCFid *fid; + char *file; + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + file = EARGF(usage()); + fid = ixp_create(client, file, 0777, P9_OREAD); + if(fid == nil) + ixp_eprint("ixpc: error: Can't create file '%s': %s\n", file, errstr); + + if((fid->qid.type&P9_DMDIR) == 0) + write_data(fid); + + return 0; +} + +static int +xremove(int argc, char *argv[]) { + char *file; + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + file = EARGF(usage()); + if(ixp_remove(client, file) == 0) + ixp_eprint("ixpc: error: Can't remove file '%s': %s\n", file, errstr); + return 0; +} + +static int +xread(int argc, char *argv[]) { + IxpCFid *fid; + char *file, *buf; + int count; + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + file = EARGF(usage()); + fid = ixp_open(client, file, P9_OREAD); + if(fid == nil) + ixp_eprint("ixpc: error: Can't open file '%s': %s\n", file, errstr); + + buf = ixp_emalloc(fid->iounit); + while((count = ixp_read(fid, buf, fid->iounit)) > 0) + write(1, buf, count); + + if(count == -1) + ixp_eprint("ixpc: cannot read file/directory '%s': %s\n", file, errstr); + + return 0; +} + +static int +xls(int argc, char *argv[]) { + Message m; + Stat *stat; + IxpCFid *fid; + char *file, *buf; + int lflag, dflag, count, nstat, mstat, i; + + lflag = dflag = 0; + + ARGBEGIN{ + case 'l': + lflag++; + break; + case 'd': + dflag++; + break; + default: + usage(); + }ARGEND; + + file = EARGF(usage()); + + stat = ixp_stat(client, file); + if(stat == nil) + ixp_eprint("ixpc: cannot stat file '%s': %s\n", file, errstr); + + if(dflag || (stat->mode&P9_DMDIR) == 0) { + print_stat(stat, lflag); + ixp_freestat(stat); + return 0; + } + ixp_freestat(stat); + + fid = ixp_open(client, file, P9_OREAD); + if(fid == nil) + ixp_eprint("ixpc: error: Can't open file '%s': %s\n", file, errstr); + + nstat = 0; + mstat = 16; + stat = ixp_emalloc(sizeof(*stat) * mstat); + buf = ixp_emalloc(fid->iounit); + while((count = ixp_read(fid, buf, fid->iounit)) > 0) { + m = ixp_message(buf, count, MsgUnpack); + while(m.pos < m.end) { + if(nstat == mstat) { + mstat <<= 1; + stat = ixp_erealloc(stat, mstat); + } + ixp_pstat(&m, &stat[nstat++]); + } + } + + qsort(stat, nstat, sizeof(*stat), comp_stat); + for(i = 0; i < nstat; i++) { + print_stat(&stat[i], lflag); + ixp_freestat(&stat[i]); + } + free(stat); + + if(count == -1) + ixp_eprint("ixpc: cannot read directory '%s': %s\n", file, errstr); + return 0; +} + +int +main(int argc, char *argv[]) { + int ret; + char *cmd, *address; + + address = getenv("IXP_ADDRESS"); + + ARGBEGIN{ + case 'v': + puts("ixpc-" VERSION ", ©2007 Kris Maglione\n"); + exit(0); + case 'a': + address = EARGF(usage()); + }ARGEND; + + cmd = EARGF(usage()); + + if(!address) + ixp_eprint("ixpc: error: $IXP_ADDRESS not set\n"); + + client = ixp_mount(address); + if(client == nil) + ixp_eprint("ixpc: %s\n", errstr); + + if(!strcmp(cmd, "create")) + ret = xcreate(argc, argv); + else if(!strcmp(cmd, "ls")) + ret = xls(argc, argv); + else if(!strcmp(cmd, "read")) + ret = xread(argc, argv); + else if(!strcmp(cmd, "remove")) + ret = xremove(argc, argv); + else if(!strcmp(cmd, "write")) + ret = xwrite(argc, argv); + else if(!strcmp(cmd, "xwrite")) + ret = xawrite(argc, argv); + else + usage(); + + ixp_unmount(client); + return ret; +} diff --git a/config.mk b/config.mk @@ -1,33 +1,31 @@ -# libixp version -VERSION = 0.3 - # Customize below to fit your system # paths PREFIX = /usr/local -MANPREFIX = ${PREFIX}/share/man +BIN = ${PREFIX}/bin +MAN = ${PREFIX}/share/man +ETC = ${PREFIX}/etc +LIBDIR = ${PREFIX}/lib +INCLUDE = ${PREFIX}/include + +# Includes and libs +INCS = -I. -I${ROOT}/include -I${INCLUDE} -I/usr/include +LIBS = -L/usr/lib -lc -# includes and libs -INCS = -I. -I/usr/include -LIBS = -L/usr/lib -lc -L. +# Flags +CFLAGS = -g -Wall ${INCS} -DVERSION=\"${VERSION}\" +LDFLAGS = -g ${LIBS} -# flags -CFLAGS = -g ${INCS} -DVERSION=\"${VERSION}\" -LDFLAGS = ${LIBS} -SOFLAGS = -fPIC -shared -#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" -#LDFLAGS = -g ${LIBS} +# Compiler +CC = cc -c +# Linker (Under normal circumstances, this should *not* be 'ld') +LD = cc +# Other +AR = ar cr +RANLIB = ranlib # Solaris #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" #LDFLAGS = ${LIBS} -R${PREFIX}/lib -#SOFLAGS = -G -#LIBS += -lsocket -lnsl +#LDFLAGS += -lsocket -lnsl #CFLAGS += -xtarget=ultra -#FCALL_H_VERSION= .nounion - -# compiler and linker -AR = ar cr -CC = cc -LD = ${CC} -RANLIB = ranlib diff --git a/convert.c b/convert.c @@ -1,225 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -/* packode/unpackode stuff */ - -void -ixp_pack_u8(uchar **msg, int *msize, uchar val) { - if(!msize || (*msize -= 1) >= 0) - *(*msg)++ = val; -} - -void -ixp_unpack_u8(uchar **msg, int *msize, uchar *val) { - if(!msize || (*msize -= 1) >= 0) - *val = *(*msg)++; -} - -void -ixp_pack_u16(uchar **msg, int *msize, ushort val) { - if(!msize || (*msize -= 2) >= 0) { - *(*msg)++ = val; - *(*msg)++ = val >> 8; - } -} - -void -ixp_unpack_u16(uchar **msg, int *msize, ushort *val) { - if(!msize || (*msize -= 2) >= 0) { - *val = *(*msg)++; - *val |= *(*msg)++ << 8; - } -} - -void -ixp_pack_u32(uchar **msg, int *msize, uint val) { - if(!msize || (*msize -= 4) >= 0) { - *(*msg)++ = val; - *(*msg)++ = val >> 8; - *(*msg)++ = val >> 16; - *(*msg)++ = val >> 24; - } -} - -void -ixp_unpack_u32(uchar **msg, int *msize, uint *val) { - if(!msize || (*msize -= 4) >= 0) { - *val = *(*msg)++; - *val |= *(*msg)++ << 8; - *val |= *(*msg)++ << 16; - *val |= *(*msg)++ << 24; - } -} - -void -ixp_pack_u64(uchar **msg, int *msize, uvlong 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(uchar **msg, int *msize, uvlong *val) { - if(!msize || (*msize -= 8) >= 0) { - *val |= *(*msg)++; - *val |= *(*msg)++ << 8; - *val |= *(*msg)++ << 16; - *val |= *(*msg)++ << 24; - *val |= (uvlong)*(*msg)++ << 32; - *val |= (uvlong)*(*msg)++ << 40; - *val |= (uvlong)*(*msg)++ << 48; - *val |= (uvlong)*(*msg)++ << 56; - } -} - -void -ixp_pack_string(uchar **msg, int *msize, const char *s) { - ushort 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(uchar **msg, int *msize, ushort n, char **strings) { - uchar *s; - uint i, size; - ushort len; - - size = *msize; - s = *msg; - for(i=0; i<n && size > 0; i++) { - ixp_unpack_u16(&s, &size, &len); - s += len; - size -= len; - } - if(size < 0) - size = 0; - size = *msize - size + n; - if(size <= 0) { - /* So we don't try to free some random value */ - *strings = NULL; - return; - } - s = ixp_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(uchar **msg, int *msize, char **string, ushort *len) { - ixp_unpack_u16(msg, msize, len); - *string = NULL; - if (!msize || (*msize -= *len) >= 0) { - *string = ixp_emalloc(*len+1); - if(*len) - memcpy(*string, *msg, *len); - (*string)[*len] = 0; - *msg += *len; - } -} - -void -ixp_pack_data(uchar **msg, int *msize, uchar *data, uint datalen) { - if(!msize || (*msize -= datalen) >= 0) { - memcpy(*msg, data, datalen); - *msg += datalen; - } -} - -void -ixp_unpack_data(uchar **msg, int *msize, uchar **data, uint datalen) { - if(!msize || (*msize -= datalen) >= 0) { - *data = ixp_emallocz(datalen); - memcpy(*data, *msg, datalen); - *msg += datalen; - } -} - -void -ixp_pack_prefix(uchar *msg, uint size, uchar id, - ushort tag) -{ - ixp_pack_u32(&msg, 0, size); - ixp_pack_u8(&msg, 0, id); - ixp_pack_u16(&msg, 0, tag); -} - -void -ixp_unpack_prefix(uchar **msg, uint *size, uchar *id, - ushort *tag) -{ - int msize; - ixp_unpack_u32(msg, NULL, size); - msize = *size; - ixp_unpack_u8(msg, &msize, id); - ixp_unpack_u16(msg, &msize, tag); -} - -void -ixp_pack_qid(uchar **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(uchar **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(uchar **msg, int *msize, Stat * stat) { - ixp_pack_u16(msg, msize, ixp_sizeof_stat(stat) - sizeof(ushort)); - 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(uchar **msg, int *msize, Stat * stat) { - ushort dummy; - - *msg += sizeof(ushort); - 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); -} diff --git a/fcall.h b/fcall.h @@ -1,54 +0,0 @@ -/* from fcall(3) in plan9port */ -typedef struct Fcall { - uchar type; - ushort tag; - uint fid; - union { - struct { /* Tversion, Rversion */ - uint msize; - char *version; - }; - struct { /* Tflush */ - ushort oldtag; - }; - struct { /* Rerror */ - char *ename; - }; - struct { /* Ropen, Rcreate */ - Qid qid; /* +Rattach */ - uint iounit; - }; - struct { /* Rauth */ - Qid aqid; - }; - struct { /* Tauth, Tattach */ - uint afid; - char *uname; - char *aname; - }; - struct { /* Tcreate */ - uint perm; - char *name; - uchar mode; /* +Topen */ - }; - struct { /* Twalk */ - uint newfid; - ushort nwname; - char *wname[IXP_MAX_WELEM]; - }; - struct { /* Rwalk */ - ushort nwqid; - Qid wqid[IXP_MAX_WELEM]; - }; - struct { /* Twrite */ - uvlong offset; /* +Tread */ - /* +Rread */ - uint count; /* +Tread */ - char *data; - }; - struct { /* Twstat, Rstat */ - ushort nstat; - uchar *stat; - }; - }; -} Fcall; diff --git a/fcall.h.nounion b/fcall.h.nounion @@ -1,41 +0,0 @@ -/* from fcall(3) in plan9port */ -typedef struct Fcall { - unsigned char type; - unsigned short tag; - unsigned int fid; - /* Tversion, Rversion */ - unsigned int msize; - char *version; - /* Tflush */ - unsigned short oldtag; - /* Rerror */ - char *ename; - /* Ropen, Rcreate */ - Qid qid; /* +Rattach */ - unsigned int iounit; - /* Rauth */ - Qid aqid; - /* Tauth, Tattach */ - unsigned int afid; - char *uname; - char *aname; - /* Tcreate */ - unsigned int perm; - char *name; - unsigned char mode; /* +Topen */ - /* Twalk */ - unsigned int newfid; - unsigned short nwname; - char *wname[IXP_MAX_WELEM]; - /* Rwalk */ - unsigned short nwqid; - Qid wqid[IXP_MAX_WELEM]; - /* Twrite */ - unsigned long long offset; /* +Tread */ - /* +Rread */ - unsigned int count; /* +Tread */ - char *data; - /* Twstat, Rstat */ - unsigned short nstat; - unsigned char *stat; -} Fcall; diff --git a/include/Makefile b/include/Makefile @@ -0,0 +1,6 @@ +ROOT= .. +include ${ROOT}/mk/hdr.mk + +HFILES = ixp.h ixp_fcall.h + +include ${ROOT}/mk/common.mk diff --git a/include/ixp.h b/include/ixp.h @@ -0,0 +1,319 @@ +/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ + +#include <sys/types.h> + +#undef uchar +#undef ushort +#undef uint +#undef ulong +#undef vlong +#undef uvlong +#define uchar _ixpuchar +#define ushort _ixpushort +#define uint _ixpuint +#define ulong _ixpulong +#define vlong _ixpvlong +#define uvlong _ixpuvlong +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef long long vlong; +typedef unsigned long long uvlong; + +char *errstr; + +#undef nil +#define nil ((void*)0) + +#define IXP_VERSION "9P2000" +#define IXP_NOTAG ((ushort)~0) /*Dummy tag */ + +enum { + IXP_NOFID = ~0U, + IXP_MAX_VERSION = 32, + IXP_MAX_MSG = 65535, + IXP_MAX_ERROR = 128, + IXP_MAX_CACHE = 32, + 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, +}; + +/* from libc.h in p9p */ +enum { P9_OREAD = 0, /* open for read */ + P9_OWRITE = 1, /* write */ + P9_ORDWR = 2, /* read and write */ + P9_OEXEC = 3, /* execute, == read but check execute permission */ + P9_OTRUNC = 16, /* or'ed in (except for exec), truncate file first */ + P9_OCEXEC = 32, /* or'ed in, close on exec */ + P9_ORCLOSE = 64, /* or'ed in, remove on close */ + P9_ODIRECT = 128, /* or'ed in, direct access */ + P9_ONONBLOCK = 256, /* or'ed in, non-blocking call */ + P9_OEXCL = 0x1000, /* or'ed in, exclusive use (create only) */ + P9_OLOCK = 0x2000, /* or'ed in, lock after opening */ + P9_OAPPEND = 0x4000 /* or'ed in, append only */ +}; + +/* bits in Qid.type */ +enum { QTDIR = 0x80, /* type bit for directories */ + QTAPPEND = 0x40, /* type bit for append only files */ + QTEXCL = 0x20, /* type bit for exclusive use files */ + QTMOUNT = 0x10, /* type bit for mounted channel */ + QTAUTH = 0x08, /* type bit for authentication file */ + QTTMP = 0x04, /* type bit for non-backed-up file */ + QTSYMLINK = 0x02, /* type bit for symbolic link */ + QTFILE = 0x00 /* type bits for plain file */ +}; + +/* bits in Dir.mode */ +enum { + P9_DMWRITE = 0x2, /* mode bit for write permission */ + P9_DMREAD = 0x4, /* mode bit for read permission */ + P9_DMEXEC = 0x1, /* mode bit for execute permission */ +}; +#define P9_DMDIR 0x80000000 /* mode bit for directories */ +#define P9_DMAPPEND 0x40000000 /* mode bit for append only files */ +#define P9_DMEXCL 0x20000000 /* mode bit for exclusive use files */ +#define P9_DMMOUNT 0x10000000 /* mode bit for mounted channel */ +#define P9_DMAUTH 0x08000000 /* mode bit for authentication file */ +#define P9_DMTMP 0x04000000 /* mode bit for non-backed-up file */ +#define P9_DMSYMLINK 0x02000000 /* mode bit for symbolic link (Unix, 9P2000.u) */ +#define P9_DMDEVICE 0x00800000 /* mode bit for device file (Unix, 9P2000.u) */ +#define P9_DMNAMEDPIPE 0x00200000 /* mode bit for named pipe (Unix, 9P2000.u) */ +#define P9_DMSOCKET 0x00100000 /* mode bit for socket (Unix, 9P2000.u) */ +#define P9_DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */ +#define P9_DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */ + +enum { MsgPack, MsgUnpack, }; +typedef struct Message Message; +struct Message { + uchar *data; + uchar *pos; + uchar *end; + uint size; + uint mode; +}; + +typedef struct Qid Qid; +struct Qid { + uchar type; + uint version; + uvlong path; + /* internal use only */ + uchar dir_type; +}; + +#include <ixp_fcall.h> + +/* stat structure */ +typedef struct Stat { + ushort type; + uint dev; + Qid qid; + uint mode; + uint atime; + uint mtime; + uvlong length; + char *name; + char *uid; + char *gid; + char *muid; +} Stat; + +typedef struct IxpServer IxpServer; +typedef struct IxpConn IxpConn; +typedef struct Intmap Intmap; + +typedef struct Intlist Intlist; +struct Intmap { + ulong 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 IxpClient; +typedef struct IxpCFid IxpCFid; + +struct IxpClient { + int fd; + uint msize; + uint lastfid; + + IxpCFid *freefid; + Message msg; +}; + +struct IxpCFid { + uint fid; + Qid qid; + uchar mode; + uint open; + uint iounit; + uvlong offset; + /* internal use only */ + IxpClient *client; + IxpCFid *next; +}; + +typedef struct Ixp9Conn Ixp9Conn; +typedef struct Fid { + Ixp9Conn *conn; + Intmap *map; + char *uid; + void *aux; + ulong fid; + Qid qid; + signed char omode; +} Fid; + +typedef struct Ixp9Req Ixp9Req; +struct Ixp9Req { + Ixp9Conn *conn; + Fid *fid; + Fid *newfid; + Ixp9Req *oldreq; + Fcall ifcall; + Fcall ofcall; + void *aux; +}; + +typedef struct Ixp9Srv { + void (*attach)(Ixp9Req *r); + void (*clunk)(Ixp9Req *r); + void (*create)(Ixp9Req *r); + void (*flush)(Ixp9Req *r); + void (*open)(Ixp9Req *r); + void (*read)(Ixp9Req *r); + void (*remove)(Ixp9Req *r); + void (*stat)(Ixp9Req *r); + void (*walk)(Ixp9Req *r); + void (*write)(Ixp9Req *r); + void (*freefid)(Fid *f); +} Ixp9Srv; + +/* client.c */ +IxpClient *ixp_mount(char *address); +IxpClient *ixp_mountfd(int fd); +void ixp_unmount(IxpClient *c); +IxpCFid *ixp_create(IxpClient *c, char *name, uint perm, uchar mode); +IxpCFid *ixp_open(IxpClient *c, char *name, uchar mode); +int ixp_remove(IxpClient *c, char *path); +Stat *ixp_stat(IxpClient *c, char *path); +int ixp_read(IxpCFid *f, void *buf, uint count); +int ixp_write(IxpCFid *f, void *buf, uint count); +int ixp_close(IxpCFid *f); + +/* convert.c */ +void ixp_pu8(Message *msg, uchar *val); +void ixp_pu16(Message *msg, ushort *val); +void ixp_pu32(Message *msg, uint *val); +void ixp_pu64(Message *msg, uvlong *val); +void ixp_pdata(Message *msg, char **data, uint len); +void ixp_pstring(Message *msg, char **s); +void ixp_pstrings(Message *msg, ushort *num, char *strings[]); +void ixp_pqid(Message *msg, Qid *qid); +void ixp_pqids(Message *msg, ushort *num, Qid qid[]); +void ixp_pstat(Message *msg, Stat *stat); + +/* request.c */ +void respond(Ixp9Req *r, char *error); +void serve_9pcon(IxpConn *c); + +/* intmap.c */ +void initmap(Intmap *m, ulong nhash, void *hash); +void incref_map(Intmap *m); +void decref_map(Intmap *m); +void freemap(Intmap *map, void (*destroy)(void*)); +void execmap(Intmap *map, void (*destroy)(void*)); +void *lookupkey(Intmap *map, ulong id); +void *insertkey(Intmap *map, ulong id, void *v); +void *deletekey(Intmap *map, ulong id); +int caninsertkey(Intmap *map, ulong id, void *v); + +/* message.c */ +ushort ixp_sizeof_stat(Stat *stat); +Message ixp_message(uchar *data, uint length, uint mode); +void ixp_freestat(Stat *s); +void ixp_freefcall(Fcall *fcall); +uint ixp_msg2fcall(Message *msg, Fcall *fcall); +uint ixp_fcall2msg(Message *msg, Fcall *fcall); + +/* server.c */ +IxpConn *ixp_listen(IxpServer *s, int fd, void *aux, + void (*read)(IxpConn *c), + void (*close)(IxpConn *c)); +void ixp_hangup(IxpConn *c); +char *ixp_serverloop(IxpServer *s); +void ixp_server_close(IxpServer *s); + +/* socket.c */ +int ixp_dial(char *address); +int ixp_announce(char *address); + +/* transport.c */ +uint ixp_sendmsg(int fd, Message *msg); +uint ixp_recvmsg(int fd, Message *msg); + +/* util.c */ +void *ixp_emalloc(uint size); +void *ixp_emallocz(uint size); +void *ixp_erealloc(void *ptr, uint size); +char *ixp_estrdup(const char *str); +void ixp_eprint(const char *fmt, ...); +uint ixp_tokenize(char **result, uint reslen, char *str, char delim); +uint ixp_strlcat(char *dst, const char *src, uint siz); diff --git a/intmap.c b/intmap.c @@ -1,135 +0,0 @@ -/* This file is derived from src/lib9p/intmap.c from plan9port */ -/* See LICENCE.p9p for terms of use */ - -#include "ixp.h" -#include <stdlib.h> -#define USED(v) if(v){}else{} - -struct Intlist { - ulong id; - void* aux; - Intlist* link; - uint ref; -}; - -static ulong -hashid(Intmap *map, ulong id) { - return id%map->nhash; -} - -static void -nop(void *v) { - USED(v); -} - -void -initmap(Intmap *m, ulong nhash, void *hash) { - m->nhash = nhash; - m->hash = hash; -} - -static Intlist** -llookup(Intmap *map, ulong 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 == NULL) - 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, ulong id) { - Intlist *f; - void *v; - - if((f = *llookup(map, id))) - v = f->aux; - else - v = NULL; - return v; -} - -void * -insertkey(Intmap *map, ulong id, void *v) { - Intlist *f; - void *ov; - ulong h; - - if((f = *llookup(map, id))){ - /* no decrement for ov because we're returning it */ - ov = f->aux; - f->aux = v; - }else{ - f = ixp_emallocz(sizeof(*f)); - f->id = id; - f->aux = v; - h = hashid(map, id); - f->link = map->hash[h]; - map->hash[h] = f; - ov = NULL; - } - return ov; -} - -int -caninsertkey(Intmap *map, ulong id, void *v) { - Intlist *f; - int rv; - ulong h; - - if(*llookup(map, id)) - rv = 0; - else{ - f = ixp_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, ulong id) { - Intlist **lf, *f; - void *ov; - - if((f = *(lf = llookup(map, id)))){ - ov = f->aux; - *lf = f->link; - free(f); - }else - ov = NULL; - return ov; -} diff --git a/ixp.h b/ixp.h @@ -1,325 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * (C)opyright MMVI Kris Maglione <fbsdaemon at gmail dot com> - * See LICENSE file for license details. - */ - -#include <sys/types.h> - -#define uchar _ixpuchar -#define ushort _ixpushort -#define uint _ixpuint -#define ulong _ixpulong -#define vlong _ixpvlong -#define uvlong _ixpuvlong -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; -typedef long long vlong; -typedef unsigned long long uvlong; - -#define IXP_VERSION "9P2000" -#define IXP_NOTAG (ushort)~0U /*Dummy tag */ -#define IXP_NOFID (uint)~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, -}; - -/* 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 { - uchar type; - uint version; - uvlong path; - /* internal use only */ - uchar dir_type; -}; - -#include <ixp_fcall.h> - -/* stat structure */ -typedef struct Stat { - ushort type; - uint dev; - Qid qid; - uint mode; - uint atime; - uint mtime; - uvlong length; - char *name; - char *uid; - char *gid; - char *muid; -} Stat; - -typedef struct IXPServer IXPServer; -typedef struct IXPConn IXPConn; -typedef struct Intmap Intmap; - -typedef struct Intlist Intlist; -struct Intmap { - ulong 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; - uint 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; - ulong 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, uint rootfid); -extern void ixp_client_hangup(IXPClient *c); -extern int ixp_client_remove(IXPClient *c, uint newfid, char *filepath); -extern int ixp_client_create(IXPClient *c, uint dirfid, char *name, - uint perm, uchar mode); -extern int ixp_client_walk(IXPClient *c, uint newfid, char *filepath); -extern int ixp_client_stat(IXPClient *c, uint newfid, char *filepath); -extern int ixp_client_walkopen(IXPClient *c, uint newfid, char *filepath, - uchar mode); -extern int ixp_client_open(IXPClient *c, uint newfid, uchar mode); -extern int ixp_client_read(IXPClient *c, uint fid, - uvlong offset, void *result, - uint res_len); -extern int ixp_client_write(IXPClient *c, uint fid, - uvlong offset, - uint count, uchar *data); -extern int ixp_client_close(IXPClient *c, uint fid); -extern int ixp_client_do_fcall(IXPClient * c); - -/* convert.c */ -extern void ixp_pack_u8(uchar **msg, int *msize, uchar val); -extern void ixp_unpack_u8(uchar **msg, int *msize, uchar *val); -extern void ixp_pack_u16(uchar **msg, int *msize, ushort val); -extern void ixp_unpack_u16(uchar **msg, int *msize, ushort *val); -extern void ixp_pack_u32(uchar **msg, int *msize, uint val); -extern void ixp_unpack_u32(uchar **msg, int *msize, uint *val); -extern void ixp_pack_u64(uchar **msg, int *msize, uvlong val); -extern void ixp_unpack_u64(uchar **msg, int *msize, uvlong *val); -extern void ixp_pack_string(uchar **msg, int *msize, const char *s); -extern void ixp_unpack_strings(uchar **msg, int *msize, ushort n, char **strings); -extern void ixp_unpack_string(uchar **msg, int *msize, char **string, ushort *len); -extern void ixp_pack_data(uchar **msg, int *msize, uchar *data, - uint datalen); -extern void ixp_unpack_data(uchar **msg, int *msize, uchar **data, - uint datalen); -extern void ixp_pack_prefix(uchar *msg, uint size, - uchar id, ushort tag); -extern void ixp_unpack_prefix(uchar **msg, uint *size, - uchar *id, ushort *tag); -extern void ixp_pack_qid(uchar **msg, int *msize, Qid *qid); -extern void ixp_unpack_qid(uchar **msg, int *msize, Qid *qid); -extern void ixp_pack_stat(uchar **msg, int *msize, Stat *stat); -extern void ixp_unpack_stat(uchar **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, ulong 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, ulong id); -extern void * insertkey(Intmap *map, ulong id, void *v); -extern int caninsertkey(Intmap *map, ulong id, void *v); -extern void * deletekey(Intmap *map, ulong id); - -/* message.c */ -extern ushort ixp_sizeof_stat(Stat *stat); -extern uint ixp_fcall2msg(void *msg, Fcall *fcall, uint msglen); -extern uint ixp_msg2fcall(Fcall *call, void *msg, uint 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 uint 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 uint ixp_send_message(int fd, void *msg, uint msize, char **errstr); -extern uint ixp_recv_message(int fd, void *msg, uint msglen, char **errstr); - -/* util.c */ -extern void * ixp_emalloc(uint size); -extern void * ixp_emallocz(uint size); -extern void ixp_eprint(const char *errstr, ...); -extern void * ixp_erealloc(void *ptr, uint size); -extern char * ixp_estrdup(const char *str); -extern uint ixp_tokenize(char **result, uint reslen, char *str, char delim); -extern uint ixp_strlcat(char *dst, const char *src, uint siz); diff --git a/ixpc.1 b/ixpc.1 @@ -1,92 +0,0 @@ -.TH IXPC 1 ixpc-VERSION -.SH NAME -ixpc \- ixp client -.SH SYNOPSIS -.B ixpc -.RB [ \-a -.IR address ] -.I action -.I file -.br -.B ixpc -.B \-v -.SH DESCRIPTION -.SS Overview -.B ixpc -is a client to access a 9P file server 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 ixpc -will establish a connection. If this option is not supplied, and the -environment variable IXP_ADDRESS is set, -.B ixpc -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 the standard input 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 xwrite -The same as write, but the data is taken from subsequent arguments, -rather than the standard input. -.TP -.B create -Creates file or directory. If the file exists, -nothing is done. -.TP -.B ls -Lists files and directories. -.TP -.B read -Reads file or directory contents. -.TP -.B remove -Removes file or directory tree. -.SH ENVIRONMENT -.TP -IXP_ADDRESS -See above. -.SH EXAMPLES -.TP -.B ixpc ls / -This prints the root directory of the wmii filesystem, if IXP_ADDRESS is set -to the address of wmii. For more information about the contents of this -filesystem, see -.BR wmiiwm (1). -.TP -.B ixpc xwrite /ctl quit -Write 'quit' to the main control file of the wmii filesystem, effectively -leaving wmii. -.TP -.B ixpc write /keys \< keys.txt -Replace the contents of -.I /keys -with the contents of -.I keys.txt -.SH SEE ALSO -.BR wmii (1) - -http://www.cs.bell-labs.com/sys/man/5/INDEX.html diff --git a/ixpc.c b/ixpc.c @@ -1,300 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include <ixp.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <dirent.h> -#include <time.h> - -static IXPClient c = { 0 }; -static char buffer[1024] = { 0 }; - -static void -write_data(uint fid) { - void *data = ixp_emallocz(c.ofcall.iounit); - uvlong offset = 0; - uint len = 0; - - while((len = read(0, data, c.ofcall.iounit)) > 0) { - if(ixp_client_write(&c, fid, offset, len, data) != len) { - fprintf(stderr, "ixpc: 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, "ixpc: cannot write file: %s\n", c.errstr); - free(data); -} - -static int -xcreate(char *file) { - uint 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, "ixpc: cannot walk to '%s': %s\n", file, c.errstr); - return -1; - } - p++; - if(ixp_client_create(&c, fid, p, P9DMWRITE, P9OWRITE) == -1) { - fprintf(stderr, "ixpc: 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, uchar mode) { - /* open */ - uint fid = c.root_fid << 2; - if(ixp_client_walkopen(&c, fid, file, mode) == -1) { - fprintf(stderr, "ixpc: cannot open file '%s': %s\n", file, c.errstr); - return -1; - } - write_data(fid); - return ixp_client_close(&c, fid); -} - -static int -xawrite(char *file, uchar mode) { - /* open */ - uint fid = c.root_fid << 2; - if(ixp_client_walkopen(&c, fid, file, mode) == -1) { - fprintf(stderr, "ixpc: cannot open file '%s': %s\n", file, c.errstr); - return -1; - } - if(ixp_client_write(&c, fid, 0, strlen(buffer), (uchar*)buffer) != strlen(buffer)) - fprintf(stderr, "ixpc: cannot write file: %s\n", c.errstr); - 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(uint mode) { - static char buf[16]; - - if(mode & P9DMDIR) - 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(uint val) { - static char buf[32]; - time_t t = (time_t)(int)val; - char *tstr = ctime(&t); - - strncpy(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 & P9DMDIR) - fprintf(stdout, "%s/\n", s->name); - else - fprintf(stdout, "%s\n", s->name); - } -} - -static void -xls(void *result, uint msize, int details) { - uint n = 0, i = 0; - uchar *p = result; - Stat *dir; - static Stat stat; - - do { - ixp_unpack_stat(&p, NULL, &stat); - n++; - } - while(p - (uchar*)result < msize); - dir = (Stat *)ixp_emallocz(sizeof(Stat) * n); - p = result; - do { - ixp_unpack_stat(&p, NULL, &dir[i++]); - } - while(p - (uchar*)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) { - uint fid = c.root_fid << 2; - /* XXX: buffer overflow */ - Stat *s = ixp_emallocz(sizeof(Stat)); - uchar *buf; - int count; - static uchar result[IXP_MAX_MSG]; - void *data = NULL; - uvlong offset = 0; - - if(ixp_client_stat(&c, fid, file) == -1) { - fprintf(stderr, "ixpc: cannot stat file '%s': %s\n", file, c.errstr); - return -1; - } - buf = c.ofcall.stat; - ixp_unpack_stat(&buf, NULL, s); - if(!(s->mode & P9DMDIR)) { - print_stat(s, details); - fflush(stdout); - return 0; - } - /* directory */ - if(ixp_client_open(&c, fid, P9OREAD) == -1) { - fprintf(stderr, "ixpc: 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 = ixp_erealloc(data, offset + count); - memcpy((uchar*)data + offset, result, count); - offset += count; - } - if(count == -1) { - fprintf(stderr, "ixpc: 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) { - uint fid = c.root_fid << 2; - int count; - static uchar result[IXP_MAX_MSG]; - uvlong offset = 0; - - if(ixp_client_walkopen(&c, fid, file, P9OREAD) == -1) { - fprintf(stderr, "ixpc: 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, "ixpc: cannot read file/directory '%s': %s\n", file, c.errstr); - return -1; - } - return ixp_client_close(&c, fid); -} - -static int -xremove(char *file) { - uint fid; - - fid = c.root_fid << 2; - if(ixp_client_remove(&c, fid, file) == -1) { - fprintf(stderr, "ixpc: 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("IXP_ADDRESS"); - - /* command line args */ - if(argc < 2) - goto Usage; - for(i = 1; i < argc && argv[i][0] == '-'; i++) - if(!strncmp(argv[i], "-v", 3)) { - fputs("ixpc-"VERSION", (C)opyright MMIV-MMVI Anselm R. Garbe\n", stdout); - exit(EXIT_SUCCESS); - } - else if(!strncmp(argv[i], "-a", 3)) - address = argv[++i]; - if(i + 2 > argc) - goto Usage; - cmd = argv[i++]; - if(!strcmp(argv[i], "-l")) { - details = 1; - if(++i >= argc || strcmp(cmd, "ls")) - goto Usage; - } - file = argv[i++]; - if(!address) - ixp_eprint("ixpc: error: $IXP_ADDRESS not set\n"); - if(ixp_client_dial(&c, address, getpid()) == -1) - ixp_eprint("ixpc: %s\n", c.errstr); - 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, P9OWRITE); - else if(!strncmp(cmd, "xwrite", 7)) { - while(i < argc) { - if(ixp_strlcat(buffer, argv[i++], 1024) > 1023) - break; - if(i < argc) - ixp_strlcat(buffer, " ", 1024); - } - ret = xawrite(file, P9OWRITE); - }else { -Usage: - ixp_eprint("usage: ixpc [-a <address>] {create | read | ls [-l] | remove | write} <file>\n" - " ixpc [-a <address>] xwrite <file> <data>\n" - " ixpc -v\n"); - } - /* close socket */ - ixp_client_hangup(&c); - return ret; -} diff --git a/libixp/LICENSE b/libixp/LICENSE @@ -0,0 +1,22 @@ +MIT/X Consortium License + +(C)opyright MMV-MMVI Anselm R. Garbe <garbeam@gmail.com> +(C)opyright MMVI Kris Maglione <bsdaemon at comcast dot net> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/libixp/LICENSE.p9p b/libixp/LICENSE.p9p @@ -0,0 +1,251 @@ +The bulk of this software is derived from Plan 9 and is thus distributed +under the Lucent Public License, Version 1.02, reproduced below. + +There are a few exceptions: libutf, libfmt, and libregexp are distributed +under simpler BSD-like boilerplates. See the LICENSE files in those +directories. There are other exceptions, also marked with LICENSE files +in their directories. + +The bitmap fonts in the font/luc, font/lucm, font/lucsans, and font/pelm +directory are copyright B&H Inc. and distributed under more restricted +terms under agreement with B&H. See the NOTICE file in those directories. + +=================================================================== + +Lucent Public License Version 1.02 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE +PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original + Program, and + b. in the case of each Contributor, + + i. changes to the Program, and + ii. additions to the Program; + + where such changes and/or additions to the Program were added to the + Program by such Contributor itself or anyone acting on such + Contributor's behalf, and the Contributor explicitly consents, in + accordance with Section 3C, to characterization of the changes and/or + additions as Contributions. + +"Contributor" means LUCENT and any other entity that has Contributed a +Contribution to the Program. + +"Distributor" means a Recipient that distributes the Program, +modifications to the Program, or any part thereof. + +"Licensed Patents" mean patent claims licensable by a Contributor +which are necessarily infringed by the use or sale of its Contribution +alone or when combined with the Program. + +"Original Program" means the original version of the software +accompanying this Agreement as released by LUCENT, including source +code, object code and documentation, if any. + +"Program" means the Original Program and Contributions or any part +thereof + +"Recipient" means anyone who receives the Program under this +Agreement, including all Contributors. + +2. GRANT OF RIGHTS + + a. Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b. Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. The patent license granted + by a Contributor shall also apply to the combination of the + Contribution of that Contributor and the Program if, at the time the + Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license granted by a Contributor shall not apply + to (i) any other combinations which include the Contribution, nor to + (ii) Contributions of other Contributors. No hardware per se is + licensed hereunder. + + c. Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility + to secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow + Recipient to distribute the Program, it is Recipient's responsibility + to acquire that license before distributing the Program. + + d. Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + +3. REQUIREMENTS + +A. Distributor may choose to distribute the Program in any form under +this Agreement or under its own license agreement, provided that: + + a. it complies with the terms and conditions of this Agreement; + + b. if the Program is distributed in source code or other tangible + form, a copy of this Agreement or Distributor's own license agreement + is included with each copy of the Program; and + + c. if distributed under Distributor's own license agreement, such + license agreement: + + i. effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or + conditions of title and non-infringement, and implied warranties or + conditions of merchantability and fitness for a particular purpose; + ii. effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; and + iii. states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party. + +B. Each Distributor must include the following in a conspicuous + location in the Program: + + Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights + Reserved. + +C. In addition, each Contributor must identify itself as the +originator of its Contribution in a manner that reasonably allows +subsequent Recipients to identify the originator of the Contribution. +Also, each Contributor must agree that the additions and/or changes +are intended to be a Contribution. Once a Contribution is contributed, +it may not thereafter be revoked. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use +of the Program, the Distributor who includes the Program in a +commercial product offering should do so in a manner which does not +create potential liability for Contributors. Therefore, if a +Distributor includes the Program in a commercial product offering, +such Distributor ("Commercial Distributor") hereby agrees to defend +and indemnify every Contributor ("Indemnified Contributor") against +any losses, damages and costs (collectively"Losses") arising from +claims, lawsuits and other legal actions brought by a third party +against the Indemnified Contributor to the extent caused by the acts +or omissions of such Commercial Distributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. +In order to qualify, an Indemnified Contributor must: a) promptly +notify the Commercial Distributor in writing of such claim, and b) +allow the Commercial Distributor to control, and cooperate with the +Commercial Distributor in, the defense and any related settlement +negotiations. The Indemnified Contributor may participate in any such +claim at its own expense. + +For example, a Distributor might include the Program in a commercial +product offering, Product X. That Distributor is then a Commercial +Distributor. If that Commercial Distributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Distributor's responsibility +alone. Under this section, the Commercial Distributor would have to +defend claims against the Contributors related to those performance +claims and warranties, and if a court requires any Contributor to pay +any damages as a result, the Commercial Distributor must pay those +damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY +WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement, including but not limited to +the risks and costs of program errors, compliance with applicable +laws, damage to or loss of data, programs or equipment, and +unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR +ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. EXPORT CONTROL + +Recipient agrees that Recipient alone is responsible for compliance +with the United States export administration regulations (and the +export control laws and regulation of any other countries). + +8. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with +respect to a patent applicable to software (including a cross-claim or +counterclaim in a lawsuit), then any patent licenses granted by that +Contributor to such Recipient under this Agreement shall terminate as +of the date such litigation is filed. In addition, if Recipient +institutes patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Program +itself (excluding combinations of the Program with other software or +hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and +survive. + +LUCENT may publish new versions (including revisions) of this +Agreement from time to time. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new +version of the Agreement is published, Contributor may elect to +distribute the Program (including its Contributions) under the new +version. No one other than LUCENT has the right to modify this +Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, +Recipient receives no rights or licenses to the intellectual property +of any Contributor under this Agreement, whether expressly, by +implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No +party to this Agreement will bring a legal action under this Agreement +more than one year after the cause of action arose. Each party waives +its rights to a jury trial in any resulting litigation. + diff --git a/libixp/Makefile b/libixp/Makefile @@ -0,0 +1,22 @@ +ROOT= .. +include ${ROOT}/mk/hdr.mk +include ${ROOT}/mk/ixp.mk + +TARG = libixp +HFILES = ixp_fcall.h + +OBJ = client \ + convert \ + intmap \ + message \ + request \ + server \ + socket \ + transport \ + util + +include ${ROOT}/mk/lib.mk + +ixp_fcall.h: fcall.h fcall.h.nounion ${ROOT}/config.mk + cat fcall.h${FCALL_H_VERSION} > ixp_fcall.h + cp -f ixp_fcall.h ${ROOT}/include/ diff --git a/libixp/README b/libixp/README @@ -0,0 +1,14 @@ +libixp - simple 9P client-/server-library +========================================= +libixp is an extremly simple 9P stand-alone library. + + +Installation +------------ +Edit config.mk to match your local setup. libixp is installed into +/usr/local by default. + +Afterwards enter the following command to build and install libixp +(if necessary as root): + + $ make clean install diff --git a/libixp/client.c b/libixp/client.c @@ -0,0 +1,398 @@ +/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include "ixp.h" + +#define nelem(ary) (sizeof(ary) / sizeof(*ary)) +static char errbuf[1024]; + +enum { + RootFid = 1, + Tag = 1, +}; + +static int +min(int a, int b) { + if(a < b) + return a; + return b; +} + +static IxpCFid * +getfid(IxpClient *c) { + IxpCFid *temp; + uint i; + + if(!c->freefid) { + i = 15; + temp = ixp_emallocz(sizeof(IxpCFid) * i); + while(i--) { + temp->client = c; + temp->fid = ++c->lastfid; + temp->next = c->freefid; + c->freefid = temp++; + } + } + temp = c->freefid; + c->freefid = temp->next; + temp->next = nil; + temp->open = 0; + return temp; +} + +static void +putfid(IxpCFid *f) { + IxpClient *c; + + c = f->client; + f->next = c->freefid; + c->freefid = f; +} + +static int +dofcall(IxpClient *c, Fcall *fcall) { + int type; + + type = fcall->type; + if(ixp_fcall2msg(&c->msg, fcall) == 0) { + errstr = "failed to pack message"; + return 0; + } + if(ixp_sendmsg(c->fd, &c->msg) == 0) + return 0; + if(ixp_recvmsg(c->fd, &c->msg) == 0) + return 0; + if(ixp_msg2fcall(&c->msg, fcall) == 0) { + errstr = "received bad message"; + return 0; + } + if(fcall->type != (type^1)) { + ixp_freefcall(fcall); + errstr = "received mismatched fcall"; + } + if(fcall->type == RError) { + strncpy(errbuf, fcall->ename, sizeof errbuf); + ixp_freefcall(fcall); + errstr = errbuf; + return 0; + } + return 1; +} + +void +ixp_unmount(IxpClient *c) { + shutdown(c->fd, SHUT_RDWR); + close(c->fd); + free(c); +} + +IxpClient * +ixp_mountfd(int fd) { + IxpClient *c; + Fcall fcall; + + c = ixp_emallocz(sizeof(*c)); + c->fd = fd; + + c->msg.size = 64; + c->msg.data = ixp_emalloc(c->msg.size); + + fcall.type = TVersion; + fcall.tag = IXP_NOTAG; + fcall.msize = IXP_MAX_MSG; + fcall.version = IXP_VERSION; + + if(dofcall(c, &fcall) == 0) { + ixp_unmount(c); + return nil; + } + + if(strcmp(fcall.version, IXP_VERSION) != 0) { + errstr = "bad 9P version response"; + ixp_unmount(c); + return nil; + } + + c->msg.size = fcall.msize; + c->msg.data = ixp_erealloc(c->msg.data, c->msg.size); + ixp_freefcall(&fcall); + + fcall.type = TAttach; + fcall.tag = Tag; + fcall.fid = RootFid; + fcall.afid = IXP_NOFID; + fcall.uname = getenv("USER"); + fcall.aname = ""; + if(dofcall(c, &fcall) == 0) { + ixp_unmount(c); + return nil; + } + + return c; +} + +IxpClient * +ixp_mount(char *address) { + int fd; + + fd = ixp_dial(address); + if(fd < 0) + return nil; + return ixp_mountfd(fd); +} + +static IxpCFid * +walk(IxpClient *c, char *path) { + IxpCFid *f; + Fcall fcall; + int n; + + path = ixp_estrdup(path); + n = ixp_tokenize(fcall.wname, nelem(fcall.wname), path, '/'); + f = getfid(c); + + fcall.type = TWalk; + fcall.fid = RootFid; + fcall.nwname = n; + fcall.newfid = f->fid; + if(dofcall(c, &fcall) == 0) + goto fail; + if(fcall.nwqid < n) + goto fail; + + f->qid = fcall.wqid[n-1]; + + ixp_freefcall(&fcall); + free(path); + return f; +fail: + putfid(f); + return nil; +} + +static IxpCFid * +walkdir(IxpClient *c, char *path, char **rest) { + char *p; + + p = path + strlen(path) - 1; + assert(p >= path); + while(*p == '/') + *p-- = '\0'; + + while((p > path) && (*p != '/')) + p--; + if(*p != '/') { + errstr = "bad path"; + return nil; + } + + *p++ = '\0'; + *rest = p; + return walk(c, path); +} + +static int +clunk(IxpCFid *f) { + IxpClient *c; + Fcall fcall; + int ret; + + c = f->client; + + fcall.type = TClunk; + fcall.tag = Tag; + fcall.fid = f->fid; + ret = dofcall(c, &fcall); + if(ret) + putfid(f); + ixp_freefcall(&fcall); + return ret; +} + +int +ixp_remove(IxpClient *c, char *path) { + Fcall fcall; + IxpCFid *f; + int ret; + + if((f = walk(c, path)) == nil) + return 0; + + fcall.type = TRemove; + fcall.tag = Tag; + fcall.fid = f->fid;; + ret = dofcall(c, &fcall); + ixp_freefcall(&fcall); + putfid(f); + + return ret; +} + +void +initfid(IxpCFid *f, Fcall *fcall) { + f->open = 1; + f->offset = 0; + f->iounit = min(fcall->iounit, IXP_MAX_MSG-32); + f->qid = fcall->qid; +} + +IxpCFid * +ixp_create(IxpClient *c, char *name, uint perm, uchar mode) { + Fcall fcall; + IxpCFid *f; + char *path;; + + path = ixp_estrdup(name); + + f = walkdir(c, path, &name); + if(f == nil) + goto done; + + fcall.type = TCreate; + fcall.tag = Tag; + fcall.fid = f->fid; + fcall.name = name; + fcall.perm = perm; + fcall.mode = mode; + + if(dofcall(c, &fcall) == 0) { + clunk(f); + f = nil; + goto done; + } + + initfid(f, &fcall); + f->mode = mode; + + ixp_freefcall(&fcall); + +done: + free(path); + return f; +} + +IxpCFid * +ixp_open(IxpClient *c, char *name, uchar mode) { + Fcall fcall; + IxpCFid *f; + + f = walk(c, name); + if(f == nil) + return nil; + + fcall.type = TOpen; + fcall.tag = Tag; + fcall.fid = f->fid; + fcall.mode = mode; + + if(dofcall(c, &fcall) == 0) { + clunk(f); + return nil; + } + + initfid(f, &fcall); + f->mode = mode; + + ixp_freefcall(&fcall); + return f; +} + +int +ixp_close(IxpCFid *f) { + return clunk(f); +} + +Stat * +ixp_stat(IxpClient *c, char *path) { + Message msg; + Fcall fcall; + Stat *stat; + IxpCFid *f; + + stat = nil; + f = walk(c, path); + if(f == nil) + return nil; + + fcall.type = TStat; + fcall.tag = Tag; + fcall.fid = f->fid; + if(dofcall(c, &fcall) == 0) + goto done; + + msg = ixp_message(fcall.stat, fcall.nstat, MsgUnpack); + + stat = ixp_emalloc(sizeof(*stat)); + ixp_pstat(&msg, stat); + ixp_freefcall(&fcall); + if(msg.pos > msg.end) { + free(stat); + stat = 0; + } + +done: + clunk(f); + return stat; +} + +int +ixp_read(IxpCFid *f, void *buf, uint count) { + Fcall fcall; + int n, len; + + len = 0; + while(len < count) { + n = min(count-len, f->iounit); + + fcall.type = TRead; + fcall.tag = IXP_NOTAG; + fcall.fid = f->fid; + fcall.offset = f->offset; + fcall.count = n; + if(dofcall(f->client, &fcall) == 0) + return -1; + + memcpy(buf+len, fcall.data, fcall.count); + f->offset += fcall.count; + len += fcall.count; + + ixp_freefcall(&fcall); + if(fcall.count < n) + break; + } + return len; +} + +int +ixp_write(IxpCFid *f, void *buf, uint count) { + Fcall fcall; + int n, len; + + len = 0; + do { + n = min(count-len, f->iounit); + fcall.type = TRead; + fcall.tag = IXP_NOTAG; + fcall.fid = f->fid; + fcall.offset = f->offset; + fcall.data = (uchar*)buf + len; + fcall.count = n; + if(dofcall(f->client, &fcall) == 0) + return -1; + + f->offset += fcall.count; + len += fcall.count; + + ixp_freefcall(&fcall); + if(fcall.count < n) + break; + } while(len < count); + return len; +} diff --git a/libixp/convert.c b/libixp/convert.c @@ -0,0 +1,195 @@ +/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ixp.h" + +enum { + SByte = 1, + SWord = 2, + SDWord = 4, + SQWord = 8, +}; + +void +ixp_puint(Message *msg, uint size, uint *val) { + int v; + + if(msg->pos + size <= msg->end) { + switch(msg->mode) { + case MsgPack: + v = *val; + switch(size) { + case SDWord: + msg->pos[3] = v>>24; + msg->pos[2] = v>>16; + case SWord: + msg->pos[1] = v>>8; + case SByte: + msg->pos[0] = v; + break; + } + case MsgUnpack: + v = 0; + switch(size) { + case SDWord: + v |= msg->pos[3]<<24; + v |= msg->pos[2]<<16; + case SWord: + v |= msg->pos[1]<<8; + case SByte: + v |= msg->pos[0]; + break; + } + *val = v; + } + } + msg->pos += size; +} + +void +ixp_pu32(Message *msg, uint *val) { + ixp_puint(msg, SDWord, val); +} +void +ixp_pu8(Message *msg, uchar *val) { + uint v; + + v = *val; + ixp_puint(msg, SByte, &v); + *val = (uchar)v; +} +void +ixp_pu16(Message *msg, ushort *val) { + uint v; + + v = *val; + ixp_puint(msg, SWord, &v); + *val = (ushort)v; +} +void +ixp_pu64(Message *msg, uvlong *val) { + uint vl, vb; + + vl = (uint)*val; + vb = (uint)(*val>>32); + ixp_puint(msg, SDWord, &vl); + ixp_puint(msg, SDWord, &vb); + *val = vl | ((uvlong)vb<<32); +} + +void +ixp_pstring(Message *msg, char **s) { + ushort len; + + if(msg->mode == MsgPack) + len = strlen(*s); + ixp_pu16(msg, &len); + + if(msg->pos + len <= msg->end) { + if(msg->mode == MsgUnpack) { + *s = ixp_emalloc(len + 1); + memcpy(*s, msg->pos, len); + (*s)[len] = '\0'; + }else + memcpy(msg->pos, *s, len); + } + msg->pos += len; +} + +void +ixp_pstrings(Message *msg, ushort *num, char *strings[]) { + uchar *s; + uint i, size; + ushort len; + + ixp_pu16(msg, num); + if(*num > IXP_MAX_WELEM) { + msg->pos = msg->end+1; + return; + } + + if(msg->mode == MsgUnpack) { + s = msg->pos; + size = 0; + for(i=0; i < *num; i++) { + ixp_pu16(msg, &len); + msg->pos += len; + size += len; + if(msg->pos > msg->end) + return; + } + msg->pos = s; + size += *num; + s = ixp_emalloc(size); + } + + for(i=0; i < *num; i++) { + if(msg->mode == MsgPack) + len = strlen(strings[i]); + ixp_pu16(msg, &len); + + if(msg->mode == MsgUnpack) { + strings[i] = s; + s += len; + *s++ = '\0'; + } + ixp_pdata(msg, &strings[i], len); + } +} + +void +ixp_pdata(Message *msg, char **data, uint len) { + if(msg->pos + len <= msg->end) { + if(msg->mode == MsgUnpack) { + *data = ixp_emalloc(len); + memcpy(*data, msg->pos, len); + }else + memcpy(msg->pos, *data, len); + } + msg->pos += len; +} + +void +ixp_pqid(Message *msg, Qid *qid) { + ixp_pu8(msg, &qid->type); + ixp_pu32(msg, &qid->version); + ixp_pu64(msg, &qid->path); +} + +void +ixp_pqids(Message *msg, ushort *num, Qid qid[]) { + int i; + + ixp_pu16(msg, num); + if(*num > IXP_MAX_WELEM) { + msg->pos = msg->end+1; + return; + } + + for(i = 0; i < *num; i++) + ixp_pqid(msg, &qid[i]); +} + +void +ixp_pstat(Message *msg, Stat *stat) { + ushort size; + + if(msg->mode == MsgPack) + size = ixp_sizeof_stat(stat); + + ixp_pu16(msg, &size); + ixp_pu16(msg, &stat->type); + ixp_pu32(msg, &stat->dev); + ixp_pqid(msg, &stat->qid); + ixp_pu32(msg, &stat->mode); + ixp_pu32(msg, &stat->atime); + ixp_pu32(msg, &stat->mtime); + ixp_pu64(msg, &stat->length); + ixp_pstring(msg, &stat->name); + ixp_pstring(msg, &stat->uid); + ixp_pstring(msg, &stat->gid); + ixp_pstring(msg, &stat->muid); +} diff --git a/libixp/fcall.h b/libixp/fcall.h @@ -0,0 +1,54 @@ +/* from fcall(3) in plan9port */ +typedef struct Fcall { + uchar type; + ushort tag; + uint fid; + union { + struct { /* Tversion, Rversion */ + uint msize; + char *version; + }; + struct { /* Tflush */ + ushort oldtag; + }; + struct { /* Rerror */ + char *ename; + }; + struct { /* Ropen, Rcreate */ + Qid qid; /* +Rattach */ + uint iounit; + }; + struct { /* Rauth */ + Qid aqid; + }; + struct { /* Tauth, Tattach */ + uint afid; + char *uname; + char *aname; + }; + struct { /* Tcreate */ + uint perm; + char *name; + uchar mode; /* +Topen */ + }; + struct { /* Twalk */ + uint newfid; + ushort nwname; + char *wname[IXP_MAX_WELEM]; + }; + struct { /* Rwalk */ + ushort nwqid; + Qid wqid[IXP_MAX_WELEM]; + }; + struct { /* Twrite */ + uvlong offset; /* +Tread */ + /* +Rread */ + uint count; /* +Tread */ + char *data; + }; + struct { /* Twstat, Rstat */ + ushort nstat; + uchar *stat; + }; + }; +} Fcall; diff --git a/libixp/fcall.h.nounion b/libixp/fcall.h.nounion @@ -0,0 +1,53 @@ +/* from fcall(3) in plan9port */ +typedef struct Fcall { + uchar type; + ushort tag; + uint fid; + + /* Tversion, Rversion */ + uint msize; + char *version; + + /* Tflush */ + ushort oldtag; + + /* Rerror */ + char *ename; + + /* Ropen, Rcreate */ + Qid qid; /* +Rattach */ + uint iounit; + + /* Rauth */ + Qid aqid; + + /* Tauth, Tattach */ + uint afid; + char *uname; + char *aname; + + /* Tcreate */ + uint perm; + char *name; + uchar mode; /* +Topen */ + + /* Twalk */ + uint newfid; + ushort nwname; + char *wname[IXP_MAX_WELEM]; + + /* Rwalk */ + ushort nwqid; + Qid wqid[IXP_MAX_WELEM]; + + /* Twrite */ + uvlong offset; /* +Tread */ + + /* +Rread */ + uint count; /* +Tread */ + char *data; + + /* Twstat, Rstat */ + ushort nstat; + uchar *stat; +} Fcall; diff --git a/libixp/intmap.c b/libixp/intmap.c @@ -0,0 +1,136 @@ +/* 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 { + ulong id; + void* aux; + Intlist* link; + uint ref; +}; + +static ulong +hashid(Intmap *map, ulong id) { + return id%map->nhash; +} + +static void +nop(void *v) { + USED(v); +} + +void +initmap(Intmap *m, ulong nhash, void *hash) { + m->nhash = nhash; + m->hash = hash; +} + +static Intlist** +llookup(Intmap *map, ulong 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, ulong id) { + Intlist *f; + void *v; + + if((f = *llookup(map, id))) + v = f->aux; + else + v = nil; + return v; +} + +void * +insertkey(Intmap *map, ulong id, void *v) { + Intlist *f; + void *ov; + ulong h; + + if((f = *llookup(map, id))){ + /* no decrement for ov because we're returning it */ + ov = f->aux; + f->aux = v; + }else{ + f = ixp_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, ulong id, void *v) { + Intlist *f; + int rv; + ulong h; + + if(*llookup(map, id)) + rv = 0; + else{ + f = ixp_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, ulong 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; +} diff --git a/libixp/message.c b/libixp/message.c @@ -0,0 +1,202 @@ +/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "ixp.h" + +enum { + SByte = 1, + SWord = 2, + SDWord = 4, + SQWord = 8, +}; + +#define SString(s) (SWord + strlen(s)) +enum { + SQid = SByte + SDWord + SQWord, +}; + +Message +ixp_message(uchar *data, uint length, uint mode) { + Message m; + + m.data = data; + m.pos = data; + m.end = data + length; + m.size = length; + m.mode = mode; + return m; +} + +void +ixp_freestat(Stat *s) { + free(s->name); + free(s->uid); + free(s->gid); + free(s->muid); + s->name = s->uid = s->gid = s->muid = nil; +} + +void +ixp_freefcall(Fcall *fcall) { + switch(fcall->type) { + case RStat: + free(fcall->stat); + fcall->stat = nil; + break; + case RRead: + free(fcall->data); + fcall->data = nil; + break; + case RVersion: + free(fcall->version); + fcall->version = nil; + break; + case RError: + free(fcall->ename); + fcall->ename = nil; + break; + } +} + +ushort +ixp_sizeof_stat(Stat * stat) { + return SWord /* size */ + + SWord /* type */ + + SDWord /* dev */ + + SQid /* qid */ + + 3 * SDWord /* mode, atime, mtime */ + + SQWord /* length */ + + SString(stat->name) + + SString(stat->uid) + + SString(stat->gid) + + SString(stat->muid); +} + +void +ixp_pfcall(Message *msg, Fcall *fcall) { + ixp_pu8(msg, &fcall->type); + ixp_pu16(msg, &fcall->tag); + + switch (fcall->type) { + case TVersion: + case RVersion: + ixp_pu32(msg, &fcall->msize); + ixp_pstring(msg, &fcall->version); + break; + case TAuth: + ixp_pu32(msg, &fcall->afid); + ixp_pstring(msg, &fcall->uname); + ixp_pstring(msg, &fcall->aname); + break; + case RAuth: + ixp_pqid(msg, &fcall->aqid); + break; + case RAttach: + ixp_pqid(msg, &fcall->qid); + break; + case TAttach: + ixp_pu32(msg, &fcall->fid); + ixp_pu32(msg, &fcall->afid); + ixp_pstring(msg, &fcall->uname); + ixp_pstring(msg, &fcall->aname); + break; + case RError: + ixp_pstring(msg, &fcall->ename); + break; + case TFlush: + ixp_pu16(msg, &fcall->oldtag); + break; + case TWalk: + ixp_pu32(msg, &fcall->fid); + ixp_pu32(msg, &fcall->newfid); + ixp_pstrings(msg, &fcall->nwname, fcall->wname); + break; + case RWalk: + ixp_pqids(msg, &fcall->nwqid, fcall->wqid); + break; + case TOpen: + ixp_pu32(msg, &fcall->fid); + ixp_pu8(msg, &fcall->mode); + break; + case ROpen: + case RCreate: + ixp_pqid(msg, &fcall->qid); + ixp_pu32(msg, &fcall->iounit); + break; + case TCreate: + ixp_pu32(msg, &fcall->fid); + ixp_pstring(msg, &fcall->name); + ixp_pu32(msg, &fcall->perm); + ixp_pu8(msg, &fcall->mode); + break; + case TRead: + ixp_pu32(msg, &fcall->fid); + ixp_pu64(msg, &fcall->offset); + ixp_pu32(msg, &fcall->count); + break; + case RRead: + ixp_pu32(msg, &fcall->count); + ixp_pdata(msg, &fcall->data, fcall->count); + break; + case TWrite: + ixp_pu32(msg, &fcall->fid); + ixp_pu64(msg, &fcall->offset); + ixp_pu32(msg, &fcall->count); + ixp_pdata(msg, &fcall->data, fcall->count); + break; + case RWrite: + ixp_pu32(msg, &fcall->count); + break; + case TClunk: + case TRemove: + case TStat: + ixp_pu32(msg, &fcall->fid); + break; + case RStat: + ixp_pu16(msg, &fcall->nstat); + ixp_pdata(msg, (char**)&fcall->stat, fcall->nstat); + break; + case TWStat: + ixp_pu32(msg, &fcall->fid); + ixp_pu16(msg, &fcall->nstat); + ixp_pdata(msg, (char**)&fcall->stat, fcall->nstat); + break; + } +} + +uint +ixp_fcall2msg(Message *msg, Fcall *fcall) { + int size; + + msg->end = msg->data + msg->size; + msg->pos = msg->data + SDWord; + msg->mode = MsgPack; + ixp_pfcall(msg, fcall); + + if(msg->pos > msg->end) + return 0; + + msg->end = msg->pos; + size = msg->end - msg->data; + + msg->pos = msg->data; + ixp_pu32(msg, &size); + + msg->pos = msg->data; + return size; +} + +uint +ixp_msg2fcall(Message *msg, Fcall *fcall) { + msg->pos = msg->data + SDWord; + msg->mode = MsgUnpack; + ixp_pfcall(msg, fcall); + + if(msg->pos > msg->end) + return 0; + + return msg->pos - msg->data; +} diff --git a/libixp/request.c b/libixp/request.c @@ -0,0 +1,461 @@ +/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include "ixp.h" + +static void handlereq(Ixp9Req *r); + +static int +min(int a, int b) { + if(a < b) + return a; + return b; +} + +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", + Eintr[] = "interrupted", + Eisdir[] = "cannot perform operation on a directory"; + +enum { + TAG_BUCKETS = 64, + FID_BUCKETS = 64, +}; + +struct Ixp9Conn { + Intmap tagmap; + void *taghash[TAG_BUCKETS]; + Intmap fidmap; + void *fidhash[FID_BUCKETS]; + Ixp9Srv *srv; + IxpConn *conn; + Message msg; + uint ref; +}; + +static void +free_p9conn(Ixp9Conn *pc) { + free(pc->msg.data); + free(pc); +} + +static void * +createfid(Intmap *map, int fid, Ixp9Conn *pc) { + Fid *f; + + pc->ref++; + f = ixp_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(Ixp9Conn *pc, ulong fid) { + Fid *f; + + f = deletekey(&pc->fidmap, fid); + if(f == nil) + return 0; + + if(pc->srv->freefid) + pc->srv->freefid(f); + + pc->ref--; + free(f); + return 1; +} + +static void +handlefcall(IxpConn *c) { + Fcall fcall = {0}; + Ixp9Conn *pc; + Ixp9Req *req; + + pc = c->aux; + errstr = nil; + + if(ixp_recvmsg(c->fd, &pc->msg) == 0) + goto Fail; + if(ixp_msg2fcall(&pc->msg, &fcall) == 0) + goto Fail; + + req = ixp_emallocz(sizeof(Ixp9Req)); + req->conn = pc; + req->ifcall = fcall; + pc->ref++; + pc->conn = c; + if(caninsertkey(&pc->tagmap, fcall.tag, req) == 0) { + respond(req, Eduptag); + return; + } + handlereq(req); + return; + +Fail: + ixp_hangup(c); + return; +} + +static void +handlereq(Ixp9Req *r) { + Ixp9Conn *pc; + Ixp9Srv *srv; + + pc = r->conn; + srv = pc->srv; + + switch(r->ifcall.type) { + default: + respond(r, Enofunc); + break; + case TVersion: + if(!strcmp(r->ifcall.version, "9P")) + r->ofcall.version = "9P"; + else if(!strcmp(r->ifcall.version, "9P2000")) + 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))) { + respond(r, Edupfid); + return; + } + /* attach is a required function */ + srv->attach(r); + break; + case TClunk: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if(!srv->clunk) { + respond(r, nil); + return; + } + srv->clunk(r); + break; + case TFlush: + if(!(r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag))) { + respond(r, Enotag); + return; + } + if(!srv->flush) { + respond(r, Enofunc); + return; + } + srv->flush(r); + break; + case TCreate: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if(r->fid->omode != -1) { + respond(r, Ebotch); + return; + } + if(!(r->fid->qid.type&QTDIR)) { + respond(r, Enotdir); + return; + } + if(!pc->srv->create) { + respond(r, Enofunc); + return; + } + pc->srv->create(r); + break; + case TOpen: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if((r->fid->qid.type&QTDIR) && (r->ifcall.mode|P9_ORCLOSE) != (P9_OREAD|P9_ORCLOSE)) { + respond(r, Eisdir); + return; + } + r->ofcall.qid = r->fid->qid; + if(!pc->srv->open) { + respond(r, Enofunc); + return; + } + pc->srv->open(r); + break; + case TRead: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if(r->fid->omode == -1 || r->fid->omode == P9_OWRITE) { + respond(r, Ebotch); + return; + } + if(!pc->srv->read) { + respond(r, Enofunc); + return; + } + pc->srv->read(r); + break; + case TRemove: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if(!pc->srv->remove) { + respond(r, Enofunc); + return; + } + pc->srv->remove(r); + break; + case TStat: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if(!pc->srv->stat) { + respond(r, Enofunc); + return; + } + pc->srv->stat(r); + break; + case TWalk: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if(r->fid->omode != -1) { + respond(r, "cannot walk from an open fid"); + return; + } + if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)) { + respond(r, Enotdir); + return; + } + if((r->ifcall.fid != r->ifcall.newfid)) { + if(!(r->newfid = createfid(&pc->fidmap, r->ifcall.newfid, pc))) { + respond(r, Edupfid); + return; + } + }else + r->newfid = r->fid; + if(!pc->srv->walk) { + respond(r, Enofunc); + return; + } + pc->srv->walk(r); + break; + case TWrite: + if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { + respond(r, Enofid); + return; + } + if((r->fid->omode&3) != P9_OWRITE && (r->fid->omode&3) != P9_ORDWR) { + respond(r, "write on fid not opened for writing"); + return; + } + if(!pc->srv->write) { + respond(r, Enofunc); + return; + } + pc->srv->write(r); + break; + /* Still to be implemented: flush, wstat, auth */ + } +} + +void +respond(Ixp9Req *r, char *error) { + Ixp9Conn *pc; + int msize; + + pc = r->conn; + + switch(r->ifcall.type) { + default: + if(!error) + assert(!"Respond called on unsupported fcall type"); + break; + case TVersion: + assert(error == nil); + free(r->ifcall.version); + + pc->msg.size = min(r->ofcall.msize, IXP_MAX_MSG); + pc->msg.data = ixp_erealloc(pc->msg.data, pc->msg.size); + r->ofcall.msize = pc->msg.size; + 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->msg.size - sizeof(ulong); + 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); + break; + case TFlush: + if((r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag))) + respond(r->oldreq, Eintr); + break; + case TRead: + case TStat: + break; + /* Still to be implemented: flush, wstat, auth */ + } + + r->ofcall.tag = r->ifcall.tag; + + if(error == nil) + r->ofcall.type = r->ifcall.type + 1; + else { + r->ofcall.type = RError; + r->ofcall.ename = error; + } + + deletekey(&pc->tagmap, r->ifcall.tag);; + + if(pc->conn) { + msize = ixp_fcall2msg(&pc->msg, &r->ofcall); + if(ixp_sendmsg(pc->conn->fd, &pc->msg) != msize) + ixp_hangup(pc->conn); + } + + ixp_freefcall(&r->ofcall); + free(r); + + pc->ref--; + if(!pc->conn && pc->ref == 0) + free_p9conn(pc); +} + +/* Flush a pending request */ +static void +voidrequest(void *t) { + Ixp9Req *r, *tr; + Ixp9Conn *pc; + + r = t; + pc = r->conn; + pc->ref++; + + tr = ixp_emallocz(sizeof(Ixp9Req)); + tr->ifcall.type = TFlush; + tr->ifcall.tag = IXP_NOTAG; + tr->ifcall.oldtag = r->ifcall.tag; + tr->conn = pc; + handlereq(tr); +} + +/* Clunk an open Fid */ +static void +voidfid(void *t) { + Ixp9Conn *pc; + Ixp9Req *tr; + Fid *f; + + f = t; + pc = f->conn; + pc->ref++; + + tr = ixp_emallocz(sizeof(Ixp9Req)); + tr->ifcall.type = TClunk; + tr->ifcall.tag = IXP_NOTAG; + tr->ifcall.fid = f->fid; + tr->fid = f; + tr->conn = pc; + handlereq(tr); +} + +#if 0 +static void +p9conn_incref(void *r) { + Ixp9Conn *pc; + + pc = *(Ixp9Conn **)r; + pc->ref++; +} +#endif + +static void +cleanupconn(IxpConn *c) { + Ixp9Conn *pc; + + pc = c->aux; + pc->conn = nil; + pc->ref++; + if(pc->ref > 1) { + execmap(&pc->tagmap, voidrequest); + execmap(&pc->fidmap, voidfid); + } + if(--pc->ref == 0) + free_p9conn(pc); +} + +/* Handle incoming 9P connections */ +void +serve_9pcon(IxpConn *c) { + Ixp9Conn *pc; + int fd; + + fd = accept(c->fd, nil, nil); + if(fd < 0) + return; + + pc = ixp_emallocz(sizeof(Ixp9Conn)); + pc->srv = c->aux; + pc->msg.size = 1024; + pc->msg.data = ixp_emalloc(pc->msg.size); + initmap(&pc->tagmap, TAG_BUCKETS, &pc->taghash); + initmap(&pc->fidmap, FID_BUCKETS, &pc->fidhash); + + ixp_listen(c->srv, fd, pc, handlefcall, cleanupconn); +} diff --git a/libixp/server.c b/libixp/server.c @@ -0,0 +1,98 @@ +/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <unistd.h> +#include "ixp.h" + +IxpConn * +ixp_listen(IxpServer *s, int fd, void *aux, + void (*read)(IxpConn *c), + void (*close)(IxpConn *c) + ) { + IxpConn *c; + + c = ixp_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_hangup(IxpConn *c) { + IxpServer *s; + IxpConn **tc; + + s = c->srv; + for(tc=&s->conn; *tc; tc=&(*tc)->next) + if(*tc == c) break; + 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->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; c; c = n) { + n = c->next; + if(FD_ISSET(c->fd, &s->rd)) + c->read(c); + } +} + +char * +ixp_serverloop(IxpServer *s) { + int r; + + s->running = 1; + while(s->running) { + prepare_select(s); + r = select(s->maxfd + 1, &s->rd, 0, 0, 0); + if(r < 0) { + if(errno == EINTR) + continue; + return "fatal select error"; + } + handle_conns(s); + } + return nil; +} + +void +ixp_server_close(IxpServer *s) { + IxpConn *c, *next; + for(c = s->conn; c; c = next) { + next = c->next; + ixp_hangup(c); + } +} diff --git a/libixp/socket.c b/libixp/socket.c @@ -0,0 +1,230 @@ +/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <errno.h> +#include <netdb.h> +#include <netinet/in.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include "ixp.h" + +typedef struct sockaddr sockaddr; + +static int +dial_unix(char *address) { + struct sockaddr_un sa; + socklen_t su_len; + int fd; + + memset(&sa, 0, sizeof(sa)); + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, address, sizeof(sa.sun_path)); + su_len = sizeof(sa) + strlen(sa.sun_path); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd < 0) { + errstr = strerror(errno); + return -1; + } + if(connect(fd, (sockaddr*) &sa, su_len)) { + errstr = strerror(errno); + close(fd); + return -1; + } + return fd; +} + +static int +dial_tcp(char *host) { + struct sockaddr_in sa; + struct hostent *hp; + char *port; + uint prt; + int fd; + + memset(&sa, 0, sizeof(sa)); + + port = strrchr(host, '!'); + if(port == nil) { + errstr = "no port provided"; + return -1; + } + *port++ = '\0'; + + if(sscanf(port, "%u", &prt) != 1) + return -1; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if(fd < 0) { + errstr = strerror(errno); + return -1; + } + + hp = gethostbyname(host); + sa.sin_family = AF_INET; + sa.sin_port = htons(prt); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + + if(connect(fd, (sockaddr*)&sa, sizeof(struct sockaddr_in))) { + errstr = strerror(errno); + close(fd); + return -1; + } + return fd; +} + +static int +announce_tcp(char *host) { + struct sockaddr_in sa; + struct hostent *he; + char *port; + uint prt; + int fd; + + memset(&sa, 0, sizeof(sa)); + + port = strrchr(host, '!'); + if(port == nil) { + errstr = "no port provided"; + return -1; + } + + *port++ = '\0'; + if(sscanf(port, "%u", &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; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(prt); + + if(!strcmp(host, "*")) + sa.sin_addr.s_addr = htonl(INADDR_ANY); + else if((he = gethostbyname(host))) + memcpy(&sa.sin_addr, he->h_addr, he->h_length); + else { + errstr = "cannot translate hostname to an address"; + return -1; + } + + if(bind(fd, (sockaddr*)&sa, sizeof(struct sockaddr_in)) < 0) { + errstr = strerror(errno); + close(fd); + return -1; + } + + if(listen(fd, IXP_MAX_CACHE) < 0) { + errstr = strerror(errno); + close(fd); + return -1; + } + return fd; +} + +static int +announce_unix(char *file) { + const int yes = 1; + struct sockaddr_un sa; + socklen_t su_len; + int fd; + + memset(&sa, 0, sizeof(sa)); + + signal(SIGPIPE, SIG_IGN); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd < 0) { + errstr = "cannot open socket"; + return -1; + } + + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0) { + errstr = strerror(errno); + close(fd); + return -1; + } + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, file, sizeof(sa.sun_path)); + su_len = sizeof(sa) + strlen(sa.sun_path); + + unlink(file); + + if(bind(fd, (sockaddr*)&sa, su_len) < 0) { + errstr = strerror(errno); + close(fd); + return -1; + } + + chmod(file, S_IRWXU); + if(listen(fd, IXP_MAX_CACHE) < 0) { + errstr = strerror(errno); + close(fd); + return -1; + } + return fd; +} + +int +ixp_dial(char *address) { + char *addr, *type; + int ret; + + ret = -1; + type = ixp_estrdup(address); + + addr = strchr(type, '!'); + if(addr == nil) + errstr = "no address type defined"; + else { + *addr++ = '\0'; + if(strcmp(type, "unix") == 0) + ret = dial_unix(addr); + else if(strcmp(type, "tcp") == 0) + ret = dial_tcp(addr); + else + errstr = "unkown address type"; + } + + free(type); + return ret; +} + +int +ixp_announce(char *address) { + char *addr, *type; + int ret; + + ret = -1; + type = ixp_estrdup(address); + + addr = strchr(type, '!'); + if(addr == nil) + errstr = "no address type defined"; + else { + *addr++ = '\0'; + if(strcmp(type, "unix") == 0) + ret = announce_unix(addr); + else if(strcmp(type, "tcp") == 0) + ret = announce_tcp(addr); + else + errstr = "unkown address type"; + } + + free(type); + return ret; +} diff --git a/libixp/transport.c b/libixp/transport.c @@ -0,0 +1,98 @@ +/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "ixp.h" +#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> + +static int +mread(int fd, Message *msg, uint count) { + int r, n; + + n = msg->end - msg->pos; + if(n <= 0) { + errstr = "buffer full"; + return -1; + } + if(n > count) + n = count; + + r = read(fd, msg->pos, n); + if(r > 0) + msg->pos += r; + return r; +} + +static int +readn(int fd, Message *msg, uint count) { + uint num; + int r; + + errstr = nil; + num = count; + while(num > 0) { + r = mread(fd, msg, num); + if(r < 1) { + if(errstr == nil) + errstr = "broken pipe"; + else if(errno == EINTR) + continue; + return count - num; + } + num -= r; + } + return count - num; +} + +uint +ixp_sendmsg(int fd, Message *msg) { + int r; + + msg->pos = msg->data; + while(msg->pos < msg->end) { + r = write(fd, msg->pos, msg->end - msg->pos); + if(r < 1) { + if(errno == EINTR) + continue; + errstr = "broken pipe"; + return 0; + } + msg->pos += r; + } + return msg->pos - msg->data; +} + +uint +ixp_recvmsg(int fd, Message *msg) { + enum { SSize = 4 }; + uint msize, size; + + msg->mode = MsgUnpack; + msg->pos = msg->data; + msg->end = msg->data + msg->size; + if(readn(fd, msg, SSize) != SSize) + return 0; + + msg->pos = msg->data; + ixp_pu32(msg, &msize); + + size = msize - SSize; + if(msg->pos + size >= msg->end) { + errstr = "message too large"; + return 0; + } + if(readn(fd, msg, size) != size) { + errstr = "message incomplete"; + return 0; + } + + msg->end = msg->pos; + return msize; +} diff --git a/libixp/util.c b/libixp/util.c @@ -0,0 +1,126 @@ +/* Written by Kris Maglione <fbsdaemon at gmail dot com> */ +/* Public domain */ +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "ixp.h" + +void +ixp_eprint(const char *fmt, ...) { + va_list ap; + int err; + + err = errno; + fprintf(stderr, "libixp: fatal: "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if(fmt[strlen(fmt)-1] == ':') + fprintf(stderr, " %s\n", strerror(err)); + else + fprintf(stderr, "\n"); + + exit(1); +} + +/* Can't malloc */ +static void +mfatal(char *name, uint size) { + const char + couldnot[] = "libixp: fatal: Could not ", + paren[] = "() ", + bytes[] = " bytes\n"; + char sizestr[8]; + int i; + + i = sizeof(sizestr); + do { + sizestr[--i] = '0' + (size%10); + size /= 10; + } while(size > 0); + + write(1, couldnot, sizeof(couldnot)-1); + write(1, name, strlen(name)); + write(1, paren, sizeof(paren)-1); + write(1, sizestr+i, sizeof(sizestr)-i); + write(1, bytes, sizeof(bytes)-1); + + exit(1); +} + +void * +ixp_emalloc(uint size) { + void *ret = malloc(size); + if(!ret) + mfatal("malloc", size); + return ret; +} + +void * +ixp_emallocz(uint size) { + void *ret = ixp_emalloc(size); + memset(ret, 0, size); + return ret; +} + +void * +ixp_erealloc(void *ptr, uint size) { + void *ret = realloc(ptr, size); + if(!ret) + mfatal("realloc", size); + return ret; +} + +char * +ixp_estrdup(const char *str) { + void *ret = strdup(str); + if(!ret) + mfatal("strdup", strlen(str)); + return ret; +} + +uint +ixp_tokenize(char *res[], uint reslen, char *str, char delim) { + char *s; + uint i; + + i = 0; + s = str; + while(i < reslen && *s) { + while(*s == delim) + *(s++) = '\0'; + if(*s) + res[i++] = s; + while(*s && *s != delim) + s++; + } + return i; +} + +uint +ixp_strlcat(char *dst, const char *src, uint size) { + const char *s; + char *d; + int n, len; + + d = dst; + s = src; + n = size; + while(n-- > 0 && *d != '\0') + d++; + len = n; + + while(*s != '\0') { + if(n-- > 0) + *d++ = *s; + s++; + } + if(len > 0) + *d = '\0'; + return size - n - 1; +} diff --git a/man/Makefile b/man/Makefile @@ -0,0 +1,8 @@ +ROOT=.. +include ${ROOT}/mk/hdr.mk + +TARG = ixpc.1 + +FILTER = cat + +include ${ROOT}/mk/man.mk diff --git a/man/ixpc.1 b/man/ixpc.1 @@ -0,0 +1,92 @@ +.TH IXPC 1 ixpc-VERSION +.SH NAME +ixpc \- ixp client +.SH SYNOPSIS +.B ixpc +.RB [ \-a +.IR address ] +.I action +.I file +.br +.B ixpc +.B \-v +.SH DESCRIPTION +.SS Overview +.B ixpc +is a client to access a 9P file server 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 ixpc +will establish a connection. If this option is not supplied, and the +environment variable IXP_ADDRESS is set, +.B ixpc +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 the standard input 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 xwrite +The same as write, but the data is taken from subsequent arguments, +rather than the standard input. +.TP +.B create +Creates file or directory. If the file exists, +nothing is done. +.TP +.B ls +Lists files and directories. +.TP +.B read +Reads file or directory contents. +.TP +.B remove +Removes file or directory tree. +.SH ENVIRONMENT +.TP +IXP_ADDRESS +See above. +.SH EXAMPLES +.TP +.B ixpc ls / +This prints the root directory of the wmii filesystem, if IXP_ADDRESS is set +to the address of wmii. For more information about the contents of this +filesystem, see +.BR wmiiwm (1). +.TP +.B ixpc xwrite /ctl quit +Write 'quit' to the main control file of the wmii filesystem, effectively +leaving wmii. +.TP +.B ixpc write /keys \< keys.txt +Replace the contents of +.I /keys +with the contents of +.I keys.txt +.SH SEE ALSO +.BR wmii (1) + +http://www.cs.bell-labs.com/sys/man/5/INDEX.html diff --git a/message.c b/message.c @@ -1,239 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define IXP_QIDSZ (sizeof(uchar) + sizeof(uint)\ - + sizeof(uvlong)) - -static ushort -sizeof_string(const char *s) { - return sizeof(ushort) + strlen(s); -} - -ushort -ixp_sizeof_stat(Stat * stat) { - return IXP_QIDSZ - + 2 * sizeof(ushort) - + 4 * sizeof(uint) - + sizeof(uvlong) - + sizeof_string(stat->name) - + sizeof_string(stat->uid) - + sizeof_string(stat->gid) - + sizeof_string(stat->muid); -} - -uint -ixp_fcall2msg(void *msg, Fcall *fcall, uint msglen) { - int msize; - uint i; - uchar *p; - - i = sizeof(uchar) + sizeof(ushort) + sizeof(uint); - msize = msglen - i; - p = (uchar*)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, (uchar *)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, (uchar *)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; -} - -uint -ixp_msg2fcall(Fcall *fcall, void *msg, uint msglen) { - int msize; - uint i, tsize; - ushort len; - uchar *p; - - p = msg; - ixp_unpack_prefix(&p, (uint *)&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; -} diff --git a/mk/common.mk b/mk/common.mk @@ -0,0 +1,18 @@ +all: + +install: all +depend: cleandep + +MANDIRS=${MAN}/man1 +mkdirs: + for i in ${BIN} ${ETC} ${MANDIRS} ${DIRS}; do \ + test -d $$i || echo MKDIR $$i; \ + mkdir -pm 0755 $$i; \ + done + +install: ${HFILES:.h=.install} + +cleandep: + rm .depend 2>/dev/null || true + +.PHONY: all options clean dist install uninstall depend cleandep diff --git a/mk/dir.mk b/mk/dir.mk @@ -0,0 +1,25 @@ +dall: + for i in ${DIRS}; do \ + echo MAKE all ${BASE}$$i/; \ + (cd $$i && ${MAKE} BASE="${BASE}$$i/" all) || exit 1; \ + done +dclean: + for i in ${DIRS}; do \ + echo MAKE clean ${BASE}$$i/; \ + (cd $$i && ${MAKE} BASE="${BASE}$$i/" clean) || exit 1; \ + done +dinstall: + for i in ${DIRS}; do \ + echo MAKE install ${BASE}$$i/; \ + (cd $$i && ${MAKE} BASE="${BASE}$$i/" install) || exit 1; \ + done +ddepend: + for i in ${DIRS}; do \ + echo MAKE depend ${BASE}$$i/; \ + (cd $$i && ${MAKE} BASE="${BASE}$$i/" depend) || exit 1; \ + done + +all: dall +clean: dclean +install: dinstall +depend: ddepend diff --git a/mk/hdr.mk b/mk/hdr.mk @@ -0,0 +1,60 @@ +.SILENT: +.SUFFIXES: .O .o .c .sh .rc .awk .1 .depend .install .clean +all: + +.c.o: + ${COMPILE} $@ $< + +.c.depend: + ${DEPEND} $< >>.depend + +.o.O: + ${LINK} $@ $< + +.awk.O: + echo FILTER ${BASE}$< + ${FILTER} $< >$@ + +.rc.O: + echo FILTER ${BASE}$< + ${FILTER} $< >$@ + +.sh.O: + echo FILTER ${BASE}$< + ${FILTER} $< >$@ + +.O.install: + echo INSTALL $* + cp -f $< ${BIN}/$* + chmod 0755 ${BIN}/$* + +.a.install: + echo INSTALL $< + cp -f $< ${LIBDIR}/$< + chmod 0644 ${LIBDIR}/$< + +.h.install: + echo INSTALL $< + cp -f $< ${INCLUDE}/$< + chmod 0644 ${INCLUDE}/$< + +.1.install: + echo INSTALL man $*'(1)' + ${FILTER} $< >${MAN}/man1/$< + chmod 0644 ${MAN}/man1/$< + +.O.clean: + rm $< || true 2>/dev/null + rm $*.o || true 2>/dev/null +.o.clean: + rm $< || true 2>/dev/null + +printinstall: +mkdirs: +clean: +install: printinstall mkdirs + +COMPILE= CC="${CC}" CFLAGS="${CFLAGS} ${EXCFLAGS}" ${ROOT}/util/compile +LINK= LD="${LD}" LDFLAGS="${LDFLAGS} ${EXLDFLAGS}" ${ROOT}/util/link + +include ${ROOT}/config.mk diff --git a/mk/ixp.mk b/mk/ixp.mk @@ -0,0 +1 @@ +VERSION = 0.3 diff --git a/mk/lib.mk b/mk/lib.mk @@ -0,0 +1,24 @@ +LIB = ${TARG}.a +OFILES = ${OBJ:=.o} + +all: ${HFILES} ${LIB} + +install: ${TARG}.install +clean: libclean +depend: ${OBJ:=.depend} + +libclean: + for i in ${LIB} ${OFILES}; do \ + rm $$i; \ + done 2>/dev/null || true + +printinstall: + echo 'Install directories:' + echo ' Lib: ${LIBDIR}' + +${LIB}: ${OFILES} + @echo AR $@ + @${AR} $@ ${OFILES} + @${RANLIB} $@ + +include ${ROOT}/mk/common.mk diff --git a/mk/man.mk b/mk/man.mk @@ -0,0 +1,7 @@ +install: ${TARG:.1=.install} + +printinstall: + echo 'Install directories:' + echo ' Man: ${MAN}' + +include ${ROOT}/mk/common.mk diff --git a/mk/many.mk b/mk/many.mk @@ -0,0 +1,18 @@ +PROGS = ${TARG:=.O} + +all: ${PROGS} + +install: ${TARG:=.install} +clean: manyclean + +printinstall: + echo 'Install directories:' + echo ' Bin: ${BIN}' + +manyclean: + for i in ${TARG}; do \ + rm $$i.o; rm $$i.O; \ + done 2>/dev/null || true + +include ${ROOT}/mk/common.mk + diff --git a/mk/one.mk b/mk/one.mk @@ -0,0 +1,22 @@ +PROG = ${TARG}.O +OFILES = ${OBJ:=.o} + +all: ${PROG} + +install: ${TARG}.install +clean: oneclean +depend: ${OBJ:=.depend} + +printinstall: + echo 'Install directories:' + echo ' Bin: ${BIN}' + +oneclean: + for i in ${PROG} ${OFILES}; do \ + rm $$i; \ + done 2>/dev/null || true + +${PROG}: ${OFILES} ${LIB} + ${LINK} $@ ${OFILES} ${LIB} + +include ${ROOT}/mk/common.mk diff --git a/request.c b/request.c @@ -1,435 +0,0 @@ -/* (C)opyright MMVI Kris Maglione <fbsdaemon at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/socket.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; - uint msize; - uchar *buf; - uint ref; -}; - -static void -free_p9conn(P9Conn *pc) { - free(pc->buf); - free(pc); -} - -static void * -createfid(Intmap *map, int fid, P9Conn *pc) { - Fid *f; - pc->ref++; - f = ixp_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 NULL; -} - -static int -destroyfid(P9Conn *pc, ulong fid) { - Fid *f; - if(!(f = deletekey(&pc->fidmap, fid))) - return 0; - if(pc->srv->freefid) - pc->srv->freefid(f); - pc->ref--; - free(f); - return 1; -} - -void -ixp_server_handle_fcall(IXPConn *c) { - Fcall fcall = {0}; - P9Conn *pc = c->aux; - P9Req *req; - uint msize; - char *errstr = NULL; - - 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 = ixp_emallocz(sizeof(P9Req)); - req->conn = pc; - req->ifcall = fcall; - pc->ref++; - pc->conn = c; - if(lookupkey(&pc->tagmap, fcall.tag)) { - respond(req, Eduptag); - return; - } - insertkey(&pc->tagmap, fcall.tag, req); - ixp_handle_req(req); - return; -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, NULL); - break; - case TATTACH: - if(!(r->fid = createfid(&pc->fidmap, r->ifcall.fid, pc))) { - respond(r, Edupfid); - return; - } - /* attach is a required function */ - srv->attach(r); - break; - case TCLUNK: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if(!srv->clunk) { - respond(r, NULL); - return; - } - srv->clunk(r); - break; - case TFLUSH: - if(!(r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag))) { - respond(r, Enotag); - return; - } - if(!srv->flush) { - respond(r, Enofunc); - return; - } - srv->flush(r); - break; - case TCREATE: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if(r->fid->omode != -1) { - respond(r, Ebotch); - return; - } - if(!(r->fid->qid.type&P9QTDIR)) { - respond(r, Enotdir); - return; - } - if(!pc->srv->create) { - respond(r, Enofunc); - return; - } - pc->srv->create(r); - break; - case TOPEN: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if((r->fid->qid.type&P9QTDIR) && (r->ifcall.mode|P9ORCLOSE) != (P9OREAD|P9ORCLOSE)) { - respond(r, Eisdir); - return; - } - r->ofcall.qid = r->fid->qid; - if(!pc->srv->open) { - respond(r, Enofunc); - return; - } - pc->srv->open(r); - break; - case TREAD: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if(r->fid->omode == -1 || r->fid->omode == P9OWRITE) { - respond(r, Ebotch); - return; - } - if(!pc->srv->read) { - respond(r, Enofunc); - return; - } - pc->srv->read(r); - break; - case TREMOVE: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if(!pc->srv->remove) { - respond(r, Enofunc); - return; - } - pc->srv->remove(r); - break; - case TSTAT: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if(!pc->srv->stat) { - respond(r, Enofunc); - return; - } - pc->srv->stat(r); - break; - case TWALK: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if(r->fid->omode != -1) { - respond(r, "cannot walk from an open fid"); - return; - } - if(r->ifcall.nwname && !(r->fid->qid.type&P9QTDIR)) { - respond(r, Enotdir); - return; - } - if((r->ifcall.fid != r->ifcall.newfid)) { - if(!(r->newfid = createfid(&pc->fidmap, r->ifcall.newfid, pc))) { - respond(r, Edupfid); - return; - } - }else - r->newfid = r->fid; - if(!pc->srv->walk) { - respond(r, Enofunc); - return; - } - pc->srv->walk(r); - break; - case TWRITE: - if(!(r->fid = lookupkey(&pc->fidmap, r->ifcall.fid))) { - respond(r, Enofid); - return; - } - if((r->fid->omode&3) != P9OWRITE && (r->fid->omode&3) != P9ORDWR) { - respond(r, "write on fid not opened for writing"); - return; - } - if(!pc->srv->write) { - respond(r, Enofunc); - return; - } - 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) - assert(!"Respond called on unsupported fcall type"); - break; - case TVERSION: - 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 = ixp_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(ulong); - 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); - break; - case TFLUSH: - if((r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag))) - respond(r->oldreq, Einterrupted); - 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; - } - deletekey(&pc->tagmap, r->ifcall.tag);; - 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; - } - free(r); - pc->ref--; - 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; - pc->ref++; - tr = ixp_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; - pc->ref++; - tr = ixp_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 = NULL; - pc->ref++; - 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, NULL, NULL); - if(fd < 0) - return; - - P9Conn *pc = ixp_emallocz(sizeof(P9Conn)); - pc->srv = c->aux; - /* XXX */ - pc->msize = 1024; - pc->buf = ixp_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); -} diff --git a/server.c b/server.c @@ -1,121 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#include <assert.h> -#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> - -static uchar *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 = ixp_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); - 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 NULL; -} - -uint -ixp_server_receive_fcall(IXPConn *c, Fcall *fcall) -{ - uint 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; - uint 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); - } -} diff --git a/socket.c b/socket.c @@ -1,187 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#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> - -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; - uint prt; - - port = strrchr(host, '!'); - if(!port) - return -1; - *port = 0; - port++; - if(sscanf(port, "%u", &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; - int ret; - - address = strdup(address); - ret = -1; - if((p = strchr(address, '!'))) { - *p = 0; - p++; - if(!strncmp(address, "unix", 5)) - ret = connect_unix_sock(p); - else if(!strncmp(address, "tcp", 4)) - ret = connect_inet_sock(p); - } - free(address); - return ret; -} - -static int -create_inet_sock(char *host, char **errstr) { - int fd; - struct sockaddr_in addr = { 0 }; - struct hostent *hp; - char *port; - uint prt; - - port = strrchr(host, '!'); - if(!port) { - *errstr = "no port provided in address"; - return -1; - } - *port = 0; - port++; - if(sscanf(port, "%u", &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; - char *addr, *type; - - p = strchr(address, '!'); - 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; -} diff --git a/transport.c b/transport.c @@ -1,71 +0,0 @@ -/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#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> - -uint -ixp_send_message(int fd, void *msg, uint msize, char **errstr) { - uint num = 0; - int r; - - /* send message */ - while(num < msize) { - r = write(fd, (uchar*)msg + num, msize - num); - if(r == -1 && errno == EINTR) - continue; - if(r < 1) { - *errstr = "broken pipe"; - return 0; - } - num += r; - } - return num; -} - -static uint -ixp_recv_data(int fd, void *msg, uint msize, char **errstr) { - uint num = 0; - int r = 0; - - /* receive data */ - while(num < msize) { - r = read(fd, (uchar*)msg + num, msize - num); - if(r == -1 && errno == EINTR) - continue; - if(r < 1) { - *errstr = "broken pipe"; - return 0; - } - num += r; - } - return num; -} - -uint -ixp_recv_message(int fd, void *msg, uint msglen, char **errstr) { - uint msize; - - /* receive header */ - if(ixp_recv_data(fd, msg, sizeof(uint), errstr) != - sizeof(uint)) - return 0; - ixp_unpack_u32((void *)&msg, NULL, &msize); - if(msize > msglen) { - *errstr = "invalid message header"; - return 0; - } - /* receive message */ - if(ixp_recv_data(fd, msg, msize - sizeof(uint), errstr) - != msize - sizeof(uint)) - return 0; - return msize; -} diff --git a/util.c b/util.c @@ -1,147 +0,0 @@ -/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ -#include "ixp.h" -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/wait.h> -#include <unistd.h> - -void * -ixp_emalloc(uint size) { - void *res = malloc(size); - - if(!res) - ixp_eprint("fatal: could not malloc() %u bytes\n", size); - return res; -} - -void * -ixp_emallocz(uint size) { - void *res = calloc(1, size); - - if(!res) - ixp_eprint("fatal: could not malloc() %u bytes\n", size); - return res; -} - -void -ixp_eprint(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void * -ixp_erealloc(void *ptr, uint size) { - void *res = realloc(ptr, size); - - if(!res) - ixp_eprint("fatal: could not malloc() %u bytes\n", size); - return res; -} - -char * -ixp_estrdup(const char *str) { - void *res = strdup(str); - - if(!res) - ixp_eprint("fatal: could not malloc() %u bytes\n", strlen(str)); - return res; -} - -uint -ixp_tokenize(char **result, uint reslen, char *str, char delim) { - char *p, *n; - uint 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 */ -} - -/* - * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * 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. - */ -uint -ixp_strlcat(char *dst, const char *src, uint siz) -{ - const char *s; - char *d; - uint n, dlen; - - n = siz; - s = src; - d = dst; - - /* 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 */ -} - diff --git a/util/compile b/util/compile @@ -0,0 +1,20 @@ +#!/bin/sh -f + +outfile="$1"; shift + +# Derived from Russ Cox's 9c in plan9port. + +xtmp=/tmp/cc.$$.$USER.out + +echo CC $outfile +$CC -o $outfile $CFLAGS $@ 2>$xtmp +status=$? + +cat $xtmp \ +| egrep -v ': error: .Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|In file included from| from|use of C99 long long|ISO C forbids conversion' \ +| sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' \ +| uniq 1>&2 + +rm -f $xtmp $xtmp.status +exit $status + diff --git a/util/link b/util/link @@ -0,0 +1,31 @@ +#!/bin/sh -f + +outfile="$1"; shift + +# Derived from Russ Cox's 9l in plan9port. +ofiles="" +args="" +for i +do + case "$i" in + *.[ao]) + ofiles="$ofiles $i" + ;; + *) + args="$args $i" + ;; + esac +done + +xtmp=/tmp/ld.$$.$USER.out + +echo LD $outfile +$LD -o $outfile $ofiles $LDFLAGS $args >$xtmp 2>&1 +status=$? + +sed 's/.*: In function `[^:]*: *//' $xtmp | egrep . | +egrep -v 'is almost always misused|is dangerous, better use' +rm -f $xtmp + +exit $status +