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
+