summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/bsd
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/ape/lib/bsd
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/ape/lib/bsd')
-rwxr-xr-xsys/src/ape/lib/bsd/_sock_ingetaddr.c47
-rwxr-xr-xsys/src/ape/lib/bsd/_sock_ipattr.c45
-rwxr-xr-xsys/src/ape/lib/bsd/_sock_srv.c60
-rwxr-xr-xsys/src/ape/lib/bsd/accept.c121
-rwxr-xr-xsys/src/ape/lib/bsd/bcopy.c21
-rwxr-xr-xsys/src/ape/lib/bsd/bind.c70
-rwxr-xr-xsys/src/ape/lib/bsd/connect.c111
-rwxr-xr-xsys/src/ape/lib/bsd/endhostent.c4
-rwxr-xr-xsys/src/ape/lib/bsd/ffs.c23
-rwxr-xr-xsys/src/ape/lib/bsd/getdtablesize.c8
-rwxr-xr-xsys/src/ape/lib/bsd/gethostbyaddr.c29
-rwxr-xr-xsys/src/ape/lib/bsd/gethostbyname.c131
-rwxr-xr-xsys/src/ape/lib/bsd/gethostname.c25
-rwxr-xr-xsys/src/ape/lib/bsd/getopt.c52
-rwxr-xr-xsys/src/ape/lib/bsd/getpeername.c49
-rwxr-xr-xsys/src/ape/lib/bsd/getprotobyname.c90
-rwxr-xr-xsys/src/ape/lib/bsd/getservbyaddr.c18
-rwxr-xr-xsys/src/ape/lib/bsd/getservbyname.c100
-rwxr-xr-xsys/src/ape/lib/bsd/getsockname.c48
-rwxr-xr-xsys/src/ape/lib/bsd/gettimeofday.c56
-rwxr-xr-xsys/src/ape/lib/bsd/inet_addr.c52
-rwxr-xr-xsys/src/ape/lib/bsd/inet_ntoa.c22
-rwxr-xr-xsys/src/ape/lib/bsd/ioctl.c33
-rwxr-xr-xsys/src/ape/lib/bsd/listen.c176
-rwxr-xr-xsys/src/ape/lib/bsd/lstat.c23
-rwxr-xr-xsys/src/ape/lib/bsd/mkfile55
-rwxr-xr-xsys/src/ape/lib/bsd/mktemp.c33
-rwxr-xr-xsys/src/ape/lib/bsd/nptohl.c10
-rwxr-xr-xsys/src/ape/lib/bsd/ntohl.c47
-rwxr-xr-xsys/src/ape/lib/bsd/popen.c84
-rwxr-xr-xsys/src/ape/lib/bsd/priv.h46
-rwxr-xr-xsys/src/ape/lib/bsd/pty.c111
-rwxr-xr-xsys/src/ape/lib/bsd/putenv.c32
-rwxr-xr-xsys/src/ape/lib/bsd/rcmd.c138
-rwxr-xr-xsys/src/ape/lib/bsd/readv.c30
-rwxr-xr-xsys/src/ape/lib/bsd/rresvport.c37
-rwxr-xr-xsys/src/ape/lib/bsd/send.c31
-rwxr-xr-xsys/src/ape/lib/bsd/sendto.c28
-rwxr-xr-xsys/src/ape/lib/bsd/sethostent.c5
-rwxr-xr-xsys/src/ape/lib/bsd/setlinebuf.c9
-rwxr-xr-xsys/src/ape/lib/bsd/shutdown.c11
-rwxr-xr-xsys/src/ape/lib/bsd/socket.c175
-rwxr-xr-xsys/src/ape/lib/bsd/socketpair.c21
-rwxr-xr-xsys/src/ape/lib/bsd/strcasecmp.c28
-rwxr-xr-xsys/src/ape/lib/bsd/strdup.c16
-rwxr-xr-xsys/src/ape/lib/bsd/strncasecmp.c29
-rwxr-xr-xsys/src/ape/lib/bsd/writev.c62
47 files changed, 2452 insertions, 0 deletions
diff --git a/sys/src/ape/lib/bsd/_sock_ingetaddr.c b/sys/src/ape/lib/bsd/_sock_ingetaddr.c
new file mode 100755
index 000000000..bc9f90512
--- /dev/null
+++ b/sys/src/ape/lib/bsd/_sock_ingetaddr.c
@@ -0,0 +1,47 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#include "priv.h"
+
+void
+_sock_ingetaddr(Rock *r, struct sockaddr_in *ip, int *alen, char *a)
+{
+ int n, fd;
+ char *p;
+ char name[Ctlsize];
+
+ /* get remote address */
+ strcpy(name, r->ctl);
+ p = strrchr(name, '/');
+ strcpy(p+1, a);
+ fd = open(name, O_RDONLY);
+ if(fd >= 0){
+ n = read(fd, name, sizeof(name)-1);
+ if(n > 0){
+ name[n] = 0;
+ p = strchr(name, '!');
+ if(p){
+ *p++ = 0;
+ ip->sin_family = AF_INET;
+ ip->sin_port = atoi(p);
+ ip->sin_addr.s_addr = inet_addr(name);
+ if(alen)
+ *alen = sizeof(struct sockaddr_in);
+ }
+ }
+ close(fd);
+ }
+
+}
diff --git a/sys/src/ape/lib/bsd/_sock_ipattr.c b/sys/src/ape/lib/bsd/_sock_ipattr.c
new file mode 100755
index 000000000..b9b0c8ac8
--- /dev/null
+++ b/sys/src/ape/lib/bsd/_sock_ipattr.c
@@ -0,0 +1,45 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "priv.h"
+
+/*
+ * return ndb attribute type of an ip name
+ */
+int
+_sock_ipattr(char *name)
+{
+ char *p;
+ int dot = 0;
+ int alpha = 0;
+
+ for(p = name; *p; p++){
+ if(isdigit(*p))
+ ;
+ else if(isalpha(*p) || *p == '-')
+ alpha = 1;
+ else if(*p == '.')
+ dot = 1;
+ else
+ return Tsys;
+ }
+
+ if(alpha){
+ if(dot)
+ return Tdom;
+ else
+ return Tsys;
+ }
+
+ if(dot)
+ return Tip;
+ else
+ return Tsys;
+}
diff --git a/sys/src/ape/lib/bsd/_sock_srv.c b/sys/src/ape/lib/bsd/_sock_srv.c
new file mode 100755
index 000000000..1f2988d03
--- /dev/null
+++ b/sys/src/ape/lib/bsd/_sock_srv.c
@@ -0,0 +1,60 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* socket extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "priv.h"
+
+/* we can't avoid overrunning npath because we don't know how big it is. */
+void
+_sock_srvname(char *npath, char *path)
+{
+ char *p;
+
+ strcpy(npath, "/srv/UD.");
+ p = strrchr(path, '/');
+ if(p == 0)
+ p = path;
+ else
+ p++;
+ strcat(npath, p);
+}
+
+int
+_sock_srv(char *path, int fd)
+{
+ int sfd;
+ char msg[8+256+1];
+
+ /* change the path to something in srv */
+ _sock_srvname(msg, path);
+
+ /* remove any previous instance */
+ unlink(msg);
+
+ /* put the fd in /srv and then close it */
+ sfd = creat(msg, 0666);
+ if(sfd < 0){
+ close(fd);
+ _syserrno();
+ return -1;
+ }
+ snprintf(msg, sizeof msg, "%d", fd);
+ if(write(sfd, msg, strlen(msg)) < 0){
+ _syserrno();
+ close(sfd);
+ close(fd);
+ return -1;
+ }
+ close(sfd);
+ close(fd);
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/accept.c b/sys/src/ape/lib/bsd/accept.c
new file mode 100755
index 000000000..483e4c6ed
--- /dev/null
+++ b/sys/src/ape/lib/bsd/accept.c
@@ -0,0 +1,121 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#include "priv.h"
+
+int
+accept(int fd, void *a, int *alen)
+{
+ int n, nfd, cfd;
+ Rock *r, *nr;
+ struct sockaddr_in *ip;
+ char name[Ctlsize];
+ char file[8+Ctlsize+1];
+ char *p, *net;
+
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+
+ switch(r->domain){
+ case PF_INET:
+ switch(r->stype){
+ case SOCK_DGRAM:
+ net = "udp";
+ break;
+ case SOCK_STREAM:
+ net = "tcp";
+ break;
+ }
+
+ /* get control file name from listener process */
+ n = read(fd, name, sizeof(name)-1);
+ if(n <= 0){
+ _syserrno();
+ return -1;
+ }
+ name[n] = 0;
+ cfd = open(name, O_RDWR);
+ if(cfd < 0){
+ _syserrno();
+ return -1;
+ }
+
+ nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
+ if(nfd < 0){
+ _syserrno();
+ return -1;
+ }
+
+ if(write(fd, "OK", 2) < 0){
+ close(nfd);
+ _syserrno();
+ return -1;
+ }
+
+ /* get remote address */
+ ip = (struct sockaddr_in*)&nr->raddr;
+ _sock_ingetaddr(nr, ip, &n, "remote");
+ if(a){
+ memmove(a, ip, sizeof(struct sockaddr_in));
+ *alen = sizeof(struct sockaddr_in);
+ }
+
+ return nfd;
+ case PF_UNIX:
+ if(r->other >= 0){
+ errno = EGREG;
+ return -1;
+ }
+
+ for(;;){
+ /* read path to new connection */
+ n = read(fd, name, sizeof(name) - 1);
+ if(n < 0)
+ return -1;
+ if(n == 0)
+ continue;
+ name[n] = 0;
+
+ /* open new connection */
+ _sock_srvname(file, name);
+ nfd = open(file, O_RDWR);
+ if(nfd < 0)
+ continue;
+
+ /* confirm opening on new connection */
+ if(write(nfd, name, strlen(name)) > 0)
+ break;
+
+ close(nfd);
+ }
+
+ nr = _sock_newrock(nfd);
+ if(nr == 0){
+ close(nfd);
+ return -1;
+ }
+ nr->domain = r->domain;
+ nr->stype = r->stype;
+ nr->protocol = r->protocol;
+
+ return nfd;
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+}
diff --git a/sys/src/ape/lib/bsd/bcopy.c b/sys/src/ape/lib/bsd/bcopy.c
new file mode 100755
index 000000000..6e3e02224
--- /dev/null
+++ b/sys/src/ape/lib/bsd/bcopy.c
@@ -0,0 +1,21 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+void
+bcopy(void *f, void *t, size_t n)
+{
+ memmove(t, f, n);
+}
+
+int
+bcmp(void *a, void *b, size_t n)
+{
+ return memcmp(a, b, n);
+}
+
+void
+bzero(void *a, size_t n)
+{
+ memset(a, 0, n);
+}
diff --git a/sys/src/ape/lib/bsd/bind.c b/sys/src/ape/lib/bsd/bind.c
new file mode 100755
index 000000000..040c62fa0
--- /dev/null
+++ b/sys/src/ape/lib/bsd/bind.c
@@ -0,0 +1,70 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+/* socket extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+/* plan 9 */
+#include "lib.h"
+#include "sys9.h"
+
+#include "priv.h"
+
+int
+bind(int fd, void *a, int alen)
+{
+ int n, len, cfd;
+ Rock *r;
+ char msg[128];
+ struct sockaddr_in *lip;
+
+ /* assign the address */
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+ if(alen > sizeof(r->addr)){
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memmove(&r->addr, a, alen);
+
+ /* the rest is IP sepecific */
+ if (r->domain != PF_INET)
+ return 0;
+
+ cfd = open(r->ctl, O_RDWR);
+ if(cfd < 0){
+ errno = EBADF;
+ return -1;
+ }
+ lip = (struct sockaddr_in*)&r->addr;
+ if(lip->sin_port > 0)
+ snprintf(msg, sizeof msg, "bind %d", ntohs(lip->sin_port));
+ else
+ strcpy(msg, "bind *");
+ n = write(cfd, msg, strlen(msg));
+ if(n < 0){
+ errno = EOPNOTSUPP; /* Improve error reporting!!! */
+ close(cfd);
+ return -1;
+ }
+ close(cfd);
+
+ if(lip->sin_port <= 0)
+ _sock_ingetaddr(r, lip, &len, "local");
+
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/connect.c b/sys/src/ape/lib/bsd/connect.c
new file mode 100755
index 000000000..3f7dcd6b4
--- /dev/null
+++ b/sys/src/ape/lib/bsd/connect.c
@@ -0,0 +1,111 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#include "priv.h"
+
+int
+connect(int fd, void *a, int alen)
+{
+ Rock *r;
+ int n, cfd, nfd;
+ char msg[8+256+1], file[8+256+1];
+ struct sockaddr_in *lip, *rip;
+ struct sockaddr_un *runix;
+ static int vers;
+
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+ if(alen > sizeof(r->raddr)){
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memmove(&r->raddr, a, alen);
+
+ switch(r->domain){
+ case PF_INET:
+ /* set up a tcp or udp connection */
+ cfd = open(r->ctl, O_RDWR);
+ if(cfd < 0){
+ _syserrno();
+ return -1;
+ }
+ rip = a;
+ lip = (struct sockaddr_in*)&r->addr;
+ if(lip->sin_port)
+ snprintf(msg, sizeof msg, "connect %s!%d%s %d",
+ inet_ntoa(rip->sin_addr), ntohs(rip->sin_port),
+ r->reserved ? "!r" : "",
+ ntohs(lip->sin_port));
+ else
+ snprintf(msg, sizeof msg, "connect %s!%d%s",
+ inet_ntoa(rip->sin_addr), ntohs(rip->sin_port),
+ r->reserved ? "!r" : "");
+ n = write(cfd, msg, strlen(msg));
+ if(n < 0){
+ _syserrno();
+ close(cfd);
+ return -1;
+ }
+ close(cfd);
+ return 0;
+ case PF_UNIX:
+ /* null terminate the address */
+ if(alen == sizeof(r->raddr))
+ alen--;
+ *(((char*)&r->raddr)+alen) = 0;
+
+ if(r->other < 0){
+ errno = EGREG;
+ return -1;
+ }
+
+ /* put far end of our pipe in /srv */
+ snprintf(msg, sizeof msg, "UD.%d.%d", getpid(), vers++);
+ if(_sock_srv(msg, r->other) < 0){
+ r->other = -1;
+ return -1;
+ }
+ r->other = -1;
+
+ /* tell server the /srv file to open */
+ runix = (struct sockaddr_un*)&r->raddr;
+ _sock_srvname(file, runix->sun_path);
+ nfd = open(file, O_RDWR);
+ if(nfd < 0){
+ _syserrno();
+ unlink(msg);
+ return -1;
+ }
+ if(write(nfd, msg, strlen(msg)) < 0){
+ _syserrno();
+ close(nfd);
+ unlink(msg);
+ return -1;
+ }
+ close(nfd);
+
+ /* wait for server to open it and then remove it */
+ read(fd, file, sizeof(file));
+ _sock_srvname(file, msg);
+ unlink(file);
+ return 0;
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
diff --git a/sys/src/ape/lib/bsd/endhostent.c b/sys/src/ape/lib/bsd/endhostent.c
new file mode 100755
index 000000000..aa798b87d
--- /dev/null
+++ b/sys/src/ape/lib/bsd/endhostent.c
@@ -0,0 +1,4 @@
+void
+endhostent(void)
+{
+}
diff --git a/sys/src/ape/lib/bsd/ffs.c b/sys/src/ape/lib/bsd/ffs.c
new file mode 100755
index 000000000..508345365
--- /dev/null
+++ b/sys/src/ape/lib/bsd/ffs.c
@@ -0,0 +1,23 @@
+/* Find the first set bit
+ * i.e. least signifigant 1 bit:
+ * 0 => 0
+ * 1 => 1
+ * 2 => 2
+ * 3 => 1
+ * 4 => 3
+ */
+
+int
+ffs(unsigned int mask)
+{
+ int i;
+
+ if (!mask)
+ return 0;
+ i = 1;
+ while (!(mask & 1)){
+ i++;
+ mask = mask >> 1;
+ }
+ return i;
+}
diff --git a/sys/src/ape/lib/bsd/getdtablesize.c b/sys/src/ape/lib/bsd/getdtablesize.c
new file mode 100755
index 000000000..20e23b17f
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getdtablesize.c
@@ -0,0 +1,8 @@
+/* posix */
+#include <sys/limits.h>
+
+int
+getdtablesize(void)
+{
+ return OPEN_MAX;
+}
diff --git a/sys/src/ape/lib/bsd/gethostbyaddr.c b/sys/src/ape/lib/bsd/gethostbyaddr.c
new file mode 100755
index 000000000..bd58b1dff
--- /dev/null
+++ b/sys/src/ape/lib/bsd/gethostbyaddr.c
@@ -0,0 +1,29 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+int h_errno;
+
+struct hostent*
+gethostbyaddr(void *addr, int len, int type)
+{
+ unsigned long a, y;
+ struct in_addr x;
+ unsigned char *p = addr;
+
+ if(type != AF_INET || len != 4){
+ h_errno = NO_RECOVERY;
+ return 0;
+ }
+
+ y = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+ x.s_addr = htonl(y);
+
+ return gethostbyname(inet_ntoa(x));
+}
diff --git a/sys/src/ape/lib/bsd/gethostbyname.c b/sys/src/ape/lib/bsd/gethostbyname.c
new file mode 100755
index 000000000..749798510
--- /dev/null
+++ b/sys/src/ape/lib/bsd/gethostbyname.c
@@ -0,0 +1,131 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "priv.h"
+
+int h_errno;
+
+enum
+{
+ Nname= 6,
+};
+
+/*
+ * for inet addresses only
+ */
+struct hostent*
+gethostbyname(char *name)
+{
+ int i, t, fd, m;
+ char *p, *bp;
+ int nn, na;
+ unsigned long x;
+ static struct hostent h;
+ static char buf[1024];
+ static char *nptr[Nname+1];
+ static char *aptr[Nname+1];
+ static char addr[Nname][4];
+
+ h.h_name = 0;
+ t = _sock_ipattr(name);
+
+ /* connect to server */
+ fd = open("/net/cs", O_RDWR);
+ if(fd < 0){
+ _syserrno();
+ h_errno = NO_RECOVERY;
+ return 0;
+ }
+
+ /* construct the query, always expect an ip# back */
+ switch(t){
+ case Tsys:
+ snprintf(buf, sizeof buf, "!sys=%s ip=*", name);
+ break;
+ case Tdom:
+ snprintf(buf, sizeof buf, "!dom=%s ip=*", name);
+ break;
+ case Tip:
+ snprintf(buf, sizeof buf, "!ip=%s", name);
+ break;
+ }
+
+ /* query the server */
+ if(write(fd, buf, strlen(buf)) < 0){
+ _syserrno();
+ h_errno = TRY_AGAIN;
+ return 0;
+ }
+ lseek(fd, 0, 0);
+ for(i = 0; i < sizeof(buf)-1; i += m){
+ m = read(fd, buf+i, sizeof(buf) - 1 - i);
+ if(m <= 0)
+ break;
+ buf[i+m++] = ' ';
+ }
+ close(fd);
+ buf[i] = 0;
+
+ /* parse the reply */
+ nn = na = 0;
+ for(bp = buf;;){
+ p = strchr(bp, '=');
+ if(p == 0)
+ break;
+ *p++ = 0;
+ if(strcmp(bp, "dom") == 0){
+ if(h.h_name == 0)
+ h.h_name = p;
+ if(nn < Nname)
+ nptr[nn++] = p;
+ } else if(strcmp(bp, "sys") == 0){
+ if(nn < Nname)
+ nptr[nn++] = p;
+ } else if(strcmp(bp, "ip") == 0){
+ x = inet_addr(p);
+ x = ntohl(x);
+ if(na < Nname){
+ addr[na][0] = x>>24;
+ addr[na][1] = x>>16;
+ addr[na][2] = x>>8;
+ addr[na][3] = x;
+ aptr[na] = addr[na];
+ na++;
+ }
+ }
+ while(*p && *p != ' ')
+ p++;
+ if(*p)
+ *p++ = 0;
+ bp = p;
+ }
+ if(nn+na == 0){
+ h_errno = HOST_NOT_FOUND;
+ return 0;
+ }
+
+ nptr[nn] = 0;
+ aptr[na] = 0;
+ h.h_aliases = nptr;
+ h.h_addr_list = aptr;
+ h.h_length = 4;
+ h.h_addrtype = AF_INET;
+ if(h.h_name == 0)
+ h.h_name = nptr[0];
+ if(h.h_name == 0)
+ h.h_name = aptr[0];
+
+ return &h;
+}
diff --git a/sys/src/ape/lib/bsd/gethostname.c b/sys/src/ape/lib/bsd/gethostname.c
new file mode 100755
index 000000000..5ecdd94b8
--- /dev/null
+++ b/sys/src/ape/lib/bsd/gethostname.c
@@ -0,0 +1,25 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+int
+gethostname(char *name, int namelen)
+{
+ int n, fd;
+ char buf[128];
+
+ fd = open("/dev/sysname", O_RDONLY);
+ if(fd < 0)
+ return -1;
+ n = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if(n <= 0)
+ return -1;
+ buf[n] = 0;
+ strncpy(name, buf, namelen);
+ name[namelen-1] = 0;
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/getopt.c b/sys/src/ape/lib/bsd/getopt.c
new file mode 100755
index 000000000..0116b1183
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getopt.c
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#define ERR(str, chr) if(opterr){fprintf(stderr, "%s%s%c\n", argv[0], str, chr);}
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+int
+getopt (int argc, char **argv, char *opts)
+{
+ static int sp = 1;
+ register c;
+ register char *cp;
+
+ if (sp == 1)
+ if (optind >= argc ||
+ argv[optind][0] != '-' || argv[optind][1] == '\0')
+ return EOF;
+ else if (strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return EOF;
+ }
+ optopt = c = argv[optind][sp];
+ if (c == ':' || (cp=strchr(opts, c)) == NULL) {
+ ERR (": illegal option -- ", c);
+ if (argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return '?';
+ }
+ if (*++cp == ':') {
+ if (argv[optind][sp+1] != '\0')
+ optarg = &argv[optind++][sp+1];
+ else if (++optind >= argc) {
+ ERR (": option requires an argument -- ", c);
+ sp = 1;
+ return '?';
+ } else
+ optarg = argv[optind++];
+ sp = 1;
+ } else {
+ if (argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return c;
+}
diff --git a/sys/src/ape/lib/bsd/getpeername.c b/sys/src/ape/lib/bsd/getpeername.c
new file mode 100755
index 000000000..e4dd3109c
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getpeername.c
@@ -0,0 +1,49 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#include "priv.h"
+
+int
+getpeername(int fd, struct sockaddr *addr, int *alen)
+{
+ Rock *r;
+ int i;
+ struct sockaddr_in *rip;
+ struct sockaddr_un *runix;
+
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+
+ switch(r->domain){
+ case PF_INET:
+ rip = (struct sockaddr_in*)&r->raddr;
+ memmove(addr, rip, sizeof(struct sockaddr_in));
+ *alen = sizeof(struct sockaddr_in);
+ break;
+ case PF_UNIX:
+ runix = (struct sockaddr_un*)&r->raddr;
+ i = &runix->sun_path[strlen(runix->sun_path)] - (char*)runix;
+ memmove(addr, runix, i);
+ *alen = i;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/getprotobyname.c b/sys/src/ape/lib/bsd/getprotobyname.c
new file mode 100755
index 000000000..f88d70148
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getprotobyname.c
@@ -0,0 +1,90 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "priv.h"
+
+extern int h_errno;
+
+enum
+{
+ Nname= 6,
+};
+
+static struct protoent r;
+
+struct protoent *getprotobyname(const char *name) {
+ int fd, i, m;
+ char *p, *bp;
+ int nn, na;
+ unsigned long x;
+ static char buf[1024], proto[1024];
+ static char *nptr[Nname+1];
+
+ /* connect to server */
+ fd = open("/net/cs", O_RDWR);
+ if(fd < 0){
+ _syserrno();
+ h_errno = NO_RECOVERY;
+ return 0;
+ }
+
+ /* construct the query, always expect a protocol# back */
+ snprintf(buf, sizeof buf, "!protocol=%s ipv4proto=*", name);
+
+ /* query the server */
+ if(write(fd, buf, strlen(buf)) < 0){
+ _syserrno();
+ h_errno = TRY_AGAIN;
+ return 0;
+ }
+ lseek(fd, 0, 0);
+ for(i = 0; i < sizeof(buf)-1; i += m){
+ m = read(fd, buf+i, sizeof(buf) - 1 - i);
+ if(m <= 0)
+ break;
+ buf[i+m++] = ' ';
+ }
+ close(fd);
+ buf[i] = 0;
+
+ /* parse the reply */
+ nn = na = 0;
+ for(bp = buf;;){
+ p = strchr(bp, '=');
+ if(p == 0)
+ break;
+ *p++ = 0;
+ if(strcmp(bp, "protocol") == 0){
+ if(!nn)
+ r.p_name = p;
+ if(nn < Nname)
+ nptr[nn++] = p;
+ } else if(strcmp(bp, "ipv4proto") == 0){
+ r.p_proto = atoi(p);
+ na++;
+ }
+ while(*p && *p != ' ')
+ p++;
+ if(*p)
+ *p++ = 0;
+ bp = p;
+ }
+ nptr[nn] = 0;
+ r.p_aliases = nptr;
+ if (nn+na == 0)
+ return 0;
+
+ return &r;
+}
diff --git a/sys/src/ape/lib/bsd/getservbyaddr.c b/sys/src/ape/lib/bsd/getservbyaddr.c
new file mode 100755
index 000000000..cafb72d04
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getservbyaddr.c
@@ -0,0 +1,18 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+struct servent*
+getservbyport(int port, char *proto)
+{
+ char buf[32];
+
+ snprintf(buf, sizeof buf, "%d", port);
+ return getservbyname(buf, proto);
+}
diff --git a/sys/src/ape/lib/bsd/getservbyname.c b/sys/src/ape/lib/bsd/getservbyname.c
new file mode 100755
index 000000000..0212d5403
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getservbyname.c
@@ -0,0 +1,100 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "priv.h"
+
+enum
+{
+ Nname= 6,
+};
+
+/*
+ * for inet addresses only
+ */
+struct servent*
+getservbyname(char *name, char *proto)
+{
+ int i, fd, m, num;
+ char *p, *bp;
+ int nn, na;
+ static struct servent s;
+ static char buf[1024];
+ static char *nptr[Nname+1];
+
+ num = 1;
+ for(p = name; *p; p++)
+ if(!isdigit(*p))
+ num = 0;
+
+ s.s_name = 0;
+
+ /* connect to server */
+ fd = open("/net/cs", O_RDWR);
+ if(fd < 0){
+ _syserrno();
+ return 0;
+ }
+
+ /* construct the query, always expect an ip# back */
+ if(num)
+ snprintf(buf, sizeof buf, "!port=%s %s=*", name, proto);
+ else
+ snprintf(buf, sizeof buf, "!%s=%s port=*", proto, name);
+
+ /* query the server */
+ if(write(fd, buf, strlen(buf)) < 0){
+ _syserrno();
+ return 0;
+ }
+ lseek(fd, 0, 0);
+ for(i = 0; i < sizeof(buf)-1; i += m){
+ m = read(fd, buf+i, sizeof(buf) - 1 - i);
+ if(m <= 0)
+ break;
+ buf[i+m++] = ' ';
+ }
+ close(fd);
+ buf[i] = 0;
+
+ /* parse the reply */
+ nn = na = 0;
+ for(bp = buf;;){
+ p = strchr(bp, '=');
+ if(p == 0)
+ break;
+ *p++ = 0;
+ if(strcmp(bp, proto) == 0){
+ if(nn < Nname)
+ nptr[nn++] = p;
+ } else if(strcmp(bp, "port") == 0){
+ s.s_port = htons(atoi(p));
+ }
+ while(*p && *p != ' ')
+ p++;
+ if(*p)
+ *p++ = 0;
+ bp = p;
+ }
+ if(nn+na == 0)
+ return 0;
+
+ nptr[nn] = 0;
+ s.s_aliases = nptr;
+ if(s.s_name == 0)
+ s.s_name = nptr[0];
+
+ return &s;
+}
diff --git a/sys/src/ape/lib/bsd/getsockname.c b/sys/src/ape/lib/bsd/getsockname.c
new file mode 100755
index 000000000..aa22d3217
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getsockname.c
@@ -0,0 +1,48 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#include "priv.h"
+
+int
+getsockname(int fd, struct sockaddr *addr, int *alen)
+{
+ Rock *r;
+ int i;
+ struct sockaddr_in *lip;
+ struct sockaddr_un *lunix;
+
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+
+ switch(r->domain){
+ case PF_INET:
+ lip = (struct sockaddr_in*)addr;
+ _sock_ingetaddr(r, lip, alen, "local");
+ break;
+ case PF_UNIX:
+ lunix = (struct sockaddr_un*)&r->addr;
+ i = &lunix->sun_path[strlen(lunix->sun_path)] - (char*)lunix;
+ memmove(addr, lunix, i);
+ *alen = i;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/gettimeofday.c b/sys/src/ape/lib/bsd/gettimeofday.c
new file mode 100755
index 000000000..ee347f36a
--- /dev/null
+++ b/sys/src/ape/lib/bsd/gettimeofday.c
@@ -0,0 +1,56 @@
+#include <sys/types.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include "sys9.h"
+
+typedef unsigned long long uvlong;
+typedef long long vlong;
+typedef unsigned char uchar;
+
+static uvlong order = 0x0001020304050607ULL;
+
+static void
+be2vlong(vlong *to, uchar *f)
+{
+ uchar *t, *o;
+ int i;
+
+ t = (uchar*)to;
+ o = (uchar*)&order;
+ for(i = 0; i < 8; i++)
+ t[o[i]] = f[i];
+}
+
+int
+gettimeofday(struct timeval *tp, struct timezone *tzp)
+{
+ uchar b[8];
+ vlong t;
+ int opened;
+ static int fd = -1;
+
+ opened = 0;
+ for(;;) {
+ if(fd < 0)
+ if(opened++ ||
+ (fd = _OPEN("/dev/bintime", OREAD|OCEXEC)) < 0)
+ return 0;
+ if(_PREAD(fd, b, sizeof b, 0) == sizeof b)
+ break; /* leave fd open for future use */
+ /* short read, perhaps try again */
+ _CLOSE(fd);
+ fd = -1;
+ }
+ be2vlong(&t, b);
+
+ tp->tv_sec = t/1000000000;
+ tp->tv_usec = (t/1000)%1000000;
+
+ if(tzp) {
+ tzp->tz_minuteswest = 4*60; /* BUG */
+ tzp->tz_dsttime = 1;
+ }
+
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/inet_addr.c b/sys/src/ape/lib/bsd/inet_addr.c
new file mode 100755
index 000000000..63cd69cc4
--- /dev/null
+++ b/sys/src/ape/lib/bsd/inet_addr.c
@@ -0,0 +1,52 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#define CLASS(x) (x[0]>>6)
+
+unsigned long
+inet_addr(char *from)
+{
+ int i;
+ char *p;
+ unsigned char to[4];
+ unsigned long x;
+
+ p = from;
+ memset(to, 0, 4);
+ for(i = 0; i < 4 && *p; i++){
+ to[i] = strtoul(p, &p, 0);
+ if(*p == '.')
+ p++;
+ }
+
+ switch(CLASS(to)){
+ case 0: /* class A - 1 byte net */
+ case 1:
+ if(i == 3){
+ to[3] = to[2];
+ to[2] = to[1];
+ to[1] = 0;
+ } else if (i == 2){
+ to[3] = to[1];
+ to[1] = 0;
+ }
+ break;
+ case 2: /* class B - 2 byte net */
+ if(i == 3){
+ to[3] = to[2];
+ to[2] = 0;
+ }
+ break;
+ }
+ x = nptohl(to);
+ x = htonl(x);
+ return x;
+}
diff --git a/sys/src/ape/lib/bsd/inet_ntoa.c b/sys/src/ape/lib/bsd/inet_ntoa.c
new file mode 100755
index 000000000..03dd714dd
--- /dev/null
+++ b/sys/src/ape/lib/bsd/inet_ntoa.c
@@ -0,0 +1,22 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+char*
+inet_ntoa(struct in_addr in)
+{
+ static char s[18];
+ unsigned char *p;
+
+ p = (unsigned char*)&in.s_addr;
+ snprintf(s, sizeof s, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ return s;
+}
diff --git a/sys/src/ape/lib/bsd/ioctl.c b/sys/src/ape/lib/bsd/ioctl.c
new file mode 100755
index 000000000..0155de573
--- /dev/null
+++ b/sys/src/ape/lib/bsd/ioctl.c
@@ -0,0 +1,33 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+int
+ioctl(int fd, unsigned long request, void* arg)
+{
+ struct stat d;
+
+ if(request == FIONREAD) {
+ if(fstat(fd, &d) < 0) {
+ errno = EBADF;
+ return -1;
+ }
+ /* this works if the file is buffered somehow */
+ *(long*)arg = d.st_size;
+ return 0;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+}
diff --git a/sys/src/ape/lib/bsd/listen.c b/sys/src/ape/lib/bsd/listen.c
new file mode 100755
index 000000000..655e2a06f
--- /dev/null
+++ b/sys/src/ape/lib/bsd/listen.c
@@ -0,0 +1,176 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+/* socket extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+/* plan 9 */
+#include "lib.h"
+#include "sys9.h"
+
+#include "priv.h"
+
+extern int _muxsid;
+extern void _killmuxsid(void);
+
+/*
+ * replace the fd with a pipe and start a process to
+ * accept calls in. this is all to make select work.
+ */
+static int
+listenproc(Rock *r, int fd)
+{
+ Rock *nr;
+ char *net;
+ int cfd, nfd, dfd;
+ int pfd[2];
+ struct stat d;
+ char *p;
+ char listen[Ctlsize];
+ char name[Ctlsize];
+
+ switch(r->stype){
+ case SOCK_DGRAM:
+ net = "udp";
+ break;
+ case SOCK_STREAM:
+ net = "tcp";
+ break;
+ }
+
+ strcpy(listen, r->ctl);
+ p = strrchr(listen, '/');
+ if(p == 0)
+ return -1;
+ strcpy(p+1, "listen");
+
+ if(pipe(pfd) < 0)
+ return -1;
+
+ /* replace fd with a pipe */
+ nfd = dup(fd);
+ dup2(pfd[0], fd);
+ close(pfd[0]);
+ fstat(fd, &d);
+ r->inode = d.st_ino;
+ r->dev = d.st_dev;
+
+ /* start listening process */
+ switch(fork()){
+ case -1:
+ close(pfd[1]);
+ close(nfd);
+ return -1;
+ case 0:
+ if(_muxsid == -1) {
+ _RFORK(RFNOTEG);
+ _muxsid = getpgrp();
+ } else
+ setpgid(getpid(), _muxsid);
+ _RENDEZVOUS(2, _muxsid);
+ break;
+ default:
+ atexit(_killmuxsid);
+ _muxsid = _RENDEZVOUS(2, 0);
+ close(pfd[1]);
+ close(nfd);
+ return 0;
+ }
+
+/* for(fd = 0; fd < 30; fd++)
+ if(fd != nfd && fd != pfd[1])
+ close(fd);/**/
+
+ for(;;){
+ cfd = open(listen, O_RDWR);
+ if(cfd < 0)
+ break;
+
+ dfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
+ if(dfd < 0)
+ break;
+
+ if(write(pfd[1], nr->ctl, strlen(nr->ctl)) < 0)
+ break;
+ if(read(pfd[1], name, sizeof(name)) <= 0)
+ break;
+
+ close(dfd);
+ }
+ exit(0);
+}
+
+int
+listen(fd, backlog)
+ int fd;
+ int backlog;
+{
+ Rock *r;
+ int n, cfd;
+ char msg[128];
+ struct sockaddr_in *lip;
+ struct sockaddr_un *lunix;
+
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+
+ switch(r->domain){
+ case PF_INET:
+ cfd = open(r->ctl, O_RDWR);
+ if(cfd < 0){
+ errno = EBADF;
+ return -1;
+ }
+ lip = (struct sockaddr_in*)&r->addr;
+ if(lip->sin_port >= 0) {
+ if(write(cfd, "bind 0", 6) < 0) {
+ errno = EGREG;
+ close(cfd);
+ return -1;
+ }
+ snprintf(msg, sizeof msg, "announce %d",
+ ntohs(lip->sin_port));
+ }
+ else
+ strcpy(msg, "announce *");
+ n = write(cfd, msg, strlen(msg));
+ if(n < 0){
+ errno = EOPNOTSUPP; /* Improve error reporting!!! */
+ close(cfd);
+ return -1;
+ }
+ close(cfd);
+
+ return listenproc(r, fd);
+ case PF_UNIX:
+ if(r->other < 0){
+ errno = EGREG;
+ return -1;
+ }
+ lunix = (struct sockaddr_un*)&r->addr;
+ if(_sock_srv(lunix->sun_path, r->other) < 0){
+ _syserrno();
+ r->other = -1;
+ return -1;
+ }
+ r->other = -1;
+ return 0;
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
diff --git a/sys/src/ape/lib/bsd/lstat.c b/sys/src/ape/lib/bsd/lstat.c
new file mode 100755
index 000000000..d929e7ef1
--- /dev/null
+++ b/sys/src/ape/lib/bsd/lstat.c
@@ -0,0 +1,23 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+int
+lstat(char *name, struct stat *ans)
+{
+ return stat(name, ans);
+}
+
+int
+symlink(char *name1, char *name2)
+{
+ errno = EPERM;
+ return -1;
+}
+
+int
+readlink(char *name, char *buf, int size)
+{
+ errno = EIO;
+ return -1;
+}
diff --git a/sys/src/ape/lib/bsd/mkfile b/sys/src/ape/lib/bsd/mkfile
new file mode 100755
index 000000000..44b4b05fb
--- /dev/null
+++ b/sys/src/ape/lib/bsd/mkfile
@@ -0,0 +1,55 @@
+APE=/sys/src/ape
+<$APE/config
+
+LIB=/$objtype/lib/ape/libbsd.a
+OFILES=\
+ accept.$O\
+ bcopy.$O\
+ bind.$O\
+ connect.$O\
+ endhostent.$O\
+ ffs.$O\
+ getdtablesize.$O\
+ gethostbyname.$O\
+ gethostbyaddr.$O\
+ gethostname.$O\
+ getopt.$O\
+ getpeername.$O\
+ getprotobyname.$O\
+ getservbyaddr.$O\
+ getservbyname.$O\
+ getsockname.$O\
+ gettimeofday.$O\
+ inet_addr.$O\
+ inet_ntoa.$O\
+ ioctl.$O\
+ listen.$O\
+ lstat.$O\
+ mktemp.$O\
+ ntohl.$O\
+ nptohl.$O\
+ popen.$O\
+ putenv.$O\
+ rcmd.$O\
+ readv.$O\
+ rresvport.$O\
+ send.$O\
+ sendto.$O\
+ setlinebuf.$O\
+ shutdown.$O\
+ _sock_ingetaddr.$O\
+ _sock_ipattr.$O\
+ _sock_srv.$O\
+ strcasecmp.$O\
+ strncasecmp.$O\
+ socket.$O\
+ socketpair.$O\
+ strdup.$O\
+ pty.$O\
+ writev.$O\
+
+HFILES=priv.h
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_BSD_EXTENSION -D_PLAN9_SOURCE -I../ap/plan9
diff --git a/sys/src/ape/lib/bsd/mktemp.c b/sys/src/ape/lib/bsd/mktemp.c
new file mode 100755
index 000000000..d48714a32
--- /dev/null
+++ b/sys/src/ape/lib/bsd/mktemp.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+char*
+mktemp(char *template)
+{
+ int n;
+ long x;
+ char *p;
+ int c;
+ struct stat stbuf;
+
+ n = strlen(template);
+ p = template+n-6;
+ if (n < 6 || strcmp(p, "XXXXXX") != 0) {
+ *template = 0;
+ } else {
+ x = getpid() % 100000;
+ sprintf(p, "%05d", x);
+ p += 5;
+ for(c = 'a'; c <= 'z'; c++) {
+ *p = c;
+ if (stat(template, &stbuf) < 0)
+ return template;
+ }
+ *template = 0;
+ }
+ return template;
+}
diff --git a/sys/src/ape/lib/bsd/nptohl.c b/sys/src/ape/lib/bsd/nptohl.c
new file mode 100755
index 000000000..c012493e9
--- /dev/null
+++ b/sys/src/ape/lib/bsd/nptohl.c
@@ -0,0 +1,10 @@
+unsigned long
+nptohl(void *p)
+{
+ unsigned char *up;
+ unsigned long x;
+
+ up = p;
+ x = (up[0]<<24)|(up[1]<<16)|(up[2]<<8)|up[3];
+ return x;
+}
diff --git a/sys/src/ape/lib/bsd/ntohl.c b/sys/src/ape/lib/bsd/ntohl.c
new file mode 100755
index 000000000..29c19d6fb
--- /dev/null
+++ b/sys/src/ape/lib/bsd/ntohl.c
@@ -0,0 +1,47 @@
+unsigned long
+ntohl(int x)
+{
+ unsigned long n;
+ unsigned char *p;
+
+ n = x;
+ p = (unsigned char*)&n;
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+}
+
+unsigned long
+htonl(unsigned long h)
+{
+ unsigned long n;
+ unsigned char *p;
+
+ p = (unsigned char*)&n;
+ p[0] = h>>24;
+ p[1] = h>>16;
+ p[2] = h>>8;
+ p[3] = h;
+ return n;
+}
+
+unsigned short
+ntohs(int x)
+{
+ unsigned short n;
+ unsigned char *p;
+
+ n = x;
+ p = (unsigned char*)&n;
+ return (p[0]<<8)|p[1];
+}
+
+unsigned short
+htons(unsigned short h)
+{
+ unsigned short n;
+ unsigned char *p;
+
+ p = (unsigned char*)&n;
+ p[0] = h>>8;
+ p[1] = h;
+ return n;
+}
diff --git a/sys/src/ape/lib/bsd/popen.c b/sys/src/ape/lib/bsd/popen.c
new file mode 100755
index 000000000..32af1de3d
--- /dev/null
+++ b/sys/src/ape/lib/bsd/popen.c
@@ -0,0 +1,84 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#define MAXFORKS 20
+#define NSYSFILE 3
+#define tst(a,b) (*mode == 'r'? (b) : (a))
+#define RDR 0
+#define WTR 1
+
+struct a_fork {
+ short done;
+ short fd;
+ int pid;
+ int status;
+};
+static struct a_fork the_fork[MAXFORKS];
+
+FILE *
+popen(char *cmd, char *mode)
+{
+ int p[2];
+ int myside, hisside, pid;
+ int i, ind;
+
+ for (ind = 0; ind < MAXFORKS; ind++)
+ if (the_fork[ind].pid == 0)
+ break;
+ if (ind == MAXFORKS)
+ return NULL;
+ if(pipe(p) < 0)
+ return NULL;
+ myside = tst(p[WTR], p[RDR]);
+ hisside = tst(p[RDR], p[WTR]);
+ switch (pid = fork()) {
+ case -1:
+ return NULL;
+ case 0:
+ /* myside and hisside reverse roles in child */
+ close(myside);
+ dup2(hisside, tst(0, 1));
+ for (i=NSYSFILE; i<FOPEN_MAX; i++)
+ close(i);
+ execl("/bin/ape/sh", "sh", "-c", cmd, NULL);
+ _exit(1);
+ default:
+ the_fork[ind].pid = pid;
+ the_fork[ind].fd = myside;
+ the_fork[ind].done = 0;
+ close(hisside);
+ return(fdopen(myside, mode));
+ }
+}
+
+int
+pclose(FILE *ptr)
+{
+ int f, r, ind;
+ int status;
+
+ f = fileno(ptr);
+ fclose(ptr);
+ for (ind = 0; ind < MAXFORKS; ind++)
+ if (the_fork[ind].fd == f && the_fork[ind].pid != 0)
+ break;
+ if (ind == MAXFORKS)
+ return 0;
+ if (!the_fork[ind].done) {
+ do {
+ r = wait(&status);
+ for (f = 0; f < MAXFORKS; f++)
+ if (the_fork[f].pid == r) {
+ the_fork[f].done = 1;
+ the_fork[f].status = status;
+ break;
+ }
+ } while(r != the_fork[ind].pid && r != -1);
+ the_fork[ind].status = r == -1 ? -1 : status;
+ }
+ the_fork[ind].pid = 0;
+ return (the_fork[ind].status);
+}
diff --git a/sys/src/ape/lib/bsd/priv.h b/sys/src/ape/lib/bsd/priv.h
new file mode 100755
index 000000000..f99fc5673
--- /dev/null
+++ b/sys/src/ape/lib/bsd/priv.h
@@ -0,0 +1,46 @@
+typedef struct Rock Rock;
+
+enum
+{
+ Ctlsize= 128,
+
+ /* states */
+ Sopen= 0,
+ Sbound,
+ Sconnected,
+
+ /* types of name */
+ Tsys= 0,
+ Tip,
+ Tdom,
+};
+
+/*
+ * since BSD programs expect to perform both control and data functions
+ * through a single fd, we need to hide enough info under a rock to
+ * be able to open the control file when we need it.
+ */
+struct Rock
+{
+ Rock *next;
+ unsigned long dev; /* inode & dev of data file */
+ unsigned long inode; /* ... */
+ int domain; /* from socket call */
+ int stype; /* ... */
+ int protocol; /* ... */
+ struct sockaddr addr; /* address from bind */
+ int reserved; /* use a priveledged port # (< 1024) */
+ struct sockaddr raddr; /* peer address */
+ char ctl[Ctlsize]; /* name of control file (if any) */
+ int other; /* fd of the remote end for Unix domain */
+};
+
+extern Rock* _sock_findrock(int, struct stat*);
+extern Rock* _sock_newrock(int);
+extern void _sock_srvname(char*, char*);
+extern int _sock_srv(char*, int);
+extern int _sock_data(int, char*, int, int, int, Rock**);
+extern int _sock_ipattr(char*);
+extern void _sock_ingetaddr(Rock*, struct sockaddr_in*, int*, char*);
+
+extern void _syserrno(void);
diff --git a/sys/src/ape/lib/bsd/pty.c b/sys/src/ape/lib/bsd/pty.c
new file mode 100755
index 000000000..3189d24e1
--- /dev/null
+++ b/sys/src/ape/lib/bsd/pty.c
@@ -0,0 +1,111 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sys/pty.h>
+#include "lib.h"
+#include "sys9.h"
+#include "dir.h"
+
+/*
+ * return the name of the slave
+ */
+char*
+ptsname(int fd)
+{
+ Dir *d;
+ static char buf[32];
+
+ if((d = _dirfstat(fd)) == nil || strlen(d->name) < 4){
+ free(d);
+ _syserrno();
+ return 0;
+ }
+ snprintf(buf, sizeof buf, "/dev/ptty%d", atoi(d->name+4));
+ free(d);
+ return buf;
+}
+
+/*
+ * return the name of the master
+ */
+char*
+ptmname(int fd)
+{
+ Dir *d;
+ static char buf[32];
+
+ if((d = _dirfstat(fd)) == nil || strlen(d->name) < 4){
+ free(d);
+ _syserrno();
+ return 0;
+ }
+
+ snprintf(buf, sizeof buf, "/dev/ttym%d", atoi(d->name+4));
+ return buf;
+}
+
+static char ptycl[] = "/dev/ptyclone";
+static char fssrv[] = "/srv/ptyfs";
+
+static void
+mkserver(void)
+{
+ int fd, i;
+ char *argv[3];
+
+ fd = _OPEN(fssrv, O_RDWR);
+ if(_MOUNT(fd, -1, "/dev", MAFTER, "") < 0) {
+ /*
+ * remove fssrv here, if it exists, to avoid a race
+ * between the loop in the default case below and the
+ * new ptyfs removing fssrv when it starts.
+ * we otherwise might be unlucky enough to open the old
+ * (hung channel) fssrv before ptyfs removes it and break
+ * out of the loop with an open fd to a hung channel?
+ */
+ _CLOSE(fd);
+ _REMOVE(fssrv);
+ switch(_RFORK(RFPROC|RFFDG)) {
+ case -1:
+ return;
+ case 0:
+ argv[0] = "ptyfs";
+ argv[1] = 0;
+ _EXEC("/bin/ape/ptyfs", argv);
+ _EXITS(0);
+ default:
+ for(i = 0; i < 3; i++) {
+ fd = _OPEN(fssrv, O_RDWR);
+ if(fd >= 0)
+ break;
+ _SLEEP(1000);
+ }
+ }
+ if(fd < 0)
+ return;
+ if(_MOUNT(fd, -1, "/dev", MAFTER, "") < 0)
+ _CLOSE(fd);
+ }
+ /* successful _MOUNT closes fd */
+}
+
+/*
+ * allocate a new pty
+ */
+int
+_getpty(void)
+{
+ struct stat sb;
+
+ if(stat(ptycl, &sb) < 0)
+ mkserver();
+
+ return open(ptycl, O_RDWR);
+}
diff --git a/sys/src/ape/lib/bsd/putenv.c b/sys/src/ape/lib/bsd/putenv.c
new file mode 100755
index 000000000..63695ba76
--- /dev/null
+++ b/sys/src/ape/lib/bsd/putenv.c
@@ -0,0 +1,32 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+int
+putenv(char *s)
+{
+ int f, n;
+ char *value;
+ char buf[300];
+
+ value = strchr(s, '=');
+ if (value) {
+ n = value-s;
+ if(n<=0 || n > sizeof(buf)-6)
+ return -1;
+ strcpy(buf, "/env/");
+ strncpy(buf+5, s, n);
+ buf[n+5] = 0;
+ f = creat(buf, 0666);
+ if(f < 0)
+ return 1;
+ value++;
+ n = strlen(value);
+ if(write(f, value, n) != n)
+ return -1;
+ close(f);
+ return 0;
+ } else
+ return -1;
+}
diff --git a/sys/src/ape/lib/bsd/rcmd.c b/sys/src/ape/lib/bsd/rcmd.c
new file mode 100755
index 000000000..bac11735f
--- /dev/null
+++ b/sys/src/ape/lib/bsd/rcmd.c
@@ -0,0 +1,138 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+/* socket extensions */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#include "priv.h"
+
+static char pbotch[] = "rcmd: protocol botch\n";
+static char lbotch[] = "rcmd: botch starting error stream\n";
+
+static void
+ding(int x)
+{
+}
+
+int
+rcmd(char **dst, int port, char *luser, char *ruser, char *cmd, int *fd2p)
+{
+ char c;
+ int i, fd, lfd, fd2, port2;
+ struct hostent *h;
+ Rock *r;
+ struct sockaddr_in in;
+ char buf[128];
+ void (*x)(int);
+
+ h = gethostbyname(*dst);
+ if(h == 0)
+ return -1;
+ *dst = h->h_name;
+
+ /* connect using a reserved tcp port */
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if(fd < 0)
+ return -1;
+ r = _sock_findrock(fd, 0);
+ if(r == 0){
+ errno = ENOTSOCK;
+ return -1;
+ }
+ r->reserved = 1;
+ in.sin_family = AF_INET;
+ in.sin_port = htons(port);
+ memmove(&in.sin_addr, h->h_addr_list[0], sizeof(in.sin_addr));
+ if(connect(fd, &in, sizeof(in)) < 0){
+ close(fd);
+ return -1;
+ }
+
+ /* error stream */
+ if(fd2p){
+ /* create an error stream and wait for a call in */
+ for(i = 0; i < 10; i++){
+ lfd = rresvport(&port2);
+ if(lfd < 0)
+ continue;
+ if(listen(lfd, 1) == 0)
+ break;
+ close(lfd);
+ }
+ if(i >= 10){
+ fprintf(stderr, pbotch);
+ return -1;
+ }
+
+ snprintf(buf, sizeof buf, "%d", port2);
+ if(write(fd, buf, strlen(buf)+1) < 0){
+ close(fd);
+ close(lfd);
+ fprintf(stderr, lbotch);
+ return -1;
+ }
+ } else {
+ if(write(fd, "", 1) < 0){
+ fprintf(stderr, pbotch);
+ return -1;
+ }
+ }
+
+ /* pass id's and command */
+ if(write(fd, luser, strlen(luser)+1) < 0
+ || write(fd, ruser, strlen(ruser)+1) < 0
+ || write(fd, cmd, strlen(cmd)+1) < 0){
+ if(fd2p)
+ close(fd2);
+ fprintf(stderr, pbotch);
+ return -1;
+ }
+
+ if(fd2p){
+ x = signal(SIGALRM, ding);
+ alarm(15);
+ fd2 = accept(lfd, &in, &i);
+ alarm(0);
+ close(lfd);
+ signal(SIGALRM, x);
+
+ if(fd2 < 0){
+ close(fd);
+ close(lfd);
+ fprintf(stderr, lbotch);
+ return -1;
+ }
+ *fd2p = fd2;
+ }
+
+ /* get reply */
+ if(read(fd, &c, 1) != 1){
+ if(fd2p)
+ close(fd2);
+ fprintf(stderr, pbotch);
+ return -1;
+ }
+ if(c == 0)
+ return fd;
+ i = 0;
+ while(c){
+ buf[i++] = c;
+ if(read(fd, &c, 1) != 1)
+ break;
+ if(i >= sizeof(buf)-1)
+ break;
+ }
+ buf[i] = 0;
+ fprintf(stderr, "rcmd: %s\n", buf);
+ close(fd);
+ return -1;
+}
diff --git a/sys/src/ape/lib/bsd/readv.c b/sys/src/ape/lib/bsd/readv.c
new file mode 100755
index 000000000..91a7157d0
--- /dev/null
+++ b/sys/src/ape/lib/bsd/readv.c
@@ -0,0 +1,30 @@
+#include <unistd.h>
+#include <string.h>
+#include <sys/uio.h>
+
+int
+readv(int fd, struct iovec *v, int ent)
+{
+ int x, i, n, len;
+ char *t;
+ char buf[10*1024];
+
+ for(len = i = 0; i < ent; i++)
+ len += v[i].iov_len;
+ if(len > sizeof(buf))
+ len = sizeof(buf);
+
+ len = read(fd, buf, len);
+ if(len <= 0)
+ return len;
+
+ for(n = i = 0; n < len && i < ent; i++){
+ x = len - n;
+ if(x > v[i].iov_len)
+ x = v[i].iov_len;
+ memmove(v[i].iov_base, buf + n, x);
+ n += x;
+ }
+
+ return len;
+}
diff --git a/sys/src/ape/lib/bsd/rresvport.c b/sys/src/ape/lib/bsd/rresvport.c
new file mode 100755
index 000000000..6df09c87d
--- /dev/null
+++ b/sys/src/ape/lib/bsd/rresvport.c
@@ -0,0 +1,37 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+/* socket extensions */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+int
+rresvport(int *p)
+{
+ int fd;
+ short i;
+ struct sockaddr_in in;
+ static int next;
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if(fd < 0)
+ return -1;
+ i = 600 + ((getpid()+next++)%(1024-600));
+ memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ in.sin_port = htons(i);
+printf("in.sin_port = %d\n", in.sin_port);
+ if(bind(fd, &in, sizeof(in)) < 0){
+ close(fd);
+ return -1;
+ }
+ if(p)
+ *p = i;
+ return fd;
+}
diff --git a/sys/src/ape/lib/bsd/send.c b/sys/src/ape/lib/bsd/send.c
new file mode 100755
index 000000000..e46346a03
--- /dev/null
+++ b/sys/src/ape/lib/bsd/send.c
@@ -0,0 +1,31 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "priv.h"
+
+int
+send(int fd, char *a, int n, int flags)
+{
+ if(flags & MSG_OOB){
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+ return write(fd, a, n);
+}
+
+int
+recv(int fd, char *a, int n, int flags)
+{
+ if(flags & MSG_OOB){
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+ return read(fd, a, n);
+}
diff --git a/sys/src/ape/lib/bsd/sendto.c b/sys/src/ape/lib/bsd/sendto.c
new file mode 100755
index 000000000..0ab450471
--- /dev/null
+++ b/sys/src/ape/lib/bsd/sendto.c
@@ -0,0 +1,28 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "priv.h"
+
+int
+sendto(int fd, void *a, int n, int flags,
+ void *to, int tolen)
+{
+ /* actually, should do connect if not done already */
+ return send(fd, a, n, flags);
+}
+
+int
+recvfrom(int fd, void *a, int n, int flags,
+ void *from, int *fromlen)
+{
+ if(getsockname(fd, from, fromlen) < 0)
+ return -1;
+ return recv(fd, a, n, flags);
+}
diff --git a/sys/src/ape/lib/bsd/sethostent.c b/sys/src/ape/lib/bsd/sethostent.c
new file mode 100755
index 000000000..73867c96b
--- /dev/null
+++ b/sys/src/ape/lib/bsd/sethostent.c
@@ -0,0 +1,5 @@
+int
+sethostent(int)
+{
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/setlinebuf.c b/sys/src/ape/lib/bsd/setlinebuf.c
new file mode 100755
index 000000000..acc907e8d
--- /dev/null
+++ b/sys/src/ape/lib/bsd/setlinebuf.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+void
+setlinebuf(FILE *f)
+{
+ static char buf[BUFSIZ];
+
+ setvbuf (f, buf, _IOLBF, BUFSIZ);
+}
diff --git a/sys/src/ape/lib/bsd/shutdown.c b/sys/src/ape/lib/bsd/shutdown.c
new file mode 100755
index 000000000..dcb15a847
--- /dev/null
+++ b/sys/src/ape/lib/bsd/shutdown.c
@@ -0,0 +1,11 @@
+#include <sys/types.h>
+#include <unistd.h>
+
+int
+shutdown(int fd, int how)
+{
+ if(how == 2)
+ close(fd);
+
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/socket.c b/sys/src/ape/lib/bsd/socket.c
new file mode 100755
index 000000000..6623936b8
--- /dev/null
+++ b/sys/src/ape/lib/bsd/socket.c
@@ -0,0 +1,175 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "priv.h"
+
+Rock *_sock_rock;
+
+Rock*
+_sock_findrock(int fd, struct stat *dp)
+{
+ Rock *r;
+ struct stat d;
+
+ if(dp == 0)
+ dp = &d;
+ fstat(fd, dp);
+ for(r = _sock_rock; r; r = r->next){
+ if(r->inode == dp->st_ino
+ && r->dev == dp->st_dev)
+ break;
+ }
+ return r;
+}
+
+Rock*
+_sock_newrock(int fd)
+{
+ Rock *r;
+ struct stat d;
+
+ r = _sock_findrock(fd, &d);
+ if(r == 0){
+ r = malloc(sizeof(Rock));
+ if(r == 0)
+ return 0;
+ r->dev = d.st_dev;
+ r->inode = d.st_ino;
+ r->other = -1;
+ r->next = _sock_rock;
+ _sock_rock = r;
+ }
+ memset(&r->raddr, 0, sizeof(r->raddr));
+ memset(&r->addr, 0, sizeof(r->addr));
+ r->reserved = 0;
+ r->dev = d.st_dev;
+ r->inode = d.st_ino;
+ r->other = -1;
+ return r;
+}
+
+int
+_sock_data(int cfd, char *net, int domain, int stype, int protocol, Rock **rp)
+{
+ int n, fd;
+ Rock *r;
+ char name[Ctlsize];
+
+ /* get the data file name */
+ n = read(cfd, name, sizeof(name)-1);
+ if(n < 0){
+ close(cfd);
+ errno = ENOBUFS;
+ return -1;
+ }
+ name[n] = 0;
+ n = strtoul(name, 0, 0);
+ snprintf(name, sizeof name, "/net/%s/%d/data", net, n);
+
+ /* open data file */
+ fd = open(name, O_RDWR);
+ close(cfd);
+ if(fd < 0){
+ close(cfd);
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ /* hide stuff under the rock */
+ snprintf(name, sizeof name, "/net/%s/%d/ctl", net, n);
+ r = _sock_newrock(fd);
+ if(r == 0){
+ errno = ENOBUFS;
+ close(fd);
+ return -1;
+ }
+ if(rp)
+ *rp = r;
+ memset(&r->raddr, 0, sizeof(r->raddr));
+ memset(&r->addr, 0, sizeof(r->addr));
+ r->domain = domain;
+ r->stype = stype;
+ r->protocol = protocol;
+ strcpy(r->ctl, name);
+ return fd;
+}
+
+int
+socket(int domain, int stype, int protocol)
+{
+ Rock *r;
+ int cfd, fd, n;
+ int pfd[2];
+ char *net;
+
+ switch(domain){
+ case PF_INET:
+ /* get a free network directory */
+ switch(stype){
+ case SOCK_DGRAM:
+ net = "udp";
+ cfd = open("/net/udp/clone", O_RDWR);
+ break;
+ case SOCK_STREAM:
+ net = "tcp";
+ cfd = open("/net/tcp/clone", O_RDWR);
+ break;
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+ if(cfd < 0){
+ _syserrno();
+ return -1;
+ }
+ return _sock_data(cfd, net, domain, stype, protocol, 0);
+ case PF_UNIX:
+ if(pipe(pfd) < 0){
+ _syserrno();
+ return -1;
+ }
+ r = _sock_newrock(pfd[0]);
+ r->domain = domain;
+ r->stype = stype;
+ r->protocol = protocol;
+ r->other = pfd[1];
+ return pfd[0];
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+}
+
+int
+issocket(int fd)
+{
+ Rock *r;
+
+ r = _sock_findrock(fd, 0);
+ return (r != 0);
+}
+
+/*
+ * probably should do better than this
+ */
+int getsockopt(int, int, int, void *, int *)
+{
+ return -1;
+}
+
+int setsockopt(int, int, int, void *, int)
+{
+ return 0;
+}
+
diff --git a/sys/src/ape/lib/bsd/socketpair.c b/sys/src/ape/lib/bsd/socketpair.c
new file mode 100755
index 000000000..990c3f77f
--- /dev/null
+++ b/sys/src/ape/lib/bsd/socketpair.c
@@ -0,0 +1,21 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+int
+socketpair(int domain, int type, int protocol, int *sv)
+{
+ switch(domain){
+ case PF_UNIX:
+ return pipe(sv);
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+}
diff --git a/sys/src/ape/lib/bsd/strcasecmp.c b/sys/src/ape/lib/bsd/strcasecmp.c
new file mode 100755
index 000000000..7fb8c8a80
--- /dev/null
+++ b/sys/src/ape/lib/bsd/strcasecmp.c
@@ -0,0 +1,28 @@
+#include <string.h>
+
+typedef unsigned char uchar;
+
+
+int
+strcasecmp(char *s1, char *s2)
+{
+ int c1, c2;
+
+ while(*s1){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ return -*s2;
+}
diff --git a/sys/src/ape/lib/bsd/strdup.c b/sys/src/ape/lib/bsd/strdup.c
new file mode 100755
index 000000000..5e4a3759e
--- /dev/null
+++ b/sys/src/ape/lib/bsd/strdup.c
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+char*
+strdup(char *p)
+{
+ int n;
+ char *np;
+
+ n = strlen(p)+1;
+ np = malloc(n);
+ if(np)
+ memmove(np, p, n);
+ return np;
+}
diff --git a/sys/src/ape/lib/bsd/strncasecmp.c b/sys/src/ape/lib/bsd/strncasecmp.c
new file mode 100755
index 000000000..a9ddc8dee
--- /dev/null
+++ b/sys/src/ape/lib/bsd/strncasecmp.c
@@ -0,0 +1,29 @@
+#include <string.h>
+
+typedef unsigned char uchar;
+
+int
+strncasecmp(char *s1, char *s2, int n)
+{
+ int c1, c2;
+
+ while(*s1 && n-- > 0){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ if(n <= 0)
+ return 0;
+ return -*s2;
+}
diff --git a/sys/src/ape/lib/bsd/writev.c b/sys/src/ape/lib/bsd/writev.c
new file mode 100755
index 000000000..fbb36b692
--- /dev/null
+++ b/sys/src/ape/lib/bsd/writev.c
@@ -0,0 +1,62 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "priv.h"
+
+int
+writev(int fd, struct iovec *v, int ent)
+{
+ int i, n, written;
+ char *t, *e, *f;
+ char buf[10*1024];
+
+ written = n = 0;
+ t = buf;
+ e = buf+sizeof(buf);
+ for(;ent ; v++, ent--){
+ n = v->iov_len;
+ f = v->iov_base;
+ while(n > 0){
+ i = e-t;
+ if(n < i){
+ memmove(t, f, n);
+ t += n;
+ break;
+ }
+ memmove(t, f, i);
+ n -= i;
+ f += i;
+ i = write(fd, buf, sizeof(buf));
+ if(i < 0){
+ if(written > 0){
+ return written;
+ }else{
+ _syserrno();
+ return -1;
+ }
+ }
+ written += i;
+ if(i != sizeof(buf)) {
+ return written;
+ }
+ t = buf;
+ }
+ }
+ i = t - buf;
+ if(i > 0){
+ n = write(fd, buf, i);
+ if(n < 0){
+ if(written == 0){
+ _syserrno();
+ return -1;
+ }
+ } else
+ written += n;
+ }
+ return written;
+}