├── .github └── workflows │ ├── c.yml │ └── coverity.yml ├── .hgignore ├── LICENSE ├── Makefile ├── NEWS ├── PKGBUILD ├── README.md ├── cmd ├── Makefile └── ixpc.c ├── config.mk ├── debian ├── changelog ├── compat ├── control ├── copyright └── rules ├── examples ├── Makefile └── ixpsrv.c ├── include ├── Makefile ├── ixp.h ├── ixp_local.h └── ixp_srvutil.h ├── lib ├── Makefile ├── libixp │ ├── Makefile │ ├── README │ ├── client.c │ ├── convert.c │ ├── error.c │ ├── map.c │ ├── message.c │ ├── request.c │ ├── rpc.c │ ├── server.c │ ├── socket.c │ ├── srv_util.c │ ├── thread.c │ ├── timer.c │ ├── transport.c │ └── util.c ├── libixp_pthread │ ├── Makefile │ └── thread_pthread.c ├── libixp_rubythread │ ├── Makefile │ └── thread_ruby.c └── libixp_task │ ├── Makefile │ └── thread_task.c ├── man ├── IXP_API.3 ├── Ixp9Srv.3 ├── IxpFcall.3 ├── IxpFid.3 ├── IxpMsg.3 ├── IxpThread.3 ├── Makefile ├── header.t2t ├── ixp_close.3 ├── ixp_dial.3 ├── ixp_emalloc.3 ├── ixp_eprint.3 ├── ixp_errbuf.3 ├── ixp_fcall2msg.3 ├── ixp_freestat.3 ├── ixp_hangup.3 ├── ixp_listen.3 ├── ixp_mount.3 ├── ixp_msec.3 ├── ixp_namespace.3 ├── ixp_open.3 ├── ixp_pdata.3 ├── ixp_pending_write.3 ├── ixp_pfcall.3 ├── ixp_print.3 ├── ixp_printfcall.3 ├── ixp_pstring.3 ├── ixp_pstrings.3 ├── ixp_pthread_init.3 ├── ixp_pu8.3 ├── ixp_read.3 ├── ixp_remove.3 ├── ixp_respond.3 ├── ixp_rubyinit.3 ├── ixp_sendmsg.3 ├── ixp_serverloop.3 ├── ixp_settimer.3 ├── ixp_smprint.3 ├── ixp_srv_clonefiles.3 ├── ixp_srv_data2cstring.3 ├── ixp_srv_freefile.3 ├── ixp_srv_getfile.3 ├── ixp_srv_readbuf.3 ├── ixp_srv_walkandclone.3 ├── ixp_srv_writectl.3 ├── ixp_srvutils.3 ├── ixp_srvutils.man3 ├── ixp_stat.3 ├── ixp_taskinit.3 ├── ixp_unmount.3 ├── ixp_unsettimer.3 ├── ixp_write.3 ├── ixpc.1 ├── libixp.3 ├── libixp.man3 └── targets.mk ├── mk ├── common.mk ├── dir.mk ├── gcc.mk ├── hdr.mk ├── ixp.mk ├── lib.mk ├── man.mk ├── many.mk ├── one.mk └── so.mk ├── test ├── README ├── client.c ├── mkfile └── o.client └── util ├── cleanname ├── compile ├── genchangelog ├── grepdoc └── link /.github/workflows/c.yml: -------------------------------------------------------------------------------- 1 | name: C 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: make clean 17 | run: make clean 18 | - name: make 19 | run: make 20 | -------------------------------------------------------------------------------- /.github/workflows/coverity.yml: -------------------------------------------------------------------------------- 1 | name: Coverity Scan 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | coverity: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: vapier/coverity-scan-action@v1 13 | with: 14 | email: ${{ secrets.COVERITY_SCAN_EMAIL }} 15 | token: ${{ secrets.COVERITY_SCAN_TOKEN }} 16 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: regexp 2 | (^|/)\.((.*\.)?sw.|depend|hgignore)$ 3 | (^|/)(tags|mkfile|diff)$ 4 | \.([oa]|out|o_pic|so|pyc|pyo|diff|man3)$ 5 | \.(diff|orig|rej|bak)$ 6 | \.(aux|idx|ilg|ind|log|toc)$ 7 | ^(pkg|src|doc)/ 8 | /bak/ 9 | syntax: glob 10 | config.local.mk 11 | *.pkg.tar.?z 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | © 2005-2006 Anselm R. Garbe 3 | © 2006-2010 Kris Maglione 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ROOT=. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | DIRS = lib \ 6 | cmd \ 7 | include \ 8 | man 9 | 10 | doc: 11 | perl $(ROOT)/util/grepdoc $$(hg manifest | grep -E '^(lib|include)') \ 12 | >$(ROOT)/man/targets.mk 13 | $(MAKE) -Cman 14 | 15 | deb-dep: 16 | IFS=', '; \ 17 | apt-get -qq install build-essential $$(sed -n 's/([^)]*)//; s/^Build-Depends: \(.*\)/\1/p' debian/control) 18 | 19 | DISTRO = unstable 20 | deb: 21 | $(ROOT)/util/genchangelog libixp-hg $(VERSION) $(DISTRO) 22 | dpkg-buildpackage -rfakeroot -b -nc 23 | [ -d .hg ] && hg revert debian/changelog || true 24 | 25 | .PHONY: doc 26 | include $(ROOT)/mk/dir.mk 27 | 28 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2 | 0.6: 3 | Add API documentation and manual pages. 4 | Now fully MIT licensed. 5 | Fix build problems on case insensitive filesystems. 6 | Change ixp_srv_clonefiles specification. 7 | 8 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | 2 | pkgname="libixp" 3 | pkgver=131 4 | pkgrel=1 5 | pkgdesc="a simple 9P filesystem library" 6 | url="http://github.com/0intro/libixp" 7 | license=(MIT) 8 | arch=(i686 x86_64) 9 | provides=(libixp) 10 | conflicts=(libixp) 11 | source=() 12 | options=(!strip) 13 | 14 | build() 15 | { 16 | cd $startdir 17 | flags=(PREFIX=/usr \ 18 | ETC=/etc \ 19 | DESTDIR="$pkgdir") 20 | 21 | make "${flags[@]}" || return 1 22 | } 23 | package() 24 | { 25 | cd $startdir 26 | flags=(PREFIX=/usr \ 27 | ETC=/etc \ 28 | DESTDIR="$pkgdir") 29 | 30 | make "${flags[@]}" install || return 1 31 | 32 | install -m644 -D ./LICENSE $pkgdir/usr/share/licenses/$pkgname/LICENSE 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/0intro/libixp/workflows/C/badge.svg)](https://github.com/0intro/libixp/actions/workflows/c.yml) 2 | [![Coverity Scan Build Status](https://scan.coverity.com/projects/0intro-libixp/badge.svg)](https://scan.coverity.com/projects/0intro-libixp) 3 | 4 | libixp 5 | ====== 6 | 7 | Portable, simple C-language 9P client and server libary. 8 | -------------------------------------------------------------------------------- /cmd/Makefile: -------------------------------------------------------------------------------- 1 | ROOT=.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | LDLIBS = -L$(ROOT)/lib -lixp 6 | TARG = ixpc 7 | LIB = $(ROOT)/lib/libixp.a 8 | 9 | include $(ROOT)/mk/many.mk 10 | 11 | -------------------------------------------------------------------------------- /cmd/ixpc.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007-2010 Kris Maglione 2 | * See LICENSE file for license details. 3 | */ 4 | #define IXP_NO_P9_ 5 | #define IXP_P9_STRUCTS 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static char *argv0; 14 | 15 | /* Temporary */ 16 | #define fatal(...) ixp_eprint("ixpc: fatal: " __VA_ARGS__); \ 17 | 18 | static IxpClient *client; 19 | 20 | static void 21 | usage(void) { 22 | fprintf(stderr, 23 | "usage: %1$s [-a
] {create | read | ls [-ld] | remove | write | append} \n" 24 | " %1$s [-a
] xwrite \n" 25 | " %1$s -v\n", argv0); 26 | exit(1); 27 | } 28 | 29 | /* Utility Functions */ 30 | static void 31 | write_data(IxpCFid *fid, char *name) { 32 | void *buf; 33 | long len; 34 | 35 | buf = emalloc(fid->iounit);; 36 | do { 37 | len = read(0, buf, fid->iounit); 38 | if(len >= 0 && ixp_write(fid, buf, len) != len) 39 | fatal("cannot write file '%s': %s\n", name, ixp_errbuf()); 40 | } while(len > 0); 41 | 42 | free(buf); 43 | } 44 | 45 | static int 46 | comp_stat(const void *s1, const void *s2) { 47 | Stat *st1, *st2; 48 | 49 | st1 = (Stat*)s1; 50 | st2 = (Stat*)s2; 51 | return strcmp(st1->name, st2->name); 52 | } 53 | 54 | static void 55 | setrwx(long m, char *s) { 56 | static char *modes[] = { 57 | "---", "--x", "-w-", 58 | "-wx", "r--", "r-x", 59 | "rw-", "rwx", 60 | }; 61 | strncpy(s, modes[m], 3); 62 | } 63 | 64 | static char * 65 | str_of_mode(uint mode) { 66 | static char buf[16]; 67 | 68 | buf[0]='-'; 69 | if(mode & P9_DMDIR) 70 | buf[0]='d'; 71 | buf[1]='-'; 72 | setrwx((mode >> 6) & 7, &buf[2]); 73 | setrwx((mode >> 3) & 7, &buf[5]); 74 | setrwx((mode >> 0) & 7, &buf[8]); 75 | buf[11] = 0; 76 | return buf; 77 | } 78 | 79 | static char * 80 | str_of_time(uint val) { 81 | static char buf[32]; 82 | 83 | ctime_r((time_t*)&val, buf); 84 | buf[strlen(buf) - 1] = '\0'; 85 | return buf; 86 | } 87 | 88 | static void 89 | print_stat(Stat *s, int details) { 90 | if(details) 91 | fprintf(stdout, "%s %s %s %5llu %s %s\n", str_of_mode(s->mode), 92 | s->uid, s->gid, s->length, str_of_time(s->mtime), s->name); 93 | else { 94 | if((s->mode&P9_DMDIR) && strcmp(s->name, "/")) 95 | fprintf(stdout, "%s/\n", s->name); 96 | else 97 | fprintf(stdout, "%s\n", s->name); 98 | } 99 | } 100 | 101 | /* Service Functions */ 102 | static int 103 | xappend(int argc, char *argv[]) { 104 | IxpCFid *fid; 105 | IxpStat *stat; 106 | char *file; 107 | 108 | ARGBEGIN{ 109 | default: 110 | usage(); 111 | }ARGEND; 112 | 113 | file = EARGF(usage()); 114 | fid = ixp_open(client, file, P9_OWRITE); 115 | if(fid == nil) 116 | fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 117 | 118 | stat = ixp_stat(client, file); 119 | fid->offset = stat->length; 120 | ixp_freestat(stat); 121 | free(stat); 122 | write_data(fid, file); 123 | return 0; 124 | } 125 | 126 | static int 127 | xwrite(int argc, char *argv[]) { 128 | IxpCFid *fid; 129 | char *file; 130 | 131 | ARGBEGIN{ 132 | default: 133 | usage(); 134 | }ARGEND; 135 | 136 | file = EARGF(usage()); 137 | fid = ixp_open(client, file, P9_OWRITE); 138 | if(fid == nil) 139 | fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 140 | 141 | write_data(fid, file); 142 | return 0; 143 | } 144 | 145 | static int 146 | xawrite(int argc, char *argv[]) { 147 | IxpCFid *fid; 148 | char *file, *buf, *arg; 149 | int nbuf, mbuf, len; 150 | 151 | ARGBEGIN{ 152 | default: 153 | usage(); 154 | }ARGEND; 155 | 156 | file = EARGF(usage()); 157 | fid = ixp_open(client, file, P9_OWRITE); 158 | if(fid == nil) 159 | fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 160 | 161 | nbuf = 0; 162 | mbuf = 128; 163 | buf = emalloc(mbuf); 164 | while(argc) { 165 | arg = ARGF(); 166 | len = strlen(arg); 167 | if(nbuf + len > mbuf) { 168 | mbuf <<= 1; 169 | buf = ixp_erealloc(buf, mbuf); 170 | } 171 | memcpy(buf+nbuf, arg, len); 172 | nbuf += len; 173 | if(argc) 174 | buf[nbuf++] = ' '; 175 | } 176 | 177 | if(ixp_write(fid, buf, nbuf) == -1) 178 | fatal("cannot write file '%s': %s\n", file, ixp_errbuf()); 179 | return 0; 180 | } 181 | 182 | static int 183 | xcreate(int argc, char *argv[]) { 184 | IxpCFid *fid; 185 | char *file; 186 | 187 | ARGBEGIN{ 188 | default: 189 | usage(); 190 | }ARGEND; 191 | 192 | file = EARGF(usage()); 193 | fid = ixp_create(client, file, 0777, P9_OWRITE); 194 | if(fid == nil) 195 | fatal("Can't create file '%s': %s\n", file, ixp_errbuf()); 196 | 197 | if((fid->qid.type&P9_DMDIR) == 0) 198 | write_data(fid, file); 199 | 200 | return 0; 201 | } 202 | 203 | static int 204 | xremove(int argc, char *argv[]) { 205 | char *file; 206 | 207 | ARGBEGIN{ 208 | default: 209 | usage(); 210 | }ARGEND; 211 | 212 | file = EARGF(usage()); 213 | if(ixp_remove(client, file) == 0) 214 | fatal("Can't remove file '%s': %s\n", file, ixp_errbuf()); 215 | return 0; 216 | } 217 | 218 | static int 219 | xread(int argc, char *argv[]) { 220 | IxpCFid *fid; 221 | char *file, *buf; 222 | int count; 223 | 224 | ARGBEGIN{ 225 | default: 226 | usage(); 227 | }ARGEND; 228 | 229 | file = EARGF(usage()); 230 | fid = ixp_open(client, file, P9_OREAD); 231 | if(fid == nil) 232 | fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 233 | 234 | buf = emalloc(fid->iounit); 235 | while((count = ixp_read(fid, buf, fid->iounit)) > 0) 236 | write(1, buf, count); 237 | 238 | if(count == -1) 239 | fatal("cannot read file/directory '%s': %s\n", file, ixp_errbuf()); 240 | 241 | return 0; 242 | } 243 | 244 | static int 245 | xls(int argc, char *argv[]) { 246 | IxpMsg m; 247 | Stat *stat; 248 | IxpCFid *fid; 249 | char *file, *buf; 250 | int lflag, dflag, count, nstat, mstat, i; 251 | 252 | lflag = dflag = 0; 253 | 254 | ARGBEGIN{ 255 | case 'l': 256 | lflag++; 257 | break; 258 | case 'd': 259 | dflag++; 260 | break; 261 | default: 262 | usage(); 263 | }ARGEND; 264 | 265 | file = EARGF(usage()); 266 | 267 | stat = ixp_stat(client, file); 268 | if(stat == nil) 269 | fatal("cannot stat file '%s': %s\n", file, ixp_errbuf()); 270 | 271 | if(dflag || (stat->mode&P9_DMDIR) == 0) { 272 | print_stat(stat, lflag); 273 | ixp_freestat(stat); 274 | return 0; 275 | } 276 | ixp_freestat(stat); 277 | 278 | fid = ixp_open(client, file, P9_OREAD); 279 | if(fid == nil) 280 | fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 281 | 282 | nstat = 0; 283 | mstat = 16; 284 | stat = emalloc(sizeof(*stat) * mstat); 285 | buf = emalloc(fid->iounit); 286 | while((count = ixp_read(fid, buf, fid->iounit)) > 0) { 287 | m = ixp_message(buf, count, MsgUnpack); 288 | while(m.pos < m.end) { 289 | if(nstat == mstat) { 290 | mstat <<= 1; 291 | stat = ixp_erealloc(stat, sizeof(*stat) * mstat); 292 | } 293 | ixp_pstat(&m, &stat[nstat++]); 294 | } 295 | } 296 | 297 | qsort(stat, nstat, sizeof(*stat), comp_stat); 298 | for(i = 0; i < nstat; i++) { 299 | print_stat(&stat[i], lflag); 300 | ixp_freestat(&stat[i]); 301 | } 302 | free(stat); 303 | 304 | if(count == -1) 305 | fatal("cannot read directory '%s': %s\n", file, ixp_errbuf()); 306 | return 0; 307 | } 308 | 309 | typedef struct exectab exectab; 310 | struct exectab { 311 | char *cmd; 312 | int (*fn)(int, char**); 313 | } etab[] = { 314 | {"append", xappend}, 315 | {"write", xwrite}, 316 | {"xwrite", xawrite}, 317 | {"read", xread}, 318 | {"create", xcreate}, 319 | {"remove", xremove}, 320 | {"ls", xls}, 321 | {0, 0} 322 | }; 323 | 324 | int 325 | main(int argc, char *argv[]) { 326 | char *cmd, *address; 327 | exectab *tab; 328 | int ret; 329 | 330 | address = getenv("IXP_ADDRESS"); 331 | 332 | ARGBEGIN{ 333 | case 'v': 334 | printf("%s-" VERSION ", ©2007 Kris Maglione\n", argv0); 335 | exit(0); 336 | case 'a': 337 | address = EARGF(usage()); 338 | break; 339 | default: 340 | usage(); 341 | }ARGEND; 342 | 343 | cmd = EARGF(usage()); 344 | 345 | if(!address) 346 | fatal("$IXP_ADDRESS not set\n"); 347 | 348 | client = ixp_mount(address); 349 | if(client == nil) 350 | fatal("%s\n", ixp_errbuf()); 351 | 352 | for(tab = etab; tab->cmd; tab++) 353 | if(strcmp(cmd, tab->cmd) == 0) break; 354 | if(tab->cmd == 0) 355 | usage(); 356 | 357 | ret = tab->fn(argc, argv); 358 | 359 | ixp_unmount(client); 360 | return ret; 361 | } 362 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | # Customize below to fit your system 2 | 3 | COMPONENTS = \ 4 | libixp \ 5 | libixp_pthread 6 | 7 | # Paths 8 | PREFIX = /usr/local 9 | BIN = $(PREFIX)/bin 10 | MAN = $(PREFIX)/share/man 11 | ETC = $(PREFIX)/etc 12 | LIBDIR = $(PREFIX)/lib 13 | INCLUDE = $(PREFIX)/include 14 | 15 | # Includes and libs 16 | INCLUDES = -I. -I$(ROOT)/include -I$(INCLUDE) -I/usr/include 17 | LIBS = -L/usr/lib -lc 18 | 19 | # Flags 20 | include $(ROOT)/mk/gcc.mk 21 | CFLAGS += $(DEBUGCFLAGS) $(INCS) 22 | LDFLAGS = -g $(LDLIBS) $(LIBS) 23 | 24 | # Compiler, Linker. Linker should usually *not* be ld. 25 | CC = cc -c 26 | LD = cc 27 | # Archiver 28 | AR = ar crs 29 | #AR = sh -c 'ar cr "$$@" && ranlib "$$@"' 30 | 31 | # Solaris 32 | #CFLAGS = -fast $(INCS) 33 | #LDFLAGS = $(LIBS) -R$(PREFIX)/lib -lsocket -lnsl 34 | #CFLAGS += -xtarget=ultra 35 | 36 | # Misc 37 | #MAKESO = 1 38 | 39 | # Extra Components 40 | IGNORE = \ 41 | libixp_task \ 42 | libixp_rubythread 43 | 44 | RUBYINC = -I/usr/local/lib/ruby/1.8/i386-freebsd6 45 | TASKINC = -I$(HOME)/libtask 46 | 47 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libixp-hg (137) unstable; urgency=low 2 | 3 | * [debian] Add 'deb' make target. 4 | 5 | -- Kris Maglione Tue, 06 Jul 2010 21:24:20 -0400 6 | 7 | libixp-hg (136) unstable; urgency=low 8 | 9 | * Add debhelper to debian build dependency list. 10 | 11 | -- Kris Maglione Wed, 23 Jun 2010 14:29:13 -0400 12 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: libixp-hg 2 | Section: x11 3 | Priority: optional 4 | Maintainer: Kris Maglione 5 | Build-Depends: debhelper (>= 7.0) 6 | Standards-Version: 3.8.4 7 | Homepage: http://libs.suckless.org/libixp 8 | 9 | Package: libixp-hg 10 | Architecture: any 11 | Depends: ${shlibs:Depends}, ${misc:Depends} 12 | Conflicts: libixp 13 | Replaces: libixp 14 | Provides: libixp 15 | Description: Simple 9P filesystem library. 16 | This is a an extremly simple 9P stand-alone library. 9P is a virtual 17 | filesystem from the Plan9 operating system. 18 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | 2 | © 2005-2006 Anselm R. Garbe 3 | © 2006-2010 Kris Maglione 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | PACKAGE=$(shell awk 'NR == 1 { print $$2 }' debian/control) 4 | 5 | FLAGS = PREFIX=/usr \ 6 | DESTDIR=$(CURDIR)/debian/$(PACKAGE)/ 7 | 8 | %: 9 | dh $@ 10 | 11 | override_dh_auto_build: 12 | $(MAKE) $(FLAGS) all 13 | 14 | override_dh_auto_install: 15 | $(MAKE) $(FLAGS) install 16 | 17 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | ROOT=.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | LDFLAGS += -L$(ROOT)/lib -lixp 6 | TARG = ixpsrv 7 | LIB = $(ROOT)/lib/libixp.a 8 | 9 | include $(ROOT)/mk/many.mk 10 | 11 | -------------------------------------------------------------------------------- /examples/ixpsrv.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007 Ron Minnich 2 | /* Copyright ©2007-2010 Kris Maglione 3 | * See LICENSE file for license details. 4 | */ 5 | 6 | /* This is a simple 9P file server which serves a normal filesystem 7 | * hierarchy. While some of the code is from wmii, the server is by 8 | * Ron. 9 | * 10 | * Note: I added an ifdef for Linux vs. BSD for the mount call, so 11 | * this compiles on BSD, but it won't actually run. It should, 12 | * ideally, have the option of not mounting the FS. 13 | * --Kris 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | /* Temporary */ 35 | #define fatal(...) ixp_eprint("ixpsrv: fatal: " __VA_ARGS__) 36 | #define debug(...) if(debuglevel) fprintf(stderr, "ixpsrv: " __VA_ARGS__) 37 | 38 | /* Datatypes: */ 39 | typedef struct FidAux FidAux; 40 | struct FidAux { 41 | DIR *dir; 42 | int fd; 43 | char name[]; /* c99 */ 44 | }; 45 | 46 | /* Error messages */ 47 | static char 48 | Enoperm[] = "permission denied", 49 | Enofile[] = "file not found", 50 | Ebadvalue[] = "bad value"; 51 | /* Macros */ 52 | #define QID(t, i) ((int64_t)(t)) 53 | 54 | /* Global Vars */ 55 | static IxpServer server; 56 | static char *user; 57 | static int debuglevel = 0; 58 | 59 | static char *argv0; 60 | 61 | static void fs_open(Ixp9Req *r); 62 | static void fs_walk(Ixp9Req *r); 63 | static void fs_read(Ixp9Req *r); 64 | static void fs_stat(Ixp9Req *r); 65 | static void fs_write(Ixp9Req *r); 66 | static void fs_clunk(Ixp9Req *r); 67 | static void fs_flush(Ixp9Req *r); 68 | static void fs_attach(Ixp9Req *r); 69 | static void fs_create(Ixp9Req *r); 70 | static void fs_remove(Ixp9Req *r); 71 | static void fs_freefid(IxpFid *f); 72 | 73 | Ixp9Srv p9srv = { 74 | .open= fs_open, 75 | .walk= fs_walk, 76 | .read= fs_read, 77 | .stat= fs_stat, 78 | .write= fs_write, 79 | .clunk= fs_clunk, 80 | .flush= fs_flush, 81 | .attach=fs_attach, 82 | .create=fs_create, 83 | .remove=fs_remove, 84 | .freefid=fs_freefid 85 | }; 86 | 87 | static void 88 | usage() { 89 | fprintf(stderr, 90 | "usage: %1$s [-a
] {create | read | ls [-ld] | remove | write} \n" 91 | " %1$s [-a
] xwrite \n" 92 | " %1$s -v\n", argv0); 93 | exit(1); 94 | } 95 | 96 | 97 | /* Utility Functions */ 98 | 99 | static FidAux* 100 | newfidaux(char *name) { 101 | FidAux *f; 102 | 103 | f = ixp_emallocz(sizeof(*f) + strlen(name) + 1); 104 | f->fd = -1; 105 | strcpy(f->name, name); 106 | return f; 107 | } 108 | /* is this a dir? */ 109 | /* -1 means it ain't anything .. */ 110 | static int 111 | isdir(char *path) { 112 | struct stat buf; 113 | 114 | if (stat(path, &buf) < 0) 115 | return -1; 116 | 117 | return S_ISDIR(buf.st_mode); 118 | } 119 | 120 | static void 121 | dostat(IxpStat *s, char *name, struct stat *buf) { 122 | 123 | s->type = 0; 124 | s->dev = 0; 125 | s->qid.type = buf->st_mode&S_IFMT; 126 | s->qid.path = buf->st_ino; 127 | s->qid.version = 0; 128 | s->mode = buf->st_mode & 0777; 129 | if (S_ISDIR(buf->st_mode)) { 130 | s->mode |= P9_DMDIR; 131 | s->qid.type |= QTDIR; 132 | } 133 | s->atime = buf->st_atime; 134 | s->mtime = buf->st_mtime; 135 | s->length = buf->st_size; 136 | s->name =name; 137 | s->uid = user; 138 | s->gid = user; 139 | s->muid = user; 140 | } 141 | 142 | /* the gnu/linux guys have made a real mess of errno ... don't ask --ron */ 143 | /* I agree. --Kris */ 144 | void 145 | rerrno(Ixp9Req *r, char *m) { 146 | /* 147 | char errbuf[128]; 148 | ixp_respond(r, strerror_r(errno, errbuf, sizeof(errbuf))); 149 | */ 150 | ixp_respond(r, m); 151 | } 152 | 153 | void 154 | fs_attach(Ixp9Req *r) { 155 | 156 | debug("fs_attach(%p)\n", r); 157 | 158 | r->fid->qid.type = QTDIR; 159 | r->fid->qid.path = (uintptr_t)r->fid; 160 | r->fid->aux = newfidaux("/"); 161 | r->ofcall.rattach.qid = r->fid->qid; 162 | ixp_respond(r, nil); 163 | } 164 | 165 | void 166 | fs_walk(Ixp9Req *r) { 167 | struct stat buf; 168 | char *name; 169 | FidAux *f; 170 | int i; 171 | 172 | debug("fs_walk(%p)\n", r); 173 | 174 | f = r->fid->aux; 175 | name = malloc(PATH_MAX); 176 | strcpy(name, f->name); 177 | if (stat(name, &buf) < 0){ 178 | ixp_respond(r, Enofile); 179 | return; 180 | } 181 | 182 | /* build full path. Stat full path. Done */ 183 | for(i=0; i < r->ifcall.twalk.nwname; i++) { 184 | strcat(name, "/"); 185 | strcat(name, r->ifcall.twalk.wname[i]); 186 | if (stat(name, &buf) < 0){ 187 | ixp_respond(r, Enofile); 188 | free(name); 189 | return; 190 | } 191 | r->ofcall.rwalk.wqid[i].type = buf.st_mode&S_IFMT; 192 | r->ofcall.rwalk.wqid[i].path = buf.st_ino; 193 | } 194 | 195 | r->newfid->aux = newfidaux(name); 196 | r->ofcall.rwalk.nwqid = i; 197 | free(name); 198 | ixp_respond(r, nil); 199 | } 200 | 201 | void 202 | fs_stat(Ixp9Req *r) { 203 | struct stat st; 204 | IxpStat s; 205 | IxpMsg m; 206 | char *name; 207 | char *buf; 208 | FidAux *f; 209 | int size; 210 | 211 | f = r->fid->aux; 212 | debug("fs_stat(%p)\n", r); 213 | debug("fs_stat %s\n", f->name); 214 | 215 | name = f->name; 216 | if (stat(name, &st) < 0){ 217 | ixp_respond(r, Enofile); 218 | return; 219 | } 220 | 221 | dostat(&s, name, &st); 222 | r->fid->qid = s.qid; 223 | r->ofcall.rstat.nstat = size = ixp_sizeof_stat(&s); 224 | 225 | buf = ixp_emallocz(size); 226 | 227 | m = ixp_message(buf, size, MsgPack); 228 | ixp_pstat(&m, &s); 229 | 230 | r->ofcall.rstat.stat = m.data; 231 | ixp_respond(r, nil); 232 | } 233 | 234 | void 235 | fs_read(Ixp9Req *r) { 236 | FidAux *f; 237 | char *buf; 238 | int n, offset; 239 | int size; 240 | 241 | debug("fs_read(%p)\n", r); 242 | 243 | f = r->fid->aux; 244 | 245 | if (f->dir) { 246 | IxpStat s; 247 | IxpMsg m; 248 | 249 | offset = 0; 250 | size = r->ifcall.tread.count; 251 | buf = ixp_emallocz(size); 252 | m = ixp_message(buf, size, MsgPack); 253 | 254 | /* note: we don't really handle lots of things well, so do one thing 255 | * at a time 256 | */ 257 | /*for(f=f->next; f; f=f->next) */{ 258 | struct dirent *d; 259 | struct stat st; 260 | d = readdir(f->dir); 261 | if (d) { 262 | stat(d->d_name, &st); 263 | dostat(&s, d->d_name, &st); 264 | n = ixp_sizeof_stat(&s); 265 | ixp_pstat(&m, &s); 266 | offset += n; 267 | } else n = 0; 268 | } 269 | r->ofcall.rread.count = n; 270 | r->ofcall.rread.data = (char*)m.data; 271 | ixp_respond(r, nil); 272 | return; 273 | } else { 274 | r->ofcall.rread.data = ixp_emallocz(r->ifcall.tread.count); 275 | if (! r->ofcall.rread.data) { 276 | ixp_respond(r, nil); 277 | return; 278 | } 279 | r->ofcall.rread.count = pread(f->fd, r->ofcall.rread.data, r->ifcall.tread.count, r->ifcall.tread.offset); 280 | if (r->ofcall.rread.count < 0) 281 | rerrno(r, Enoperm); 282 | else 283 | ixp_respond(r, nil); 284 | return; 285 | } 286 | 287 | /* 288 | * This is an assert because this should this should not be called if 289 | * the file is not open for reading. 290 | */ 291 | assert(!"Read called on an unreadable file"); 292 | } 293 | 294 | void 295 | fs_write(Ixp9Req *r) { 296 | FidAux *f; 297 | 298 | debug("fs_write(%p)\n", r); 299 | 300 | if(r->ifcall.twrite.count == 0) { 301 | ixp_respond(r, nil); 302 | return; 303 | } 304 | f = r->fid->aux; 305 | /* 306 | * This is an assert because this function should not be called if 307 | * the file is not open for writing. 308 | */ 309 | assert(!"Write called on an unwritable file"); 310 | } 311 | 312 | void 313 | fs_open(Ixp9Req *r) { 314 | int dir; 315 | FidAux *f; 316 | 317 | debug("fs_open(%p)\n", r); 318 | 319 | f = r->fid->aux; 320 | dir = isdir(f->name); 321 | /* fucking stupid linux -- open dir is a DIR */ 322 | 323 | if (dir) { 324 | f->dir = opendir(f->name); 325 | if (! f->dir){ 326 | rerrno(r, Enoperm); 327 | return; 328 | } 329 | } else { 330 | f->fd = open(f->name, O_RDONLY); 331 | if (f->fd < 0){ 332 | rerrno(r, Enoperm); 333 | return; 334 | } 335 | } 336 | ixp_respond(r, nil); 337 | } 338 | 339 | 340 | void 341 | fs_create(Ixp9Req *r) { 342 | debug("fs_create(%p)\n", r); 343 | ixp_respond(r, Enoperm); 344 | } 345 | 346 | void 347 | fs_remove(Ixp9Req *r) { 348 | debug("fs_remove(%p)\n", r); 349 | ixp_respond(r, Enoperm); 350 | 351 | } 352 | 353 | void 354 | fs_clunk(Ixp9Req *r) { 355 | int dir; 356 | FidAux *f; 357 | 358 | debug("fs_clunk(%p)\n", f); 359 | 360 | f = r->fid->aux; 361 | dir = isdir(f->name); 362 | if (dir) { 363 | (void) closedir(f->dir); 364 | f->dir = NULL; 365 | } else { 366 | (void) close(f->fd); 367 | f->fd = -1; 368 | } 369 | 370 | ixp_respond(r, nil); 371 | } 372 | 373 | void 374 | fs_flush(Ixp9Req *r) { 375 | debug("fs_flush(%p)\n", r); 376 | ixp_respond(r, nil); 377 | } 378 | 379 | void 380 | fs_freefid(IxpFid *f) { 381 | debug("fs_freefid(%p)\n", f); 382 | free(f->aux); 383 | } 384 | 385 | // mount -t 9p 127.1 /tmp/cache -o port=20006,noextend 386 | /* Yuck. */ 387 | #if defined(__linux__) 388 | # define MF(n) MS_##n 389 | # define mymount(src, dest, flags, opts) mount(src, dest, "9p", flags, opts) 390 | #elif defined(__FreeBSD__) || defined(__OpenBSD__) 391 | # define MF(n) MNT_##n 392 | # define mymount(src, dest, flags, opts) mount("9p", dest, flags, src) 393 | #endif 394 | 395 | static ulong mountflags = 396 | MF(NOATIME) 397 | | MF(NODEV) 398 | /* | MF(NODIRATIME) */ 399 | | MF(NOEXEC) 400 | | MF(NOSUID) 401 | | MF(RDONLY); 402 | 403 | int 404 | getaddr(char *mountaddr, char **ip, char **port) { 405 | char *cp; 406 | 407 | if (!mountaddr) 408 | mountaddr = getenv("XCPU_PARENT"); 409 | if (!mountaddr) 410 | return -1; 411 | 412 | cp = mountaddr; 413 | if (strcmp(cp, "tcp!")) 414 | cp += 4; 415 | 416 | *ip = cp; 417 | 418 | cp = strstr(cp, "!"); 419 | if (cp) 420 | *port = cp + 1; 421 | return strtoul(*port, 0, 0); 422 | } 423 | 424 | int 425 | main(int argc, char *argv[]) { 426 | int fd; 427 | int ret; 428 | int domount, mountonly; 429 | char *mountaddr; 430 | char *address; 431 | char *msg; 432 | IxpConn *acceptor; 433 | 434 | domount = 0; 435 | mountonly = 0; 436 | address = getenv("IXP_ADDRESS"); 437 | mountaddr = nil; 438 | 439 | ARGBEGIN{ 440 | case 'v': 441 | printf("%s-" VERSION ", ©2007 Ron Minnich\n", argv0); 442 | exit(0); 443 | case 'a': 444 | address = EARGF(usage()); 445 | break; 446 | case 'd': 447 | debuglevel++; 448 | break; 449 | case 'm': 450 | domount++; 451 | break; 452 | case 'M': 453 | mountonly++; 454 | break; 455 | default: 456 | usage(); 457 | }ARGEND; 458 | 459 | if(!address) 460 | fatal("$IXP_ADDRESS not set\n"); 461 | 462 | if(!(user = getenv("USER"))) 463 | fatal("$USER not set\n"); 464 | 465 | fd = ixp_announce(address); 466 | if(fd < 0) 467 | fatal("%s\n", errstr); 468 | 469 | /* set up a fake client so we can grap connects. */ 470 | acceptor = ixp_listen(&server, fd, &p9srv, ixp_serve9conn, NULL); 471 | 472 | /* we might need to mount ourselves. The bit of complexity is the need to fork so 473 | * we can serve ourselves. We've done the listen so that's ok. 474 | */ 475 | if (domount){ 476 | int f = fork(); 477 | if (f < 0) 478 | errx(1, "fork!"); 479 | if (!f){ 480 | char *addr, *aport; 481 | int port; 482 | char options[128]; 483 | 484 | port = getaddr(mountaddr, &addr, &aport); 485 | sprintf(options, "port=%d,noextend", port); 486 | if (mymount(addr, "/tmp/cache", mountflags, options) < 0) 487 | errx(1, "Mount failed"); 488 | } 489 | 490 | } 491 | 492 | if (mountonly) 493 | exit(0); 494 | 495 | ixp_serverloop(&server); 496 | printf("msg %s\n", ixp_errbuf()); 497 | return ret; 498 | } 499 | 500 | -------------------------------------------------------------------------------- /include/Makefile: -------------------------------------------------------------------------------- 1 | ROOT= .. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | HFILES = ixp.h \ 6 | ixp_srvutil.h 7 | 8 | install: $(HFILES:.h=.install) 9 | 10 | -------------------------------------------------------------------------------- /include/ixp_local.h: -------------------------------------------------------------------------------- 1 | #define IXP_NO_P9_ 2 | #include 3 | #include 4 | 5 | #undef ulong 6 | #define ulong _ixpulong 7 | typedef uint32_t ulong; 8 | 9 | #ifdef CPROTO 10 | # undef bool 11 | typedef int bool; 12 | typedef char* va_list; 13 | #endif 14 | 15 | #define ARGBEGIN \ 16 | int _argtmp=0, _inargv=0; char *_argv=nil; \ 17 | if(!argv0) {argv0=*argv; argv++, argc--;} \ 18 | _inargv=1; USED(_inargv); \ 19 | while(argc && argv[0][0] == '-') { \ 20 | _argv=&argv[0][1]; argv++; argc--; \ 21 | if(_argv[0] == '-' && _argv[1] == '\0') \ 22 | break; \ 23 | while(*_argv) switch(*_argv++) 24 | #define ARGEND }_inargv=0;USED(_argtmp, _argv, _inargv) 25 | 26 | #define EARGF(f) ((_inargv && *_argv) ? \ 27 | (_argtmp=strlen(_argv), _argv+=_argtmp, _argv-_argtmp) \ 28 | : ((argc > 0) ? \ 29 | (--argc, ++argv, _used(argc), *(argv-1)) \ 30 | : ((f), (char*)0))) 31 | #define ARGF() EARGF(_used(0)) 32 | 33 | #ifndef KENC 34 | static inline void _used(long a, ...) { if(a){} } 35 | # define USED(...) _used((long)__VA_ARGS__) 36 | # define SET(x) (x = 0) 37 | /* # define SET(x) USED(&x) GCC 4 is 'too smart' for this. */ 38 | #endif 39 | 40 | #undef nil 41 | #define nil ((void*)0) 42 | #define nelem(ary) (sizeof(ary) / sizeof(*ary)) 43 | 44 | #define thread ixp_thread 45 | 46 | #define eprint ixp_eprint 47 | #define emalloc ixp_emalloc 48 | #define emallocz ixp_emallocz 49 | #define estrdup ixp_estrdup 50 | #define erealloc ixp_erealloc 51 | #define strlcat ixp_strlcat 52 | #define tokenize ixp_tokenize 53 | 54 | #define muxinit ixp_muxinit 55 | #define muxfree ixp_muxfree 56 | #define muxrpc ixp_muxrpc 57 | 58 | #define errstr ixp_errstr 59 | #define rerrstr ixp_rerrstr 60 | #define werrstr ixp_werrstr 61 | 62 | typedef struct IxpMap Map; 63 | typedef struct MapEnt MapEnt; 64 | 65 | typedef IxpTimer Timer; 66 | 67 | typedef struct timeval timeval; 68 | 69 | struct IxpMap { 70 | MapEnt** bucket; 71 | int nhash; 72 | 73 | IxpRWLock lock; 74 | }; 75 | 76 | struct IxpTimer { 77 | Timer* link; 78 | uint64_t msec; 79 | long id; 80 | void (*fn)(long, void*); 81 | void* aux; 82 | }; 83 | 84 | /* map.c */ 85 | void ixp_mapfree(IxpMap*, void(*)(void*)); 86 | void ixp_mapexec(IxpMap*, void(*)(void*, void*), void*); 87 | void ixp_mapinit(IxpMap*, MapEnt**, int); 88 | bool ixp_mapinsert(IxpMap*, ulong, void*, bool); 89 | void* ixp_mapget(IxpMap*, ulong); 90 | void* ixp_maprm(IxpMap*, ulong); 91 | 92 | /* mux.c */ 93 | void muxfree(IxpClient*); 94 | void muxinit(IxpClient*); 95 | IxpFcall* muxrpc(IxpClient*, IxpFcall*); 96 | 97 | /* timer.c */ 98 | long ixp_nexttimer(IxpServer*); 99 | 100 | -------------------------------------------------------------------------------- /include/ixp_srvutil.h: -------------------------------------------------------------------------------- 1 | 2 | typedef struct IxpDirtab IxpDirtab; 3 | typedef struct IxpFileId IxpFileId; 4 | typedef struct IxpPendingLink IxpPendingLink; 5 | typedef struct IxpPending IxpPending; 6 | typedef struct IxpQueue IxpQueue; 7 | typedef struct IxpRequestLink IxpRequestLink; 8 | 9 | typedef IxpFileId* (*IxpLookupFn)(IxpFileId*, char*); 10 | 11 | struct IxpPendingLink { 12 | /* Private members */ 13 | IxpPendingLink* next; 14 | IxpPendingLink* prev; 15 | IxpFid* fid; 16 | IxpQueue* queue; 17 | IxpPending* pending; 18 | }; 19 | 20 | struct IxpRequestLink { 21 | /* Private members */ 22 | IxpRequestLink* next; 23 | IxpRequestLink* prev; 24 | Ixp9Req* req; 25 | }; 26 | 27 | struct IxpPending { 28 | /* Private members */ 29 | IxpRequestLink req; 30 | IxpPendingLink fids; 31 | }; 32 | 33 | struct IxpDirtab { 34 | char* name; 35 | uint8_t qtype; 36 | uint type; 37 | uint perm; 38 | uint flags; 39 | }; 40 | 41 | struct IxpFileId { 42 | IxpFileId* next; 43 | IxpFileIdU p; 44 | bool pending; 45 | uint id; 46 | uint index; 47 | IxpDirtab tab; 48 | uint nref; 49 | char volatil; 50 | }; 51 | 52 | enum { 53 | FLHide = 1, 54 | }; 55 | 56 | bool ixp_pending_clunk(Ixp9Req*); 57 | void ixp_pending_flush(Ixp9Req*); 58 | int ixp_pending_print(IxpPending*, const char*, ...); 59 | void ixp_pending_pushfid(IxpPending*, IxpFid*); 60 | void ixp_pending_respond(Ixp9Req*); 61 | int ixp_pending_vprint(IxpPending*, const char*, va_list ap); 62 | void ixp_pending_write(IxpPending*, const char*, long); 63 | IxpFileId* ixp_srv_clonefiles(IxpFileId*); 64 | void ixp_srv_data2cstring(Ixp9Req*); 65 | void ixp_srv_freefile(IxpFileId*); 66 | void ixp_srv_readbuf(Ixp9Req*, char*, uint); 67 | void ixp_srv_readdir(Ixp9Req*, IxpLookupFn, void (*)(IxpStat*, IxpFileId*)); 68 | bool ixp_srv_verifyfile(IxpFileId*, IxpLookupFn); 69 | void ixp_srv_walkandclone(Ixp9Req*, IxpLookupFn); 70 | void ixp_srv_writebuf(Ixp9Req*, char**, uint*, uint); 71 | char* ixp_srv_writectl(Ixp9Req*, char* (*)(void*, IxpMsg*)); 72 | IxpFileId* ixp_srv_getfile(void); 73 | 74 | 75 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | ROOT=.. 2 | include $(ROOT)/mk/hdr.mk 3 | 4 | DIRS = $(COMPONENTS) 5 | 6 | include $(ROOT)/mk/dir.mk 7 | 8 | -------------------------------------------------------------------------------- /lib/libixp/Makefile: -------------------------------------------------------------------------------- 1 | ROOT= ../.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | TARG = libixp 6 | 7 | OBJ = client \ 8 | convert \ 9 | error \ 10 | map \ 11 | message \ 12 | request \ 13 | rpc \ 14 | server \ 15 | srv_util \ 16 | socket \ 17 | thread \ 18 | timer \ 19 | transport \ 20 | util 21 | 22 | include $(ROOT)/mk/lib.mk 23 | 24 | -------------------------------------------------------------------------------- /lib/libixp/README: -------------------------------------------------------------------------------- 1 | libixp - simple 9P client-/server-library 2 | =============================== 3 | libixp is an extremly simple, stand-alone 9P library. 4 | 5 | 6 | Installation 7 | ------------ 8 | Edit config.mk to match your local setup. libixp is installed into 9 | /usr/local by default. 10 | 11 | Afterwards enter the following command to build and install libixp 12 | (if necessary as root): 13 | 14 | $ make clean install 15 | -------------------------------------------------------------------------------- /lib/libixp/convert.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007-2010 Kris Maglione 2 | * See LICENSE file for license details. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include "ixp_local.h" 8 | 9 | int _IXP_ASSERT_VERSION; 10 | 11 | enum { 12 | SByte = 1, 13 | SWord = 2, 14 | SDWord = 4, 15 | SQWord = 8, 16 | }; 17 | 18 | static void 19 | ixp_puint(IxpMsg *msg, uint size, uint32_t *val) { 20 | uint8_t *pos; 21 | int v; 22 | 23 | if(msg->pos + size <= msg->end) { 24 | pos = (uint8_t*)msg->pos; 25 | switch(msg->mode) { 26 | case MsgPack: 27 | v = *val; 28 | switch(size) { 29 | case SDWord: 30 | pos[3] = v>>24; 31 | pos[2] = v>>16; 32 | case SWord: 33 | pos[1] = v>>8; 34 | case SByte: 35 | pos[0] = v; 36 | break; 37 | } 38 | case MsgUnpack: 39 | v = 0; 40 | switch(size) { 41 | case SDWord: 42 | v |= pos[3]<<24; 43 | v |= pos[2]<<16; 44 | case SWord: 45 | v |= pos[1]<<8; 46 | case SByte: 47 | v |= pos[0]; 48 | break; 49 | } 50 | *val = v; 51 | } 52 | } 53 | msg->pos += size; 54 | } 55 | 56 | /** 57 | * Function: ixp_pu8 58 | * Function: ixp_pu16 59 | * Function: ixp_pu32 60 | * Function: ixp_pu64 61 | * 62 | * These functions pack or unpack an unsigned integer of the 63 | * specified size. 64 | * 65 | * If P->mode is MsgPack, the value pointed to by P is 66 | * packed into the buffer at P->pos. If P->mode is 67 | * MsgUnpack, the packed value at P->pos is loaded into the 68 | * location pointed to by P. In both cases, P->pos is 69 | * advanced by the number of bytes read or written. If the call 70 | * would advance P->pos beyond P->end, P->pos is 71 | * advanced, but nothing is modified. 72 | * 73 | * See also: 74 | * T 75 | */ 76 | void 77 | ixp_pu8(IxpMsg *msg, uint8_t *val) { 78 | uint32_t v; 79 | 80 | v = *val; 81 | ixp_puint(msg, SByte, &v); 82 | *val = (uint8_t)v; 83 | } 84 | void 85 | ixp_pu16(IxpMsg *msg, uint16_t *val) { 86 | uint32_t v; 87 | 88 | v = *val; 89 | ixp_puint(msg, SWord, &v); 90 | *val = (uint16_t)v; 91 | } 92 | void 93 | ixp_pu32(IxpMsg *msg, uint32_t *val) { 94 | ixp_puint(msg, SDWord, val); 95 | } 96 | void 97 | ixp_pu64(IxpMsg *msg, uint64_t *val) { 98 | uint32_t vl, vb; 99 | 100 | vl = (uint)*val; 101 | vb = (uint)(*val>>32); 102 | ixp_puint(msg, SDWord, &vl); 103 | ixp_puint(msg, SDWord, &vb); 104 | *val = vl | ((uint64_t)vb<<32); 105 | } 106 | 107 | /** 108 | * Function: ixp_pstring 109 | * 110 | * Packs or unpacks a UTF-8 encoded string. The packed 111 | * representation of the string consists of a 16-bit unsigned 112 | * integer followed by the contents of the string. The unpacked 113 | * representation is a nul-terminated character array. 114 | * 115 | * If P->mode is MsgPack, the string pointed to by P is 116 | * packed into the buffer at P->pos. If P->mode is 117 | * MsgUnpack, the address pointed to by P is loaded with a 118 | * malloc(3) allocated, nul-terminated representation of the 119 | * string packed at P->pos. In either case, P->pos is 120 | * advanced by the number of bytes read or written. If the 121 | * action would advance P->pos beyond P->end, 122 | * P->pos is still advanced but no other action is taken. 123 | * 124 | * See also: 125 | * T, F, F 126 | */ 127 | void 128 | ixp_pstring(IxpMsg *msg, char **s) { 129 | uint16_t len; 130 | 131 | if(msg->mode == MsgPack) 132 | len = strlen(*s); 133 | ixp_pu16(msg, &len); 134 | 135 | if(msg->pos + len <= msg->end) { 136 | if(msg->mode == MsgUnpack) { 137 | *s = emalloc(len + 1); 138 | memcpy(*s, msg->pos, len); 139 | (*s)[len] = '\0'; 140 | }else 141 | memcpy(msg->pos, *s, len); 142 | } 143 | msg->pos += len; 144 | } 145 | 146 | /** 147 | * Function: ixp_pstrings 148 | * 149 | * Packs or unpacks an array of UTF-8 encoded strings. The packed 150 | * representation consists of a 16-bit element count followed by 151 | * an array of strings as packed by F. The unpacked 152 | * representation is an array of nul-terminated character arrays. 153 | * 154 | * If P->mode is MsgPack, P<*num> strings in the array 155 | * pointed to by P are packed into the buffer at 156 | * P->pos. If P->mode is MsgUnpack, P<*num> is loaded 157 | * with the number of strings unpacked, the array at 158 | * P<*strings> is loaded with pointers to the unpacked strings, 159 | * and P<(*strings)[0]> must be freed by the user. In either 160 | * case, P->pos is advanced by the number of bytes read or 161 | * written. If the action would advance P->pos beyond 162 | * P->end, P->pos is still advanced, but no other 163 | * action is taken. If P<*num> is greater than P, 164 | * P->pos is set beyond P->end and no other action is 165 | * taken. 166 | * 167 | * See also: 168 | * P, P, P 169 | */ 170 | void 171 | ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings[], uint max) { 172 | char *s; 173 | uint i, size; 174 | uint16_t len; 175 | 176 | ixp_pu16(msg, num); 177 | if(*num > max) { 178 | msg->pos = msg->end+1; 179 | return; 180 | } 181 | 182 | SET(s); 183 | if(msg->mode == MsgUnpack) { 184 | s = msg->pos; 185 | size = 0; 186 | for(i=0; i < *num; i++) { 187 | ixp_pu16(msg, &len); 188 | msg->pos += len; 189 | size += len; 190 | if(msg->pos > msg->end) 191 | return; 192 | } 193 | msg->pos = s; 194 | size += *num; 195 | s = emalloc(size); 196 | } 197 | 198 | for(i=0; i < *num; i++) { 199 | if(msg->mode == MsgPack) 200 | len = strlen(strings[i]); 201 | ixp_pu16(msg, &len); 202 | 203 | if(msg->mode == MsgUnpack) { 204 | memcpy(s, msg->pos, len); 205 | strings[i] = (char*)s; 206 | s += len; 207 | msg->pos += len; 208 | *s++ = '\0'; 209 | }else 210 | ixp_pdata(msg, &strings[i], len); 211 | } 212 | } 213 | 214 | /** 215 | * Function: ixp_pdata 216 | * 217 | * Packs or unpacks a raw character buffer of size P. 218 | * 219 | * If P->mode is MsgPack, buffer pointed to by P is 220 | * packed into the buffer at P->pos. If P->mode is 221 | * MsgUnpack, the address pointed to by P is loaded with a 222 | * malloc(3) allocated buffer with the contents of the buffer at 223 | * P->pos. In either case, P->pos is advanced by the 224 | * number of bytes read or written. If the action would advance 225 | * P->pos beyond P->end, P->pos is still advanced 226 | * but no other action is taken. 227 | * 228 | * See also: 229 | * T, F 230 | */ 231 | void 232 | ixp_pdata(IxpMsg *msg, char **data, uint len) { 233 | if(msg->pos + len <= msg->end) { 234 | if(msg->mode == MsgUnpack) { 235 | *data = emalloc(len); 236 | memcpy(*data, msg->pos, len); 237 | }else 238 | memcpy(msg->pos, *data, len); 239 | } 240 | msg->pos += len; 241 | } 242 | 243 | /** 244 | * Function: ixp_pfcall 245 | * Function: ixp_pqid 246 | * Function: ixp_pqids 247 | * Function: ixp_pstat 248 | * Function: ixp_sizeof_stat 249 | * 250 | * These convenience functions pack or unpack the contents of 251 | * libixp structures into their wire format. They behave as if 252 | * F, F, F, F, and 253 | * F were called for each member of the structure 254 | * in question. ixp_pqid is to ixp_pqid as F is to 255 | * ixp_pstring. 256 | * 257 | * ixp_sizeof_stat returns the size of the packed represention 258 | * of P. 259 | * 260 | * See also: 261 | * T, F, F, F, 262 | * F, F, F 263 | */ 264 | void 265 | ixp_pqid(IxpMsg *msg, IxpQid *qid) { 266 | ixp_pu8(msg, &qid->type); 267 | ixp_pu32(msg, &qid->version); 268 | ixp_pu64(msg, &qid->path); 269 | } 270 | 271 | void 272 | ixp_pqids(IxpMsg *msg, uint16_t *num, IxpQid qid[], uint max) { 273 | int i; 274 | 275 | ixp_pu16(msg, num); 276 | if(*num > max) { 277 | msg->pos = msg->end+1; 278 | return; 279 | } 280 | 281 | for(i = 0; i < *num; i++) 282 | ixp_pqid(msg, &qid[i]); 283 | } 284 | 285 | void 286 | ixp_pstat(IxpMsg *msg, IxpStat *stat) { 287 | uint16_t size; 288 | 289 | if(msg->mode == MsgPack) 290 | size = ixp_sizeof_stat(stat) - 2; 291 | 292 | ixp_pu16(msg, &size); 293 | ixp_pu16(msg, &stat->type); 294 | ixp_pu32(msg, &stat->dev); 295 | ixp_pqid(msg, &stat->qid); 296 | ixp_pu32(msg, &stat->mode); 297 | ixp_pu32(msg, &stat->atime); 298 | ixp_pu32(msg, &stat->mtime); 299 | ixp_pu64(msg, &stat->length); 300 | ixp_pstring(msg, &stat->name); 301 | ixp_pstring(msg, &stat->uid); 302 | ixp_pstring(msg, &stat->gid); 303 | ixp_pstring(msg, &stat->muid); 304 | } 305 | -------------------------------------------------------------------------------- /lib/libixp/error.c: -------------------------------------------------------------------------------- 1 | /* Public Domain --Kris Maglione */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "ixp_local.h" 8 | 9 | static int 10 | _vsnprint(char *buf, int nbuf, const char *fmt, va_list ap) { 11 | return vsnprintf(buf, nbuf, fmt, ap); 12 | } 13 | 14 | static char* 15 | _vsmprint(const char *fmt, va_list ap) { 16 | va_list al; 17 | char *buf = ""; 18 | int n; 19 | 20 | va_copy(al, ap); 21 | n = vsnprintf(buf, 0, fmt, al); 22 | va_end(al); 23 | 24 | buf = malloc(++n); 25 | if(buf) 26 | vsnprintf(buf, n, fmt, ap); 27 | return buf; 28 | } 29 | 30 | int (*ixp_vsnprint)(char*, int, const char*, va_list) = _vsnprint; 31 | char* (*ixp_vsmprint)(const char*, va_list) = _vsmprint; 32 | 33 | /* Approach to errno handling taken from Plan 9 Port. */ 34 | enum { 35 | EPLAN9 = 0x19283745, 36 | }; 37 | 38 | /** 39 | * Function: ixp_errbuf 40 | * Function: ixp_errstr 41 | * Function: ixp_rerrstr 42 | * Function: ixp_werrstr 43 | * Variable: ixp_vsnprint 44 | * 45 | * Params: 46 | * buf: The buffer to read and/or fill. 47 | * nbuf: The size of the buffer. 48 | * fmt: A format string with which to write the errstr. 49 | * ...: Arguments to P. 50 | * 51 | * These functions simulate Plan 9's errstr functionality. 52 | * They replace errno in libixp. Note that these functions 53 | * are not internationalized. 54 | * 55 | * F returns the errstr buffer for the current 56 | * thread. F fills P with the data from 57 | * the current thread's error buffer, while F 58 | * exchanges P's contents with those of the current 59 | * thread's error buffer. F formats the given 60 | * format string, P, via V and writes it to 61 | * the error buffer. 62 | * 63 | * V may be set to a function which will format 64 | * its arguments write the result to the P length buffer 65 | * V. The default value is F. The function must 66 | * format '%s' as a nul-terminated string and may not consume 67 | * any arguments not indicated by a %-prefixed format specifier, 68 | * but may otherwise behave in any manner chosen by the user. 69 | * 70 | * See also: 71 | * V 72 | */ 73 | char* 74 | ixp_errbuf() { 75 | char *errbuf; 76 | 77 | errbuf = thread->errbuf(); 78 | if(errno == EINTR) 79 | strncpy(errbuf, "interrupted", IXP_ERRMAX); 80 | else if(errno != EPLAN9) 81 | strncpy(errbuf, strerror(errno), IXP_ERRMAX); 82 | return errbuf; 83 | } 84 | 85 | void 86 | errstr(char *buf, int nbuf) { 87 | char tmp[IXP_ERRMAX]; 88 | 89 | strncpy(tmp, buf, sizeof tmp); 90 | rerrstr(buf, nbuf); 91 | strncpy(thread->errbuf(), tmp, IXP_ERRMAX); 92 | errno = EPLAN9; 93 | } 94 | 95 | void 96 | rerrstr(char *buf, int nbuf) { 97 | strncpy(buf, ixp_errbuf(), nbuf); 98 | } 99 | 100 | void 101 | werrstr(const char *fmt, ...) { 102 | char tmp[IXP_ERRMAX]; 103 | va_list ap; 104 | 105 | va_start(ap, fmt); 106 | ixp_vsnprint(tmp, sizeof tmp, fmt, ap); 107 | va_end(ap); 108 | strncpy(thread->errbuf(), tmp, IXP_ERRMAX); 109 | errno = EPLAN9; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /lib/libixp/map.c: -------------------------------------------------------------------------------- 1 | /* Written by Kris Maglione */ 2 | /* Public domain */ 3 | #include 4 | #include "ixp_local.h" 5 | 6 | /* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */ 7 | 8 | struct MapEnt { 9 | ulong hash; 10 | const char* key; 11 | void* val; 12 | MapEnt* next; 13 | }; 14 | 15 | static MapEnt *NM; 16 | 17 | static void 18 | insert(MapEnt **e, ulong val, const char *key) { 19 | MapEnt *te; 20 | 21 | te = emallocz(sizeof *te); 22 | te->hash = val; 23 | te->key = key; 24 | te->next = *e; 25 | *e = te; 26 | } 27 | 28 | static MapEnt** 29 | map_getp(IxpMap *map, ulong val, bool create, bool *exists) { 30 | MapEnt **e; 31 | 32 | e = &map->bucket[val%map->nhash]; 33 | for(; *e; e = &(*e)->next) 34 | if((*e)->hash >= val) break; 35 | if(exists) 36 | *exists = *e && (*e)->hash == val; 37 | 38 | if(*e == nil || (*e)->hash != val) { 39 | if(create) 40 | insert(e, val, nil); 41 | else 42 | e = &NM; 43 | } 44 | return e; 45 | } 46 | 47 | void 48 | ixp_mapfree(IxpMap *map, void (*destroy)(void*)) { 49 | int i; 50 | MapEnt *e; 51 | 52 | thread->wlock(&map->lock); 53 | for(i=0; i < map->nhash; i++) 54 | while((e = map->bucket[i])) { 55 | map->bucket[i] = e->next; 56 | if(destroy) 57 | destroy(e->val); 58 | free(e); 59 | } 60 | thread->wunlock(&map->lock); 61 | thread->rwdestroy(&map->lock); 62 | } 63 | 64 | void 65 | ixp_mapexec(IxpMap *map, void (*run)(void*, void*), void *context) { 66 | int i; 67 | MapEnt *e; 68 | 69 | thread->rlock(&map->lock); 70 | for(i=0; i < map->nhash; i++) 71 | for(e=map->bucket[i]; e; e=e->next) 72 | run(context, e->val); 73 | thread->runlock(&map->lock); 74 | } 75 | 76 | void 77 | ixp_mapinit(IxpMap *map, MapEnt **buckets, int nbuckets) { 78 | 79 | map->bucket = buckets; 80 | map->nhash = nbuckets; 81 | 82 | thread->initrwlock(&map->lock); 83 | } 84 | 85 | bool 86 | ixp_mapinsert(IxpMap *map, ulong key, void *val, bool overwrite) { 87 | MapEnt *e; 88 | bool existed, res; 89 | 90 | res = true; 91 | thread->wlock(&map->lock); 92 | e = *map_getp(map, key, true, &existed); 93 | if(existed && !overwrite) 94 | res = false; 95 | else 96 | e->val = val; 97 | thread->wunlock(&map->lock); 98 | return res; 99 | } 100 | 101 | void* 102 | ixp_mapget(IxpMap *map, ulong val) { 103 | MapEnt *e; 104 | void *res; 105 | 106 | thread->rlock(&map->lock); 107 | e = *map_getp(map, val, false, nil); 108 | res = e ? e->val : nil; 109 | thread->runlock(&map->lock); 110 | return res; 111 | } 112 | 113 | void* 114 | ixp_maprm(IxpMap *map, ulong val) { 115 | MapEnt **e, *te; 116 | void *ret; 117 | 118 | ret = nil; 119 | thread->wlock(&map->lock); 120 | e = map_getp(map, val, false, nil); 121 | if(*e) { 122 | te = *e; 123 | ret = te->val; 124 | *e = te->next; 125 | thread->wunlock(&map->lock); 126 | free(te); 127 | } 128 | else 129 | thread->wunlock(&map->lock); 130 | return ret; 131 | } 132 | 133 | -------------------------------------------------------------------------------- /lib/libixp/message.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007-2010 Kris Maglione 2 | * See LICENSE file for license details. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include "ixp_local.h" 8 | 9 | enum { 10 | SByte = 1, 11 | SWord = 2, 12 | SDWord = 4, 13 | SQWord = 8, 14 | }; 15 | 16 | #define SString(s) (SWord + strlen(s)) 17 | enum { 18 | SQid = SByte + SDWord + SQWord, 19 | }; 20 | 21 | /** 22 | * Type: IxpMsg 23 | * Type: IxpMsgMode 24 | * Function: ixp_message 25 | * 26 | * The IxpMsg struct represents a binary message, and is used 27 | * extensively by libixp for converting messages to and from 28 | * wire format. The location and size of a buffer are stored in 29 | * P and P, respectively. P points to the 30 | * location in the message currently being packed or unpacked, 31 | * while P points to the end of the message. The packing 32 | * functions advance P as they go, always ensuring that 33 | * they don't read or write past P. When a message is 34 | * entirely packed or unpacked, P whould be less than or 35 | * equal to P. Any other state indicates error. 36 | * 37 | * ixp_message is a convenience function to pack a construct an 38 | * IxpMsg from a buffer of a given P and a given 39 | * P. P and P are set to P and P is 40 | * set to P + P. 41 | * 42 | * See also: 43 | * F, F, F, F, 44 | * F, F 45 | */ 46 | IxpMsg 47 | ixp_message(char *data, uint length, uint mode) { 48 | IxpMsg m; 49 | 50 | m.data = data; 51 | m.pos = data; 52 | m.end = data + length; 53 | m.size = length; 54 | m.mode = mode; 55 | return m; 56 | } 57 | 58 | /** 59 | * Function: ixp_freestat 60 | * Function: ixp_freefcall 61 | * 62 | * These functions free malloc(3) allocated data in the members 63 | * of the passed structures and set those members to nil. They 64 | * do not free the structures themselves. 65 | * 66 | * See also: 67 | * S, S 68 | */ 69 | void 70 | ixp_freestat(IxpStat *s) { 71 | free(s->name); 72 | free(s->uid); 73 | free(s->gid); 74 | free(s->muid); 75 | s->name = s->uid = s->gid = s->muid = nil; 76 | } 77 | 78 | void 79 | ixp_freefcall(IxpFcall *fcall) { 80 | switch(fcall->hdr.type) { 81 | case RStat: 82 | free(fcall->rstat.stat); 83 | fcall->rstat.stat = nil; 84 | break; 85 | case RRead: 86 | free(fcall->rread.data); 87 | fcall->rread.data = nil; 88 | break; 89 | case RVersion: 90 | free(fcall->version.version); 91 | fcall->version.version = nil; 92 | break; 93 | case RError: 94 | free(fcall->error.ename); 95 | fcall->error.ename = nil; 96 | break; 97 | } 98 | } 99 | 100 | uint16_t 101 | ixp_sizeof_stat(IxpStat *stat) { 102 | return SWord /* size */ 103 | + SWord /* type */ 104 | + SDWord /* dev */ 105 | + SQid /* qid */ 106 | + 3 * SDWord /* mode, atime, mtime */ 107 | + SQWord /* length */ 108 | + SString(stat->name) 109 | + SString(stat->uid) 110 | + SString(stat->gid) 111 | + SString(stat->muid); 112 | } 113 | 114 | void 115 | ixp_pfcall(IxpMsg *msg, IxpFcall *fcall) { 116 | ixp_pu8(msg, &fcall->hdr.type); 117 | ixp_pu16(msg, &fcall->hdr.tag); 118 | 119 | switch (fcall->hdr.type) { 120 | case TVersion: 121 | case RVersion: 122 | ixp_pu32(msg, &fcall->version.msize); 123 | ixp_pstring(msg, &fcall->version.version); 124 | break; 125 | case TAuth: 126 | ixp_pu32(msg, &fcall->tauth.afid); 127 | ixp_pstring(msg, &fcall->tauth.uname); 128 | ixp_pstring(msg, &fcall->tauth.aname); 129 | break; 130 | case RAuth: 131 | ixp_pqid(msg, &fcall->rauth.aqid); 132 | break; 133 | case RAttach: 134 | ixp_pqid(msg, &fcall->rattach.qid); 135 | break; 136 | case TAttach: 137 | ixp_pu32(msg, &fcall->hdr.fid); 138 | ixp_pu32(msg, &fcall->tattach.afid); 139 | ixp_pstring(msg, &fcall->tattach.uname); 140 | ixp_pstring(msg, &fcall->tattach.aname); 141 | break; 142 | case RError: 143 | ixp_pstring(msg, &fcall->error.ename); 144 | break; 145 | case TFlush: 146 | ixp_pu16(msg, &fcall->tflush.oldtag); 147 | break; 148 | case TWalk: 149 | ixp_pu32(msg, &fcall->hdr.fid); 150 | ixp_pu32(msg, &fcall->twalk.newfid); 151 | ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname, nelem(fcall->twalk.wname)); 152 | break; 153 | case RWalk: 154 | ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid, nelem(fcall->rwalk.wqid)); 155 | break; 156 | case TOpen: 157 | ixp_pu32(msg, &fcall->hdr.fid); 158 | ixp_pu8(msg, &fcall->topen.mode); 159 | break; 160 | case ROpen: 161 | case RCreate: 162 | ixp_pqid(msg, &fcall->ropen.qid); 163 | ixp_pu32(msg, &fcall->ropen.iounit); 164 | break; 165 | case TCreate: 166 | ixp_pu32(msg, &fcall->hdr.fid); 167 | ixp_pstring(msg, &fcall->tcreate.name); 168 | ixp_pu32(msg, &fcall->tcreate.perm); 169 | ixp_pu8(msg, &fcall->tcreate.mode); 170 | break; 171 | case TRead: 172 | ixp_pu32(msg, &fcall->hdr.fid); 173 | ixp_pu64(msg, &fcall->tread.offset); 174 | ixp_pu32(msg, &fcall->tread.count); 175 | break; 176 | case RRead: 177 | ixp_pu32(msg, &fcall->rread.count); 178 | ixp_pdata(msg, &fcall->rread.data, fcall->rread.count); 179 | break; 180 | case TWrite: 181 | ixp_pu32(msg, &fcall->hdr.fid); 182 | ixp_pu64(msg, &fcall->twrite.offset); 183 | ixp_pu32(msg, &fcall->twrite.count); 184 | ixp_pdata(msg, &fcall->twrite.data, fcall->twrite.count); 185 | break; 186 | case RWrite: 187 | ixp_pu32(msg, &fcall->rwrite.count); 188 | break; 189 | case TClunk: 190 | case TRemove: 191 | case TStat: 192 | ixp_pu32(msg, &fcall->hdr.fid); 193 | break; 194 | case RStat: 195 | ixp_pu16(msg, &fcall->rstat.nstat); 196 | ixp_pdata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat); 197 | break; 198 | case TWStat: { 199 | uint16_t size; 200 | ixp_pu32(msg, &fcall->hdr.fid); 201 | ixp_pu16(msg, &size); 202 | ixp_pstat(msg, &fcall->twstat.stat); 203 | break; 204 | } 205 | } 206 | } 207 | 208 | /** 209 | * Function: ixp_fcall2msg 210 | * Function: ixp_msg2fcall 211 | * 212 | * These functions pack or unpack a 9P protocol message. The 213 | * message is set to the appropriate mode and its position is 214 | * set to the begining of its buffer. 215 | * 216 | * Returns: 217 | * These functions return the size of the message on 218 | * success and 0 on failure. 219 | * See also: 220 | * F, F 221 | */ 222 | uint 223 | ixp_fcall2msg(IxpMsg *msg, IxpFcall *fcall) { 224 | uint32_t size; 225 | 226 | msg->end = msg->data + msg->size; 227 | msg->pos = msg->data + SDWord; 228 | msg->mode = MsgPack; 229 | ixp_pfcall(msg, fcall); 230 | 231 | if(msg->pos > msg->end) 232 | return 0; 233 | 234 | msg->end = msg->pos; 235 | size = msg->end - msg->data; 236 | 237 | msg->pos = msg->data; 238 | ixp_pu32(msg, &size); 239 | 240 | msg->pos = msg->data; 241 | return size; 242 | } 243 | 244 | uint 245 | ixp_msg2fcall(IxpMsg *msg, IxpFcall *fcall) { 246 | msg->pos = msg->data + SDWord; 247 | msg->mode = MsgUnpack; 248 | ixp_pfcall(msg, fcall); 249 | 250 | if(msg->pos > msg->end) 251 | return 0; 252 | 253 | return msg->pos - msg->data; 254 | } 255 | 256 | -------------------------------------------------------------------------------- /lib/libixp/rpc.c: -------------------------------------------------------------------------------- 1 | /* From Plan 9's libmux. 2 | * Copyright (c) 2003 Russ Cox, Massachusetts Institute of Technology 3 | * Distributed under the same terms as libixp. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ixp_local.h" 10 | 11 | static int gettag(IxpClient*, IxpRpc*); 12 | static void puttag(IxpClient*, IxpRpc*); 13 | static void enqueue(IxpClient*, IxpRpc*); 14 | static void dequeue(IxpClient*, IxpRpc*); 15 | 16 | void 17 | muxinit(IxpClient *mux) 18 | { 19 | mux->tagrend.mutex = &mux->lk; 20 | mux->sleep.next = &mux->sleep; 21 | mux->sleep.prev = &mux->sleep; 22 | thread->initmutex(&mux->lk); 23 | thread->initmutex(&mux->rlock); 24 | thread->initmutex(&mux->wlock); 25 | thread->initrendez(&mux->tagrend); 26 | } 27 | 28 | void 29 | muxfree(IxpClient *mux) 30 | { 31 | thread->mdestroy(&mux->lk); 32 | thread->mdestroy(&mux->rlock); 33 | thread->mdestroy(&mux->wlock); 34 | thread->rdestroy(&mux->tagrend); 35 | free(mux->wait); 36 | } 37 | 38 | static void 39 | initrpc(IxpClient *mux, IxpRpc *r) 40 | { 41 | r->mux = mux; 42 | r->waiting = 1; 43 | r->r.mutex = &mux->lk; 44 | r->p = nil; 45 | thread->initrendez(&r->r); 46 | } 47 | 48 | static void 49 | freemuxrpc(IxpRpc *r) 50 | { 51 | thread->rdestroy(&r->r); 52 | } 53 | 54 | static int 55 | sendrpc(IxpRpc *r, IxpFcall *f) 56 | { 57 | int ret; 58 | IxpClient *mux; 59 | 60 | ret = 0; 61 | mux = r->mux; 62 | /* assign the tag, add selves to response queue */ 63 | thread->lock(&mux->lk); 64 | r->tag = gettag(mux, r); 65 | f->hdr.tag = r->tag; 66 | enqueue(mux, r); 67 | thread->unlock(&mux->lk); 68 | 69 | thread->lock(&mux->wlock); 70 | if(!ixp_fcall2msg(&mux->wmsg, f) || !ixp_sendmsg(mux->fd, &mux->wmsg)) { 71 | /* werrstr("settag/send tag %d: %r", tag); fprint(2, "%r\n"); */ 72 | thread->lock(&mux->lk); 73 | dequeue(mux, r); 74 | puttag(mux, r); 75 | thread->unlock(&mux->lk); 76 | ret = -1; 77 | } 78 | thread->unlock(&mux->wlock); 79 | return ret; 80 | } 81 | 82 | static IxpFcall* 83 | muxrecv(IxpClient *mux) 84 | { 85 | IxpFcall *f; 86 | 87 | f = nil; 88 | thread->lock(&mux->rlock); 89 | if(ixp_recvmsg(mux->fd, &mux->rmsg) == 0) 90 | goto fail; 91 | f = emallocz(sizeof *f); 92 | if(ixp_msg2fcall(&mux->rmsg, f) == 0) { 93 | free(f); 94 | f = nil; 95 | } 96 | fail: 97 | thread->unlock(&mux->rlock); 98 | return f; 99 | } 100 | 101 | static void 102 | dispatchandqlock(IxpClient *mux, IxpFcall *f) 103 | { 104 | int tag; 105 | IxpRpc *r2; 106 | 107 | tag = f->hdr.tag - mux->mintag; 108 | thread->lock(&mux->lk); 109 | /* hand packet to correct sleeper */ 110 | if(tag < 0 || tag >= mux->mwait) { 111 | fprintf(stderr, "libixp: received unfeasible tag: %d (min: %d, max: %d)\n", f->hdr.tag, mux->mintag, mux->mintag+mux->mwait); 112 | goto fail; 113 | } 114 | r2 = mux->wait[tag]; 115 | if(r2 == nil || r2->prev == nil) { 116 | fprintf(stderr, "libixp: received message with bad tag\n"); 117 | goto fail; 118 | } 119 | r2->p = f; 120 | dequeue(mux, r2); 121 | thread->wake(&r2->r); 122 | return; 123 | fail: 124 | ixp_freefcall(f); 125 | free(f); 126 | } 127 | 128 | static void 129 | electmuxer(IxpClient *mux) 130 | { 131 | IxpRpc *rpc; 132 | 133 | /* if there is anyone else sleeping, wake them to mux */ 134 | for(rpc=mux->sleep.next; rpc != &mux->sleep; rpc = rpc->next){ 135 | if(!rpc->async){ 136 | mux->muxer = rpc; 137 | thread->wake(&rpc->r); 138 | return; 139 | } 140 | } 141 | mux->muxer = nil; 142 | } 143 | 144 | IxpFcall* 145 | muxrpc(IxpClient *mux, IxpFcall *tx) 146 | { 147 | IxpRpc r; 148 | IxpFcall *p; 149 | 150 | initrpc(mux, &r); 151 | if(sendrpc(&r, tx) < 0) 152 | return nil; 153 | 154 | thread->lock(&mux->lk); 155 | /* wait for our packet */ 156 | while(mux->muxer && mux->muxer != &r && !r.p) 157 | thread->sleep(&r.r); 158 | 159 | /* if not done, there's no muxer; start muxing */ 160 | if(!r.p){ 161 | assert(mux->muxer == nil || mux->muxer == &r); 162 | mux->muxer = &r; 163 | while(!r.p){ 164 | thread->unlock(&mux->lk); 165 | p = muxrecv(mux); 166 | if(p == nil){ 167 | /* eof -- just give up and pass the buck */ 168 | thread->lock(&mux->lk); 169 | dequeue(mux, &r); 170 | break; 171 | } 172 | dispatchandqlock(mux, p); 173 | } 174 | electmuxer(mux); 175 | } 176 | p = r.p; 177 | puttag(mux, &r); 178 | thread->unlock(&mux->lk); 179 | if(p == nil) 180 | werrstr("unexpected eof"); 181 | return p; 182 | } 183 | 184 | static void 185 | enqueue(IxpClient *mux, IxpRpc *r) 186 | { 187 | r->next = mux->sleep.next; 188 | r->prev = &mux->sleep; 189 | r->next->prev = r; 190 | r->prev->next = r; 191 | } 192 | 193 | static void 194 | dequeue(IxpClient *mux, IxpRpc *r) 195 | { 196 | r->next->prev = r->prev; 197 | r->prev->next = r->next; 198 | r->prev = nil; 199 | r->next = nil; 200 | } 201 | 202 | static int 203 | gettag(IxpClient *mux, IxpRpc *r) 204 | { 205 | int i, mw; 206 | IxpRpc **w; 207 | 208 | for(;;){ 209 | /* wait for a free tag */ 210 | while(mux->nwait == mux->mwait){ 211 | if(mux->mwait < mux->maxtag-mux->mintag){ 212 | mw = mux->mwait; 213 | if(mw == 0) 214 | mw = 1; 215 | else 216 | mw <<= 1; 217 | w = realloc(mux->wait, mw * sizeof *w); 218 | if(w == nil) 219 | return -1; 220 | memset(w+mux->mwait, 0, (mw-mux->mwait) * sizeof *w); 221 | mux->wait = w; 222 | mux->freetag = mux->mwait; 223 | mux->mwait = mw; 224 | break; 225 | } 226 | thread->sleep(&mux->tagrend); 227 | } 228 | 229 | i=mux->freetag; 230 | if(mux->wait[i] == 0) 231 | goto Found; 232 | for(; imwait; i++) 233 | if(mux->wait[i] == 0) 234 | goto Found; 235 | for(i=0; ifreetag; i++) 236 | if(mux->wait[i] == 0) 237 | goto Found; 238 | /* should not fall out of while without free tag */ 239 | abort(); 240 | } 241 | 242 | Found: 243 | mux->nwait++; 244 | mux->wait[i] = r; 245 | r->tag = i+mux->mintag; 246 | return r->tag; 247 | } 248 | 249 | static void 250 | puttag(IxpClient *mux, IxpRpc *r) 251 | { 252 | int i; 253 | 254 | i = r->tag - mux->mintag; 255 | assert(mux->wait[i] == r); 256 | mux->wait[i] = nil; 257 | mux->nwait--; 258 | mux->freetag = i; 259 | thread->wake(&mux->tagrend); 260 | freemuxrpc(r); 261 | } 262 | 263 | -------------------------------------------------------------------------------- /lib/libixp/server.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2006-2010 Kris Maglione 2 | /* Copyright ©2004-2006 Anselm R. Garbe 3 | * See LICENSE file for license details. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "ixp_local.h" 12 | 13 | /** 14 | * Function: ixp_listen 15 | * Type: IxpConn 16 | * 17 | * Params: 18 | * fs: The file descriptor on which to listen. 19 | * aux: A piece of data to store in the connection's 20 | * P member of the IxpConn data structure. 21 | * read: The function called when the connection has 22 | * data available to read. 23 | * close: A cleanup function called when the 24 | * connection is closed. 25 | * 26 | * Starts the server P listening on P. The optional 27 | * P and P callbacks are called with the IxpConn 28 | * structure for the connection as their sole argument. 29 | * 30 | * Returns: 31 | * Returns the connection's new IxpConn data structure. 32 | * 33 | * See also: 34 | * F, F, F 35 | */ 36 | IxpConn* 37 | ixp_listen(IxpServer *srv, int fd, void *aux, 38 | void (*read)(IxpConn*), 39 | void (*close)(IxpConn*) 40 | ) { 41 | IxpConn *c; 42 | 43 | c = emallocz(sizeof *c); 44 | c->fd = fd; 45 | c->aux = aux; 46 | c->srv = srv; 47 | c->read = read; 48 | c->close = close; 49 | c->next = srv->conn; 50 | srv->conn = c; 51 | return c; 52 | } 53 | 54 | /** 55 | * Function: ixp_hangup 56 | * Function: ixp_server_close 57 | * 58 | * ixp_hangup closes a connection, and stops the server 59 | * listening on it. It calls the connection's close 60 | * function, if it exists. ixp_server_close calls ixp_hangup 61 | * on all of the connections on which the server is 62 | * listening. 63 | * 64 | * See also: 65 | * F, S, S 66 | */ 67 | 68 | void 69 | ixp_hangup(IxpConn *c) { 70 | IxpServer *s; 71 | IxpConn **tc; 72 | 73 | s = c->srv; 74 | for(tc=&s->conn; *tc; tc=&(*tc)->next) 75 | if(*tc == c) break; 76 | assert(*tc == c); 77 | 78 | *tc = c->next; 79 | c->closed = 1; 80 | if(c->close) 81 | c->close(c); 82 | else 83 | shutdown(c->fd, SHUT_RDWR); 84 | 85 | close(c->fd); 86 | free(c); 87 | } 88 | 89 | void 90 | ixp_server_close(IxpServer *s) { 91 | IxpConn *c, *next; 92 | 93 | for(c = s->conn; c; c = next) { 94 | next = c->next; 95 | ixp_hangup(c); 96 | } 97 | } 98 | 99 | static void 100 | prepare_select(IxpServer *s) { 101 | IxpConn *c; 102 | 103 | FD_ZERO(&s->rd); 104 | for(c = s->conn; c; c = c->next) 105 | if(c->read) { 106 | if(s->maxfd < c->fd) 107 | s->maxfd = c->fd; 108 | FD_SET(c->fd, &s->rd); 109 | } 110 | } 111 | 112 | static void 113 | handle_conns(IxpServer *s) { 114 | IxpConn *c, *n; 115 | for(c = s->conn; c; c = n) { 116 | n = c->next; 117 | if(FD_ISSET(c->fd, &s->rd)) 118 | c->read(c); 119 | } 120 | } 121 | 122 | /** 123 | * Function: ixp_serverloop 124 | * Type: IxpServer 125 | * 126 | * Enters the main loop of the server. Exits when 127 | * P->running becomes false, or when select(2) returns an 128 | * error other than EINTR. 129 | * 130 | * Returns: 131 | * Returns 0 when the loop exits normally, and 1 when 132 | * it exits on error. V or the return value of 133 | * F may be inspected. 134 | * See also: 135 | * F, F 136 | */ 137 | 138 | int 139 | ixp_serverloop(IxpServer *srv) { 140 | timeval *tvp; 141 | timeval tv; 142 | long timeout; 143 | int r; 144 | 145 | srv->running = 1; 146 | thread->initmutex(&srv->lk); 147 | while(srv->running) { 148 | tvp = nil; 149 | timeout = ixp_nexttimer(srv); 150 | if(timeout > 0) { 151 | tv.tv_sec = timeout/1000; 152 | tv.tv_usec = timeout%1000 * 1000; 153 | tvp = &tv; 154 | } 155 | 156 | if(srv->preselect) 157 | srv->preselect(srv); 158 | 159 | if(!srv->running) 160 | break; 161 | 162 | prepare_select(srv); 163 | r = thread->select(srv->maxfd + 1, &srv->rd, 0, 0, tvp); 164 | if(r < 0) { 165 | if(errno == EINTR) 166 | continue; 167 | return 1; 168 | } 169 | handle_conns(srv); 170 | } 171 | return 0; 172 | } 173 | 174 | -------------------------------------------------------------------------------- /lib/libixp/socket.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007-2010 Kris Maglione 2 | * Copyright ©2004-2006 Anselm R. Garbe 3 | * See LICENSE file for license details. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "ixp_local.h" 18 | 19 | /* Note: These functions modify the strings that they are passed. 20 | * The lookup function duplicates the original string, so it is 21 | * not modified. 22 | */ 23 | 24 | /* From FreeBSD's sys/su.h */ 25 | #define SUN_LEN(su) \ 26 | (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 27 | 28 | typedef struct addrinfo addrinfo; 29 | typedef struct sockaddr sockaddr; 30 | typedef struct sockaddr_un sockaddr_un; 31 | typedef struct sockaddr_in sockaddr_in; 32 | 33 | static char* 34 | get_port(char *addr) { 35 | char *s; 36 | 37 | s = strchr(addr, '!'); 38 | if(s == nil) { 39 | werrstr("no port provided"); 40 | return nil; 41 | } 42 | 43 | *s++ = '\0'; 44 | if(*s == '\0') { 45 | werrstr("invalid port number"); 46 | return nil; 47 | } 48 | return s; 49 | } 50 | 51 | static int 52 | sock_unix(char *address, sockaddr_un *sa, socklen_t *salen) { 53 | int fd; 54 | 55 | memset(sa, 0, sizeof *sa); 56 | 57 | sa->sun_family = AF_UNIX; 58 | strncpy(sa->sun_path, address, sizeof sa->sun_path); 59 | *salen = SUN_LEN(sa); 60 | 61 | fd = socket(AF_UNIX, SOCK_STREAM, 0); 62 | if(fd < 0) 63 | return -1; 64 | return fd; 65 | } 66 | 67 | static int 68 | dial_unix(char *address) { 69 | sockaddr_un sa; 70 | socklen_t salen; 71 | int fd; 72 | 73 | fd = sock_unix(address, &sa, &salen); 74 | if(fd == -1) 75 | return fd; 76 | 77 | if(connect(fd, (sockaddr*) &sa, salen)) { 78 | close(fd); 79 | return -1; 80 | } 81 | return fd; 82 | } 83 | 84 | static int 85 | announce_unix(char *file) { 86 | const int yes = 1; 87 | sockaddr_un sa; 88 | socklen_t salen; 89 | int fd; 90 | 91 | signal(SIGPIPE, SIG_IGN); 92 | 93 | fd = sock_unix(file, &sa, &salen); 94 | if(fd == -1) 95 | return fd; 96 | 97 | if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof yes) < 0) 98 | goto fail; 99 | 100 | unlink(file); 101 | if(bind(fd, (sockaddr*)&sa, salen) < 0) 102 | goto fail; 103 | 104 | chmod(file, S_IRWXU); 105 | if(listen(fd, IXP_MAX_CACHE) < 0) 106 | goto fail; 107 | 108 | return fd; 109 | 110 | fail: 111 | close(fd); 112 | return -1; 113 | } 114 | 115 | static addrinfo* 116 | alookup(char *host, int announce) { 117 | addrinfo hints, *ret; 118 | char *port; 119 | int err; 120 | 121 | /* Truncates host at '!' */ 122 | port = get_port(host); 123 | if(port == nil) 124 | return nil; 125 | 126 | memset(&hints, 0, sizeof hints); 127 | hints.ai_family = AF_INET; 128 | hints.ai_socktype = SOCK_STREAM; 129 | 130 | if(announce) { 131 | hints.ai_flags = AI_PASSIVE; 132 | if(!strcmp(host, "*")) 133 | host = nil; 134 | } 135 | 136 | err = getaddrinfo(host, port, &hints, &ret); 137 | if(err) { 138 | werrstr("getaddrinfo: %s", gai_strerror(err)); 139 | return nil; 140 | } 141 | return ret; 142 | } 143 | 144 | static int 145 | ai_socket(addrinfo *ai) { 146 | return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 147 | } 148 | 149 | static int 150 | dial_tcp(char *host) { 151 | addrinfo *ai, *aip; 152 | int fd; 153 | 154 | aip = alookup(host, 0); 155 | if(aip == nil) 156 | return -1; 157 | 158 | SET(fd); 159 | for(ai = aip; ai; ai = ai->ai_next) { 160 | fd = ai_socket(ai); 161 | if(fd == -1) { 162 | werrstr("socket: %s", strerror(errno)); 163 | continue; 164 | } 165 | 166 | if(connect(fd, ai->ai_addr, ai->ai_addrlen) == 0) 167 | break; 168 | 169 | werrstr("connect: %s", strerror(errno)); 170 | close(fd); 171 | fd = -1; 172 | } 173 | 174 | freeaddrinfo(aip); 175 | return fd; 176 | } 177 | 178 | static int 179 | announce_tcp(char *host) { 180 | addrinfo *ai, *aip; 181 | int fd; 182 | 183 | aip = alookup(host, 1); 184 | if(aip == nil) 185 | return -1; 186 | 187 | /* Probably don't need to loop */ 188 | SET(fd); 189 | for(ai = aip; ai; ai = ai->ai_next) { 190 | fd = ai_socket(ai); 191 | if(fd == -1) 192 | continue; 193 | 194 | if(bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) 195 | goto fail; 196 | 197 | if(listen(fd, IXP_MAX_CACHE) < 0) 198 | goto fail; 199 | break; 200 | fail: 201 | close(fd); 202 | fd = -1; 203 | } 204 | 205 | freeaddrinfo(aip); 206 | return fd; 207 | } 208 | 209 | typedef struct addrtab addrtab; 210 | static 211 | struct addrtab { 212 | char *type; 213 | int (*fn)(char*); 214 | } dtab[] = { 215 | {"tcp", dial_tcp}, 216 | {"unix", dial_unix}, 217 | {0, 0} 218 | }, atab[] = { 219 | {"tcp", announce_tcp}, 220 | {"unix", announce_unix}, 221 | {0, 0} 222 | }; 223 | 224 | static int 225 | lookup(const char *address, addrtab *tab) { 226 | char *addr, *type; 227 | int ret; 228 | 229 | ret = -1; 230 | type = estrdup(address); 231 | 232 | addr = strchr(type, '!'); 233 | if(addr == nil) 234 | werrstr("no address type defined"); 235 | else { 236 | *addr++ = '\0'; 237 | for(; tab->type; tab++) 238 | if(strcmp(tab->type, type) == 0) break; 239 | if(tab->type == nil) 240 | werrstr("unsupported address type"); 241 | else 242 | ret = tab->fn(addr); 243 | } 244 | 245 | free(type); 246 | return ret; 247 | } 248 | 249 | /** 250 | * Function: ixp_dial 251 | * Function: ixp_announce 252 | * 253 | * Params: 254 | * address: An address on which to connect or listen, 255 | * specified in the Plan 9 resources 256 | * specification format 257 | * (!address[!]) 258 | * 259 | * These functions hide some of the ugliness of Berkely 260 | * Sockets. ixp_dial connects to the resource at P
, 261 | * while ixp_announce begins listening on P
. 262 | * 263 | * Returns: 264 | * These functions return file descriptors on success, and -1 265 | * on failure. ixp_errbuf(3) may be inspected on failure. 266 | * See also: 267 | * socket(2) 268 | */ 269 | 270 | int 271 | ixp_dial(const char *address) { 272 | return lookup(address, dtab); 273 | } 274 | 275 | int 276 | ixp_announce(const char *address) { 277 | return lookup(address, atab); 278 | } 279 | 280 | -------------------------------------------------------------------------------- /lib/libixp/thread.c: -------------------------------------------------------------------------------- 1 | /* Public Domain --Kris Maglione */ 2 | #include 3 | #include "ixp_local.h" 4 | 5 | static IxpThread ixp_nothread; 6 | IxpThread* ixp_thread = &ixp_nothread; 7 | 8 | static char* 9 | errbuf(void) { 10 | static char errbuf[IXP_ERRMAX]; 11 | 12 | return errbuf; 13 | } 14 | 15 | static void 16 | mvoid(IxpMutex *m) { 17 | USED(m); 18 | return; 19 | } 20 | 21 | static int 22 | mtrue(IxpMutex *m) { 23 | USED(m); 24 | return 1; 25 | } 26 | 27 | static int 28 | mfalse(IxpMutex *m) { 29 | USED(m); 30 | return 0; 31 | } 32 | 33 | static void 34 | rwvoid(IxpRWLock *rw) { 35 | USED(rw); 36 | return; 37 | } 38 | 39 | static int 40 | rwtrue(IxpRWLock *rw) { 41 | USED(rw); 42 | return 1; 43 | } 44 | 45 | static int 46 | rwfalse(IxpRWLock *m) { 47 | USED(m); 48 | return 0; 49 | } 50 | 51 | static void 52 | rvoid(IxpRendez *r) { 53 | USED(r); 54 | return; 55 | } 56 | 57 | static int 58 | rfalse(IxpRendez *r) { 59 | USED(r); 60 | return 0; 61 | } 62 | 63 | static void 64 | rsleep(IxpRendez *r) { 65 | USED(r); 66 | eprint("rsleep called when not implemented\n"); 67 | } 68 | 69 | static IxpThread ixp_nothread = { 70 | /* RWLock */ 71 | .initrwlock = rwfalse, 72 | .rlock = rwvoid, 73 | .runlock = rwvoid, 74 | .canrlock = rwtrue, 75 | .wlock = rwvoid, 76 | .wunlock = rwvoid, 77 | .canwlock = rwtrue, 78 | .rwdestroy = rwvoid, 79 | /* Mutex */ 80 | .initmutex = mfalse, 81 | .lock = mvoid, 82 | .unlock = mvoid, 83 | .canlock = mtrue, 84 | .mdestroy = mvoid, 85 | /* Rendez */ 86 | .initrendez = rfalse, 87 | .sleep = rsleep, 88 | .wake = rfalse, 89 | .wakeall = rfalse, 90 | .rdestroy = rvoid, 91 | /* Other */ 92 | .errbuf = errbuf, 93 | .read = read, 94 | .write = write, 95 | .select = select, 96 | }; 97 | 98 | -------------------------------------------------------------------------------- /lib/libixp/timer.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2008-2010 Kris Maglione 2 | * See LICENSE file for license details. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include "ixp_local.h" 8 | 9 | /* 10 | * This really needn't be threadsafe, as it has little use in 11 | * threaded programs, but it nonetheless is. 12 | */ 13 | 14 | static long lastid = 1; 15 | 16 | /** 17 | * Function: ixp_msec 18 | * 19 | * Returns the time since the Epoch in milliseconds. 20 | */ 21 | uint64_t 22 | ixp_msec(void) { 23 | timeval tv; 24 | 25 | gettimeofday(&tv, 0); 26 | return (uint64_t)tv.tv_sec*1000 + (uint64_t)tv.tv_usec/1000; 27 | } 28 | 29 | /** 30 | * Function: ixp_settimer 31 | * 32 | * Params: 33 | * msec: The timeout in milliseconds. 34 | * fn: The function to call after P milliseconds 35 | * have elapsed. 36 | * aux: An arbitrary argument to pass to P when it 37 | * is called. 38 | * 39 | * Initializes a callback-based timer to be triggerred after 40 | * P milliseconds. The timer is passed its id number 41 | * and the value of P. 42 | * 43 | * Returns: 44 | * Returns the new timer's unique id number. 45 | * See also: 46 | * F, F 47 | */ 48 | long 49 | ixp_settimer(IxpServer *srv, long msec, void (*fn)(long, void*), void *aux) { 50 | Timer **tp; 51 | Timer *t; 52 | uint64_t time; 53 | 54 | time = ixp_msec() + msec; 55 | 56 | t = emallocz(sizeof *t); 57 | thread->lock(&srv->lk); 58 | t->id = lastid++; 59 | t->msec = time; 60 | t->fn = fn; 61 | t->aux = aux; 62 | 63 | for(tp=&srv->timer; *tp; tp=&tp[0]->link) 64 | if(tp[0]->msec < time) 65 | break; 66 | t->link = *tp; 67 | *tp = t; 68 | thread->unlock(&srv->lk); 69 | return t->id; 70 | } 71 | 72 | /** 73 | * Function: ixp_unsettimer 74 | * 75 | * Params: 76 | * id: The id number of the timer to void. 77 | * 78 | * Voids the timer identified by P. 79 | * 80 | * Returns: 81 | * Returns true if a timer was stopped, false 82 | * otherwise. 83 | * See also: 84 | * F, F 85 | */ 86 | int 87 | ixp_unsettimer(IxpServer *srv, long id) { 88 | Timer **tp; 89 | Timer *t; 90 | 91 | thread->lock(&srv->lk); 92 | for(tp=&srv->timer; (t=*tp); tp=&t->link) 93 | if(t->id == id) 94 | break; 95 | if(t) { 96 | *tp = t->link; 97 | free(t); 98 | } 99 | thread->unlock(&srv->lk); 100 | return t != nil; 101 | } 102 | 103 | /* 104 | * Function: ixp_nexttimer 105 | * 106 | * Triggers any timers whose timeouts have ellapsed. This is 107 | * primarily intended to be called from libixp's select 108 | * loop. 109 | * 110 | * Returns: 111 | * Returns the number of milliseconds until the next 112 | * timer's timeout. 113 | * See also: 114 | * F, F 115 | */ 116 | long 117 | ixp_nexttimer(IxpServer *srv) { 118 | Timer *t; 119 | uint64_t time; 120 | long ret; 121 | 122 | SET(time); 123 | thread->lock(&srv->lk); 124 | while((t = srv->timer)) { 125 | time = ixp_msec(); 126 | if(t->msec > time) 127 | break; 128 | srv->timer = t->link; 129 | 130 | thread->unlock(&srv->lk); 131 | t->fn(t->id, t->aux); 132 | free(t); 133 | thread->lock(&srv->lk); 134 | } 135 | ret = 0; 136 | if(t) 137 | ret = t->msec - time; 138 | thread->unlock(&srv->lk); 139 | return ret; 140 | } 141 | 142 | -------------------------------------------------------------------------------- /lib/libixp/transport.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007-2010 Kris Maglione 2 | * See LICENSE file for license details. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "ixp_local.h" 14 | 15 | static int 16 | mread(int fd, IxpMsg *msg, uint count) { 17 | int r, n; 18 | 19 | n = msg->end - msg->pos; 20 | if(n <= 0) { 21 | werrstr("buffer full"); 22 | return -1; 23 | } 24 | if(n > count) 25 | n = count; 26 | 27 | r = thread->read(fd, msg->pos, n); 28 | if(r > 0) 29 | msg->pos += r; 30 | return r; 31 | } 32 | 33 | static int 34 | readn(int fd, IxpMsg *msg, uint count) { 35 | uint num; 36 | int r; 37 | 38 | num = count; 39 | while(num > 0) { 40 | r = mread(fd, msg, num); 41 | if(r == -1 && errno == EINTR) 42 | continue; 43 | if(r == 0) { 44 | werrstr("broken pipe: %s", ixp_errbuf()); 45 | return count - num; 46 | } 47 | num -= r; 48 | } 49 | return count - num; 50 | } 51 | 52 | /** 53 | * Function: ixp_sendmsg 54 | * Function: ixp_recvmsg 55 | * 56 | * These functions read and write messages to and from the given 57 | * file descriptors. 58 | * 59 | * ixp_sendmsg writes the data at P->pos upto P->end. 60 | * If the call returns non-zero, all data is assured to have 61 | * been written. 62 | * 63 | * ixp_recvmsg first reads a 32 bit, little-endian length from 64 | * P and then reads a message of that length (including the 65 | * 4 byte size specifier) into the buffer at P->data, so 66 | * long as the size is less than P->size. 67 | * 68 | * Returns: 69 | * These functions return the number of bytes read or 70 | * written, or 0 on error. Errors are stored in 71 | * F. 72 | */ 73 | uint 74 | ixp_sendmsg(int fd, IxpMsg *msg) { 75 | int r; 76 | 77 | msg->pos = msg->data; 78 | while(msg->pos < msg->end) { 79 | r = thread->write(fd, msg->pos, msg->end - msg->pos); 80 | if(r < 1) { 81 | if(errno == EINTR) 82 | continue; 83 | werrstr("broken pipe: %s", ixp_errbuf()); 84 | return 0; 85 | } 86 | msg->pos += r; 87 | } 88 | return msg->pos - msg->data; 89 | } 90 | 91 | uint 92 | ixp_recvmsg(int fd, IxpMsg *msg) { 93 | enum { SSize = 4 }; 94 | uint32_t msize, size; 95 | 96 | msg->mode = MsgUnpack; 97 | msg->pos = msg->data; 98 | msg->end = msg->data + msg->size; 99 | if(readn(fd, msg, SSize) != SSize) 100 | return 0; 101 | 102 | msg->pos = msg->data; 103 | ixp_pu32(msg, &msize); 104 | 105 | size = msize - SSize; 106 | if(size >= msg->end - msg->pos) { 107 | werrstr("message too large"); 108 | return 0; 109 | } 110 | if(readn(fd, msg, size) != size) { 111 | werrstr("message incomplete"); 112 | return 0; 113 | } 114 | 115 | msg->end = msg->pos; 116 | return msize; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /lib/libixp/util.c: -------------------------------------------------------------------------------- 1 | /* Written by Kris Maglione */ 2 | /* Public domain */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "ixp_local.h" 13 | 14 | /** 15 | * Function: ixp_smprint 16 | * 17 | * This function formats its arguments as F and returns 18 | * a F allocated string containing the result. 19 | */ 20 | char* 21 | ixp_smprint(const char *fmt, ...) { 22 | va_list ap; 23 | char *s; 24 | 25 | va_start(ap, fmt); 26 | s = ixp_vsmprint(fmt, ap); 27 | va_end(ap); 28 | if(s == nil) 29 | ixp_werrstr("no memory"); 30 | return s; 31 | } 32 | 33 | static char* 34 | _user(void) { 35 | static char *user; 36 | struct passwd *pw; 37 | 38 | if(user == nil) { 39 | pw = getpwuid(getuid()); 40 | if(pw) 41 | user = strdup(pw->pw_name); 42 | } 43 | if(user == nil) 44 | user = "none"; 45 | return user; 46 | } 47 | 48 | static int 49 | rmkdir(char *path, int mode) { 50 | char *p; 51 | int ret; 52 | char c; 53 | 54 | for(p = path+1; ; p++) { 55 | c = *p; 56 | if((c == '/') || (c == '\0')) { 57 | *p = '\0'; 58 | ret = mkdir(path, mode); 59 | if((ret == -1) && (errno != EEXIST)) { 60 | ixp_werrstr("Can't create path '%s': %s", path, ixp_errbuf()); 61 | return 0; 62 | } 63 | *p = c; 64 | } 65 | if(c == '\0') 66 | break; 67 | } 68 | return 1; 69 | } 70 | 71 | static char* 72 | ns_display(void) { 73 | char *path, *disp; 74 | struct stat st; 75 | 76 | disp = getenv("DISPLAY"); 77 | if(disp == nil || disp[0] == '\0') { 78 | ixp_werrstr("$DISPLAY is unset"); 79 | return nil; 80 | } 81 | 82 | disp = estrdup(disp); 83 | path = &disp[strlen(disp) - 2]; 84 | if(path > disp && !strcmp(path, ".0")) 85 | *path = '\0'; 86 | 87 | path = ixp_smprint("/tmp/ns.%s.%s", _user(), disp); 88 | free(disp); 89 | 90 | if(!rmkdir(path, 0700)) 91 | ; 92 | else if(stat(path, &st)) 93 | ixp_werrstr("Can't stat Namespace path '%s': %s", path, ixp_errbuf()); 94 | else if(getuid() != st.st_uid) 95 | ixp_werrstr("Namespace path '%s' exists but is not owned by you", path); 96 | else if((st.st_mode & 077) && chmod(path, st.st_mode & ~077)) 97 | ixp_werrstr("Namespace path '%s' exists, but has wrong permissions: %s", path, ixp_errbuf()); 98 | else 99 | return path; 100 | free(path); 101 | return nil; 102 | } 103 | 104 | /** 105 | * Function: ixp_namespace 106 | * 107 | * Returns the path of the canonical 9p namespace directory. 108 | * Either the value of $NAMESPACE, if it's set, or, roughly, 109 | * /tmp/ns.${USER}.${DISPLAY:%.0=%}. In the latter case, the 110 | * directory is created if it doesn't exist, and it is 111 | * ensured to be owned by the current user, with no group or 112 | * other permissions. 113 | * 114 | * Returns: 115 | * A statically allocated string which must not be freed 116 | * or altered by the caller. The same value is returned 117 | * upon successive calls. 118 | * Bugs: 119 | * This function is not thread safe until after its first 120 | * call. 121 | */ 122 | /* Not especially threadsafe. */ 123 | char* 124 | ixp_namespace(void) { 125 | static char *namespace; 126 | 127 | if(namespace == nil) 128 | namespace = getenv("NAMESPACE"); 129 | if(namespace == nil) 130 | namespace = ns_display(); 131 | return namespace; 132 | } 133 | 134 | /** 135 | * Function: ixp_eprint 136 | * 137 | * libixp calls this function on error. It formats its arguments 138 | * as F and exits the program. 139 | */ 140 | void 141 | ixp_eprint(const char *fmt, ...) { 142 | va_list ap; 143 | int err; 144 | 145 | err = errno; 146 | fprintf(stderr, "libixp: fatal: "); 147 | 148 | va_start(ap, fmt); 149 | vfprintf(stderr, fmt, ap); 150 | va_end(ap); 151 | 152 | if(fmt[strlen(fmt)-1] == ':') 153 | fprintf(stderr, " %s\n", strerror(err)); 154 | else 155 | fprintf(stderr, "\n"); 156 | 157 | exit(1); 158 | } 159 | 160 | /* Can't malloc */ 161 | static void 162 | mfatal(char *name, uint size) { 163 | const char 164 | couldnot[] = "libixp: fatal: Could not ", 165 | paren[] = "() ", 166 | bytes[] = " bytes\n"; 167 | char sizestr[8]; 168 | int i; 169 | 170 | i = sizeof sizestr; 171 | do { 172 | sizestr[--i] = '0' + (size%10); 173 | size /= 10; 174 | } while(size > 0); 175 | 176 | write(1, couldnot, sizeof(couldnot)-1); 177 | write(1, name, strlen(name)); 178 | write(1, paren, sizeof(paren)-1); 179 | write(1, sizestr+i, sizeof(sizestr)-i); 180 | write(1, bytes, sizeof(bytes)-1); 181 | 182 | exit(1); 183 | } 184 | 185 | /** 186 | * Function: ixp_emalloc 187 | * Function: ixp_emallocz 188 | * Function: ixp_erealloc 189 | * Function: ixp_estrdup 190 | * 191 | * These functions act like their stdlib counterparts, but print 192 | * an error message and exit the program if allocation fails. 193 | * ixp_emallocz acts like ixp_emalloc but additionally zeros the 194 | * result of the allocation. 195 | */ 196 | void* 197 | ixp_emalloc(uint size) { 198 | void *ret = malloc(size); 199 | if(!ret) 200 | mfatal("malloc", size); 201 | return ret; 202 | } 203 | 204 | void* 205 | ixp_emallocz(uint size) { 206 | void *ret = emalloc(size); 207 | memset(ret, 0, size); 208 | return ret; 209 | } 210 | 211 | void* 212 | ixp_erealloc(void *ptr, uint size) { 213 | void *ret = realloc(ptr, size); 214 | if(!ret) 215 | mfatal("realloc", size); 216 | return ret; 217 | } 218 | 219 | char* 220 | ixp_estrdup(const char *str) { 221 | void *ret = strdup(str); 222 | if(!ret) 223 | mfatal("strdup", strlen(str)); 224 | return ret; 225 | } 226 | 227 | uint 228 | ixp_tokenize(char *res[], uint reslen, char *str, char delim) { 229 | char *s; 230 | uint i; 231 | 232 | i = 0; 233 | s = str; 234 | while(i < reslen && *s) { 235 | while(*s == delim) 236 | *(s++) = '\0'; 237 | if(*s) 238 | res[i++] = s; 239 | while(*s && *s != delim) 240 | s++; 241 | } 242 | return i; 243 | } 244 | 245 | uint 246 | ixp_strlcat(char *dst, const char *src, uint size) { 247 | const char *s; 248 | char *d; 249 | int n, len; 250 | 251 | d = dst; 252 | s = src; 253 | n = size; 254 | while(n-- > 0 && *d != '\0') 255 | d++; 256 | len = n; 257 | 258 | while(*s != '\0' && n-- > 0) 259 | *d++ = *s++; 260 | while(*s++ != '\0') 261 | n--; 262 | if(len > 0) 263 | *d = '\0'; 264 | return size - n - 1; 265 | } 266 | 267 | -------------------------------------------------------------------------------- /lib/libixp_pthread/Makefile: -------------------------------------------------------------------------------- 1 | ROOT= ../.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | LIBS += -lpthread 6 | 7 | TARG = libixp_pthread 8 | 9 | OBJ = thread_pthread 10 | 11 | include $(ROOT)/mk/lib.mk 12 | 13 | -------------------------------------------------------------------------------- /lib/libixp_pthread/thread_pthread.c: -------------------------------------------------------------------------------- 1 | /* Written by Kris Maglione */ 2 | /* Public domain */ 3 | #define _XOPEN_SOURCE 600 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "ixp_local.h" 9 | 10 | static IxpThread ixp_pthread; 11 | static pthread_key_t errstr_k; 12 | 13 | /** 14 | * Function: ixp_pthread_init 15 | * 16 | * This function initializes libixp for use in multithreaded 17 | * programs using the POSIX thread system. When using libixp in such 18 | * programs, this function must be called before any other libixp 19 | * functions. This function is part of libixp_pthread, which you 20 | * must explicitly link against. 21 | */ 22 | int 23 | ixp_pthread_init() { 24 | int ret; 25 | 26 | IXP_ASSERT_VERSION; 27 | 28 | ret = pthread_key_create(&errstr_k, free); 29 | if(ret) { 30 | werrstr("can't create TLS value: %s", ixp_errbuf()); 31 | return 1; 32 | } 33 | 34 | ixp_thread = &ixp_pthread; 35 | return 0; 36 | } 37 | 38 | static char* 39 | errbuf(void) { 40 | char *ret; 41 | 42 | ret = pthread_getspecific(errstr_k); 43 | if(ret == nil) { 44 | ret = emallocz(IXP_ERRMAX); 45 | pthread_setspecific(errstr_k, (void*)ret); 46 | } 47 | return ret; 48 | } 49 | 50 | static void 51 | mlock(IxpMutex *m) { 52 | pthread_mutex_lock(m->aux); 53 | } 54 | 55 | static int 56 | mcanlock(IxpMutex *m) { 57 | return !pthread_mutex_trylock(m->aux); 58 | } 59 | 60 | static void 61 | munlock(IxpMutex *m) { 62 | pthread_mutex_unlock(m->aux); 63 | } 64 | 65 | static void 66 | mdestroy(IxpMutex *m) { 67 | pthread_mutex_destroy(m->aux); 68 | free(m->aux); 69 | } 70 | 71 | static int 72 | initmutex(IxpMutex *m) { 73 | pthread_mutex_t *mutex; 74 | 75 | mutex = emalloc(sizeof *mutex); 76 | if(pthread_mutex_init(mutex, nil)) { 77 | free(mutex); 78 | return 1; 79 | } 80 | 81 | m->aux = mutex; 82 | return 0; 83 | } 84 | 85 | static void 86 | rlock(IxpRWLock *rw) { 87 | pthread_rwlock_rdlock(rw->aux); 88 | } 89 | 90 | static int 91 | canrlock(IxpRWLock *rw) { 92 | return !pthread_rwlock_tryrdlock(rw->aux); 93 | } 94 | 95 | static void 96 | wlock(IxpRWLock *rw) { 97 | pthread_rwlock_rdlock(rw->aux); 98 | } 99 | 100 | static int 101 | canwlock(IxpRWLock *rw) { 102 | return !pthread_rwlock_tryrdlock(rw->aux); 103 | } 104 | 105 | static void 106 | rwunlock(IxpRWLock *rw) { 107 | pthread_rwlock_unlock(rw->aux); 108 | } 109 | 110 | static void 111 | rwdestroy(IxpRWLock *rw) { 112 | pthread_rwlock_destroy(rw->aux); 113 | free(rw->aux); 114 | } 115 | 116 | static int 117 | initrwlock(IxpRWLock *rw) { 118 | pthread_rwlock_t *rwlock; 119 | 120 | rwlock = emalloc(sizeof *rwlock); 121 | if(pthread_rwlock_init(rwlock, nil)) { 122 | free(rwlock); 123 | return 1; 124 | } 125 | 126 | rw->aux = rwlock; 127 | return 0; 128 | } 129 | 130 | static void 131 | rsleep(IxpRendez *r) { 132 | pthread_cond_wait(r->aux, r->mutex->aux); 133 | } 134 | 135 | static int 136 | rwake(IxpRendez *r) { 137 | pthread_cond_signal(r->aux); 138 | return 0; 139 | } 140 | 141 | static int 142 | rwakeall(IxpRendez *r) { 143 | pthread_cond_broadcast(r->aux); 144 | return 0; 145 | } 146 | 147 | static void 148 | rdestroy(IxpRendez *r) { 149 | pthread_cond_destroy(r->aux); 150 | free(r->aux); 151 | } 152 | 153 | static int 154 | initrendez(IxpRendez *r) { 155 | pthread_cond_t *cond; 156 | 157 | cond = emalloc(sizeof *cond); 158 | if(pthread_cond_init(cond, nil)) { 159 | free(cond); 160 | return 1; 161 | } 162 | 163 | r->aux = cond; 164 | return 0; 165 | } 166 | 167 | static IxpThread ixp_pthread = { 168 | /* Mutex */ 169 | .initmutex = initmutex, 170 | .lock = mlock, 171 | .canlock = mcanlock, 172 | .unlock = munlock, 173 | .mdestroy = mdestroy, 174 | /* RWLock */ 175 | .initrwlock = initrwlock, 176 | .rlock = rlock, 177 | .canrlock = canrlock, 178 | .wlock = wlock, 179 | .canwlock = canwlock, 180 | .runlock = rwunlock, 181 | .wunlock = rwunlock, 182 | .rwdestroy = rwdestroy, 183 | /* Rendez */ 184 | .initrendez = initrendez, 185 | .sleep = rsleep, 186 | .wake = rwake, 187 | .wakeall = rwakeall, 188 | .rdestroy = rdestroy, 189 | /* Other */ 190 | .errbuf = errbuf, 191 | .read = read, 192 | .write = write, 193 | .select = select, 194 | }; 195 | 196 | -------------------------------------------------------------------------------- /lib/libixp_rubythread/Makefile: -------------------------------------------------------------------------------- 1 | ROOT= ../.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | CFLAGS += $(RUBYINC) 6 | 7 | TARG = libixp_rubythread 8 | OBJ = thread_ruby 9 | 10 | include $(ROOT)/mk/lib.mk 11 | 12 | -------------------------------------------------------------------------------- /lib/libixp_rubythread/thread_ruby.c: -------------------------------------------------------------------------------- 1 | /* Copyright ©2007-2010 Kris Maglione 2 | * See LICENSE file for license details. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "ixp_local.h" 9 | 10 | static IxpThread ixp_rthread; 11 | static char RWLock[]; 12 | 13 | /** 14 | * Function: ixp_rubyinit 15 | * 16 | * This function initializes libixp for use in multithreaded 17 | * programs embedded in the ruby interpreter. When using a pthread 18 | * edition of ruby, ixp_pthread_init should be used instead. When 19 | * using libixp in such programs, this function must be called 20 | * before any other libixp functions. 21 | * 22 | * This function is part of libixp_rubythread, which is part of the 23 | * libixp distribution, but is not built by default unless enabled 24 | * in config.mk. 25 | */ 26 | int 27 | ixp_rubyinit(void) { 28 | rb_require("thread.rb"); 29 | rb_eval_string(RWLock); 30 | ixp_thread = &ixp_rthread; 31 | return 0; 32 | } 33 | 34 | static char* 35 | errbuf(void) { 36 | static ID key; 37 | volatile VALUE val; 38 | 39 | if(key == 0L) 40 | key = rb_intern("_ixp_errbuf"); 41 | 42 | val = rb_thread_local_aref(rb_thread_current(), key); 43 | if(NIL_P(val)) { 44 | val = rb_str_new(nil, IXP_ERRMAX); 45 | rb_thread_local_aset(rb_thread_current(), key, val); 46 | } 47 | 48 | Check_Type(val, T_STRING); 49 | return RSTRING(val)->ptr; 50 | } 51 | 52 | static void 53 | save(char *eval, void **place) { 54 | *place = (void*)rb_eval_string(eval); 55 | rb_gc_register_address((VALUE*)place); 56 | } 57 | 58 | static void 59 | unsave(void **place) { 60 | rb_gc_unregister_address((VALUE*)place); 61 | } 62 | 63 | #define call(obj, meth, ...) rb_funcall((VALUE)obj, rb_intern(meth), __VA_ARGS__) 64 | 65 | /* Mutex */ 66 | static int 67 | initmutex(IxpMutex *m) { 68 | save("Mutex.new", &m->aux); 69 | return 0; 70 | } 71 | 72 | static void 73 | mdestroy(IxpMutex *m) { 74 | unsave(&m->aux); 75 | } 76 | 77 | static void 78 | mlock(IxpMutex *m) { 79 | call(m->aux, "lock", 0); 80 | } 81 | 82 | static int 83 | mcanlock(IxpMutex *m) { 84 | return call(m->aux, "trylock", 0); 85 | } 86 | 87 | static void 88 | munlock(IxpMutex *m) { 89 | call(m->aux, "unlock", 0); 90 | } 91 | 92 | /* RWLock */ 93 | static int 94 | initrwlock(IxpRWLock *rw) { 95 | save("RWLock.new", &rw->aux); 96 | return 0; 97 | } 98 | 99 | static void 100 | rwdestroy(IxpRWLock *rw) { 101 | unsave(&rw->aux); 102 | } 103 | 104 | static void 105 | rlock(IxpRWLock *rw) { 106 | call(rw->aux, "rdlock", 0); 107 | } 108 | 109 | static int 110 | canrlock(IxpRWLock *rw) { 111 | return call(rw->aux, "tryrdlock", 0) == Qtrue; 112 | } 113 | 114 | static void 115 | wlock(IxpRWLock *rw) { 116 | call(rw->aux, "wrlock", 0); 117 | } 118 | 119 | static int 120 | canwlock(IxpRWLock *rw) { 121 | return call(rw->aux, "trywrlock", 0) == Qtrue; 122 | } 123 | 124 | static void 125 | rwunlock(IxpRWLock *rw) { 126 | call(rw->aux, "unlock", 0); 127 | } 128 | 129 | /* Rendez */ 130 | static int 131 | initrendez(IxpRendez *r) { 132 | save("ConditionVariable.new", &r->aux); 133 | return 0; 134 | } 135 | 136 | static void 137 | rdestroy(IxpRendez *r) { 138 | unsave(&r->aux); 139 | } 140 | 141 | static void 142 | rsleep(IxpRendez *r) { 143 | call(r->aux, "wait", 1, (VALUE)r->mutex->aux); 144 | } 145 | 146 | static int 147 | rwake(IxpRendez *r) { 148 | call(r->aux, "signal", 0); 149 | return 0; 150 | } 151 | 152 | static int 153 | rwakeall(IxpRendez *r) { 154 | call(r->aux, "broadcast", 0); 155 | return 0; 156 | } 157 | 158 | /* Yielding IO */ 159 | static ssize_t 160 | _read(int fd, void *buf, size_t size) { 161 | int n; 162 | 163 | rb_thread_wait_fd(fd); 164 | n = read(fd, buf, size); 165 | 166 | if(n < 0 && errno == EINTR) 167 | rb_thread_schedule(); 168 | return n; 169 | } 170 | 171 | static ssize_t 172 | _write(int fd, const void *buf, size_t size) { 173 | int n; 174 | 175 | rb_thread_fd_writable(fd); 176 | n = write(fd, buf, size); 177 | 178 | if(n < 0 && errno == EINTR) 179 | rb_thread_schedule(); 180 | return n; 181 | } 182 | 183 | static IxpThread ixp_rthread = { 184 | /* Mutex */ 185 | .initmutex = initmutex, 186 | .lock = mlock, 187 | .canlock = mcanlock, 188 | .unlock = munlock, 189 | .mdestroy = mdestroy, 190 | /* RWLock */ 191 | .initrwlock = initrwlock, 192 | .rlock = rlock, 193 | .canrlock = canrlock, 194 | .wlock = wlock, 195 | .canwlock = canwlock, 196 | .runlock = rwunlock, 197 | .wunlock = rwunlock, 198 | .rwdestroy = rwdestroy, 199 | /* Rendez */ 200 | .initrendez = initrendez, 201 | .sleep = rsleep, 202 | .wake = rwake, 203 | .wakeall = rwakeall, 204 | .rdestroy = rdestroy, 205 | /* Other */ 206 | .errbuf = errbuf, 207 | .read = _read, 208 | .write = _write, 209 | .select = rb_thread_select, 210 | }; 211 | 212 | static char RWLock[] = 213 | "class RWLock \n" 214 | " def initialize \n" 215 | " @rdqueue = [] \n" 216 | " @wrqueue = [] \n" 217 | " @wrheld = nil \n" 218 | " @rdheld = [] \n" 219 | " end \n" 220 | " \n" 221 | " def rdlock \n" 222 | " cr = Thread.critical \n" 223 | " while (Thread.critical = true; @wrheld != nil && @rwheld != Thread.current)\n" 224 | " @rdqueue.push Thread.current \n" 225 | " Thread.stop \n" 226 | " end \n" 227 | " @wrheld = nil \n" 228 | " @rdheld.push Thread.current \n" 229 | " \n" 230 | " @rdqueue.each {|t| t.wakeup} \n" 231 | " Thread.critical = cr \n" 232 | " self \n" 233 | " end \n" 234 | " \n" 235 | " def wrlock \n" 236 | " cr = Thread.critical \n" 237 | " while (Thread.critical = true; \n" 238 | " !@rdheld.empty? || (@wrheld != Thread.current && @wrheld != nil)) \n" 239 | " @wrqueue.push Thread.current \n" 240 | " Thread.stop \n" 241 | " end \n" 242 | " @wrheld = Thread.current \n" 243 | " Thread.critical = cr \n" 244 | " self \n" 245 | " end \n" 246 | " \n" 247 | " \n" 248 | " def tryrdlock \n" 249 | " cr = Thread.critical \n" 250 | " if @wrheld == nil \n" 251 | " rdlock \n" 252 | " true \n" 253 | " else \n" 254 | " false \n" 255 | " end \n" 256 | " ensure \n" 257 | " Thread.critical = cr \n" 258 | " end \n" 259 | " \n" 260 | " def trywrlock \n" 261 | " cr = Thread.critical \n" 262 | " if @wrheld == nil && @rdheld.empty? \n" 263 | " wrlock \n" 264 | " true \n" 265 | " else \n" 266 | " false \n" 267 | " end \n" 268 | " ensure \n" 269 | " Thread.critical = cr \n" 270 | " end \n" 271 | " \n" 272 | " def unlock \n" 273 | " cr = Thread.critical \n" 274 | " Thread.critical = true \n" 275 | " \n" 276 | " if @rdheld.include?(Thread.current) \n" 277 | " @rdheld.remove!(Thread.current) \n" 278 | " raise if @wrheld \n" 279 | " elsif @rwheld != Thread.current \n" 280 | " raise \n" 281 | " end \n" 282 | " \n" 283 | " @wrheld = nil \n" 284 | " if !@rwqueue.empty? && @rdheld.empty? \n" 285 | " @wrheld = @wrqueue.shift \n" 286 | " elsif !@rdqueue.empty \n" 287 | " @wrheld = @rdqueue.shift \n" 288 | " end \n" 289 | " @wrheld.wakeup if @wrheld \n" 290 | " ensure \n" 291 | " Thread.critical = cr \n" 292 | " end \n" 293 | "end \n"; 294 | 295 | -------------------------------------------------------------------------------- /lib/libixp_task/Makefile: -------------------------------------------------------------------------------- 1 | ROOT= ../.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | CFLAGS += $(TASKINC) 6 | 7 | TARG = libixp_task 8 | OBJ = thread_task 9 | 10 | include $(ROOT)/mk/lib.mk 11 | 12 | -------------------------------------------------------------------------------- /lib/libixp_task/thread_task.c: -------------------------------------------------------------------------------- 1 | /* Written by Kris Maglione */ 2 | /* Public domain */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "ixp_local.h" 8 | 9 | static IxpThread ixp_task; 10 | 11 | /** 12 | * Function: ixp_taskinit 13 | * 14 | * This function initializes libixp for use in multithreaded 15 | * programs using the libtask threading system. When using libixp in 16 | * such programs, this function must be called before any other 17 | * libixp functions. 18 | * 19 | * This function is part of libixp_task, which is part of the libixp 20 | * distribution, but is not built by default unless enabled in 21 | * config.mk. 22 | */ 23 | int 24 | ixp_taskinit() { 25 | ixp_thread = &ixp_task; 26 | return 0; 27 | } 28 | 29 | static char* 30 | errbuf(void) { 31 | void **p; 32 | 33 | p = taskdata(); 34 | if(*p == nil) 35 | *p = emallocz(IXP_ERRMAX); 36 | return *p; 37 | } 38 | 39 | /* Mutex */ 40 | static int 41 | initmutex(IxpMutex *m) { 42 | m->aux = emallocz(sizeof(QLock)); 43 | return 0; 44 | } 45 | 46 | static void 47 | mdestroy(IxpMutex *m) { 48 | free(m->aux); 49 | m->aux = nil; 50 | } 51 | 52 | static void 53 | mlock(IxpMutex *m) { 54 | qlock(m->aux); 55 | } 56 | 57 | static int 58 | mcanlock(IxpMutex *m) { 59 | return canqlock(m->aux); 60 | } 61 | 62 | static void 63 | munlock(IxpMutex *m) { 64 | qunlock(m->aux); 65 | } 66 | 67 | /* RWLock */ 68 | static int 69 | initrwlock(IxpRWLock *rw) { 70 | rw->aux = emallocz(sizeof(RWLock)); 71 | return 0; 72 | } 73 | 74 | static void 75 | rwdestroy(IxpRWLock *rw) { 76 | free(rw->aux); 77 | rw->aux = nil; 78 | } 79 | 80 | static void 81 | _rlock(IxpRWLock *rw) { 82 | rlock(rw->aux); 83 | } 84 | 85 | static int 86 | _canrlock(IxpRWLock *rw) { 87 | return canrlock(rw->aux); 88 | } 89 | 90 | static void 91 | _wlock(IxpRWLock *rw) { 92 | wlock(rw->aux); 93 | } 94 | 95 | static int 96 | _canwlock(IxpRWLock *rw) { 97 | return canwlock(rw->aux); 98 | } 99 | 100 | static void 101 | _runlock(IxpRWLock *rw) { 102 | runlock(rw->aux); 103 | } 104 | 105 | static void 106 | _wunlock(IxpRWLock *rw) { 107 | wunlock(rw->aux); 108 | } 109 | 110 | /* Rendez */ 111 | static int 112 | initrendez(IxpRendez *r) { 113 | r->aux = emallocz(sizeof(Rendez)); 114 | return 0; 115 | } 116 | 117 | static void 118 | rdestroy(IxpRendez *r) { 119 | free(r->aux); 120 | r->aux = nil; 121 | } 122 | 123 | static void 124 | rsleep(IxpRendez *r) { 125 | Rendez *rz; 126 | 127 | rz = r->aux; 128 | rz->l = r->mutex->aux; 129 | tasksleep(rz); 130 | } 131 | 132 | static int 133 | rwake(IxpRendez *r) { 134 | Rendez *rz; 135 | 136 | rz = r->aux; 137 | rz->l = r->mutex->aux; 138 | return taskwakeup(rz); 139 | } 140 | 141 | static int 142 | rwakeall(IxpRendez *r) { 143 | Rendez *rz; 144 | 145 | rz = r->aux; 146 | rz->l = r->mutex->aux; 147 | return taskwakeupall(rz); 148 | } 149 | 150 | /* Yielding IO */ 151 | static ssize_t 152 | _read(int fd, void *buf, size_t size) { 153 | fdnoblock(fd); 154 | return fdread(fd, buf, size); 155 | } 156 | 157 | static ssize_t 158 | _write(int fd, const void *buf, size_t size) { 159 | fdnoblock(fd); 160 | return fdwrite(fd, (void*)buf, size); 161 | } 162 | 163 | static IxpThread ixp_task = { 164 | /* Mutex */ 165 | .initmutex = initmutex, 166 | .lock = mlock, 167 | .canlock = mcanlock, 168 | .unlock = munlock, 169 | .mdestroy = mdestroy, 170 | /* RWLock */ 171 | .initrwlock = initrwlock, 172 | .rlock = _rlock, 173 | .canrlock = _canrlock, 174 | .wlock = _wlock, 175 | .canwlock = _canwlock, 176 | .runlock = _runlock, 177 | .wunlock = _wunlock, 178 | .rwdestroy = rwdestroy, 179 | /* Rendez */ 180 | .initrendez = initrendez, 181 | .sleep = rsleep, 182 | .wake = rwake, 183 | .wakeall = rwakeall, 184 | .rdestroy = rdestroy, 185 | /* Other */ 186 | .errbuf = errbuf, 187 | .read = _read, 188 | .write = _write, 189 | .select = select, /* wrong */ 190 | }; 191 | 192 | -------------------------------------------------------------------------------- /man/IXP_API.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_API" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | IXP_API, IXP_NEEDAPI, IXP_MAXAPI, IXP_ASSERT_VERSION 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | #define IXP_API ... 15 | 16 | #define IXP_NEEDAPI ... 17 | 18 | #define IXP_MAXAPI ... 19 | 20 | #define IXP_ASSERT_VERSION ... 21 | .fi 22 | 23 | 24 | .SH DESCRIPTION 25 | 26 | .P 27 | IXP_API contains the current libixp API revision number. 28 | 29 | .P 30 | IXP_NEEDAPI, if defined before ixp.h is included, directs the 31 | header to present an older version of the libixp API. This allows 32 | code written for older versions of libixp to compile against 33 | newer versions without modification. It does not, however, ensure 34 | that it will link against a different version of libixp than the 35 | ixp.h header belongs to. 36 | 37 | .P 38 | IXP_MAXAPI, if defined before ixp.h is included, prevents code 39 | from compiling with a newer version of libixp than specified. 40 | 41 | .P 42 | When inserted into any function, IXP_ASSERT_VERSION ensures that 43 | the resulting object will fail to link link against any version 44 | of libixp with a different API version than it was compiled 45 | against. 46 | 47 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 48 | .\" cmdline: txt2tags -o- IXP_API.man3 49 | -------------------------------------------------------------------------------- /man/Ixp9Srv.3: -------------------------------------------------------------------------------- 1 | .TH "IXP9SRV" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | Ixp9Srv, Ixp9Req, ixp_serve9conn 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | typedef struct Ixp9Srv Ixp9Srv; 15 | struct Ixp9Srv { 16 | void* aux; 17 | void (*attach)(Ixp9Req*); 18 | void (*clunk)(Ixp9Req*); 19 | void (*create)(Ixp9Req*); 20 | void (*flush)(Ixp9Req*); 21 | void (*open)(Ixp9Req*); 22 | void (*read)(Ixp9Req*); 23 | void (*remove)(Ixp9Req*); 24 | void (*stat)(Ixp9Req*); 25 | void (*walk)(Ixp9Req*); 26 | void (*write)(Ixp9Req*); 27 | void (*wstat)(Ixp9Req*); 28 | void (*freefid)(IxpFid*); 29 | } 30 | 31 | typedef struct Ixp9Req Ixp9Req; 32 | struct Ixp9Req { 33 | Ixp9Srv* srv; 34 | IxpFid* fid; /* Fid structure corresponding to IxpFHdr.fid */ 35 | IxpFid* newfid; /* Corresponds to IxpFTWStat.newfid */ 36 | Ixp9Req* oldreq; /* For TFlush requests, the original request. */ 37 | IxpFcall ifcall; /* The incoming request fcall. */ 38 | IxpFcall ofcall; /* The response fcall, to be filled by handler. */ 39 | void* aux; /* Arbitrary pointer, to be used by handlers. */ 40 | 41 | /* Private members */ 42 | ... 43 | } 44 | 45 | void ixp_serve9conn(IxpConn *c); 46 | .fi 47 | 48 | 49 | .SH DESCRIPTION 50 | 51 | .P 52 | The ixp_serve9conn handles incoming 9P connections. It is 53 | ordinarily passed as the \fIread\fR member to \fBixp_listen(3)\fR with an 54 | Ixp9Srv structure passed as the \fIaux\fR member. The handlers 55 | defined in the Ixp9Srv structure are called whenever a matching 56 | Fcall type is received. The handlers are expected to call 57 | \fBixp_respond(3)\fR at some point, whether before they return or at 58 | some undefined point in the future. Whenever a client 59 | disconnects, libixp generates whatever flush and clunk events are 60 | required to leave the connection in a clean state and waits for 61 | all responses before freeing the connections associated data 62 | structures. 63 | 64 | .P 65 | Whenever a file is closed and an \fBIxpFid(3)\fR is about to be freed, 66 | the \fIfreefid\fR member is called to perform any necessary cleanup 67 | and to free any associated resources. 68 | 69 | .SH SEE ALSO 70 | 71 | .P 72 | ixp_listen(3), ixp_respond(3), ixp_printfcall(3), 73 | IxpFcall(3), IxpFid(3) 74 | 75 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 76 | .\" cmdline: txt2tags -o- Ixp9Srv.man3 77 | -------------------------------------------------------------------------------- /man/IxpFcall.3: -------------------------------------------------------------------------------- 1 | .TH "IXPFCALL" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | IxpFcall, IxpFType, IxpFAttach, IxpFError, IxpFHdr, IxpFIO, IxpFRAuth, IxpFROpen, IxpFRStat, IxpFRWalk, IxpFTCreate, IxpFTFlush, IxpFTWStat, IxpFTWalk, IxpFVersion 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | typedef struct IxpFcall IxpFcall; 15 | typedef union IxpFcall IxpFcall; 16 | union IxpFcall { 17 | IxpFHdr hdr; 18 | IxpFVersion version; 19 | IxpFVersion tversion; 20 | IxpFVersion rversion; 21 | IxpFTFlush tflush; 22 | IxpFROpen ropen; 23 | IxpFROpen rcreate; 24 | IxpFROpen rattach; 25 | IxpFError error; 26 | IxpFRAuth rauth; 27 | IxpFAttach tattach; 28 | IxpFAttach tauth; 29 | IxpFTCreate tcreate; 30 | IxpFTCreate topen; 31 | IxpFTWalk twalk; 32 | IxpFRWalk rwalk; 33 | IxpFTWStat twstat; 34 | IxpFRStat rstat; 35 | IxpFIO twrite; 36 | IxpFIO rwrite; 37 | IxpFIO tread; 38 | IxpFIO rread; 39 | IxpFIO io; 40 | } 41 | 42 | enum IxpFType { 43 | P9_TVersion = 100, 44 | P9_RVersion, 45 | P9_TAuth = 102, 46 | P9_RAuth, 47 | P9_TAttach = 104, 48 | P9_RAttach, 49 | P9_TError = 106, /* illegal */ 50 | P9_RError, 51 | P9_TFlush = 108, 52 | P9_RFlush, 53 | P9_TWalk = 110, 54 | P9_RWalk, 55 | P9_TOpen = 112, 56 | P9_ROpen, 57 | P9_TCreate = 114, 58 | P9_RCreate, 59 | P9_TRead = 116, 60 | P9_RRead, 61 | P9_TWrite = 118, 62 | P9_RWrite, 63 | P9_TClunk = 120, 64 | P9_RClunk, 65 | P9_TRemove = 122, 66 | P9_RRemove, 67 | P9_TStat = 124, 68 | P9_RStat, 69 | P9_TWStat = 126, 70 | P9_RWStat, 71 | } 72 | 73 | typedef struct IxpFAttach IxpFAttach; 74 | struct IxpFAttach { 75 | IxpFHdr hdr; 76 | uint32_t afid; 77 | char* uname; 78 | char* aname; 79 | } 80 | 81 | typedef struct IxpFError IxpFError; 82 | struct IxpFError { 83 | IxpFHdr hdr; 84 | char* ename; 85 | } 86 | 87 | typedef struct IxpFHdr IxpFHdr; 88 | struct IxpFHdr { 89 | uint8_t type; 90 | uint16_t tag; 91 | uint32_t fid; 92 | } 93 | 94 | typedef struct IxpFIO IxpFIO; 95 | struct IxpFIO { 96 | IxpFHdr hdr; 97 | uint64_t offset; /* Tread, Twrite */ 98 | uint32_t count; /* Tread, Twrite, Rread */ 99 | char* data; /* Twrite, Rread */ 100 | } 101 | 102 | typedef struct IxpFRAuth IxpFRAuth; 103 | struct IxpFRAuth { 104 | IxpFHdr hdr; 105 | IxpQid aqid; 106 | } 107 | 108 | typedef struct IxpFROpen IxpFROpen; 109 | struct IxpFROpen { 110 | IxpFHdr hdr; 111 | IxpQid qid; /* +Rattach */ 112 | uint32_t iounit; 113 | } 114 | 115 | typedef struct IxpFRStat IxpFRStat; 116 | struct IxpFRStat { 117 | IxpFHdr hdr; 118 | uint16_t nstat; 119 | uint8_t* stat; 120 | } 121 | 122 | typedef struct IxpFRWalk IxpFRWalk; 123 | struct IxpFRWalk { 124 | IxpFHdr hdr; 125 | uint16_t nwqid; 126 | IxpQid wqid\fI[IXP_MAX_WELEM]\fR; 127 | } 128 | 129 | typedef struct IxpFTCreate IxpFTCreate; 130 | struct IxpFTCreate { 131 | IxpFHdr hdr; 132 | uint32_t perm; 133 | char* name; 134 | uint8_t mode; /* +Topen */ 135 | } 136 | 137 | typedef struct IxpFTFlush IxpFTFlush; 138 | struct IxpFTFlush { 139 | IxpFHdr hdr; 140 | uint16_t oldtag; 141 | } 142 | 143 | typedef struct IxpFTWStat IxpFTWStat; 144 | struct IxpFTWStat { 145 | IxpFHdr hdr; 146 | IxpStat stat; 147 | } 148 | 149 | typedef struct IxpFTWalk IxpFTWalk; 150 | struct IxpFTWalk { 151 | IxpFHdr hdr; 152 | uint32_t newfid; 153 | uint16_t nwname; 154 | char* wname\fI[IXP_MAX_WELEM]\fR; 155 | } 156 | 157 | typedef struct IxpFVersion IxpFVersion; 158 | struct IxpFVersion { 159 | IxpFHdr hdr; 160 | uint32_t msize; 161 | char* version; 162 | } 163 | .fi 164 | 165 | 166 | .SH DESCRIPTION 167 | 168 | .P 169 | The IxpFcall structure represents a 9P protocol message. The 170 | \fIhdr\fR element is common to all Fcall types, and may be used to 171 | determine the type and tag of the message. The IxpFcall type is 172 | used heavily in server applications, where it both presents a 173 | request to handler functions and returns a response to the 174 | client. 175 | 176 | .P 177 | Each member of the IxpFcall structure represents a certain 178 | message type, which can be discerned from the \fIhdr.type\fR field. 179 | This value corresponds to one of the IxpFType constants. Types 180 | with significant overlap use the same structures, thus TRead and 181 | RWrite are both represented by IxpFIO and can be accessed via the 182 | \fIio\fR member as well as \fItread\fR and \fIrwrite\fR respectively. 183 | 184 | .SH SEE ALSO 185 | 186 | .P 187 | Ixp9Srv(3), Ixp9Req(3) 188 | 189 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 190 | .\" cmdline: txt2tags -o- IxpFcall.man3 191 | -------------------------------------------------------------------------------- /man/IxpFid.3: -------------------------------------------------------------------------------- 1 | .TH "IXPFID" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | IxpFid 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | typedef struct IxpFid IxpFid; 15 | struct IxpFid { 16 | char* uid; /* The uid of the file opener. */ 17 | void* aux; /* Arbitrary pointer, to be used by handlers. */ 18 | uint32_t fid; /* The ID number of the fid. */ 19 | IxpQid qid; /* The filesystem-unique QID of the file. */ 20 | signed char omode; /* The open mode of the file. */ 21 | uint iounit; /* The maximum size of any IO request. */ 22 | 23 | /* Private members */ 24 | ... 25 | } 26 | .fi 27 | 28 | 29 | .SH DESCRIPTION 30 | 31 | .P 32 | Represents an open file for a 9P connection. The same 33 | structure persists as long as the file remains open, and is 34 | installed in the \fBIxp9Req(3)\fR structure for any request Fcall 35 | which references it. Handlers may use the \fIaux\fR member to 36 | store any data which must persist for the life of the open 37 | file. 38 | 39 | .SH SEE ALSO 40 | 41 | .P 42 | Ixp9Req(3), IxpQid(3), IxpOMode(3) 43 | 44 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 45 | .\" cmdline: txt2tags -o- IxpFid.man3 46 | -------------------------------------------------------------------------------- /man/IxpMsg.3: -------------------------------------------------------------------------------- 1 | .TH "IXPMSG" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | IxpMsg, IxpMsgMode, ixp_message 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | typedef struct IxpMsg IxpMsg; 15 | struct IxpMsg { 16 | char* data; /* Begining of buffer. */ 17 | char* pos; /* Current position in buffer. */ 18 | char* end; /* End of message. */ 19 | uint size; /* Size of buffer. */ 20 | uint mode; /* MsgPack or MsgUnpack. */ 21 | } 22 | 23 | enum IxpMsgMode { 24 | MsgPack, 25 | MsgUnpack, 26 | } 27 | 28 | IxpMsg ixp_message(char *data, uint length, uint mode); 29 | .fi 30 | 31 | 32 | .SH DESCRIPTION 33 | 34 | .P 35 | The IxpMsg struct represents a binary message, and is used 36 | extensively by libixp for converting messages to and from 37 | wire format. The location and size of a buffer are stored in 38 | \fIdata\fR and \fIsize\fR, respectively. \fIpos\fR points to the 39 | location in the message currently being packed or unpacked, 40 | while \fIend\fR points to the end of the message. The packing 41 | functions advance \fIpos\fR as they go, always ensuring that 42 | they don't read or write past \fIend\fR. When a message is 43 | entirely packed or unpacked, \fIpos\fR whould be less than or 44 | equal to \fIend\fR. Any other state indicates error. 45 | 46 | .P 47 | ixp_message is a convenience function to pack a construct an 48 | IxpMsg from a buffer of a given \fIlength\fR and a given 49 | \fImode\fR. \fIpos\fR and \fIdata\fR are set to \fIdata\fR and \fIend\fR is 50 | set to \fIdata\fR + \fIlength\fR. 51 | 52 | .SH SEE ALSO 53 | 54 | .P 55 | ixp_pu8(3), ixp_pu16(3), ixp_pu32(3), ixp_pu64(3), 56 | ixp_pstring(3), ixp_pstrings(3) 57 | 58 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 59 | .\" cmdline: txt2tags -o- IxpMsg.man3 60 | -------------------------------------------------------------------------------- /man/IxpThread.3: -------------------------------------------------------------------------------- 1 | .TH "IXPTHREAD" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | IxpThread, IxpMutex, IxpRWLock, IxpRendez, ixp_thread 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | typedef struct IxpThread IxpThread; 15 | struct IxpThread { 16 | /* Read/write lock */ 17 | int (*initrwlock)(IxpRWLock*); 18 | void (*rlock)(IxpRWLock*); 19 | int (*canrlock)(IxpRWLock*); 20 | void (*runlock)(IxpRWLock*); 21 | void (*wlock)(IxpRWLock*); 22 | int (*canwlock)(IxpRWLock*); 23 | void (*wunlock)(IxpRWLock*); 24 | void (*rwdestroy)(IxpRWLock*); 25 | /* Mutex */ 26 | int (*initmutex)(IxpMutex*); 27 | void (*lock)(IxpMutex*); 28 | int (*canlock)(IxpMutex*); 29 | void (*unlock)(IxpMutex*); 30 | void (*mdestroy)(IxpMutex*); 31 | /* Rendezvous point */ 32 | int (*initrendez)(IxpRendez*); 33 | void (*sleep)(IxpRendez*); 34 | int (*wake)(IxpRendez*); 35 | int (*wakeall)(IxpRendez*); 36 | void (*rdestroy)(IxpRendez*); 37 | /* Other */ 38 | char* (*errbuf)(void); 39 | ssize_t (*read)(int, void*, size_t); 40 | ssize_t (*write)(int, const void*, size_t); 41 | int (*select)(int, fd_set*, fd_set*, fd_set*, struct timeval*); 42 | } 43 | 44 | typedef struct IxpMutex IxpMutex; 45 | struct IxpMutex { 46 | void* aux; 47 | } 48 | 49 | typedef struct IxpRWLock IxpRWLock; 50 | struct IxpRWLock { 51 | void* aux; 52 | } 53 | 54 | typedef struct IxpRendez IxpRendez; 55 | struct IxpRendez { 56 | IxpMutex* mutex; 57 | void* aux; 58 | } 59 | 60 | IxpThread* ixp_thread; 61 | .fi 62 | 63 | 64 | .SH DESCRIPTION 65 | 66 | .P 67 | The IxpThread structure is used to adapt libixp to any of the 68 | myriad threading systems it may be used with. Before any 69 | other of libixp's functions is called, ixp_thread may be set 70 | to a structure filled with implementations of various locking 71 | primitives, along with primitive IO functions which may 72 | perform context switches until data is available. 73 | 74 | .P 75 | The names of the functions should be fairly self\-explanitory. 76 | Read/write locks should allow multiple readers and a single 77 | writer of a shared resource, but should not allow new readers 78 | while a writer is waitng for a lock. Mutexes should allow 79 | only one accessor at a time. Rendezvous points are similar to 80 | pthread condition types. \fIerrbuf\fR should return a 81 | thread\-local buffer or the size IXP_ERRMAX. 82 | 83 | .SH SEE ALSO 84 | 85 | .P 86 | ixp_pthread_init(3), ixp_taskinit(3), ixp_rubyinit(3) 87 | 88 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 89 | .\" cmdline: txt2tags -o- IxpThread.man3 90 | -------------------------------------------------------------------------------- /man/Makefile: -------------------------------------------------------------------------------- 1 | ROOT=.. 2 | include $(ROOT)/mk/hdr.mk 3 | include $(ROOT)/mk/ixp.mk 4 | 5 | include targets.mk 6 | MANPAGES += ixpc.1 libixp.3 ixp_srvutils.3 7 | 8 | include $(ROOT)/mk/man.mk 9 | 10 | $(TARG): Makefile $(ROOT)/mk/ixp.mk header.t2t 11 | 12 | -------------------------------------------------------------------------------- /man/header.t2t: -------------------------------------------------------------------------------- 1 | %!target: man 2 | %!encoding: UTF-8 3 | 4 | %# There's apparently no other way to do this. 5 | %!postproc(man): "^(.TH.*?) 1 " "\1 3 " 6 | 7 | %!preproc: \bPROVISIONAL\b **PROVISIONAL** 8 | %!preproc: [FMSTV]<(.*?)> **\1(3)** 9 | %!postproc(man): [P]<(.*?)> \\fI\1\\fR 10 | 11 | %!postproc(man): (\[.*?\]) \\fI\1\\fR 12 | %!postproc(man): \+$ \n.P 13 | %!postproc(man): (\$[a-zA-Z_]+) \\fB\1\\fR 14 | %!postproc(man): (\${[a-zA-Z_]+)(.*?)} \\fB\1\\fR\2\\fB}\\fR 15 | %!postproc(man): ^\.\.\.$ .RB ... 16 | 17 | -------------------------------------------------------------------------------- /man/ixp_close.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_CLOSE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_close 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_close(IxpCFid *f); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Closes the file pointed to by \fIf\fR and frees its 22 | associated data structures; 23 | 24 | .SH RETURN VALUE 25 | 26 | .P 27 | Returns 1 on success, and zero on failure. 28 | 29 | .SH SEE ALSO 30 | 31 | .P 32 | ixp_mount(3), ixp_open(3) 33 | 34 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 35 | .\" cmdline: txt2tags -o- ixp_close.man3 36 | -------------------------------------------------------------------------------- /man/ixp_dial.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_DIAL" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_dial, ixp_announce 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_dial(const char *address); 15 | 16 | int ixp_announce(const char *address); 17 | .fi 18 | 19 | 20 | .SH PARAMETERS 21 | 22 | .TP 23 | address 24 | An address on which to connect or listen, 25 | specified in the Plan 9 resources 26 | specification format 27 | (!address\fI[!]\fR) 28 | 29 | .SH DESCRIPTION 30 | 31 | .P 32 | These functions hide some of the ugliness of Berkely 33 | Sockets. ixp_dial connects to the resource at \fIaddress\fR, 34 | while ixp_announce begins listening on \fIaddress\fR. 35 | 36 | .SH RETURN VALUE 37 | 38 | .P 39 | These functions return file descriptors on success, and \-1 40 | on failure. ixp_errbuf(3) may be inspected on failure. 41 | 42 | .SH SEE ALSO 43 | 44 | .P 45 | socket(2) 46 | 47 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 48 | .\" cmdline: txt2tags -o- ixp_dial.man3 49 | -------------------------------------------------------------------------------- /man/ixp_emalloc.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_EMALLOC" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_emalloc, ixp_emallocz, ixp_erealloc, ixp_estrdup 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void *ixp_emalloc(uint size); 15 | 16 | void *ixp_emallocz(uint size); 17 | 18 | void *ixp_erealloc(void *ptr, uint size); 19 | 20 | char *ixp_estrdup(const char *str); 21 | .fi 22 | 23 | 24 | .SH DESCRIPTION 25 | 26 | .P 27 | These functions act like their stdlib counterparts, but print 28 | an error message and exit the program if allocation fails. 29 | ixp_emallocz acts like ixp_emalloc but additionally zeros the 30 | result of the allocation. 31 | 32 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 33 | .\" cmdline: txt2tags -o- ixp_emalloc.man3 34 | -------------------------------------------------------------------------------- /man/ixp_eprint.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_EPRINT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_eprint 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_eprint(const char *fmt, ...); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | libixp calls this function on error. It formats its arguments 22 | as \fBprintf(3)\fR and exits the program. 23 | 24 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 25 | .\" cmdline: txt2tags -o- ixp_eprint.man3 26 | -------------------------------------------------------------------------------- /man/ixp_errbuf.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_ERRBUF" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_errbuf, ixp_errstr, ixp_rerrstr, ixp_werrstr, ixp_vsnprint 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | char *ixp_errbuf(void); 15 | 16 | void ixp_errstr(char *buf, int nbuf); 17 | 18 | void ixp_rerrstr(char *buf, int nbuf); 19 | 20 | void ixp_werrstr(const char *fmt, ...); 21 | 22 | int (*ixp_vsnprint)(char *buf, int nbuf, const char *fmt, va_list); 23 | .fi 24 | 25 | 26 | .SH PARAMETERS 27 | 28 | .TP 29 | buf 30 | The buffer to read and/or fill. 31 | .TP 32 | nbuf 33 | The size of the buffer. 34 | .TP 35 | fmt 36 | A format string with which to write the errstr. 37 | .TP 38 | .RB ... 39 | Arguments to \fIfmt\fR. 40 | 41 | .SH DESCRIPTION 42 | 43 | .P 44 | These functions simulate Plan 9's errstr functionality. 45 | They replace errno in libixp. Note that these functions 46 | are not internationalized. 47 | 48 | .P 49 | \fBixp_errbuf(3)\fR returns the errstr buffer for the current 50 | thread. \fBixp_rerrstr(3)\fR fills \fIbuf\fR with the data from 51 | the current thread's error buffer, while \fBixp_errstr(3)\fR 52 | exchanges \fIbuf\fR's contents with those of the current 53 | thread's error buffer. \fBixp_werrstr(3)\fR formats the given 54 | format string, \fIfmt\fR, via \fBixp_vsnprint(3)\fR and writes it to 55 | the error buffer. 56 | 57 | .P 58 | \fBixp_vsnprint(3)\fR may be set to a function which will format 59 | its arguments write the result to the \fInbuf\fR length buffer 60 | \fBbuf(3)\fR. The default value is \fBvsnprintf(3)\fR. The function must 61 | format '%s' as a nul\-terminated string and may not consume 62 | any arguments not indicated by a %\-prefixed format specifier, 63 | but may otherwise behave in any manner chosen by the user. 64 | 65 | .SH SEE ALSO 66 | 67 | .P 68 | ixp_vsmprint(3) 69 | 70 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 71 | .\" cmdline: txt2tags -o- ixp_errbuf.man3 72 | -------------------------------------------------------------------------------- /man/ixp_fcall2msg.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_FCALL2MSG" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_fcall2msg, ixp_msg2fcall 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | uint ixp_fcall2msg(IxpMsg *msg, IxpFcall *fcall); 15 | 16 | uint ixp_msg2fcall(IxpMsg *msg, IxpFcall *fcall); 17 | .fi 18 | 19 | 20 | .SH DESCRIPTION 21 | 22 | .P 23 | These functions pack or unpack a 9P protocol message. The 24 | message is set to the appropriate mode and its position is 25 | set to the begining of its buffer. 26 | 27 | .SH RETURN VALUE 28 | 29 | .P 30 | These functions return the size of the message on 31 | success and 0 on failure. 32 | 33 | .SH SEE ALSO 34 | 35 | .P 36 | IxpMsg(3), ixp_pfcall(3) 37 | 38 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 39 | .\" cmdline: txt2tags -o- ixp_fcall2msg.man3 40 | -------------------------------------------------------------------------------- /man/ixp_freestat.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_FREESTAT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_freestat, ixp_freefcall 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_freestat(IxpStat *s); 15 | 16 | void ixp_freefcall(IxpFcall *fcall); 17 | .fi 18 | 19 | 20 | .SH DESCRIPTION 21 | 22 | .P 23 | These functions free malloc(3) allocated data in the members 24 | of the passed structures and set those members to nil. They 25 | do not free the structures themselves. 26 | 27 | .SH SEE ALSO 28 | 29 | .P 30 | IxpFcall(3), IxpStat(3) 31 | 32 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 33 | .\" cmdline: txt2tags -o- ixp_freestat.man3 34 | -------------------------------------------------------------------------------- /man/ixp_hangup.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_HANGUP" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_hangup, ixp_server_close 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_hangup(IxpConn *c); 15 | 16 | void ixp_server_close(IxpServer *s); 17 | .fi 18 | 19 | 20 | .SH DESCRIPTION 21 | 22 | .P 23 | ixp_hangup closes a connection, and stops the server 24 | listening on it. It calls the connection's close 25 | function, if it exists. ixp_server_close calls ixp_hangup 26 | on all of the connections on which the server is 27 | listening. 28 | 29 | .SH SEE ALSO 30 | 31 | .P 32 | ixp_listen(3), IxpServer(3), IxpConn(3) 33 | 34 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 35 | .\" cmdline: txt2tags -o- ixp_hangup.man3 36 | -------------------------------------------------------------------------------- /man/ixp_listen.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_LISTEN" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_listen, IxpConn 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | IxpConn *ixp_listen(IxpServer *srv, int fd, void *aux, void (*read)(IxpConn *), void (*close)(IxpConn *)); 15 | 16 | typedef struct IxpConn IxpConn; 17 | struct IxpConn { 18 | IxpServer* srv; 19 | void* aux; /* Arbitrary pointer, to be used by handlers. */ 20 | int fd; /* The file descriptor of the connection. */ 21 | void (*read)(IxpConn *); 22 | void (*close)(IxpConn *); 23 | char closed; /* Non-zero when \fIfd\fR has been closed. */ 24 | 25 | /* Private members */ 26 | ... 27 | } 28 | .fi 29 | 30 | 31 | .SH PARAMETERS 32 | 33 | .TP 34 | fs 35 | The file descriptor on which to listen. 36 | .TP 37 | aux 38 | A piece of data to store in the connection's 39 | \fIaux\fR member of the IxpConn data structure. 40 | .TP 41 | read 42 | The function called when the connection has 43 | data available to read. 44 | .TP 45 | close 46 | A cleanup function called when the 47 | connection is closed. 48 | 49 | .SH DESCRIPTION 50 | 51 | .P 52 | Starts the server \fIsrv\fR listening on \fIfd\fR. The optional 53 | \fIread\fR and \fIclose\fR callbacks are called with the IxpConn 54 | structure for the connection as their sole argument. 55 | 56 | .SH RETURN VALUE 57 | 58 | .P 59 | Returns the connection's new IxpConn data structure. 60 | 61 | .SH SEE ALSO 62 | 63 | .P 64 | ixp_serverloop(3), ixp_serve9conn(3), ixp_hangup(3) 65 | 66 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 67 | .\" cmdline: txt2tags -o- ixp_listen.man3 68 | -------------------------------------------------------------------------------- /man/ixp_mount.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_MOUNT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_mount, ixp_mountfd, ixp_nsmount, IxpClient 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | IxpClient *ixp_mount(const char *address); 15 | 16 | IxpClient *ixp_mountfd(int fd); 17 | 18 | IxpClient *ixp_nsmount(const char *name); 19 | 20 | typedef struct IxpClient IxpClient; 21 | struct IxpClient { 22 | int fd; 23 | uint msize; 24 | uint lastfid; 25 | 26 | /* Private members */ 27 | ... 28 | } 29 | .fi 30 | 31 | 32 | .SH PARAMETERS 33 | 34 | .TP 35 | fd 36 | A file descriptor which is already connected 37 | to a 9P server. 38 | .TP 39 | address 40 | An address (in Plan 9 resource fomat) at 41 | which to connect to a 9P server. 42 | .TP 43 | name 44 | The name of a socket in the process's canonical 45 | namespace directory. 46 | 47 | .SH DESCRIPTION 48 | 49 | .P 50 | Initiate a 9P connection with the server at \fIaddress\fR, 51 | connected to on \fIfd\fR, or under the process's namespace 52 | directory as \fIname\fR. 53 | 54 | .SH RETURN VALUE 55 | 56 | .P 57 | A pointer to a new 9P client. 58 | 59 | .SH SEE ALSO 60 | 61 | .P 62 | ixp_open(3), ixp_create(3), ixp_remove(3), ixp_unmount(3) 63 | 64 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 65 | .\" cmdline: txt2tags -o- ixp_mount.man3 66 | -------------------------------------------------------------------------------- /man/ixp_msec.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_MSEC" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_msec 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | uint64_t ixp_msec(void); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Returns the time since the Epoch in milliseconds. 22 | 23 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 24 | .\" cmdline: txt2tags -o- ixp_msec.man3 25 | -------------------------------------------------------------------------------- /man/ixp_namespace.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_NAMESPACE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_namespace 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | char *ixp_namespace(void); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Returns the path of the canonical 9p namespace directory. 22 | Either the value of \fB$NAMESPACE\fR, if it's set, or, roughly, 23 | /tmp/ns.\fB${USER\fR\fB}\fR.\fB${DISPLAY\fR:%.0=%\fB}\fR. In the latter case, the 24 | directory is created if it doesn't exist, and it is 25 | ensured to be owned by the current user, with no group or 26 | other permissions. 27 | 28 | .SH RETURN VALUE 29 | 30 | .P 31 | A statically allocated string which must not be freed 32 | or altered by the caller. The same value is returned 33 | upon successive calls. 34 | 35 | .SH BUGS 36 | 37 | .P 38 | This function is not thread safe until after its first 39 | call. 40 | 41 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 42 | .\" cmdline: txt2tags -o- ixp_namespace.man3 43 | -------------------------------------------------------------------------------- /man/ixp_open.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_OPEN" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_open, ixp_create, IxpCFid, IxpOMode 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | IxpCFid *ixp_open(IxpClient *c, const char *path, uint8_t mode); 15 | 16 | IxpCFid *ixp_create(IxpClient *c, const char *path, uint perm, uint8_t mode); 17 | 18 | typedef struct IxpCFid IxpCFid; 19 | struct IxpCFid { 20 | uint32_t fid; 21 | IxpQid qid; 22 | uint8_t mode; 23 | uint open; 24 | uint iounit; 25 | uint32_t offset; 26 | IxpClient* client; 27 | 28 | /* Private members */ 29 | ... 30 | } 31 | 32 | enum IxpOMode { 33 | P9_OREAD = 0, /* open for read */ 34 | P9_OWRITE = 1, /* write */ 35 | P9_ORDWR = 2, /* read and write */ 36 | P9_OEXEC = 3, /* execute, == read but check execute permission */ 37 | P9_OTRUNC = 16, /* or'ed in (except for exec), truncate file first */ 38 | P9_OCEXEC = 32, /* or'ed in, close on exec */ 39 | P9_ORCLOSE = 64, /* or'ed in, remove on close */ 40 | P9_ODIRECT = 128, /* or'ed in, direct access */ 41 | P9_ONONBLOCK = 256, /* or'ed in, non-blocking call */ 42 | P9_OEXCL = 0x1000, /* or'ed in, exclusive use (create only) */ 43 | P9_OLOCK = 0x2000, /* or'ed in, lock after opening */ 44 | P9_OAPPEND = 0x4000 /* or'ed in, append only */ 45 | } 46 | .fi 47 | 48 | 49 | .SH PARAMETERS 50 | 51 | .TP 52 | path 53 | The path of the file to open or create. 54 | .TP 55 | perm 56 | The permissions with which to create the new 57 | file. These will be ANDed with those of the 58 | parent directory by the server. 59 | .TP 60 | mode 61 | The file's open mode. 62 | 63 | .SH DESCRIPTION 64 | 65 | .P 66 | ixp_open and ixp_create each open a file at \fIpath\fR. 67 | \fImode\fR must include OREAD, OWRITE, or ORDWR, and may 68 | include any of the modes specified in \fBIxpOMode(3)\fR. 69 | ixp_create, additionally, creates a file at \fIpath\fR if it 70 | doesn't already exist. 71 | 72 | .SH RETURN VALUE 73 | 74 | .P 75 | A pointer on which to operate on the newly 76 | opened file. 77 | 78 | .SH SEE ALSO 79 | 80 | .P 81 | ixp_mount(3), ixp_read(3), ixp_write(3), ixp_print(3), 82 | ixp_fstat(3), ixp_close(3) 83 | 84 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 85 | .\" cmdline: txt2tags -o- ixp_open.man3 86 | -------------------------------------------------------------------------------- /man/ixp_pdata.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PDATA" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pdata 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_pdata(IxpMsg *msg, char **data, uint len); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Packs or unpacks a raw character buffer of size \fIlen\fR. 22 | 23 | .P 24 | If \fImsg\fR\->mode is MsgPack, buffer pointed to by \fIdata\fR is 25 | packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is 26 | MsgUnpack, the address pointed to by \fIs\fR is loaded with a 27 | malloc(3) allocated buffer with the contents of the buffer at 28 | \fImsg\fR\->pos. In either case, \fImsg\fR\->pos is advanced by the 29 | number of bytes read or written. If the action would advance 30 | \fImsg\fR\->pos beyond \fImsg\fR\->end, \fImsg\fR\->pos is still advanced 31 | but no other action is taken. 32 | 33 | .SH SEE ALSO 34 | 35 | .P 36 | IxpMsg(3), ixp_pstring(3) 37 | 38 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 39 | .\" cmdline: txt2tags -o- ixp_pdata.man3 40 | -------------------------------------------------------------------------------- /man/ixp_pending_write.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PENDING_WRITE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pending_write, ixp_pending_print, ixp_pending_vprint, ixp_pending_pushfid, ixp_pending_clunk, ixp_pending_flush, ixp_pending_respond, IxpPending 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_pending_write(IxpPending *pending, const char *dat, long ndat); 15 | 16 | int ixp_pending_print(IxpPending *pending, const char *fmt, ...); 17 | 18 | int ixp_pending_vprint(IxpPending *pending, const char *fmt, va_list ap); 19 | 20 | void ixp_pending_pushfid(IxpPending *pending, IxpFid *fid); 21 | 22 | bool ixp_pending_clunk(Ixp9Req *req); 23 | 24 | void ixp_pending_flush(Ixp9Req *req); 25 | 26 | void ixp_pending_respond(Ixp9Req *req); 27 | 28 | typedef struct IxpPending IxpPending; 29 | struct IxpPending { 30 | /* Private members */ 31 | ... 32 | } 33 | .fi 34 | 35 | 36 | .SH DESCRIPTION 37 | 38 | .P 39 | These functions aid in writing virtual files used for 40 | broadcasting events or writing data when it becomes 41 | available. When a file to be used with these functions is 42 | opened, ixp_pending_pushfid should be called with its 43 | \fBIxpFid(3)\fR as an argument. This sets the IxpFid's \fIpending\fR 44 | member to true. Thereafter, for each file with its 45 | \fIpending\fR member set, ixp_pending_respond should be called 46 | for each TRead request, ixp_pending_clunk for each TClunk 47 | request, and ixp_pending_flush for each TFlush request. 48 | 49 | .P 50 | ixp_pending_write queues the data in \fIdat\fR of length \fIndat\fR 51 | to be written to each currently pending fid in \fIpending\fR. If 52 | there is a read request pending for a given fid, the data is 53 | written immediately. Otherwise, it is written the next time 54 | ixp_pending_respond is called. Likewise, if there is data 55 | queued when ixp_pending_respond is called, it is written 56 | immediately, otherwise the request is queued. 57 | 58 | .P 59 | ixp_pending_print and ixp_pending_vprint call ixp_pending_write 60 | after formatting their arguments with \fBixp_vsmprint(3)\fR. 61 | 62 | .P 63 | The IxpPending data structure is opaque and should be 64 | initialized zeroed before using these functions for the first 65 | time. 66 | 67 | .SH RETURN VALUE 68 | 69 | .P 70 | ixp_pending_clunk returns true if \fIpending\fR has any 71 | more pending IxpFids. 72 | 73 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 74 | .\" cmdline: txt2tags -o- ixp_pending_write.man3 75 | -------------------------------------------------------------------------------- /man/ixp_pfcall.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PFCALL" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pfcall, ixp_pqid, ixp_pqids, ixp_pstat, ixp_sizeof_stat 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_pfcall(IxpMsg *msg, IxpFcall *fcall); 15 | 16 | void ixp_pqid(IxpMsg *msg, IxpQid *qid); 17 | 18 | void ixp_pqids(IxpMsg *msg, uint16_t *num, IxpQid qid\fI[]\fR, uint max); 19 | 20 | void ixp_pstat(IxpMsg *msg, IxpStat *stat); 21 | 22 | uint16_t ixp_sizeof_stat(IxpStat *stat); 23 | .fi 24 | 25 | 26 | .SH DESCRIPTION 27 | 28 | .P 29 | These convenience functions pack or unpack the contents of 30 | libixp structures into their wire format. They behave as if 31 | \fBixp_pu8(3)\fR, \fBixp_pu16(3)\fR, \fBixp_pu32(3)\fR, \fBixp_pu64(3)\fR, and 32 | \fBixp_pstring(3)\fR were called for each member of the structure 33 | in question. ixp_pqid is to ixp_pqid as \fBixp_pstrings(3)\fR is to 34 | ixp_pstring. 35 | 36 | .P 37 | ixp_sizeof_stat returns the size of the packed represention 38 | of \fIstat\fR. 39 | 40 | .SH SEE ALSO 41 | 42 | .P 43 | IxpMsg(3), ixp_pu8(3), ixp_pu16(3), ixp_pu32(3), 44 | ixp_pu64(3), ixp_pstring(3), ixp_pstrings(3) 45 | 46 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 47 | .\" cmdline: txt2tags -o- ixp_pfcall.man3 48 | -------------------------------------------------------------------------------- /man/ixp_print.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PRINT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_print, ixp_vprint, ixp_vsmprint 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_print(IxpCFid *fid, const char *fmt, ...); 15 | 16 | int ixp_vprint(IxpCFid *fid, const char *fmt, va_list args); 17 | 18 | char* (*ixp_vsmprint)(const char *fmt, va_list); 19 | .fi 20 | 21 | 22 | .SH PARAMETERS 23 | 24 | .TP 25 | fid 26 | An open IxpCFid to which to write the result. 27 | .TP 28 | fmt 29 | The string with which to format the data. 30 | .TP 31 | args 32 | A va_list holding the arguments to the format 33 | string. 34 | .TP 35 | .RB ... 36 | The arguments to the format string. 37 | 38 | .SH DESCRIPTION 39 | 40 | .P 41 | These functions act like the standard formatted IO 42 | functions. They write the result of the formatting to the 43 | file pointed to by C. 44 | 45 | .P 46 | \fBixp_vsmprint(3)\fR may be set to a function which will 47 | format its arguments and return a nul\-terminated string 48 | allocated by malloc(3). The default formats its arguments as 49 | printf(3). 50 | 51 | .SH RETURN VALUE 52 | 53 | .P 54 | These functions return the number of bytes written. 55 | There is currently no way to detect failure. 56 | 57 | .SH SEE ALSO 58 | 59 | .P 60 | ixp_mount(3), ixp_open(3), printf(3) 61 | 62 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 63 | .\" cmdline: txt2tags -o- ixp_print.man3 64 | -------------------------------------------------------------------------------- /man/ixp_printfcall.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PRINTFCALL" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_printfcall 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void (*ixp_printfcall)(IxpFcall*); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | When set to a non\-null value, ixp_printfcall is called once for 22 | every incoming and outgoing Fcall. It is intended to simplify the 23 | writing of debugging code for clients, but may be used for any 24 | arbitrary purpose. 25 | 26 | .SH SEE ALSO 27 | 28 | .P 29 | ixp_respond(3), ixp_serve9conn(3) 30 | 31 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 32 | .\" cmdline: txt2tags -o- ixp_printfcall.man3 33 | -------------------------------------------------------------------------------- /man/ixp_pstring.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PSTRING" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pstring 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_pstring(IxpMsg *msg, char **s); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Packs or unpacks a UTF\-8 encoded string. The packed 22 | representation of the string consists of a 16\-bit unsigned 23 | integer followed by the contents of the string. The unpacked 24 | representation is a nul\-terminated character array. 25 | 26 | .P 27 | If \fImsg\fR\->mode is MsgPack, the string pointed to by \fIs\fR is 28 | packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is 29 | MsgUnpack, the address pointed to by \fIs\fR is loaded with a 30 | malloc(3) allocated, nul\-terminated representation of the 31 | string packed at \fImsg\fR\->pos. In either case, \fImsg\fR\->pos is 32 | advanced by the number of bytes read or written. If the 33 | action would advance \fImsg\fR\->pos beyond \fImsg\fR\->end, 34 | \fImsg\fR\->pos is still advanced but no other action is taken. 35 | 36 | .SH SEE ALSO 37 | 38 | .P 39 | IxpMsg(3), ixp_pstrings(3), ixp_pdata(3) 40 | 41 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 42 | .\" cmdline: txt2tags -o- ixp_pstring.man3 43 | -------------------------------------------------------------------------------- /man/ixp_pstrings.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PSTRINGS" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pstrings 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings\fI[]\fR, uint max); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Packs or unpacks an array of UTF\-8 encoded strings. The packed 22 | representation consists of a 16\-bit element count followed by 23 | an array of strings as packed by \fBixp_pstring(3)\fR. The unpacked 24 | representation is an array of nul\-terminated character arrays. 25 | 26 | .P 27 | If \fImsg\fR\->mode is MsgPack, \fI*num\fR strings in the array 28 | pointed to by \fIstrings\fR are packed into the buffer at 29 | \fImsg\fR\->pos. If \fImsg\fR\->mode is MsgUnpack, \fI*num\fR is loaded 30 | with the number of strings unpacked, the array at 31 | \fI*strings\fR is loaded with pointers to the unpacked strings, 32 | and \fI(*strings)\fI[0]\fR\fR must be freed by the user. In either 33 | case, \fImsg\fR\->pos is advanced by the number of bytes read or 34 | written. If the action would advance \fImsg\fR\->pos beyond 35 | \fImsg\fR\->end, \fImsg\fR\->pos is still advanced, but no other 36 | action is taken. If \fI*num\fR is greater than \fImax\fR, 37 | \fImsg\fR\->pos is set beyond \fImsg\fR\->end and no other action is 38 | taken. 39 | 40 | .SH SEE ALSO 41 | 42 | .P 43 | \fIIxpMsg\fR, \fIixp_pstring\fR, \fIixp_pdata\fR 44 | 45 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 46 | .\" cmdline: txt2tags -o- ixp_pstrings.man3 47 | -------------------------------------------------------------------------------- /man/ixp_pthread_init.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PTHREAD_INIT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pthread_init 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_pthread_init(void); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | This function initializes libixp for use in multithreaded 22 | programs using the POSIX thread system. When using libixp in such 23 | programs, this function must be called before any other libixp 24 | functions. This function is part of libixp_pthread, which you 25 | must explicitly link against. 26 | 27 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 28 | .\" cmdline: txt2tags -o- ixp_pthread_init.man3 29 | -------------------------------------------------------------------------------- /man/ixp_pu8.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_PU8" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_pu8, ixp_pu16, ixp_pu32, ixp_pu64 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_pu8(IxpMsg *msg, uint8_t *val); 15 | 16 | void ixp_pu16(IxpMsg *msg, uint16_t *val); 17 | 18 | void ixp_pu32(IxpMsg *msg, uint32_t *val); 19 | 20 | void ixp_pu64(IxpMsg *msg, uint64_t *val); 21 | .fi 22 | 23 | 24 | .SH DESCRIPTION 25 | 26 | .P 27 | These functions pack or unpack an unsigned integer of the 28 | specified size. 29 | 30 | .P 31 | If \fImsg\fR\->mode is MsgPack, the value pointed to by \fIval\fR is 32 | packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is 33 | MsgUnpack, the packed value at \fImsg\fR\->pos is loaded into the 34 | location pointed to by \fIval\fR. In both cases, \fImsg\fR\->pos is 35 | advanced by the number of bytes read or written. If the call 36 | would advance \fImsg\fR\->pos beyond \fImsg\fR\->end, \fImsg\fR\->pos is 37 | advanced, but nothing is modified. 38 | 39 | .SH SEE ALSO 40 | 41 | .P 42 | IxpMsg(3) 43 | 44 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 45 | .\" cmdline: txt2tags -o- ixp_pu8.man3 46 | -------------------------------------------------------------------------------- /man/ixp_read.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_READ" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_read, ixp_pread 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | long ixp_read(IxpCFid *fid, void *buf, long count); 15 | 16 | long ixp_pread(IxpCFid *fid, void *buf, long count, int64_t offset); 17 | .fi 18 | 19 | 20 | .SH PARAMETERS 21 | 22 | .TP 23 | buf 24 | A buffer in which to store the read data. 25 | .TP 26 | count 27 | The number of bytes to read. 28 | .TP 29 | offset 30 | The offset at which to begin reading. 31 | 32 | .SH DESCRIPTION 33 | 34 | .P 35 | ixp_read and ixp_pread each read \fIcount\fR bytes of data 36 | from the file pointed to by \fIfid\fR, into \fIbuf\fR. ixp_read 37 | begins reading at its stored offset, and increments it by 38 | the number of bytes read. ixp_pread reads beginning at 39 | \fIoffset\fR and does not alter \fIfid\fR's stored offset. 40 | 41 | .SH RETURN VALUE 42 | 43 | .P 44 | These functions return the number of bytes read on 45 | success and \-1 on failure. 46 | 47 | .SH SEE ALSO 48 | 49 | .P 50 | ixp_mount(3), ixp_open(3), ixp_write(3) 51 | 52 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 53 | .\" cmdline: txt2tags -o- ixp_read.man3 54 | -------------------------------------------------------------------------------- /man/ixp_remove.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_REMOVE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_remove 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_remove(IxpClient *c, const char *path); 15 | .fi 16 | 17 | 18 | .SH PARAMETERS 19 | 20 | .TP 21 | path 22 | The path of the file to remove. 23 | 24 | .SH DESCRIPTION 25 | 26 | .P 27 | Removes a file or directory from the remote server. 28 | 29 | .SH RETURN VALUE 30 | 31 | .P 32 | ixp_remove returns 0 on failure, 1 on success. 33 | 34 | .SH SEE ALSO 35 | 36 | .P 37 | ixp_mount(3) 38 | 39 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 40 | .\" cmdline: txt2tags -o- ixp_remove.man3 41 | -------------------------------------------------------------------------------- /man/ixp_respond.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_RESPOND" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_respond 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_respond(Ixp9Req *req, const char *error); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Sends a response to the given request. The response is 22 | constructed from the \fIofcall\fR member of the \fIreq\fR parameter, or 23 | from the \fIerror\fR parameter if it is non\-null. In the latter 24 | case, the response is of type RError, while in any other case it 25 | is of the same type as \fIreq\fR\->\fIofcall\fR, which must match the 26 | request type in \fIreq\fR\->\fIifcall\fR. 27 | 28 | .SH SEE ALSO 29 | 30 | .P 31 | Ixp9Req(3), ixp_printfcall(3) 32 | 33 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 34 | .\" cmdline: txt2tags -o- ixp_respond.man3 35 | -------------------------------------------------------------------------------- /man/ixp_rubyinit.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_RUBYINIT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_rubyinit 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | ixp_rubyinit 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | This function initializes libixp for use in multithreaded 22 | programs embedded in the ruby interpreter. When using a pthread 23 | edition of ruby, ixp_pthread_init should be used instead. When 24 | using libixp in such programs, this function must be called 25 | before any other libixp functions. 26 | 27 | .P 28 | This function is part of libixp_rubythread, which is part of the 29 | libixp distribution, but is not built by default unless enabled 30 | in config.mk. 31 | 32 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 33 | .\" cmdline: txt2tags -o- ixp_rubyinit.man3 34 | -------------------------------------------------------------------------------- /man/ixp_sendmsg.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SENDMSG" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_sendmsg, ixp_recvmsg 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | uint ixp_sendmsg(int fd, IxpMsg *msg); 15 | 16 | uint ixp_recvmsg(int fd, IxpMsg *msg); 17 | .fi 18 | 19 | 20 | .SH DESCRIPTION 21 | 22 | .P 23 | These functions read and write messages to and from the given 24 | file descriptors. 25 | 26 | .P 27 | ixp_sendmsg writes the data at \fImsg\fR\->pos upto \fImsg\fR\->end. 28 | If the call returns non\-zero, all data is assured to have 29 | been written. 30 | 31 | .P 32 | ixp_recvmsg first reads a 32 bit, little\-endian length from 33 | \fIfd\fR and then reads a message of that length (including the 34 | 4 byte size specifier) into the buffer at \fImsg\fR\->data, so 35 | long as the size is less than \fImsg\fR\->size. 36 | 37 | .SH RETURN VALUE 38 | 39 | .P 40 | These functions return the number of bytes read or 41 | written, or 0 on error. Errors are stored in 42 | \fBixp_errbuf(3)\fR. 43 | 44 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 45 | .\" cmdline: txt2tags -o- ixp_sendmsg.man3 46 | -------------------------------------------------------------------------------- /man/ixp_serverloop.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SERVERLOOP" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_serverloop, IxpServer 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_serverloop(IxpServer *srv); 15 | 16 | typedef struct IxpServer IxpServer; 17 | struct IxpServer { 18 | IxpConn* conn; 19 | IxpMutex lk; 20 | IxpTimer* timer; 21 | void (*preselect)(IxpServer*); 22 | void* aux; 23 | int running; 24 | int maxfd; 25 | fd_set rd; 26 | } 27 | .fi 28 | 29 | 30 | .SH DESCRIPTION 31 | 32 | .P 33 | Enters the main loop of the server. Exits when 34 | \fIsrv\fR\->running becomes false, or when select(2) returns an 35 | error other than EINTR. 36 | 37 | .SH RETURN VALUE 38 | 39 | .P 40 | Returns 0 when the loop exits normally, and 1 when 41 | it exits on error. \fBerrno(3)\fR or the return value of 42 | \fBixp_errbuf(3)\fR may be inspected. 43 | 44 | .SH SEE ALSO 45 | 46 | .P 47 | ixp_listen(3), ixp_settimer(3) 48 | 49 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 50 | .\" cmdline: txt2tags -o- ixp_serverloop.man3 51 | -------------------------------------------------------------------------------- /man/ixp_settimer.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SETTIMER" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_settimer 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | long ixp_settimer(IxpServer *srv, long msec, void (*fn)(long, void *), void *aux); 15 | .fi 16 | 17 | 18 | .SH PARAMETERS 19 | 20 | .TP 21 | msec 22 | The timeout in milliseconds. 23 | .TP 24 | fn 25 | The function to call after \fImsec\fR milliseconds 26 | have elapsed. 27 | .TP 28 | aux 29 | An arbitrary argument to pass to \fIfn\fR when it 30 | is called. 31 | 32 | .SH DESCRIPTION 33 | 34 | .P 35 | Initializes a callback\-based timer to be triggerred after 36 | \fImsec\fR milliseconds. The timer is passed its id number 37 | and the value of \fIaux\fR. 38 | 39 | .SH RETURN VALUE 40 | 41 | .P 42 | Returns the new timer's unique id number. 43 | 44 | .SH SEE ALSO 45 | 46 | .P 47 | ixp_unsettimer(3), ixp_serverloop(3) 48 | 49 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 50 | .\" cmdline: txt2tags -o- ixp_settimer.man3 51 | -------------------------------------------------------------------------------- /man/ixp_smprint.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SMPRINT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_smprint 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | char *ixp_smprint(const char *fmt, ...); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | This function formats its arguments as \fBprintf(3)\fR and returns 22 | a \fBmalloc(3)\fR allocated string containing the result. 23 | 24 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 25 | .\" cmdline: txt2tags -o- ixp_smprint.man3 26 | -------------------------------------------------------------------------------- /man/ixp_srv_clonefiles.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_CLONEFILES" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_clonefiles 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | IxpFileId *ixp_srv_clonefiles(IxpFileId *fileid); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Increase the reference count of every IxpFileId linked 22 | to \fIfileid\fR. 23 | 24 | .SH SEE ALSO 25 | 26 | .P 27 | ixp_srv_getfile(3) 28 | 29 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 30 | .\" cmdline: txt2tags -o- ixp_srv_clonefiles.man3 31 | -------------------------------------------------------------------------------- /man/ixp_srv_data2cstring.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_DATA2CSTRING" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_data2cstring 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_srv_data2cstring(Ixp9Req *req); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Ensure that the data member of \fIreq\fR is null terminated, 22 | removing any new line from its end. 23 | 24 | .SH SEE ALSO 25 | 26 | .P 27 | Ixp9Req(3) 28 | 29 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 30 | .\" cmdline: txt2tags -o- ixp_srv_data2cstring.man3 31 | -------------------------------------------------------------------------------- /man/ixp_srv_freefile.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_FREEFILE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_freefile 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_srv_freefile(IxpFileId *fileid); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Decrease the reference count of the given IxpFileId, 22 | and push it onto the free list when it reaches 0; 23 | 24 | .SH SEE ALSO 25 | 26 | .P 27 | ixp_srv_getfile(3) 28 | 29 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 30 | .\" cmdline: txt2tags -o- ixp_srv_freefile.man3 31 | -------------------------------------------------------------------------------- /man/ixp_srv_getfile.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_GETFILE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_getfile, IxpFileId 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | IxpFileId *ixp_srv_getfile(void); 15 | 16 | typedef struct IxpFileId IxpFileId; 17 | struct IxpFileId { 18 | IxpFileId* next; 19 | IxpFileIdU p; 20 | bool pending; 21 | uint id; 22 | uint index; 23 | IxpDirtab tab; 24 | uint nref; 25 | char volatil; 26 | } 27 | .fi 28 | 29 | 30 | .SH DESCRIPTION 31 | 32 | .P 33 | Obtain an empty, reference counted IxpFileId struct. 34 | 35 | .SH SEE ALSO 36 | 37 | .P 38 | ixp_srv_clonefiles(3), ixp_srv_freefile(3) 39 | 40 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 41 | .\" cmdline: txt2tags -o- ixp_srv_getfile.man3 42 | -------------------------------------------------------------------------------- /man/ixp_srv_readbuf.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_READBUF" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_readbuf, ixp_srv_writebuf 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len); 15 | 16 | void ixp_srv_writebuf(Ixp9Req *req, char **buf, uint *len, uint max); 17 | .fi 18 | 19 | 20 | .SH DESCRIPTION 21 | 22 | .P 23 | Utility functions for handling TRead and TWrite requests for 24 | files backed by in\-memory buffers. For both functions, \fIbuf\fR 25 | points to a buffer and \fIlen\fR specifies the length of the 26 | buffer. In the case of ixp_srv_writebuf, these values add a 27 | level of pointer indirection, and updates the values if they 28 | change. 29 | 30 | .P 31 | If \fImax\fR has a value other than 0, ixp_srv_writebuf will 32 | truncate any writes to that point in the buffer. Otherwise, 33 | \fI*buf\fR is assumed to be malloc(3) allocated, and is 34 | reallocated to fit the new data as necessary. The buffer is 35 | is always left nul\-terminated. 36 | 37 | .SH BUGS 38 | 39 | .P 40 | ixp_srv_writebuf always truncates its buffer to the end 41 | of the most recent write. 42 | 43 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 44 | .\" cmdline: txt2tags -o- ixp_srv_readbuf.man3 45 | -------------------------------------------------------------------------------- /man/ixp_srv_walkandclone.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_WALKANDCLONE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_walkandclone, ixp_srv_readdir, ixp_srv_verifyfile, IxpLookupFn 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup); 15 | 16 | void ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(IxpStat *, IxpFileId *)); 17 | 18 | bool ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup); 19 | 20 | typedef IxpFileId* (*IxpLookupFn)(IxpFileId*, char*); 21 | .fi 22 | 23 | 24 | .SH DESCRIPTION 25 | 26 | .P 27 | These convenience functions simplify the writing of basic and 28 | static file servers. They use a generic file lookup function 29 | to simplify the process of walking, cloning, and returning 30 | directory listings. Given the \fBIxpFileId(3)\fR of a directory and a 31 | filename name should return a new IxpFileId (allocated via 32 | \fBixp_srv_getfile(3)\fR) for the matching directory entry, or null 33 | if there is no match. If the passed name is null, \fIlookup\fR 34 | should return a linked list of IxpFileIds, one for each child 35 | directory entry. 36 | 37 | .P 38 | ixp_srv_walkandclone handles the moderately complex process 39 | of walking from a directory entry and cloning fids, and calls 40 | \fBixp_respond(3)\fR. It should be called in response to a TWalk 41 | request. 42 | 43 | .P 44 | ixp_srv_readdir should be called to handle read requests on 45 | directories. It prepares a stat for each child of the 46 | directory, taking into account the requested offset, and 47 | calls \fBixp_respond(3)\fR. The \fIdostat\fR parameter must be a 48 | function which fills the passed \fBIxpStat(3)\fR pointer based on 49 | the contents of the passed IxpFileId. 50 | 51 | .P 52 | ixp_srv_verifyfile returns whether a file still exists in the 53 | filesystem, and should be used by filesystems that invalidate 54 | files once they have been deleted. 55 | 56 | .SH SEE ALSO 57 | 58 | .P 59 | IxpFileId(3), ixp_getfile(3), ixp_freefile(3) 60 | 61 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 62 | .\" cmdline: txt2tags -o- ixp_srv_walkandclone.man3 63 | -------------------------------------------------------------------------------- /man/ixp_srv_writectl.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_SRV_WRITECTL" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_srv_writectl 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | char *ixp_srv_writectl(Ixp9Req *req, char *(*fn)(void *, IxpMsg *)); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | This utility function is meant to simplify the writing of 22 | pseudo files to which single\-lined commands are written. 23 | In order to use this function, the \fIaux\fR member of 24 | \fIreq\fR\->fid must be nul or an \fBIxpFileId(3)\fR. Each line of the 25 | written data is stripped of its trailing newline, 26 | nul\-terminated, and stored in an \fBIxpMsg(3)\fR. For each line 27 | thus prepared, \fIfn\fR is called with the IxpMsg pointer and 28 | the the \fIp\fR member of the IxpFileId. 29 | 30 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 31 | .\" cmdline: txt2tags -o- ixp_srv_writectl.man3 32 | -------------------------------------------------------------------------------- /man/ixp_srvutils.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_API" 3 "2010 Jun" "libixp Manual" 2 | 3 | .SH SYNPOSIS 4 | 5 | .nf 6 | #include 7 | .fi 8 | 9 | 10 | .SH DESCRIPTION 11 | .P 12 | Since a large part of libixp's purpose revolves around creating 13 | virtual filesystems, a small library of utility functions are 14 | provided towards furthering that end. They are mainly intended 15 | for applications providing simple, largely static virtual 16 | filesystems containing control files and event feeds, though 17 | they are easily adaptable to other ends. 18 | .SH SEE ALSO 19 | .P 20 | \fBixp_srv_clonefiles(3)\fR, \fBixp_srv_data2cstring(3)\fR, 21 | \fBixp_srv_readbuf(3)\fR, \fBixp_srv_walkandclone(3)\fR, \fBixp_srv_writectl(3)\fR 22 | 23 | .\" man code generated by txt2tags 3.3 (http://txt2tags.org) 24 | .\" cmdline: txt2tags -o- ixp_srvutils.man3 25 | -------------------------------------------------------------------------------- /man/ixp_srvutils.man3: -------------------------------------------------------------------------------- 1 | IXP_API 2 | libixp Manual 3 | 2010 Jun 4 | 5 | %!includeconf: header.t2t 6 | 7 | = SYNPOSIS = 8 | ``` 9 | #include 10 | ``` 11 | = DESCRIPTION = 12 | 13 | Since a large part of libixp's purpose revolves around creating 14 | virtual filesystems, a small library of utility functions are 15 | provided towards furthering that end. They are mainly intended 16 | for applications providing simple, largely static virtual 17 | filesystems containing control files and event feeds, though 18 | they are easily adaptable to other ends. 19 | 20 | = SEE ALSO = 21 | F, F, 22 | F, F, F 23 | 24 | -------------------------------------------------------------------------------- /man/ixp_stat.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_STAT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_stat, ixp_fstat, IxpStat, IxpQid, IxpQType, IxpDMode 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | IxpStat *ixp_stat(IxpClient *c, const char *path); 15 | 16 | IxpStat *ixp_fstat(IxpCFid *fid); 17 | 18 | typedef struct IxpStat IxpStat; 19 | struct IxpStat { 20 | uint16_t type; 21 | uint32_t dev; 22 | IxpQid qid; 23 | uint32_t mode; 24 | uint32_t atime; 25 | uint32_t mtime; 26 | uint64_t length; 27 | char* name; 28 | char* uid; 29 | char* gid; 30 | char* muid; 31 | } 32 | 33 | typedef struct IxpQid IxpQid; 34 | struct IxpQid { 35 | uint8_t type; 36 | uint32_t version; 37 | uint64_t path; 38 | /* Private members */ 39 | ... 40 | } 41 | 42 | enum IxpQType { 43 | P9_QTDIR = 0x80, /* type bit for directories */ 44 | P9_QTAPPEND = 0x40, /* type bit for append only files */ 45 | P9_QTEXCL = 0x20, /* type bit for exclusive use files */ 46 | P9_QTMOUNT = 0x10, /* type bit for mounted channel */ 47 | P9_QTAUTH = 0x08, /* type bit for authentication file */ 48 | P9_QTTMP = 0x04, /* type bit for non-backed-up file */ 49 | P9_QTSYMLINK = 0x02, /* type bit for symbolic link */ 50 | P9_QTFILE = 0x00 /* type bits for plain file */ 51 | } 52 | 53 | enum IxpDMode { 54 | P9_DMEXEC = 0x1, /* mode bit for execute permission */ 55 | P9_DMWRITE = 0x2, /* mode bit for write permission */ 56 | P9_DMREAD = 0x4, /* mode bit for read permission */ 57 | 58 | #define P9_DMDIR 0x80000000 /* mode bit for directories */ 59 | #define P9_DMAPPEND 0x40000000 /* mode bit for append only files */ 60 | #define P9_DMEXCL 0x20000000 /* mode bit for exclusive use files */ 61 | #define P9_DMMOUNT 0x10000000 /* mode bit for mounted channel */ 62 | #define P9_DMAUTH 0x08000000 /* mode bit for authentication file */ 63 | #define P9_DMTMP 0x04000000 /* mode bit for non-backed-up file */ 64 | #define P9_DMSYMLINK 0x02000000 /* mode bit for symbolic link (Unix, 9P2000.u) */ 65 | #define P9_DMDEVICE 0x00800000 /* mode bit for device file (Unix, 9P2000.u) */ 66 | #define P9_DMNAMEDPIPE 0x00200000 /* mode bit for named pipe (Unix, 9P2000.u) */ 67 | #define P9_DMSOCKET 0x00100000 /* mode bit for socket (Unix, 9P2000.u) */ 68 | #define P9_DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */ 69 | #define P9_DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */ 70 | } 71 | .fi 72 | 73 | 74 | .SH PARAMETERS 75 | 76 | .TP 77 | path 78 | The path of the file to stat. 79 | .TP 80 | fid 81 | An open file descriptor to stat. 82 | 83 | .SH DESCRIPTION 84 | 85 | .P 86 | Stats the file at \fIpath\fR or pointed to by \fIfid\fR. 87 | 88 | .SH RETURN VALUE 89 | 90 | .P 91 | Returns an IxpStat structure, which must be freed by 92 | the caller with free(3). 93 | 94 | .SH SEE ALSO 95 | 96 | .P 97 | ixp_mount(3), ixp_open(3) 98 | 99 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 100 | .\" cmdline: txt2tags -o- ixp_stat.man3 101 | -------------------------------------------------------------------------------- /man/ixp_taskinit.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_TASKINIT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_taskinit 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | ixp_taskinit 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | This function initializes libixp for use in multithreaded 22 | programs using the libtask threading system. When using libixp in 23 | such programs, this function must be called before any other 24 | libixp functions. 25 | 26 | .P 27 | This function is part of libixp_task, which is part of the libixp 28 | distribution, but is not built by default unless enabled in 29 | config.mk. 30 | 31 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 32 | .\" cmdline: txt2tags -o- ixp_taskinit.man3 33 | -------------------------------------------------------------------------------- /man/ixp_unmount.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_UNMOUNT" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_unmount 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | void ixp_unmount(IxpClient *client); 15 | .fi 16 | 17 | 18 | .SH DESCRIPTION 19 | 20 | .P 21 | Unmounts the client \fIclient\fR and frees its data structures. 22 | 23 | .SH SEE ALSO 24 | 25 | .P 26 | ixp_mount(3) 27 | 28 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 29 | .\" cmdline: txt2tags -o- ixp_unmount.man3 30 | -------------------------------------------------------------------------------- /man/ixp_unsettimer.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_UNSETTIMER" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_unsettimer 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | int ixp_unsettimer(IxpServer *srv, long id); 15 | .fi 16 | 17 | 18 | .SH PARAMETERS 19 | 20 | .TP 21 | id 22 | The id number of the timer to void. 23 | 24 | .SH DESCRIPTION 25 | 26 | .P 27 | Voids the timer identified by \fIid\fR. 28 | 29 | .SH RETURN VALUE 30 | 31 | .P 32 | Returns true if a timer was stopped, false 33 | otherwise. 34 | 35 | .SH SEE ALSO 36 | 37 | .P 38 | ixp_settimer(3), ixp_serverloop(3) 39 | 40 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 41 | .\" cmdline: txt2tags -o- ixp_unsettimer.man3 42 | -------------------------------------------------------------------------------- /man/ixp_write.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_WRITE" 3 "2012 Dec" "libixp Manual" 2 | 3 | 4 | .SH NAME 5 | 6 | .P 7 | ixp_write, ixp_pwrite 8 | 9 | .SH SYNOPSIS 10 | 11 | .nf 12 | #include 13 | 14 | long ixp_write(IxpCFid *fid, const void *buf, long count); 15 | 16 | long ixp_pwrite(IxpCFid *fid, const void *buf, long count, int64_t offset); 17 | .fi 18 | 19 | 20 | .SH PARAMETERS 21 | 22 | .TP 23 | buf 24 | A buffer holding the contents to store. 25 | .TP 26 | count 27 | The number of bytes to store. 28 | .TP 29 | offset 30 | The offset at which to write the data. 31 | 32 | .SH DESCRIPTION 33 | 34 | .P 35 | ixp_write and ixp_pwrite each write \fIcount\fR bytes of 36 | data stored in \fIbuf\fR to the file pointed to by C. 37 | ixp_write writes its data at its stored offset, and 38 | increments it by \fIcount\fR. ixp_pwrite writes its data a 39 | \fIoffset\fR and does not alter C's stored offset. 40 | 41 | .SH RETURN VALUE 42 | 43 | .P 44 | These functions return the number of bytes actually 45 | written. Any value less than \fIcount\fR must be considered 46 | a failure. 47 | 48 | .SH SEE ALSO 49 | 50 | .P 51 | ixp_mount(3), ixp_open(3), ixp_read(3) 52 | 53 | .\" man code generated by txt2tags 2.6 (http://txt2tags.org) 54 | .\" cmdline: txt2tags -o- ixp_write.man3 55 | -------------------------------------------------------------------------------- /man/ixpc.1: -------------------------------------------------------------------------------- 1 | .TH IXPC 1 ixpc-VERSION 2 | .SH NAME 3 | ixpc \- ixp client 4 | .SH SYNOPSIS 5 | .B ixpc 6 | .RB [ \-a 7 | .IR address ] 8 | .I action 9 | .I file 10 | .br 11 | .B ixpc 12 | .B \-v 13 | .SH DESCRIPTION 14 | .SS Overview 15 | .B ixpc 16 | is a client to access a 9P file server from the command line or from shell 17 | scripts. It can be used to configure 18 | .BR wmii (1). 19 | .SS Options 20 | .TP 21 | .BI \-a " address" 22 | Lets you specify the address to which 23 | .B ixpc 24 | will establish a connection. If this option is not supplied, and the 25 | environment variable IXP_ADDRESS is set, 26 | .B ixpc 27 | will use this value as its address. Currently, the address can only be a 28 | unix socket file or a tcp socket. The syntax for 29 | .I address 30 | is taken (along with many other profound ideas) from the Plan 9 operating 31 | system and has the form 32 | .BR unix!/path/to/socket 33 | for unix socket files, and 34 | .BR tcp!hostname!port 35 | for tcp sockets. 36 | .TP 37 | .B \-v 38 | Prints version information to stdout, then exits. 39 | .TP 40 | The syntax of the actions is as follows: 41 | .TP 42 | .B write 43 | Writes the supplied data from the standard input to 44 | .IR file, 45 | overwriting any previous data. The data to be written is arbitrary 46 | and only gains meaning (and restrictions) when it is interpreted by 47 | .BR wmiiwm (1). 48 | See 49 | .B EXAMPLES 50 | below. 51 | .TP 52 | .B xwrite 53 | The same as write, but the data is taken from subsequent arguments, 54 | rather than the standard input. 55 | .TP 56 | .B create 57 | Creates file or directory. If the file exists, 58 | nothing is done. 59 | .TP 60 | .B ls 61 | Lists files and directories. 62 | .TP 63 | .B read 64 | Reads file or directory contents. 65 | .TP 66 | .B remove 67 | Removes file or directory tree. 68 | .SH ENVIRONMENT 69 | .TP 70 | IXP_ADDRESS 71 | See above. 72 | .SH EXAMPLES 73 | .TP 74 | .B ixpc ls / 75 | This prints the root directory of the wmii filesystem, if IXP_ADDRESS is set 76 | to the address of wmii. For more information about the contents of this 77 | filesystem, see 78 | .BR wmiiwm (1). 79 | .TP 80 | .B ixpc xwrite /ctl quit 81 | Write 'quit' to the main control file of the wmii filesystem, effectively 82 | leaving wmii. 83 | .TP 84 | .B ixpc write /keys \< keys.txt 85 | Replace the contents of 86 | .I /keys 87 | with the contents of 88 | .I keys.txt 89 | .SH SEE ALSO 90 | .BR wmii (1) 91 | 92 | http://www.cs.bell-labs.com/sys/man/5/INDEX.html 93 | -------------------------------------------------------------------------------- /man/libixp.3: -------------------------------------------------------------------------------- 1 | .TH "IXP_API" 3 "2010 Jun" "libixp Manual" 2 | 3 | .SH SYNPOSIS 4 | 5 | .nf 6 | #include 7 | .fi 8 | 9 | 10 | .SH DESCRIPTION 11 | .P 12 | libixp is a client and server library for interacting with the 13 | 9P filesystem protocol. It includes a straightforward 9P 14 | filesystem client, a callback\-based server library, portable 15 | utilities for opening and multiplexing sockets, a library of 16 | data marshalling functions, and utilities to ease the 17 | construction of simple virtual filesystem servers. Further, 18 | libixp is completely threadsafe and can be adapted to virtual 19 | any threading system. 20 | .SH SEE ALSO 21 | .P 22 | \fBIXP_API(3)\fR, \fBIxpThread(3)\fR, \fBIxpMsg(3)\fR, \fBixp_mount(3)\fR, \fBixp_dial(3)\fR, 23 | \fBixp_serverloop(3)\fR, \fBixp_listen(3)\fR, \fBixp_settimer(3)\fR, 24 | \fBixp_serve9conn(3)\fR, ixp_srvutils(3) 25 | 26 | .\" man code generated by txt2tags 3.3 (http://txt2tags.org) 27 | .\" cmdline: txt2tags -o- libixp.man3 28 | -------------------------------------------------------------------------------- /man/libixp.man3: -------------------------------------------------------------------------------- 1 | IXP_API 2 | libixp Manual 3 | 2010 Jun 4 | 5 | %!includeconf: header.t2t 6 | 7 | = SYNPOSIS = 8 | ``` 9 | #include 10 | ``` 11 | = DESCRIPTION = 12 | 13 | libixp is a client and server library for interacting with the 14 | 9P filesystem protocol. It includes a straightforward 9P 15 | filesystem client, a callback-based server library, portable 16 | utilities for opening and multiplexing sockets, a library of 17 | data marshalling functions, and utilities to ease the 18 | construction of simple virtual filesystem servers. Further, 19 | libixp is completely threadsafe and can be adapted to virtual 20 | any threading system. 21 | 22 | = SEE ALSO = 23 | M, S, S, F, F, 24 | F, F, F, 25 | F, ixp_srvutils(3) 26 | -------------------------------------------------------------------------------- /man/targets.mk: -------------------------------------------------------------------------------- 1 | MANPAGES = \ 2 | 'IXP_API.3 IXP_NEEDAPI.3 IXP_MAXAPI.3 IXP_ASSERT_VERSION.3' \ 3 | 'IxpFcall.3 IxpFType.3 IxpFAttach.3 IxpFError.3 IxpFHdr.3 IxpFIO.3 IxpFRAuth.3 IxpFROpen.3 IxpFRStat.3 IxpFRWalk.3 IxpFTCreate.3 IxpFTFlush.3 IxpFTWStat.3 IxpFTWalk.3 IxpFVersion.3' \ 4 | 'IxpFid.3' \ 5 | 'IxpThread.3 IxpMutex.3 IxpRWLock.3 IxpRendez.3 ixp_thread.3' \ 6 | 'ixp_unmount.3' \ 7 | 'ixp_mount.3 ixp_mountfd.3 ixp_nsmount.3 IxpClient.3' \ 8 | 'ixp_remove.3' \ 9 | 'ixp_open.3 ixp_create.3 IxpCFid.3 IxpOMode.3' \ 10 | 'ixp_close.3' \ 11 | 'ixp_stat.3 ixp_fstat.3 IxpStat.3 IxpQid.3 IxpQType.3 IxpDMode.3' \ 12 | 'ixp_read.3 ixp_pread.3' \ 13 | 'ixp_write.3 ixp_pwrite.3' \ 14 | 'ixp_print.3 ixp_vprint.3 ixp_vsmprint.3' \ 15 | 'ixp_pu8.3 ixp_pu16.3 ixp_pu32.3 ixp_pu64.3' \ 16 | 'ixp_pstring.3' \ 17 | 'ixp_pstrings.3' \ 18 | 'ixp_pdata.3' \ 19 | 'ixp_pfcall.3 ixp_pqid.3 ixp_pqids.3 ixp_pstat.3 ixp_sizeof_stat.3' \ 20 | 'ixp_errbuf.3 ixp_errstr.3 ixp_rerrstr.3 ixp_werrstr.3 ixp_vsnprint.3' \ 21 | 'IxpMsg.3 IxpMsgMode.3 ixp_message.3' \ 22 | 'ixp_freestat.3 ixp_freefcall.3' \ 23 | 'ixp_fcall2msg.3 ixp_msg2fcall.3' \ 24 | 'ixp_printfcall.3' \ 25 | 'ixp_respond.3' \ 26 | 'Ixp9Srv.3 Ixp9Req.3 ixp_serve9conn.3' \ 27 | 'ixp_listen.3 IxpConn.3' \ 28 | 'ixp_hangup.3 ixp_server_close.3' \ 29 | 'ixp_serverloop.3 IxpServer.3' \ 30 | 'ixp_dial.3 ixp_announce.3' \ 31 | 'ixp_srv_getfile.3 IxpFileId.3' \ 32 | 'ixp_srv_freefile.3' \ 33 | 'ixp_srv_clonefiles.3' \ 34 | 'ixp_srv_readbuf.3 ixp_srv_writebuf.3' \ 35 | 'ixp_srv_data2cstring.3' \ 36 | 'ixp_srv_writectl.3' \ 37 | 'ixp_pending_write.3 ixp_pending_print.3 ixp_pending_vprint.3 ixp_pending_pushfid.3 ixp_pending_clunk.3 ixp_pending_flush.3 ixp_pending_respond.3 IxpPending.3' \ 38 | 'ixp_srv_walkandclone.3 ixp_srv_readdir.3 ixp_srv_verifyfile.3 IxpLookupFn.3' \ 39 | 'ixp_msec.3' \ 40 | 'ixp_settimer.3' \ 41 | 'ixp_unsettimer.3' \ 42 | 'ixp_sendmsg.3 ixp_recvmsg.3' \ 43 | 'ixp_smprint.3' \ 44 | 'ixp_namespace.3' \ 45 | 'ixp_eprint.3' \ 46 | 'ixp_emalloc.3 ixp_emallocz.3 ixp_erealloc.3 ixp_estrdup.3' \ 47 | 'ixp_pthread_init.3' \ 48 | 'ixp_rubyinit.3' \ 49 | 'ixp_taskinit.3' 50 | -------------------------------------------------------------------------------- /mk/common.mk: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | install: all simpleinstall 4 | uninstall: simpleuninstall 5 | 6 | DOCDIR = $(DOC) 7 | simpleinstall: 8 | for f in $(DOCS); do \ 9 | $(INSTALL) 0644 $$f $(DOCDIR) $$f; \ 10 | done 11 | for f in $(TEXT); do \ 12 | $(INSTALL) 0644 $$f $(DIR) $$f; \ 13 | done 14 | for f in $(BINARY); do \ 15 | $(INSTALL) -b 0644 $$f $(DIR) $$f; \ 16 | done 17 | for f in $(EXECS); do \ 18 | $(INSTALL) -b 0755 $$f $(DIR) $$f; \ 19 | done 20 | 21 | simpleuninstall: 22 | for f in $(DOCS); do \ 23 | $(UNINSTALL) $$f $(DOCDIR) $$f; \ 24 | done 25 | for f in $(TEXT); do \ 26 | $(UNINSTALL) $$f $(DIR) $$f; \ 27 | done 28 | for f in $(BINARY); do \ 29 | $(UNINSTALL) -b $$f $(DIR) $$f; \ 30 | done 31 | for f in $(EXECS); do \ 32 | $(UNINSTALL) -b $$f $(DIR) $$f; \ 33 | done 34 | 35 | cleandep: 36 | echo CLEANDEP 37 | rm .depend 2>/dev/null || true 38 | 39 | tags: 40 | files=; \ 41 | for f in $(OBJ); do \ 42 | [ -f "$$f.c" ] && files="$$files $$f.c"; \ 43 | done; \ 44 | echo CTAGS $$files $(TAGFILES) || \ 45 | ctags $$files $(TAGFILES) 46 | 47 | .PHONY: all options clean dist install uninstall depend cleandep tags 48 | .PHONY: simpleuninstall simpleinstall 49 | -------------------------------------------------------------------------------- /mk/dir.mk: -------------------------------------------------------------------------------- 1 | MKSUBDIR = \ 2 | set -e; \ 3 | targ=$@; targ=$${targ\#d}; \ 4 | for i in $$dirs; do \ 5 | export $(SUBMAKE_EXPORT) BASE=$(BASE)$$i/; \ 6 | if [ ! -d $$i ]; then \ 7 | echo Skipping nonexistent directory: $$i 1>&2; \ 8 | else \ 9 | echo MAKE $$targ $$BASE; \ 10 | (cd $$i && $(MAKE) $$targ) || exit $?; \ 11 | fi; \ 12 | done 13 | 14 | dall: 15 | +dirs="$(DIRS)"; $(MKSUBDIR) 16 | dclean: 17 | +dirs="$(DIRS)"; $(MKSUBDIR) 18 | dinstall: 19 | +dirs="$(INSTDIRS)"; $(MKSUBDIR) 20 | duninstall: 21 | +dirs="$(INSTDIRS)"; $(MKSUBDIR) 22 | ddepend: 23 | +dirs="$(DIRS)"; $(MKSUBDIR) 24 | 25 | all: dall 26 | clean: dclean 27 | install: dinstall 28 | uninstall: duninstall 29 | depend: ddepend 30 | 31 | INSTDIRS = $(DIRS) 32 | 33 | -------------------------------------------------------------------------------- /mk/gcc.mk: -------------------------------------------------------------------------------- 1 | DEBUGCFLAGS = \ 2 | -g \ 3 | -O0 \ 4 | -fno-builtin \ 5 | -fno-inline \ 6 | -fno-omit-frame-pointer \ 7 | -fno-optimize-sibling-calls \ 8 | -fno-unroll-loops 9 | CFLAGS += \ 10 | -std=c99 \ 11 | -pedantic \ 12 | -pipe \ 13 | -fno-strict-aliasing \ 14 | -Wall \ 15 | -Wimplicit \ 16 | -Wmissing-prototypes \ 17 | -Wno-comment \ 18 | -Wno-missing-braces \ 19 | -Wno-parentheses \ 20 | -Wno-sign-compare \ 21 | -Wno-switch \ 22 | -Wpointer-arith \ 23 | -Wreturn-type \ 24 | -Wstrict-prototypes \ 25 | -Wtrigraphs 26 | MKDEP = cpp -M 27 | SOCFLAGS += -fPIC 28 | 29 | -------------------------------------------------------------------------------- /mk/hdr.mk: -------------------------------------------------------------------------------- 1 | DIR = 2 | DIRS = 3 | DOC = 4 | DOCDIR = 5 | DOCS = 6 | EXECS = 7 | HFILES = 8 | INCLUDES = 9 | LIB = 10 | LIBS = 11 | OBJ = 12 | OFILES = 13 | OFILES_PIC = 14 | PACKAGES = 15 | PROG = 16 | SO = 17 | TAGFILES = 18 | TARG = 19 | TEXT = 20 | 21 | FILTER = cat 22 | 23 | EXCFLAGS = $(INCLUDES) -D_XOPEN_SOURCE=600 24 | 25 | COMPILE_FLAGS = $(EXCFLAGS) $(CFLAGS) $$(pkg-config --cflags $(PACKAGES)) 26 | COMPILE = $(SHELL) $(ROOT)/util/compile "$(CC)" "$(COMPILE_FLAGS)" 27 | COMPILEPIC = $(SHELL) $(ROOT)/util/compile "$(CC)" "$(COMPILE_FLAGS) $(SOCFLAGS)" 28 | 29 | LINK = $(SHELL) $(ROOT)/util/link "$(LD)" "$$(pkg-config --libs $(PACKAGES)) $(LDFLAGS) $(LIBS)" 30 | LINKSO = $(SHELL) $(ROOT)/util/link "$(LD)" "$$(pkg-config --libs $(PACKAGES)) $(SOLDFLAGS) $(LIBS) $(SHARED)" 31 | 32 | CLEANNAME=$(SHELL) $(ROOT)/util/cleanname 33 | 34 | SOEXT=so 35 | TAGFILES= 36 | 37 | CTAGS=ctags 38 | 39 | PACKAGES = 2>/dev/null 40 | 41 | # and this: 42 | # Try to find a sane shell. /bin/sh is a last resort, because it's 43 | # usually bash on Linux, which means it's painfully slow. 44 | BINSH:= $(shell \ 45 | if [ -x /bin/dash ]; then echo /bin/dash; \ 46 | elif [ -x /bin/ksh ]; then echo /bin/ksh; \ 47 | else echo /bin/sh; fi) 48 | BINSH!= echo /bin/sh 49 | 50 | include $(ROOT)/config.mk 51 | 52 | # I hate this. 53 | MKCFGSH=if test -f $(ROOT)/config.local.mk; then echo $(ROOT)/config.local.mk; else echo /dev/null; fi 54 | MKCFG:=$(shell $(MKCFGSH)) 55 | MKCFG!=$(MKCFGSH) 56 | include $(MKCFG) 57 | 58 | .SILENT: 59 | .SUFFIXES: .out .o .o_pic .c .pdf .sh .rc .$(SOEXT) .awk .1 .3 .man1 .man3 .depend .install .uninstall .clean 60 | all: 61 | 62 | MAKEFILES=.depend 63 | .c.depend: 64 | echo MKDEP $< 65 | [ -n "$(noisycc)" ] && echo $(MKDEP) $(COMPILE_FLAGS) $< || true 66 | eval "$(MKDEP) $(COMPILE_FLAGS)" $< | sed '1s|.*:|$(<:%.c=%.o):|' >>.depend 67 | 68 | .sh.depend .rc.depend .1.depend .3.depend .awk.depend: 69 | : 70 | 71 | .c.o: 72 | $(COMPILE) $@ $< 73 | .c.o_pic: 74 | $(COMPILEPIC) $@ $< 75 | 76 | .o.out: 77 | $(LINK) $@ $< 78 | .c.out: 79 | $(COMPILE) $(<:.c=.o) $< 80 | $(LINK) $@ $(<:.c=.o) 81 | 82 | .rc.out .awk.out .sh.out: 83 | echo FILTER $(BASE)$< 84 | [ -n "$(<:%.sh=)" ] || $(BINSH) -n $< 85 | set -e; \ 86 | [ -n "$(noisycc)" ] && set -x; \ 87 | $(FILTER) $< >$@; \ 88 | chmod 0755 $@ 89 | 90 | .man1.1 .man3.3: 91 | echo TXT2TAGS $(BASE)$< 92 | [ -n "$(noisycc)" ] && set -x; \ 93 | txt2tags -o- $< >$@ 94 | 95 | INSTALL= _install() { set -e; \ 96 | dashb=$$1; [ $$1 = -b ] && shift; \ 97 | d=$(DESTDIR)$$3; f=$$d/$$(basename $$4); \ 98 | if [ ! -d $$d ]; then echo MKDIR $$3; mkdir -p $$d; fi; \ 99 | echo INSTALL $$($(CLEANNAME) $(BASE)$$2); \ 100 | [ -n "$(noisycc)" ] && set -x; \ 101 | rm -f $$f; \ 102 | if [ "$$dashb" = -b ]; \ 103 | then cp -f $$2 $$f; \ 104 | else $(FILTER) <$$2 >$$f; \ 105 | fi; \ 106 | chmod $$1 $$f; \ 107 | set +x; \ 108 | }; _install 109 | UNINSTALL= _uninstall() { set -e; \ 110 | echo UNINSTALL $$($(CLEANNAME) $(BASE)$$1); \ 111 | [ -n "$(noisycc)" ] && set -x; \ 112 | rm -f $(DESTDIR)$$2/$$(basename $$3); \ 113 | }; _uninstall 114 | 115 | .out.install: 116 | $(INSTALL) -b 0755 $< $(BIN) $* 117 | .out.uninstall: 118 | $(UNINSTALL) $< $(BIN) $* 119 | 120 | .a.install .$(SOEXT).install: 121 | $(INSTALL) -b 0644 $< $(LIBDIR) $< 122 | .a.uninstall .$(SOEXT).uninstall: 123 | $(UNINSTALL) $< $(LIBDIR) $< 124 | 125 | .h.install: 126 | $(INSTALL) 0644 $< $(INCLUDE) $< 127 | .h.uninstall: 128 | $(UNINSTALL) $< $(INCLUDE) $< 129 | 130 | .pdf.install: 131 | $(INSTALL) -b 0644 $< $(DOC) $< 132 | .pdf.uninstall: 133 | $(UNINSTALL) $< $(DOC) $< 134 | 135 | INSTALMAN= _installman() { man=$${1\#\#*.}; $(INSTALL) 0644 $$1 $(MAN)/man$$man $$1; }; _installman 136 | UNINSTALLMAN=_uninstallman() { man=$${1\#\#*.}; $(UNINSTALL) $$1 $(MAN)/man$$man $$1; }; _uninstallman 137 | MANSECTIONS=1 2 3 4 5 6 7 8 9 138 | $(MANSECTIONS:%=.%.install): 139 | $(INSTALMAN) $< 140 | $(MANSECTIONS:%=.%.uninstall): 141 | $(UNINSTALLMAN) $< 142 | 143 | .out.clean: 144 | echo CLEAN $$($(CLEANNAME) $(BASE)$<) 145 | rm -f $< || true 2>/dev/null 146 | rm -f $*.o || true 2>/dev/null 147 | .o.clean .o_pic.clean: 148 | echo CLEAN $$($(CLEANNAME) $(BASE)$<) 149 | rm -f $< || true 2>/dev/null 150 | 151 | printinstall: 152 | clean: 153 | install: printinstall 154 | depend: cleandep 155 | 156 | include $(ROOT)/mk/common.mk 157 | 158 | -------------------------------------------------------------------------------- /mk/ixp.mk: -------------------------------------------------------------------------------- 1 | VERSION = 0.5 2 | 3 | COPYRIGHT = ©2010 Kris Maglione 4 | 5 | $(ROOT)/include/ixp.h: $(ROOT)/config.mk 6 | CFLAGS += '-DVERSION=\"$(VERSION)\"' '-DCOPYRIGHT=\"$(COPYRIGHT)\"' 7 | 8 | -------------------------------------------------------------------------------- /mk/lib.mk: -------------------------------------------------------------------------------- 1 | PTARG = $(ROOT)/lib/$(TARG) 2 | LIB = $(PTARG).a 3 | OFILES = $(OBJ:=.o) 4 | 5 | all: $(HFILES) $(LIB) 6 | 7 | install: $(PTARG).install 8 | uninstall: $(PTARG).uninstall 9 | clean: libclean 10 | depend: $(OBJ:=.depend) 11 | 12 | libclean: 13 | for i in $(LIB) $(OFILES); do \ 14 | [ -e $$i ] && \ 15 | echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ 16 | rm -f $$i; \ 17 | done 2>/dev/null || true 18 | 19 | printinstall: 20 | echo 'Install directories:' 21 | echo ' Lib: $(LIBDIR)' 22 | 23 | $(LIB): $(OFILES) 24 | echo AR $$($(CLEANNAME) $(BASE)/$@) 25 | mkdir $(ROOT)/lib 2>/dev/null || true 26 | $(AR) $@ $(OFILES) 27 | 28 | SOMKSH=case "$(MAKESO)" in 1|[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) echo $(ROOT)/mk/so.mk;; *) echo /dev/null;; esac 29 | SOMK:=$(shell $(SOMKSH)) 30 | SOMK!=$(SOMKSH) 31 | include $(SOMK) 32 | 33 | -------------------------------------------------------------------------------- /mk/man.mk: -------------------------------------------------------------------------------- 1 | 2 | targ = for k in $(MANPAGES); do echo $$k | sed 's/ .*//'; done 3 | TARG:= $(shell $(targ)) 4 | TARG!= $(targ) 5 | 6 | all: $(TARG) 7 | install: $(TARG:.1=.install) $(TARG:.3=.install) maninstall 8 | uninstall: $(TARG:.1=.uninstall) $(TARG:.3=.uninstall) manuninstall 9 | 10 | .PHONY: maninstall manuninstall 11 | 12 | MANLOOP = \ 13 | set -ef; \ 14 | for k in $(MANPAGES); do \ 15 | set -- $$k; \ 16 | real=$$1; shift; \ 17 | for targ; do \ 18 | _ $$real $(MAN)/man$${real\#\#*.}/$$targ; \ 19 | done; \ 20 | done 21 | maninstall: 22 | _() { echo LN $$1 $${2##*/}; ln -sf $$1 $(DESTDIR)$$2; }; $(MANLOOP) 23 | manuninstall: 24 | _() { echo RM $${2##*/}; rm -f $(DESTDIR)$$2; }; $(MANLOOP) 25 | 26 | printinstall: 27 | echo 'Install directories:' 28 | echo ' Man: $(MAN)' 29 | 30 | -------------------------------------------------------------------------------- /mk/many.mk: -------------------------------------------------------------------------------- 1 | PROGS = $(TARG:=.out) 2 | 3 | all: $(OFILES) $(PROGS) 4 | 5 | install: $(TARG:=.install) 6 | uninstall: $(TARG:=.uninstall) 7 | depend: $(OFILES:.o=.depend) $(TARG:=.depend) 8 | clean: manyclean 9 | 10 | printinstall: 11 | echo 'Install directories:' 12 | echo ' Bin: $(BIN)' 13 | 14 | manyclean: 15 | for i in $(TARG:=.o) $(TARG:=.out) $(OFILES); do \ 16 | [ -e $$i ] && \ 17 | echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ 18 | rm -f $$i; \ 19 | done 2>/dev/null || true 20 | 21 | -------------------------------------------------------------------------------- /mk/one.mk: -------------------------------------------------------------------------------- 1 | PROG = $(TARG).out 2 | OFILES = $(OBJ:=.o) 3 | 4 | all: $(PROG) 5 | 6 | install: $(TARG).install 7 | uninstall: $(TARG).uninstall 8 | clean: oneclean 9 | depend: $(OBJ:=.depend) 10 | 11 | printinstall: 12 | echo 'Install directories:' 13 | echo ' Bin: $(BIN)' 14 | 15 | oneclean: 16 | for i in $(PROG) $(OFILES); do \ 17 | [ -e $$i ] && \ 18 | echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ 19 | rm -f $$i; \ 20 | done 2>/dev/null || true 21 | 22 | $(OFILES): $(HFILES) 23 | 24 | $(PROG): $(OFILES) $(LIB) 25 | $(LINK) $@ $(OFILES) $(LIB) 26 | 27 | -------------------------------------------------------------------------------- /mk/so.mk: -------------------------------------------------------------------------------- 1 | SOPTARG = $(ROOT)/lib/$(TARG) 2 | SO = $(SOPTARG).$(SOEXT) 3 | SONAME = $(TARG).$(SOEXT) 4 | OFILES_PIC = $(OBJ:=.o_pic) 5 | 6 | all: $(HFILES) $(SO) 7 | 8 | install: $(SOPTARG).install 9 | uninstall: $(SOPTARG).uninstall 10 | clean: soclean 11 | depend: $(OBJ:=.depend) 12 | 13 | soclean: 14 | for i in $(SO) $(OFILES_PIC); do \ 15 | [ -e $$i ] && \ 16 | echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ 17 | rm -f $$i; \ 18 | done 2>/dev/null || true 19 | 20 | printsoinstall: 21 | echo 'Install directories:' 22 | echo ' Lib: $(LIBDIR)' 23 | 24 | printinstall: printsoinstall 25 | 26 | $(SO): $(OFILES_PIC) 27 | mkdir $(ROOT)/lib 2>/dev/null || true 28 | $(LINKSO) $@ $(OFILES_PIC) 29 | 30 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | These tests require plan9port. 2 | 3 | -------------------------------------------------------------------------------- /test/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern char *(*_syserrstr)(void); 8 | char *path; 9 | 10 | enum { 11 | DATA = 1, 12 | THREAD = 2, 13 | TRACE = 4, 14 | READ = 8, 15 | }; 16 | int chatty = READ; 17 | 18 | typedef struct arg arg; 19 | typedef struct arg2 arg2; 20 | struct arg { 21 | Rendez r; 22 | IxpCFid *f; 23 | Channel *ch; 24 | int j, k; 25 | }; 26 | 27 | struct arg2 { 28 | Rendez r; 29 | IxpClient *c; 30 | Channel *ch; 31 | int j; 32 | }; 33 | 34 | Channel *chan; 35 | int nproc; 36 | 37 | void 38 | spawn(void(*f)(void*), void *v, int s) { 39 | nproc++; 40 | proccreate(f, v, s); 41 | } 42 | 43 | void 44 | _print(Biobuf *b, char *p, char *end, int j, int k) { 45 | for(; p < end; p++) { 46 | Bputc(b, *p); 47 | if(*p == '\n') { 48 | Bflush(b); 49 | Bprint(b, ":: %d %d: ", j, k); 50 | } 51 | } 52 | } 53 | 54 | void 55 | readfile(IxpCFid *f, int j, int k) { 56 | Biobuf *b; 57 | char *buf; 58 | int n; 59 | 60 | if(chatty&TRACE) 61 | fprint(2, "readfile(%p, %d, %d) iounit: %d\n", f, j, k, f->iounit); 62 | 63 | b = Bfdopen(dup(1, -1), OWRITE); 64 | if(chatty&DATA) 65 | Bprint(b, ":: %d %d: ", j, k); 66 | 67 | buf = ixp_emalloc(f->iounit); 68 | while((n = ixp_read(f, buf, f->iounit)) > 0) { 69 | if(chatty&READ) 70 | fprint(2, "+readfile(%p, %d, %d) n=%d\n", f, j, k, n); 71 | if(chatty&DATA) 72 | _print(b, buf, buf+n, j, k); 73 | sleep(0); 74 | } 75 | 76 | if(chatty&TRACE) 77 | fprint(2, "-readfile(%p, %d, %d) iounit: %d\n", f, j, k, f->iounit); 78 | if(chatty&DATA) 79 | Bputc(b, '\n'); 80 | Bterm(b); 81 | } 82 | 83 | static void 84 | _read(void *p) { 85 | arg *a; 86 | int k; 87 | 88 | a = p; 89 | k = a->k; 90 | if(chatty&THREAD) 91 | print("Start _read: %d\n", a->j, k); 92 | 93 | qlock(a->r.l); 94 | sendul(a->ch, 0); 95 | rsleep(&a->r); 96 | if(chatty&THREAD) 97 | print("Wake _read: %d\n", a->j, k); 98 | qunlock(a->r.l); 99 | 100 | readfile(a->f, a->j, k); 101 | sendul(chan, 0); 102 | } 103 | 104 | static void 105 | _open(void *p) { 106 | arg2 *a2; 107 | arg *a; 108 | 109 | a = malloc(sizeof *a); 110 | 111 | a2 = p; 112 | 113 | a->j = a2->j; 114 | memset(&a->r, 0, sizeof(a->r)); 115 | a->r.l = mallocz(sizeof(QLock), 1); 116 | a->ch = chancreate(sizeof(ulong), 0); 117 | 118 | if(chatty&THREAD) 119 | print("Start _open: %d\n", a2->j); 120 | 121 | qlock(a2->r.l); 122 | sendul(a2->ch, 0); 123 | rsleep(&a2->r); 124 | if(chatty&THREAD) 125 | print("Wake _open: %d\n", a2->j); 126 | qunlock(a2->r.l); 127 | 128 | a->f = ixp_open(a2->c, path, OREAD); 129 | if(a->f == nil) 130 | sysfatal("can't open %q: %r\n", path); 131 | sleep(0); 132 | 133 | for(a->k = 0; a->k < 5; a->k++) { 134 | spawn(_read, a, mainstacksize); 135 | recvul(a->ch); 136 | } 137 | 138 | qlock(a->r.l); 139 | rwakeupall(&a->r); 140 | qunlock(a->r.l); 141 | 142 | sendul(chan, 0); 143 | } 144 | 145 | const char *_malloc_options = "A"; 146 | 147 | void 148 | threadmain(int argc, char *argv[]) { 149 | arg2 *a; 150 | char *address; 151 | 152 | USED(argc); 153 | USED(argv); 154 | address = "tcp!localhost!6663"; 155 | path = "/n/local/var/log/messages"; 156 | 157 | a = malloc(sizeof *a); 158 | chan = chancreate(sizeof(ulong), 0); 159 | 160 | quotefmtinstall(); 161 | 162 | _syserrstr = ixp_errbuf; 163 | if(ixp_pthread_init()) 164 | sysfatal("can't init pthread: %r\n"); 165 | 166 | a->c = ixp_mount(address); 167 | if(a->c == nil) 168 | sysfatal("can't mount: %r\n"); 169 | 170 | memset(&a->r, 0, sizeof(a->r)); 171 | a->r.l = mallocz(sizeof(QLock), 1); 172 | a->ch = chancreate(sizeof(ulong), 0); 173 | for(a->j = 0; a->j < 5; a->j++) { 174 | spawn(_open, a, mainstacksize); 175 | recvul(a->ch); 176 | } 177 | 178 | qlock(a->r.l); 179 | if(chatty&THREAD) 180 | fprint(2, "qlock()\n"); 181 | rwakeupall(&a->r); 182 | if(chatty&THREAD) 183 | fprint(2, "wokeup\n"); 184 | qunlock(a->r.l); 185 | if(chatty&THREAD) 186 | fprint(2, "unlocked\n"); 187 | 188 | while(nproc--) 189 | recvul(chan); 190 | } 191 | 192 | -------------------------------------------------------------------------------- /test/mkfile: -------------------------------------------------------------------------------- 1 | <$PLAN9/src/mkhdr 2 | 3 | default:V: all 4 | 5 | CFLAGS=-I../include 6 | LDFLAGS=-L../lib -lixp -lixp_pthread 7 | 8 | TARG=\ 9 | client\ 10 | 11 | <$PLAN9/src/mkmany 12 | 13 | -------------------------------------------------------------------------------- /test/o.client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0intro/libixp/39bc91ae4daa39cdf0ff0bb18f8429cdacaf8a79/test/o.client -------------------------------------------------------------------------------- /util/cleanname: -------------------------------------------------------------------------------- 1 | #!/bin/sh -f 2 | 3 | echo "$@" | 4 | awk -F'/+' '{ 5 | delete a 6 | n = 0 7 | for(i = 1; i <= NF; i++) { 8 | if($i == ".." && n > 0 && a[n] != "..") 9 | n-- 10 | else if($i != "" && $i != ".") 11 | a[++n] = $i 12 | } 13 | s = "" 14 | for(i = 1; i <= n; i++) 15 | s = s "/" a[i] 16 | print substr(s, 2) 17 | }' 18 | 19 | -------------------------------------------------------------------------------- /util/compile: -------------------------------------------------------------------------------- 1 | #!/bin/sh -f 2 | 3 | CC=$1 4 | CFLAGS=$2; shift 2 5 | 6 | outfile="$1"; shift 7 | bin="$(echo $0 | sed 's,/[^/]*$,,')" 8 | 9 | # Derived from Russ Cox's 9c in plan9port. 10 | 11 | xtmp=/tmp/cc.$$.$USER.out 12 | 13 | echo CC $($bin/cleanname ${BASE}$outfile) 14 | [ -n "$noisycc" ] && echo $CC -o $outfile $CFLAGS $@ 15 | eval '$CC -o $outfile '"$CFLAGS"' $@ >$xtmp 2>&1' 16 | status=$? 17 | [ $status -eq 0 ] || echo $CC -o $outfile $CFLAGS $@ >&2 18 | 19 | base=$(echo $BASE | sed 's/,/\\,/g') 20 | re='\([^[:space:]/][^[:space:]]*\..:[0-9]\)' 21 | 22 | undup() { # GCC is crap. 23 | awk ' 24 | function shift() { 25 | for(n=1; n<=3; n++) 26 | if(2*n <= nl) 27 | for(i=1; i<=n; i++) { 28 | if(l[i] != l[i+n]) 29 | break; 30 | if(i == n) { 31 | for(i=1; i<=n; i++) 32 | print l[i] 33 | nl -= 2*n; 34 | for(i=1; i<=nl; i++) 35 | l[i] = l[i+2*n]; 36 | return; 37 | } 38 | } 39 | if(nl == 0) 40 | return 41 | print l[1] 42 | for(i=1; i 0) 57 | shift(); 58 | }' 59 | } 60 | 61 | cat $xtmp | sed "s,^$re,$base&,g; s,\([[:space:]]\)$re,\1$base\2,g" | 62 | grep -E -iv ': (error|note): .?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.|use of C99 long long|ISO C forbids conversion|warning:.*warn_unused_result' | 63 | sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' | 64 | awk '$1 == "warning:"{t=$2" "$1; sub(/^[^ ]+ [^ ]+ /, ""); $0 = t" "$0}; //' | 65 | awk '{sub(/\[/, ": [", $1); print}' | 66 | undup 1>&2 67 | 68 | rm -f $xtmp 69 | exit $status 70 | 71 | -------------------------------------------------------------------------------- /util/genchangelog: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ef 3 | 4 | ifs="$(echo)" 5 | name=$1 6 | vers=$2 7 | dist=$3 8 | desc="Upstream build" 9 | auth="Kris Maglione " 10 | date=$(date +'%a, %d %b %Y %T %z') 11 | if hg root >/dev/null 2>&1; then 12 | t() { hg log -r . --template "{$@}"; } 13 | vers=$(t rev) 14 | desc=$(t desc) 15 | auth=$(t author) 16 | date=$(t 'date|rfc822date') 17 | fi 18 | 19 | cat >debian/changelog.new <()}ge; 10 | return $str; 11 | } 12 | 13 | sub detab(_) { 14 | my ($text) = @_; 15 | 1 while $text =~ s/^(.*?)\t/$1 . " " x (8 - length($1) % 8)/me; 16 | return $text; 17 | } 18 | 19 | my @c = grep /\.c$/, @ARGV; 20 | my @h = grep /\.h$/, @ARGV; 21 | 22 | my %protos; 23 | my %headers; 24 | open(my $stderr, '>&', \*STDERR); 25 | open STDERR, '>', '/dev/null'; 26 | 27 | open my $fd, '-|', 'cproto', '-DCPROTO', '-I./include', @c, '/dev/null'; 28 | for(<$fd>) { 29 | chomp; 30 | s/\b_ixp//g; 31 | if(m/(\w+)\(/) { 32 | push @{$protos{$1}}, $_; 33 | } 34 | } 35 | open STDERR, '>&', $stderr; 36 | 37 | my @txt; 38 | @ARGV = (@h, '/dev/null'); 39 | for my $f(@h) { 40 | open my $fd, '<', $f; 41 | $_ = join "", map detab, <$fd>; 42 | push @txt, $_; 43 | 44 | $f =~ s|^(\./)?include/||; 45 | 46 | my $junk = qr/(?:\[.*\]|\)\(.*\))?/; 47 | while(m/^extern\s+(.*\b(\w+)$junk;)$/gm) { 48 | $headers{$2} = $f; 49 | push @{$protos{$2}}, $1; 50 | } 51 | while(m/^(?!extern)[a-z][^(]+\b(\w+)\(/gmi) { 52 | my $id = $1; 53 | $headers{$id} = $f unless $& =~ m{^\s*(?:#|//|/\*|\*)}; 54 | } 55 | while(m/^typedef\b.*?\b(\w+)$junk;/gm) { 56 | $headers{$1} = $f; 57 | push @{$protos{$1}}, $& unless $& =~ m{\Q/* Deprecated */}; 58 | } 59 | while(m/^\s*#\s*define\s+(\w+)((?:\(.*?\))?)/gm) { 60 | $headers{$1} = $f; 61 | push @{$protos{$1}}, "#define $1$2 ..."; 62 | } 63 | while(m/^(?:enum|struct|union)\s+(\w+).*?^\}/gsm) { 64 | $headers{$1} = $f; 65 | my $proto = \@{$protos{$1}}; 66 | push @$proto, subst {"$1$2$1..."} qr[(^ +)(\Q/* Private members */\E\n).*(?=\n\})]sm, $& 67 | unless $& =~ m{\Q/* Deprecated */}; 68 | } 69 | } 70 | 71 | # print Data::Dumper->Dump([\%protos], ['%protos']); 72 | # print Data::Dumper->Dump([\%headers], ['%headers']); 73 | 74 | @ARGV = (@c, '/dev/null'); 75 | $_ = join "", @txt, map detab, <>; 76 | 77 | sub section($$) { 78 | my ($sect, $text) = @_; 79 | $text =~ s/^\s+|\s+$//g; 80 | $text =~ s/[^:`]$/$&\n/; 81 | print "= $sect =\n\n$text\n"; 82 | } 83 | 84 | print "MANPAGES ="; 85 | while(m{(?<=/\*\*\n)(?:[^*]|\*[^/])+}g) { 86 | local $_ = $&; 87 | chop; 88 | 89 | my @names; 90 | my %section; 91 | my $header = ''; 92 | s/ \* ?//gm; 93 | 94 | s{^(\w+:.*?)\n\n}{ 95 | $header = $1; 96 | $header =~ s{^(?:Function|Type|Variable|Macro): (\w+)}{ 97 | push @names, $1; 98 | join("\n", @{$protos{$1} or [$1]}) . "\n" 99 | }gem; 100 | ""; 101 | }se; 102 | 103 | unless(@names) { 104 | print STDERR $_; 105 | next; 106 | } 107 | 108 | my %hdrs = map {($headers{$_}, "")} @names; 109 | my $includes = join "", map {"#include <$_>\n"} sort keys %hdrs; 110 | $header = "$includes\n$header" if $includes; 111 | 112 | sub despace { 113 | my ($space) = m/^(\s*)/; 114 | s/^$space//gm; 115 | $_ 116 | } 117 | 118 | s{^((?:\w.+):\n(?:.|\n)*?)(?:\n\n|\Z)}{ 119 | %section = (%section, '', map despace, split /\n?^(\w.+):\n/m, $1); 120 | ""; 121 | }gem; 122 | 123 | print " \\\n\t'", (join " ", map {"$_.3"} @names), "'"; 124 | 125 | open my $stdout, ">&", STDOUT; 126 | open STDOUT, '>', "man/$names[0].man3"; 127 | 128 | print </, $section{'See also'} 148 | if exists $section{'See also'}; 149 | open STDOUT, ">&", $stdout 150 | } 151 | print "\n"; 152 | 153 | # vim:se sts=4 sw=4 et tw=0: 154 | -------------------------------------------------------------------------------- /util/link: -------------------------------------------------------------------------------- 1 | #!/bin/sh -f 2 | 3 | LD=$1 4 | LDFLAGS=$2; shift 2 5 | 6 | outfile="$1"; shift 7 | bin="$(echo $0 | sed 's,/[^/]*$,,')" 8 | 9 | # Derived from Russ Cox's 9l in plan9port. 10 | ofiles="" 11 | args="" 12 | for i 13 | do 14 | case "$i" in 15 | *.[ao]|*.o_pic) 16 | ofiles="$ofiles $i" 17 | ;; 18 | *) 19 | args="$args $i" 20 | ;; 21 | esac 22 | done 23 | 24 | xtmp=/tmp/ld.$$.$USER.out 25 | 26 | echo LD "$($bin/cleanname ${BASE}$outfile)" 27 | [ -n "$noisycc" ] && echo $LD -o $outfile $ofiles $LDFLAGS $args 28 | $LD -o $outfile $ofiles $LDFLAGS $args >$xtmp 2>&1 29 | status=$? 30 | [ $status -eq 0 ] || echo $LD -o $outfile $ofiles $LDFLAGS $args >&2 31 | 32 | sed 's/.*: In function `[^:]*: *//' $xtmp | grep -E . | 33 | grep -E -v 'is almost always misused|is dangerous, better use|in statically linked applications requires at runtime' 34 | rm -f $xtmp 35 | 36 | exit $status 37 | 38 | --------------------------------------------------------------------------------