#include "inc/priv.h" #include #include "inc/nan.h" #include "inc/process.h" #include "inc/time.h" #include "lsd.h" u64int sec_realtime(void) { return nsec(); } void * sl_segalloc(usize sz) { return segattach(SG_CEXEC, "memory", nil, sz); } void sl_segfree(void *s, usize sz) { USED(sz); if(s != nil) segdetach(s); } void sl_segused(void *s, usize sz, usize used) { USED(s); USED(sz); USED(used); } /* * nsec() is wallclock and can be adjusted by timesync * so need to use cycles() instead, but fall back to * nsec() in case we can't */ u64int nanosec_monotonic(void) { static u64int fasthz, xstart; u64int x; if(fasthz == ~0ULL) return nsec() - xstart; if(fasthz == 0){ if(_tos->cyclefreq){ fasthz = _tos->cyclefreq; cycles(&xstart); }else{ fasthz = ~0ULL; xstart = nsec(); } return 0; } cycles(&x); x -= xstart; u64int q = x / fasthz; u64int r = x % fasthz; return q*Nsec + r*Nsec/fasthz; } void timestr(u64int ns, char *buf, int sz) { Tm tm; snprint(buf, sz, "%τ", tmfmt(tmtime(&tm, ns/Nsec, tzload("local")), nil)); } u64int parsetime(const char *s) { Tm tm; if(tmparse(&tm, "?WWW, ?MM ?DD hh:mm:ss ?Z YYYY", s, tzload("local"), nil) == nil) return -1; return tmnorm(&tm)*Nsec; } void sleep_ms(int ms) { if(ms != 0) sleep(ms); } int ftruncate(int f, soffset sz) { Dir d; nulldir(&d); d.length = sz; return dirfwstat(f, &d) > 0 ? 0 : -1; } int unsetenv(const char *name) { char ename[100]; if(*name == 0 || strchr(name, '/') != nil || strcmp(name, ".") == 0 || strcmp(name, "..") == 0 || strlen(name) >= sizeof(ename)-5){ werrstr("bad env name: %s", name); return -1; } snprint(ename, sizeof(ename), "/env/%s", name); if(access(ename, AEXIST) == 0) return remove(ename); return 0; } void sys_setcurrpc(int dummy) { USED(dummy); sys_setcallpc(dummy); } void sys_seed(void *p, int sz) { u8int *o = p; int f; if((f = open("/dev/random", OREAD)) >= 0){ while(sz > 0){ int n = read(f, o, sz); if(n < 0) break; o += n; sz -= n; } close(f); } // otherwise TOO BAD } int sys_read(int fd, u8int *buf, usize n, usize *nread) { ssize r; while(1){ r = read(fd, buf, n); if(r > -1){ *nread = (usize)r; break; } return r; } return 0; } int sys_write(int fd, const void *buf, usize n, usize *nwritten) { ssize r = write(fd, buf, n); if(r < 0) return -1; *nwritten = (usize)r; return 0; } int sys_open(const char *fname, ios_flags flags, usize mode) { int of = (flags & IOS_WRITE) ? ((flags & IOS_READ) ? ORDWR : OWRITE) : OREAD; if(flags & IOS_TRUNC) of |= OTRUNC; if(flags & IOS_EXCL) of |= OEXCL; of |= OCEXEC; if(flags & IOS_APPEND) mode |= DMAPPEND; return (flags & IOS_CREATE) ? create(fname, of, mode) : open(fname, of); } int sys_rename(const char *old, const char *new) { Dir d; nulldir(&d); d.name = (char*)new; return dirwstat(old, &d) > 0 ? 0 : -1; } soffset sys_seek(int fd, soffset offset, int whence) { return seek(fd, offset, whence); } int sys_close(int fd) { return close(fd); } int sys_dup(int oldfd, int newfd) { return dup(oldfd, newfd); } void sys_fd_setup(int fd) { USED(fd); } int sys_exec(const char *path, char *const argv[], char *env[]) { if(env != nil){ for(int i = 0; env[i] != nil; i++){ char *v = strchr(env[i], '='); if(v == nil) abort(); *v++ = 0; if(putenv(env[i], v) != 0) return -1; } } return exec(path, argv); } int sys_fork(fork_flags flags) { int rf = RFFDG|RFREND|RFPROC; if(flags & FORK_CLEAR_ENV) rf |= RFCENVG; return rfork(rf); } char * sys_getcwd(void) { char tmp[4096]; if(getwd(tmp, sizeof(tmp)) != nil) return MEM_STRDUP(tmp); return nil; } int sys_chdir(int fd, const char *dir) { USED(fd); return chdir(dir); } int sys_pipe(int fd[2], bool rd, bool wr) { if(pipe(fd) != 0) return -1; if(!rd) write(fd[1], "", 0); if(!wr) write(fd[0], "", 0); return 0; } char * sys_find_program(const char *p) { if((p[0] == '/') || (p[0] == '.' && p[1] == '/') || (p[0] == '.' && p[1] == '.' && p[2] == '/')) return MEM_STRDUP(p); char *path = getenv("path"); if(path == nil) return nil; char *s; for(s = path; s != nil;){ char *e = strchr(s, ' '); if(e != nil) *e = 0; s = smprint("%s/%s", s, p); if(s != nil){ int r = access(s, AEXEC); if(r == 0) break; free(s); } s = e != nil ? e+1 : nil; } free(path); return s; } static int mkdir_(const char *path, usize mode) { Dir *d; int r = -1; if((d = dirstat(path)) != nil){ if((d->mode & DMDIR) != 0) r = 0; free(d); }else{ int f = create(path, OREAD, DMDIR|mode); if(f >= 0) r = 0; close(f); } return r; } int sys_mkdir(const char *path, usize mode) { if(mkdir_(path, mode) == 0) return 0; char *p = MEM_STRDUP(path); if(p == nil) return -1; int r = -1; for(char *s = p+1; (s = strchr(s, '/')) != nil;){ *s = 0; if(mkdir_(p, mode) != 0) goto done; *s++ = '/'; while(*s == '/') s++; } if(mkdir_(path, mode) == 0) r = 0; done: MEM_FREE(p); return r; } int sys_postnote(int pid, const char *note, const char *sig) { USED(sig); return postnote(PNPROC, pid, note); } BUILTIN("getpid", getpid) { USED(args); noargs(); return fixnum(getpid()); } static void process_updates(int f) { char wait[128]; snprint(wait, sizeof(wait), "/proc/%lud/args", (ulong)getpid()); int nfd = open(wait, OWRITE|OCEXEC); if(nfd >= 0){ fprint(nfd, "process_updates"); close(nfd); } for(;;){ char *waitfld[5]; int n = read(f, wait, sizeof(wait)-1); if(n <= 0) break; wait[n] = 0; if(tokenize(wait, waitfld, nelem(waitfld)) != nelem(waitfld)) continue; int pid = atoi(waitfld[0]); char *m = waitfld[4]; // the only way the status isn't there is if the process has // already left the building char stat[128], *statfld[5]; process_state_t state = PSTATE_EXITED; snprint(stat, sizeof(stat), "/proc/%s/status", waitfld[0]); int s = open(stat, OREAD|OCEXEC); if(s >= 0){ n = read(s, stat, sizeof(stat)-1); close(s); if(n > 0){ stat[n] = 0; if(tokenize(stat, statfld, nelem(statfld)) >= nelem(statfld)){ if(strcmp(statfld[2], "Broken") == 0) state = PSTATE_DUMPED; else if(strcmp(statfld[2], "Stopped") == 0) state = PSTATE_STOPPED; else if(strcmp(statfld[2], "Moribund") == 0) state = PSTATE_EXITED; else state = PSTATE_RUNNING; } } } process_update(pid, state, *m == 0 ? 0 : 1, *m == 0 ? nil : m); } exits(nil); } void sys_init(void) { lsd_init(); char t[64]; snprint(t, sizeof(t), "/proc/%d/wait", getpid()); int waitfd = open(t, OREAD|OCEXEC); if(waitfd < 0) abort(); int r = rfork(RFREND|RFPROC|RFMEM); if(r < 0) abort(); if(r == 0) process_updates(waitfd); } extern uchar bootcode[]; extern ulong bootlen; void main(int argc, char **argv) { argv0 = argv[0]; setfcr(FPPDBL|FPRNR|FPOVFL); tmfmtinstall(); slmain(bootcode, bootlen, argc, argv); }