/* JJJ Shouldn't the check just be that egid/euid does not match gid/uid, since euif/egid might be set, but not to root? -jj */ int setgroups(int gidsetlen, const gid_t *gidset) { int i; int j; OSCALLENTER(OSCALL_setgroups); if (getuid() == 0 || geteuid() == 0) { if (gidsetlen > NGROUPS || gidsetlen < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_setgroups); return -1; } for (i = 0; i < gidsetlen; i++) { /* make sure we can touch all the gidset * if we failed we could return errno EFAULT */ j |= gidset[i]; } for (i = 0; i < gidsetlen; i++) { __current->groups[i] = gidset[i]; } __current->groups[i] = GROUP_END; OSCALLEXIT(OSCALL_setgroups); return 0; } else { errno = EPERM; OSCALLEXIT(OSCALL_setgroups); return -1; } }
int setegid(gid_t egid) { struct Capability cap; OSCALLENTER(OSCALL_setegid); if (__current->egid == egid) return 0; /* Layout the desired capability */ cap.c_perm = CL_DUP | CL_W; cap.c_valid = 1; cap.c_isptr = 0; cap.c_len = egid ? 3 : 1; cap.c_name[0] = 2; cap.c_name[1] = egid >> 8; cap.c_name[2] = egid & 0xFF; /* Try to forge the new gid capability with CAP_GID */ if (sys_self_forge(CAP_GID, CAP_EGID, &cap) < 0) { errno = EPERM; OSCALLEXIT(OSCALL_setegid); return -1; } __current->egid = egid; OSCALLEXIT(OSCALL_setegid); return 0; }
mode_t umask(mode_t numask) { mode_t ret; OSCALLENTER(OSCALL_umask); ret = __current->umask; __current->umask = numask; OSCALLEXIT(OSCALL_umask); return ret; }
/* HBXX not 100% of correctness, excerpt from man page: The issetugid() function returns 1 if the process was made setuid or set- gid as the result of the last execve() system call. Otherwise it returns 0. */ int issetugid(void) { int r; OSCALLENTER(OSCALL_issetugid); r = ((__current->egid == 0 && __current->gid != 0) || (__current->euid == 0 && __current->uid != 0)); OSCALLEXIT(OSCALL_issetugid); return r; }
int getgroups(int gidsetlen, gid_t gidset[]) { int i; OSCALLENTER(OSCALL_getgroups); if (gidsetlen == 0) { /* just wants to know how many */ for (i = 0; __current->groups[i] != GROUP_END ; i++); } else { for (i = 0; __current->groups[i] != GROUP_END ; i++) gidset[i] = __current->groups[i]; } OSCALLEXIT(OSCALL_getgroups); return(i); }
int msync(void *addr, size_t len, int flags) { struct mmap_ustruct *mus; struct Mmap *m; void *nextaddr; size_t nextlen; OSCALLENTER(OSCALL_msync); if (((u_int)addr & PGMASK) || len < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_msync); return -1; } if (len == 0) { OSCALLEXIT(OSCALL_msync); return 0; } nextlen = len; do { mus = (struct mmap_ustruct *)mregion_get_ustruct(addr); if (!mus) { errno = EINVAL; OSCALLEXIT(OSCALL_msync); return -1; } m = &(mus->m); if (addr+len > m->mmap_addr+m->mmap_len) len -= addr+len - (m->mmap_addr+m->mmap_len); msync_mark_bc(m, addr, (u_int)addr + len); msync_set_modtimes(m->mmap_filp); nextaddr = addr+len; nextlen -= len; addr = nextaddr; len = nextlen; } while (len > 0); OSCALLEXIT(OSCALL_msync); return 0; }
/* * Copyright (C) 1997 Massachusetts Institute of Technology * * This software is being provided by the copyright holders under the * following license. By obtaining, using and/or copying this software, * you agree that you have read, understood, and will comply with the * following terms and conditions: * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose and without fee or royalty is * hereby granted, provided that the full text of this NOTICE appears on * ALL copies of the software and documentation or portions thereof, * including modifications, that you make. * * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR * DOCUMENTATION. * * The name and trademarks of copyright holders may NOT be used in * advertising or publicity pertaining to the software without specific, * written prior permission. Title to copyright in this software and any * associated documentation will at all times remain with copyright * holders. See the file AUTHORS which should have accompanied this software * for a list of all copyright holders. * * This file may be derived from previously copyrighted software. This * copyright applies only to those changes made by the copyright * holders listed in the AUTHORS file. The rest of this file is covered by * the copyright notices, if any, listed below. */ #include <exos/callcount.h> #include <exos/uwk.h> #include <xok/sysinfo.h> #include <errno.h> #include <sys/time.h> #define DID_TIMEOUT 1 #define DID_SIGNAL 2 #define WK_SELECT_SZ 1024 #undef RATE #define RATE (__sysinfo.si_rate*1000) /* nanoseconds per tick */ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) { struct wk_term t[WK_SELECT_SZ]; int next; unsigned long long absolute_ticks = 0; OSCALLENTER(OSCALL_nanosleep); if (rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000) { errno = EINVAL; OSCALLEXIT(OSCALL_nanosleep); return -1; } absolute_ticks = ((1000000000/RATE) * rqtp->tv_sec) + (rqtp->tv_nsec + RATE - 1)/RATE + __sysinfo.si_system_ticks; next = 0; next = wk_mktag(next, t, DID_TIMEOUT); next += wk_mksleep_pred(&t[next], absolute_ticks); next = wk_mkop(next, t, WK_OR); next = wk_mktag(next, t, DID_SIGNAL); next += wk_mksig_pred(&t[next]); wk_waitfor_pred(t, next); if (rmtp) { unsigned long long curticks = __sysinfo.si_system_ticks; if (curticks > absolute_ticks) curticks = absolute_ticks; rmtp->tv_sec = ((absolute_ticks - curticks)*RATE)/1000000000; rmtp->tv_nsec = ((absolute_ticks - curticks)*RATE) % 1000000000; } if (UAREA.u_pred_tag == DID_TIMEOUT) { OSCALLEXIT(OSCALL_nanosleep); return 0; } /* it is ok to return EINTR even if we are interrupted by a restartable signal */ errno = EINTR; OSCALLEXIT(OSCALL_nanosleep); return -1; }
int setuid(uid_t uid) { struct Capability cap; OSCALLENTER(OSCALL_setuid); /* Layout the desired capability */ cap.c_perm = CL_ALL; cap.c_valid = 1; cap.c_isptr = 0; cap.c_len = uid ? 3 : 1; cap.c_name[0] = 1; cap.c_name[1] = uid >> 8; cap.c_name[2] = uid & 0xFF; /* Try to forge the new uid capability with CAP_EUID */ if (sys_self_forge(CAP_EUID, CAP_SCRATCH, &cap) < 0) { /* Couldn't forge, are we just blowing away the euid? */ if (uid == __current->uid) { sys_self_forge(CAP_UID, CAP_EUID, &__curenv->env_clist[CAP_UID]); __current->euid = uid; __current->fsuid = uid; OSCALLEXIT(OSCALL_setuid); return 0; } else { errno = EPERM; OSCALLEXIT(OSCALL_setuid); return -1; } } /* CAP_SCRATCH is now a token for `cap', move this into euid and uid */ /* These can't fail since we just forged `cap' into CAP_SCRATCH */ sys_self_forge(CAP_SCRATCH, CAP_UID, &cap); sys_self_forge(CAP_SCRATCH, CAP_EUID, &cap); __current->uid = uid; __current->euid = uid; __current->fsuid = uid; OSCALLEXIT(OSCALL_setuid); return 0; }
int setgid(gid_t gid) { struct Capability cap; OSCALLENTER(OSCALL_setgid); /* Layout the desired capability */ cap.c_perm = CL_DUP | CL_W; cap.c_valid = 1; cap.c_isptr = 0; cap.c_len = gid ? 3 : 1; cap.c_name[0] = 2; cap.c_name[1] = gid >> 8; cap.c_name[2] = gid & 0xFF; /* Try to forge the new gid capability with CAP_EGID and CAP_EUID */ if (sys_self_forge(CAP_EGID, CAP_SCRATCH, &cap) < 0 && sys_self_forge(CAP_EUID, CAP_SCRATCH, &cap) < 0) { /* Couldn't forge, Use CAP_GID only if we are setting egid back to gid */ if (gid == __current->gid) { sys_self_forge(CAP_GID, CAP_EGID, &__curenv->env_clist[CAP_GID]); __current->egid = gid; OSCALLEXIT(OSCALL_setgid); return 0; } else { errno = EPERM; OSCALLEXIT(OSCALL_setgid); return -1; } } /* CAP_SCRATCH is now a token for `cap', move this into euid and uid */ /* These can't fail since we know CAP_SCRATCH dominates/equals `cap' */ sys_self_forge(CAP_SCRATCH, CAP_GID, &cap); sys_self_forge(CAP_SCRATCH, CAP_EGID, &cap); __current->gid = gid; __current->egid = gid; OSCALLEXIT(OSCALL_setgid); return 0; }
long fpathconf(int fd, int name) { OSCALLENTER(OSCALL_fpathconf); return pathconf0(name); OSCALLEXIT(OSCALL_fpathconf); }
long pathconf(const char *path, int name) { OSCALLENTER(OSCALL_pathconf); return pathconf0(name); OSCALLEXIT(OSCALL_pathconf); }
int munmap(void *addr, size_t len) { struct Mmap *m; struct mmap_ustruct *mus; void *nextaddr; size_t nextlen; OSCALLENTER(OSCALL_munmap); /* page-ify */ len += (((u_int)addr) & PGMASK); addr = (void*)PGROUNDDOWN((u_int)addr); len = PGROUNDUP(len); /* impossible to do what man page says! */ #if 0 if ((((u_int)addr) & PGMASK) || len < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } #endif if (len == 0) { OSCALLEXIT(OSCALL_munmap); return 0; } nextlen = len; do { /* get info on the to-be-freed region */ mus = (struct mmap_ustruct *)mregion_get_ustruct(addr); if (!mus) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } m = &(mus->m); if (addr+len > m->mmap_addr+m->mmap_len) len -= addr+len - (m->mmap_addr+m->mmap_len); /* something strange, shouldn't happen */ if (addr >= m->mmap_addr+m->mmap_len || addr+len <= m->mmap_addr) { OSCALLEXIT(OSCALL_munmap); return 0; } /* if completely freed */ if (addr <= m->mmap_addr && len >= m->mmap_len) { __vm_free_region((u_int)m->mmap_addr, m->mmap_len, CAP_ROOT); /* XXX - error check */ __free(m->mmap_addr); /* if wasn't __malloc'd then this will do nothing */ LIST_REMOVE(m, mmap_link); if (m->mmap_filp) { lock_filp(m->mmap_filp); filp_refcount_dec(m->mmap_filp); if (filp_refcount_get(m->mmap_filp) == 0) { unlock_filp(m->mmap_filp); close_filp(m->mmap_filp); } else unlock_filp(m->mmap_filp); } exos_pinned_free(mus); /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } } /* if the end is freed */ else if (addr > m->mmap_addr && addr+len >= m->mmap_addr+m->mmap_len) { m->mmap_len = addr-m->mmap_addr; __vm_free_region((u_int)addr, len, CAP_ROOT); /* XXX - error check */ __free2(addr, 0); /* if wasn't __malloc'd then this will do nothing */ /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } } /* if the beginning is freed */ else if (addr <= m->mmap_addr && addr+len < m->mmap_addr+m->mmap_len) { __vm_free_region((u_int)addr, len, CAP_ROOT); /* XXX - error check */ __free2(m->mmap_addr, addr+len - m->mmap_addr); m->mmap_len = m->mmap_addr+m->mmap_len - (addr+len); m->mmap_addr = addr+len; /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } } /* if the middle is freed */ else { __vm_free_region((u_int)addr, len, CAP_ROOT); /* XXX - error check */ /* retore original handler to region */ if (mregion_alloc(addr, len, mus->oldmru) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_munmap); return -1; } assert(0); /* XXX - too much trouble right now */ } nextaddr = addr+len; nextlen -= len; addr = nextaddr; len = nextlen; } while (len > 0); OSCALLEXIT(OSCALL_munmap); return 0; }
void *mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset) { u_int pageoff; caddr_t ret; off_t pos = offset; size_t size = len; struct Mmap *m; struct stat sb; struct file *filp; struct mmap_ustruct *mus; OSCALLENTER(OSCALL_mmap); if (!mmap_inited) mmap_init(); /* if given a bad fd then return */ if (fd != -1 && fstat (fd, &sb) < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t )-1; } if ((flags & MAP_COPY) && (flags & MAP_ANON)) flags &= ~MAP_COPY; /* OpenBSD 2.1 code */ /* * Align the file position to a page boundary, * and save its page offset component. */ pageoff = (pos & PGMASK); pos -= pageoff; /* Adjust size for rounding (on both ends). */ size += pageoff; /* low end... */ size = PGROUNDUP(size); /* hi end */ /* Do not allow mappings that cause address wrap... */ if ((ssize_t)size < 0) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * Check for illegal addresses. Watch out for address wrap... */ if (flags & MAP_FIXED) { /* * The specified address must have the same remainder * as the file offset taken modulo NBPG, so it * should be aligned after adjustment by pageoff. */ addr -= pageoff; if ((u_int)addr & PGMASK) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* Address range must be all in user VM space. */ if (UTOP > 0 && (u_int)addr + size > UTOP) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } if ((u_int)addr > (u_int)addr + size) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } } if ((flags & MAP_ANON) == 0) { if (fd < 0 || fd > NR_OPEN || __current->fd[fd] == NULL) { errno = EBADF; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * XXX hack to handle use of /dev/zero to map anon * memory (ala SunOS). */ if (S_ISCHR(__current->fd[fd]->f_mode) && mmap_iszerodev(__current->fd[fd]->f_dev)) { flags |= MAP_ANON; goto is_anon; } /* * Only files and cdevs are mappable, and cdevs does not * provide private mappings of any kind. */ if (!S_ISREG(__current->fd[fd]->f_mode) && (!S_ISCHR(__current->fd[fd]->f_mode) || (flags & (MAP_PRIVATE|MAP_COPY)))) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * Ensure that file and memory protections are * compatible. Note that we only worry about * writability if mapping is shared; in this case, * current and max prot are dictated by the open file. * XXX use the vnode instead? Problem is: what * credentials do we use for determination? * What if proc does a setuid? */ if (((__current->fd[fd]->f_flags & O_ACCMODE) == O_WRONLY) && (prot & PROT_READ)) { errno = EACCES; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } /* * If we are sharing potential changes (either via MAP_SHARED * or via the implicit sharing of character device mappings), * and we are trying to get write permission although we * opened it without asking for it, bail out. */ if (((flags & MAP_SHARED) != 0 || S_ISCHR(__current->fd[fd]->f_mode)) && ((__current->fd[fd]->f_flags & O_ACCMODE) == O_RDONLY) && (prot & PROT_WRITE) != 0) { errno = EACCES; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } } else { /* * (flags & MAP_ANON) == TRUE * Mapping blank space is trivial. */ if (fd != -1) { errno = EINVAL; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } is_anon: pos = 0; } if (size == 0) { OSCALLEXIT(OSCALL_mmap); return addr; } if (fd >= 0) filp = __current->fd[fd]; else filp = NULL; if ((flags & MAP_FIXED) == 0) { addr = __malloc(size); if (addr == NULL) { __free(addr); errno = ENOMEM; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } } mus = exos_pinned_malloc(sizeof(*mus)); if (mus == NULL) { if ((flags & MAP_FIXED) == 0) __free(addr); errno = ENOMEM; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } m = &(mus->m); m->mmap_addr = addr; m->mmap_len = size; m->mmap_prot = prot; m->mmap_flags = flags; m->mmap_offset = pos; m->mmap_filp = filp; m->mmap_dev = ((fd != -1) ? sb.st_dev : 0); LIST_INSERT_HEAD (&mmap_list, m, mmap_link); mus->mru.handler = mmap_fault_handler; mus->oldmru = mregion_get_ustruct(addr); /* XXX - check return value */ if (__vm_free_region((u_int)addr, size, 0) < 0 || mregion_alloc(addr, size, (struct mregion_ustruct*)mus) != 0) { if ((flags & MAP_FIXED) == 0) __free(addr); exos_pinned_free(mus); errno = ENOMEM; OSCALLEXIT(OSCALL_mmap); return (caddr_t)-1; } if (filp) { lock_filp(filp); filp_refcount_inc(filp); unlock_filp(filp); } if (flags & MAP_COPY) ret = __mmap(addr, size, prot, flags, fd, pos, 0, __envid); else ret = addr + pageoff; OSCALLEXIT(OSCALL_mmap); return ret; }
gid_t getegid(void) { OSCALLENTER(OSCALL_getegid); OSCALLEXIT(OSCALL_getegid); return (__current->egid); }
int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { unsigned int wait_ticks = 0; int fd; #define WK_SELECT_SZ 1024 struct wk_term t[WK_SELECT_SZ]; int next; int total = 0; fd_set newreadfds, newwritefds, newexceptfds; #define DID_FDREADY 1 #define DID_TIMEOUT 2 #define DID_SIGNAL 3 struct file *filp; int had_prev_term; OSCALLENTER(OSCALL_select); width = MIN (width+1, NR_OPEN); /* make sure that all fd's set to be polled are valid fd's */ for (fd = 0; fd < width; fd++) { if ((readfds && FD_ISSET (fd, readfds)) || (writefds && FD_ISSET (fd, writefds)) || (exceptfds && FD_ISSET (fd, exceptfds))) { CHECKFD(fd, OSCALL_select); assert (CHECKOP (__current->fd[fd], select)); assert (CHECKOP (__current->fd[fd], select_pred)); } } FD_ZERO(&newreadfds); FD_ZERO(&newwritefds); FD_ZERO(&newexceptfds); /* Our basic algorithm is poll the fd's once. If any fd's are found ready return. Otherwise sleep until one of them might be ready and repeat the process. In practice we don't expect to go through this loop more than once, but theoretically we could wakeup for some reason other than haveing fd's ready. Am I just being paranoid? */ /* Note: we can _definitely_ go thru this loop more than once, because in some cases (e.g., TCP), we can only sleep on an "indication" that select might pass (e.g., a packet arrived). We have to then call select to find out if it does in fact make the socket ready, and rebuild the sleep predicate otherwise. */ do { had_prev_term = 0; /* do a poll on the fd's. We want to make sure that we do this before sleeping so on the first time through the do loop we avoid descheduling and having to wait till we're re-scheduled before noticing that there're fd's ready. */ for (fd = 0; fd < width; fd++) { if (readfds && FD_ISSET (fd, readfds)) if (DOOP (__current->fd[fd], select, (__current->fd[fd], SELECT_READ))) { total++; FD_SET (fd, &newreadfds); } if (writefds && FD_ISSET (fd, writefds)) if (DOOP (__current->fd[fd], select, (__current->fd[fd], SELECT_WRITE))) { total++; FD_SET (fd, &newwritefds); } if (SELECT_EXCEPT_CONDITIONS && exceptfds && FD_ISSET (fd, exceptfds)) if (DOOP (__current->fd[fd], select, (__current->fd[fd], SELECT_EXCEPT))) { total++; FD_SET (fd, &newexceptfds); } } /* ok, we found some fd's that we need to report. Replace the fdsets the user passed in with fdsets containing which fd's are ready and return the total number of fd's ready. */ if (total) { if (readfds) copyfds (readfds, &newreadfds, width); if (writefds) copyfds (writefds, &newwritefds, width); if (exceptfds) copyfds (exceptfds, &newexceptfds, width); /* XXX */ OSCALLEXIT(OSCALL_select); return total; } /* if the user is just polling, handle that now before going through all the work to construct a predicate */ if (timeout) { wait_ticks = ((1000000/RATE) * timeout->tv_sec) + (timeout->tv_usec + RATE - 1)/RATE; if (!wait_ticks) { if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); if (exceptfds) FD_ZERO(exceptfds); OSCALLEXIT(OSCALL_select); return 0; } } /* now construct a wakeup-predicate that will wake us when something interesting happens on these fd's. We call each fd's select_pred operation which returns a clause of the final predicate. All clauses are combined into one large predicate that we'll sleep on. */ next = 0; had_prev_term = 0; next = wk_mktag (next, t, DID_FDREADY); for (fd = 0; fd < width; fd++) { filp = __current->fd[fd]; if (readfds && FD_ISSET (fd, readfds)) { if (had_prev_term) next = wk_mkop (next, t, WK_OR); next += DOOP (filp,select_pred,(filp,SELECT_READ,&t[next])); had_prev_term = 1; } if (writefds && FD_ISSET (fd, writefds)) { if (had_prev_term) next = wk_mkop (next, t, WK_OR); next += DOOP (filp,select_pred,(filp,SELECT_WRITE,&t[next])); had_prev_term = 1; } if (SELECT_EXCEPT_CONDITIONS && exceptfds && FD_ISSET (fd, exceptfds)) { if (had_prev_term) next = wk_mkop (next, t, WK_OR); next += DOOP (filp,select_pred,(filp,SELECT_EXCEPT,&t[next])); had_prev_term = 1; } } /* slap on a final term to wake us when the timeout occurrs, if there is one */ if (timeout) { if (had_prev_term) next = wk_mkop (next, t, WK_OR); next = wk_mktag (next, t, DID_TIMEOUT); next += wk_mksleep_pred (&t[next], wait_ticks + __sysinfo.si_system_ticks); had_prev_term = 1; } /* we need to wakeup if a signal comes in */ if (had_prev_term) { next = wk_mkop (next, t, WK_OR); } next = wk_mktag (next, t, DID_SIGNAL); next += wk_mksig_pred (&t[next]); had_prev_term = 1; /* wait for predicate to evaluate to true */ wk_waitfor_pred (t, next); /* u_pred_tag is set to the piece of the predicate that caused us to wake up */ if (UAREA.u_pred_tag == DID_TIMEOUT) { if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); if (exceptfds) FD_ZERO(exceptfds); OSCALLEXIT(OSCALL_select); return 0; } if (UAREA.u_pred_tag == DID_SIGNAL) { //kprintf("%d select interrupted by signal\n",getpid()); errno = EINTR; OSCALLEXIT(OSCALL_select); return -1; } } while (1); }
/* everything is based on this exec, we have an extra flag (_EXEC_EXECONLY) to differentiate between the exec and fork_exec families. the difference is that the latter forks and then execs the process thereby returning in the parent */ static int fork_execve0(const char *path, char *const argv[], char * const envptr[], int fd, u_int flags) { u_int k = 0; int target_cpu = 0; struct Uenv cu; int NewPid = 0; int envid = 0; /* XXX -- init to supress warning */ char **old_argv = (char **)argv; int r, exec_format; struct Env e; OSCALLENTER(OSCALL_execve); /* verify executable permission */ if (!(flags & _EXEC_USE_FD) && access(path, X_OK) == -1) { /* access will set errno */ r = -errno; goto err; } if (!(envid = sys_env_alloc (0, &r))) { fprintf(stderr,"could not sys_env_alloc\n"); r = -ENOEXEC; goto err; } e = __envs[envidx(envid)]; if ((exec_format = fork_execve0_part2(path, argv, envptr, &e, fd, flags)) < 0) goto err_env_free; /* write environment */ if ((r = sys_wrenv (k, envid, &e)) < 0) { kprintf ("sys_wrenv failed\n"); r = -ENOEXEC; goto err; } if (ExecuteOnExecHandlers(k, envid, flags & _EXEC_EXECONLY) == -1) { fprintf(stderr,"cleanup code not done yet\n"); assert(-1); } #ifdef PROCESS_TABLE if (flags & _EXEC_EXECONLY) { /* because true exec */ NewPid = getpid(); dlockputs(__PROCD_LD,"fork_execve0 get lock "); EXOS_LOCK(PROCINFO_LOCK); dlockputs(__PROCD_LD,"... got lock\n"); EnterCritical (); ProcChangeEnv(NewPid,envid); EXOS_UNLOCK(PROCINFO_LOCK); dlockputs(__PROCD_LD,"fork_execve0 release lock\n"); ExitCritical (); } else { /* because we are forking */ NewPid = AllocateFreePid (envid); } cu = UAREA; if (!execonly) { AddProcEntry (&cu, (char *)path, (char **)argv, NewPid, UAREA.pid); if ((cu.parent_slot = GetChildSlot (NewPid)) < 0) { r = -ENOEXEC; goto err_env_free; } } else { /* TO TOM: what do we do this for? strncpy (UAREA.name, (char*)(((u_int)argv[0]) + ARGV_START_LOCAL - ARGV_START), U_NAMEMAX-1); UAREA.name[U_NAMEMAX-1] = '\0'; */ } /* XXX -- on an exec we'll forget to unref our children's pids */ /* TO TOM: shouldnt this clearchildinfo be at the top */ ClearChildInfo (&cu); #else #ifdef PROCD if (flags & _EXEC_EXECONLY) { NewPid = getpid(); /* only register us if we are of the right format */ if (exec_format == EXEC_EXOS_AOUT) proc_exec(envid); } else { NewPid = proc_fork(envid); } cu = UAREA; //kprintf("NewPid %d envid: %d %s proc_%s: (%d) -> %d\n", //NewPid,__envid,execonly ? "exec" : "fork",path,envid,NewPid); #else NewPid = envid; #endif /* PROCD */ #endif /* PROCESS_TABLE */ strncpy (cu.name, path, U_NAMEMAX-1); cu.name[U_NAMEMAX-1] = '\0'; cu.u_fpu = 0; cu.u_in_critical = 0; cu.u_status = U_RUN; cu.u_entprologue = e.env_tf.tf_eip; cu.u_entepilogue = e.env_tf.tf_eip; cu.u_entfault = 0; cu.u_entipc1 = 0; cu.u_entipc2 = 0; cu.u_ppc = 0; #ifdef PROCESS_TABLE cu.u_chld_state_chng = 0; #endif /* PROCESS_TABLE */ cu.u_next_timeout = 0; cu.u_in_pfault = 0; cu.u_donate = -1; cu.u_yield_count = 0; cu.u_epilogue_count = 0; cu.u_epilogue_abort_count = 0; STOPP(misc,step7); ISTART(misc,step8); cu.u_start_kern_call_counting = 0; if ((r = sys_wru (0, envid, &cu)) < 0) { fprintf (stderr,"sys_wru failed\n"); r = -ENOEXEC; goto err_env_free; } target_cpu = 0; #ifdef __SMP__ if (strncmp(path,"_cpu",4)==0 && strlen(path)>4) { target_cpu = path[4]-'0'; if (target_cpu<0 || target_cpu>sys_get_num_cpus()-1) target_cpu = 0; } #endif /* we can't do this until all the child state is setup */ if ((r = sys_quantum_alloc (k, -1, target_cpu, envid)) < 0) { fprintf (stderr,"could not alloc quantum\n"); r = -ENOEXEC; goto err_env_free; } /* if we're doing a true unix exec and not a combined fork/spawn we need to destroy ourselves since our child should have replaced us. */ if (flags & _EXEC_EXECONLY) { /* if not an exos format, should not expect normal child behaviors, so we * just quit from procd to avoid any hanging... */ if (exec_format == EXEC_SIMPLE) proc_exit(0); /* we die anyways, so free quantum and env */ ProcessFreeQuanta(__envid); sys_env_free (0, __envid); } if (old_argv != argv) __free((char**)argv); OSCALLEXIT(OSCALL_execve); return (NewPid); err_env_free: ProcessFreeQuanta(__envid); sys_env_free (k, envid); err: if (old_argv != argv) __free((char**)argv); errno = -r; OSCALLEXIT(OSCALL_execve); return -1; }