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; }
int tcsetattr(int fd, int optactions, const struct termios *t) { int n, i; char buf[100]; if(!isptty(fd)) { if(!isatty(fd)) { errno = ENOTTY; return -1; } else return 0; } n = sprintf(buf, "IOW %4.4x %4.4x %4.4x %4.4x ", t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag); for(i = 0; i < NCCS; i++) n += sprintf(buf+n, "%2.2x ", t->c_cc[i]); if(_SEEK(fd, -2, 0) != -2) { _syserrno(); return -1; } n = _WRITE(fd, buf, n); if(n < 0) { _syserrno(); return -1; } return 0; }
int tcsetpgrp(int fd, pid_t pgrpid) { int n; char buf[30]; if(!isptty(fd)) { if(!isatty(fd)) { errno = ENOTTY; return -1; } else return 0; } n = sprintf(buf, "IOW note %d", pgrpid); if(_SEEK(fd, -2, 0) != -2) { _syserrno(); return -1; } n = _WRITE(fd, buf, n); if(n < 0) { _syserrno(); return -1; } }
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; }
int tcgetattr(int fd, struct termios *t) { int n; char buf[60]; if(!isptty(fd)) { if(isatty(fd)) { /* If there is no emulation return sensible defaults */ t->c_iflag = ISTRIP|ICRNL|IXON|IXOFF; t->c_oflag = OPOST|TAB3|ONLCR; t->c_cflag = B9600; t->c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; t->c_cc[VINTR] = CINTR; t->c_cc[VQUIT] = CQUIT; t->c_cc[VERASE] = CERASE; t->c_cc[VKILL] = CKILL; t->c_cc[VEOF] = CEOF; t->c_cc[VEOL] = CEOL; t->c_cc[VSTART] = CSTART; t->c_cc[VSTOP] = CSTOP; return 0; } else { errno = ENOTTY; return -1; } } if(_SEEK(fd, -2, 0) != -2) { _syserrno(); return -1; } n = _READ(fd, buf, 57); if(n < 0) { _syserrno(); return -1; } t->c_iflag = strtoul(buf+4, 0, 16); t->c_oflag = strtoul(buf+9, 0, 16); t->c_cflag = strtoul(buf+14, 0, 16); t->c_lflag = strtoul(buf+19, 0, 16); for(n = 0; n < NCCS; n++) t->c_cc[n] = strtoul(buf+24+(n*3), 0, 16); return 0; }
int chown(const char *path, uid_t owner, gid_t group) { int num; Dir d; _nulldir(&d); /* find owner, group */ d.uid = nil; num = owner; if(!_getpw(&num, &d.uid, 0)) { errno = EINVAL; return -1; } d.gid = nil; num = group; if(!_getpw(&num, &d.gid, 0)) { errno = EINVAL; return -1; } if(_dirwstat(path, &d) < 0){ _syserrno(); return -1; } return 0; }
int close(int d) { int n; Fdinfo *f; n = -1; f = &_fdinfo[d]; if(d<0 || d>=OPEN_MAX || !(f->flags&FD_ISOPEN)) errno = EBADF; else{ if(f->flags&(FD_BUFFERED|FD_BUFFEREDX)) { if(f->flags&FD_BUFFERED) _closebuf(d); f->flags &= ~FD_BUFFERED; } n = _CLOSE(d); if(n < 0) _syserrno(); _fdinfo[d].flags = 0; _fdinfo[d].oflags = 0; if(_fdinfo[d].name){ free(_fdinfo[d].name); _fdinfo[d].name = 0; } } return n; }
int pipe(int fildes[2]) { Fdinfo *fi; int i; if(!fildes){ errno = EFAULT; return -1; } if(_PIPE(fildes) < 0) _syserrno(); else if(fildes[0] < 0 || fildes[0]>=OPEN_MAX || fildes[1] < 0 || fildes[1]>=OPEN_MAX) { errno = EMFILE; return -1; } for(i = 0; i <=1; i++) { fi = &_fdinfo[fildes[i]]; fi->flags = FD_ISOPEN; fi->oflags = O_RDWR; fi->uid = 0; /* none */ fi->gid = 0; } return 0; }
int socket(int domain, int stype, int protocol) { Rock *r; int cfd; 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 chdir(const char *f) { int n; n = _CHDIR(f); if(n < 0) _syserrno(); return n; }
pid_t setsid(void) { if(_RFORK(RFNAMEG|RFNOTEG) < 0){ _syserrno(); return -1; } _sessleader = 1; return getpgrp(); }
int fstat(int fd, struct stat *buf) { Dir *d; if((d = _dirfstat(fd)) == nil){ _syserrno(); return -1; } _dirtostat(buf, d, &_fdinfo[fd]); free(d); return 0; }
pid_t fork(void) { int n; n = _RFORK(RFENVG|RFFDG|RFPROC); if(n < 0) _syserrno(); if(n == 0) { _detachbuf(); _sessleader = 0; } return n; }
pid_t tcgetpgrp(int fd) { int n; pid_t pgrp; char buf[100]; if(!isptty(fd)) { errno = ENOTTY; return -1; } if(_SEEK(fd, -2, 0) != -2) { _syserrno(); return -1; } n = _READ(fd, buf, sizeof(buf)); if(n < 0) { _syserrno(); return -1; } pgrp = atoi(buf+24+(NCCS*3)); return pgrp; }
pid_t getpid(void) { int n, f; char pidbuf[15]; f = __sys_open("#c/pid", 0); n = __sys_read(f, pidbuf, sizeof pidbuf); if(n < 0) _syserrno(); else n = atoi(pidbuf); __sys_close(f); return n; }
ssize_t write(int d, const void *buf, size_t nbytes) { int n; if(d<0 || d>=OPEN_MAX || !(_fdinfo[d].flags&FD_ISOPEN)){ errno = EBADF; return -1; } if(_fdinfo[d].oflags&O_APPEND) _SEEK(d, 0, 2); n = _WRITE(d, buf, nbytes); if(n < 0) _syserrno(); return n; }
/* * BUG: errno mapping */ off_t lseek(int d, off_t offset, int whence) { long long n; int flags; flags = _fdinfo[d].flags; if(flags&(FD_BUFFERED|FD_BUFFEREDX|FD_ISTTY)) { errno = ESPIPE; return -1; } n = _SEEK(d, offset, whence); if(n < 0) _syserrno(); return n; }
pid_t getpgrp(void) { int n, f, pid; char pgrpbuf[15], fname[30]; pid = getpid(); sprintf(fname, "/proc/%d/noteid", pid); f = open(fname, 0); n = read(f, pgrpbuf, sizeof pgrpbuf); if(n < 0) _syserrno(); else n = atoi(pgrpbuf); close(f); return n; }
int utime(const char *path, const struct utimbuf *times) { int n; Dir nd; time_t curt; _nulldir(&nd); if(times == 0) { curt = time(0); nd.atime = curt; nd.mtime = curt; } else { nd.atime = times->actime; nd.mtime = times->modtime; } n = _dirwstat(path, &nd); if(n < 0) _syserrno(); return n; }
ssize_t read(int d, void *buf, size_t nbytes) { int n, noblock, isbuf; Fdinfo *f; if(d<0 || d>=OPEN_MAX || !(_fdinfo[d].flags&FD_ISOPEN)){ errno = EBADF; return -1; } if(nbytes <= 0) return 0; if(buf == 0){ errno = EFAULT; return -1; } f = &_fdinfo[d]; noblock = f->oflags&O_NONBLOCK; isbuf = f->flags&(FD_BUFFERED|FD_BUFFEREDX); if(noblock || isbuf){ if(f->flags&FD_BUFFEREDX) { errno = EIO; return -1; } if(!isbuf) { if(_startbuf(d) != 0) { errno = EIO; return -1; } } n = _readbuf(d, buf, nbytes, noblock); }else{ n = _READ(d, buf, nbytes); if(n < 0) _syserrno(); } return n; }
int __close(int d) { int n; Fdinfo *f; n = -1; f = &_fdinfo[d]; if(d<0 || d>=OPEN_MAX || !(f->flags&FD_ISOPEN)) errno = EBADF; else{ n = __sys_close(d); if(n < 0) _syserrno(); _fdinfo[d].flags = 0; _fdinfo[d].oflags = 0; if(_fdinfo[d].name){ free(_fdinfo[d].name); _fdinfo[d].name = 0; } } return n; }
static int seterrno(void) { _syserrno(); return -1; }
/* * for inet addresses only */ struct hostent* gethostbyname(const 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++; } }
int rename(const char *from, const char *to) { int n; char *f, *t; Dir *d, nd; if(access(to, 0) >= 0){ if(_REMOVE(to) < 0){ _syserrno(); return -1; } } if((d = _dirstat(to)) != nil){ free(d); errno = EEXIST; return -1; } if((d = _dirstat(from)) == nil){ _syserrno(); return -1; } f = strrchr(from, '/'); t = strrchr(to, '/'); f = f? f+1 : (char *)from; t = t? t+1 : (char *)to; n = 0; if(f-from==t-to && strncmp(from, to, f-from)==0){ /* from and to are in same directory (we miss some cases) */ _nulldir(&nd); nd.name = t; if(_dirwstat(from, &nd) < 0){ _syserrno(); n = -1; } }else{ /* different directories: have to copy */ int ffd, tfd; char buf[8192]; tfd = -1; if((ffd = _OPEN(from, 0)) < 0 || (tfd = _CREATE(to, 1, d->mode)) < 0){ _CLOSE(ffd); _syserrno(); n = -1; } while(n>=0 && (n = _READ(ffd, buf, 8192)) > 0) if(_WRITE(tfd, buf, n) != n){ _syserrno(); n = -1; } _CLOSE(ffd); _CLOSE(tfd); if(n>0) n = 0; if(n == 0) { if(_REMOVE(from) < 0){ _syserrno(); return -1; } } } free(d); return n; }
int execve(const char *name, const char *argv[], const char *envp[]) { int n, f, i; char **e, *ss, *se; Fdinfo *fi; unsigned long flags; char nam[256+5]; char buf[1000]; _RFORK(RFCENVG); /* * To pass _fdinfo[] across exec, put lines like * fd flags oflags * in $_fdinfo (for open fd's) */ f = _CREATE("#e/_fdinfo", OWRITE, 0666); ss = buf; for(n = 0; n<OPEN_MAX; n++){ fi = &_fdinfo[n]; flags = fi->flags; if(flags&FD_CLOEXEC){ _CLOSE(n); fi->flags = 0; fi->oflags = 0; }else if(flags&FD_ISOPEN){ ss = _ultoa(ss, n); *ss++ = ' '; ss = _ultoa(ss, flags); *ss++ = ' '; ss = _ultoa(ss, fi->oflags); *ss++ = '\n'; if(ss-buf < sizeof(buf)-50){ _WRITE(f, buf, ss-buf); ss = buf; } } } if(ss > buf) _WRITE(f, buf, ss-buf); _CLOSE(f); /* * To pass _sighdlr[] across exec, set $_sighdlr * to list of blank separated fd's that have * SIG_IGN (the rest will be SIG_DFL). * We write the variable, even if no signals * are ignored, in case the current value of the * variable ignored some. */ f = _CREATE("#e/_sighdlr", OWRITE, 0666); if(f >= 0){ ss = buf; for(i = 0; i <=MAXSIG && ss < &buf[sizeof(buf)]-5; i++) { if(_sighdlr[i] == SIG_IGN) { ss = _ultoa(ss, i); *ss++ = ' '; } } _WRITE(f, buf, ss-buf); _CLOSE(f); } if(envp){ strcpy(nam, "#e/"); for(e = (char **)envp; (ss = *e); e++) { se = strchr(ss, '='); if(!se || ss==se) continue; /* what is name? value? */ n = se-ss; if(n >= sizeof(nam)-3) n = sizeof(nam)-3-1; memcpy(nam+3, ss, n); nam[3+n] = 0; f = _CREATE(nam, OWRITE, 0666); if(f < 0) continue; se++; /* past = */ n = strlen(se); /* temporarily decode nulls (see _envsetup()) */ for(i=0; i < n; i++) if(se[i] == 1) se[i] = 0; _WRITE(f, se, n); /* put nulls back */ for(i=0; i < n; i++) if(se[i] == 0) se[i] = 1; _CLOSE(f); } } n = _EXEC(name, argv); _syserrno(); return n; }
/* * for inet addresses only */ struct servent* getservbyname(const char *name, const char *proto) { int i, fd, m, num; const char *p; char *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; not sure */ if(strcmp(bp, proto) == 0){ if(nn < Nname) nptr[nn++] = (char *)p; } else if(strcmp(bp, "port") == 0){ s.s_port = htons(atoi(p)); } while(*p && *p != ' ') p++; /* if(*p) *p++ = 0; realy I can't understand this */ bp = (char *)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; }
int listen(int fd, int i) { 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(1 || lip->sin_port >= 0) { /* sin_port is unsigned */ 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; } }
int fcntl(int fd, int cmd, ...) { int arg, i, ans, err; Fdinfo *fi, *fans; va_list va; unsigned long oflags; err = 0; ans = 0; va_start(va, cmd); arg = va_arg(va, int); va_end(va); fi = &_fdinfo[fd]; if(fd<0 || fd>=OPEN_MAX || !(fi->flags&FD_ISOPEN)) err = EBADF; else switch(cmd){ case F_DUPFD: if(fi->flags&(FD_BUFFERED|FD_BUFFEREDX)){ err = EGREG; /* dup of buffered fd not implemented */ break; } oflags = fi->oflags; for(i = (arg>0)? arg : 0; i<OPEN_MAX; i++) if(!(_fdinfo[i].flags&FD_ISOPEN)) break; if(i == OPEN_MAX) err = EMFILE; else { ans = _DUP(fd, i); if(ans != i){ if(ans < 0){ _syserrno(); err = errno; }else err = EBADF; }else{ fans = &_fdinfo[ans]; fans->flags = fi->flags&~FD_CLOEXEC; fans->oflags = oflags; fans->uid = fi->uid; fans->gid = fi->gid; } } break; case F_GETFD: ans = fi->flags&FD_CLOEXEC; break; case F_SETFD: fi->flags = (fi->flags&~FD_CLOEXEC)|(arg&FD_CLOEXEC); break; case F_GETFL: ans = fi->oflags&OFL; break; case F_SETFL: fi->oflags = (fi->oflags&~OFL)|(arg&OFL); break; case F_GETLK: case F_SETLK: case F_SETLKW: err = EINVAL; break; } if(err){ errno = err; ans = -1; } return ans; }
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 *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; default: net = "gok"; 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; } }
struct protoent *getprotobyname(const char *name) { int fd, i, m; char *p, *bp; int nn, na; static char buf[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; }