/* Create a device file named PATH relative to FD, with permission and special bits MODE and device number DEV (which can be constructed from major and minor device numbers with the `makedev' macro above). */ int __xmknodat (int vers, int fd, const char *file, mode_t mode, dev_t * dev) { if (vers != _MKNOD_VER) { __set_errno (EINVAL); return -1; } # ifndef __ASSUME_ATFCTS if (__have_atfcts >= 0) # endif { int result; /* The FreeBSD mknod() system call cannot be used to create FIFOs; we must use the mkfifo() system call for this purpose. */ if (S_ISFIFO (mode)) result = INLINE_SYSCALL (mkfifoat, 3, fd, file, mode); else result = INLINE_SYSCALL (mknodat, 4, fd, file, mode, *dev); # ifndef __ASSUME_ATFCTS if (result == -1 && errno == ENOSYS) __have_atfcts = -1; else # endif return result; } #ifndef __ASSUME_ATFCTS if (fd != AT_FDCWD && file[0] != '/') { int mib[4]; size_t kf_len = 0; char *kf_buf, *kf_bufp; size_t filelen; if (fd < 0) { __set_errno (EBADF); return -1; } filelen = strlen (file); if (__builtin_expect (filelen == 0, 0)) { __set_errno (ENOENT); return -1; } mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_FILEDESC; mib[3] = __getpid (); if (__sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0) { __set_errno (ENOSYS); return -1; } kf_buf = alloca (kf_len + filelen); if (__sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0) { __set_errno (ENOSYS); return -1; } kf_bufp = kf_buf; while (kf_bufp < kf_buf + kf_len) { struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp; if (kf->kf_fd == fd) { if (kf->kf_type != KF_TYPE_VNODE || kf->kf_vnode_type != KF_VTYPE_VDIR) { __set_errno (ENOTDIR); return -1; } strcat (kf->kf_path, "/"); strcat (kf->kf_path, file); file = kf->kf_path; break; } kf_bufp += kf->kf_structsize; } if (kf_bufp >= kf_buf + kf_len) { __set_errno (EBADF); return -1; } } return __xmknod (vers, file, mode, dev); #endif }
int _DkMutexLockTimeout (struct mutex_handle * mut, int timeout) { int i, c = 0; if (timeout == -1) return -_DkMutexLock(mut); struct atomic_int * m = &mut->value; /* Spin and try to take lock */ for (i = 0 ; i < MUTEX_SPINLOCK_TIMES ; i++) { c = atomic_dec_and_test(m); if (c) goto success; cpu_relax(); } /* The lock is now contended */ int ret; if (timeout == 0) { ret = c ? 0 : -PAL_ERROR_TRYAGAIN; goto out; } while (!c) { int val = atomic_read(m); if (val == 1) goto again; struct timespec waittime; long sec = timeout / 1000000; long microsec = timeout - (sec * 1000000); waittime.tv_sec = sec; waittime.tv_nsec = microsec * 1000; ret = INLINE_SYSCALL(futex, 6, m, FUTEX_WAIT, val, &waittime, NULL, 0); if (IS_ERR(ret) && ERRNO(ret) != EWOULDBLOCK && ERRNO(ret) != EINTR) { ret = unix_to_pal_error(ERRNO(ret)); goto out; } #ifdef DEBUG_MUTEX if (IS_ERR(ret)) printf("mutex held by thread %d\n", mut->owner); #endif again: /* Upon wakeup, we still need to check whether mutex is unlocked or * someone else took it. * If c==0 upon return from xchg (i.e., the older value of m==0), we * will exit the loop. Else, we sleep again (through a futex call). */ c = atomic_dec_and_test(m); } success: #ifdef DEBUG_MUTEX mut->owner = INLINE_SYSCALL(gettid, 0); #endif ret = 0; out: return ret; }
int __real_chown (const char *file, uid_t owner, gid_t group) { # if __ASSUME_LCHOWN_SYSCALL == 0 static int __libc_old_chown; int result; if (!__libc_old_chown) { int saved_errno = errno; # ifdef __NR_chown32 if (__libc_missing_32bit_uids <= 0) { int result; int saved_errno = errno; result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group); if (result == 0 || errno != ENOSYS) return result; __set_errno (saved_errno); __libc_missing_32bit_uids = 1; } # endif /* __NR_chown32 */ if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U)) || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U))) { __set_errno (EINVAL); return -1; } result = INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group); if (result >= 0 || errno != ENOSYS) return result; __set_errno (saved_errno); __libc_old_chown = 1; } return __lchown (file, owner, group); # elif __ASSUME_32BITUIDS /* This implies __ASSUME_LCHOWN_SYSCALL. */ return INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group); # else /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL */ # ifdef __NR_chown32 if (__libc_missing_32bit_uids <= 0) { int result; int saved_errno = errno; result = INLINE_SYSCALL (chown32, 3, CHECK_STRING (file), owner, group); if (result == 0 || errno != ENOSYS) return result; __set_errno (saved_errno); __libc_missing_32bit_uids = 1; } # endif /* __NR_chown32 */ if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U)) || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U))) { __set_errno (EINVAL); return -1; } return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group); # endif }
/* Helper function to support starting threads for SIGEV_THREAD. */ static void * timer_helper_thread (void *arg) { /* Wait for the SIGTIMER signal, allowing the setXid signal, and none else. */ sigset_t ss; sigemptyset (&ss); __sigaddset (&ss, SIGTIMER); /* Endless loop of waiting for signals. The loop is only ended when the thread is canceled. */ while (1) { siginfo_t si; /* sigwaitinfo cannot be used here, since it deletes SIGCANCEL == SIGTIMER from the set. */ int oldtype = LIBC_CANCEL_ASYNC (); /* XXX The size argument hopefully will have to be changed to the real size of the user-level sigset_t. */ int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL, _NSIG / 8); LIBC_CANCEL_RESET (oldtype); if (result > 0) { if (si.si_code == SI_TIMER) { struct timer *tk = (struct timer *) si.si_ptr; /* Check the timer is still used and will not go away while we are reading the values here. */ pthread_mutex_lock (&__active_timer_sigev_thread_lock); struct timer *runp = __active_timer_sigev_thread; while (runp != NULL) if (runp == tk) break; else runp = runp->next; if (runp != NULL) { struct thread_start_data *td = malloc (sizeof (*td)); /* There is not much we can do if the allocation fails. */ if (td != NULL) { /* This is the signal we are waiting for. */ td->thrfunc = tk->thrfunc; td->sival = tk->sival; pthread_t th; (void) pthread_create (&th, &tk->attr, timer_sigev_thread, td); } } pthread_mutex_unlock (&__active_timer_sigev_thread_lock); } else if (si.si_code == SI_TKILL) /* The thread is canceled. */ pthread_exit (NULL); } } }
pid_t __libc_fork (void) { return (pid_t) INLINE_SYSCALL (clone, 2, SIGCHLD, 0); }
/* Change the owner and group of FILE. */ int __lchown (const char *file, uid_t owner, gid_t group) { return INLINE_SYSCALL (fchownat, 5, AT_FDCWD, file, owner, group, AT_SYMLINK_NOFOLLOW); }
int _DkVirtualMemoryProtect (void * addr, int size, int prot) { int ret = INLINE_SYSCALL(mprotect, 3, addr, size, HOST_PROT(prot)); return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : 0; }
int __new_semctl (int semid, int semnum, int cmd, ...) { union semun arg; va_list ap; va_start (ap, cmd); /* Get the argument. */ arg = va_arg (ap, union semun); va_end (ap); #if __ASSUME_32BITUIDS > 0 return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64, CHECK_SEMCTL (&arg, semid, cmd | __IPC_64)); #else switch (cmd) { case SEM_STAT: case IPC_STAT: case IPC_SET: break; default: return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd, CHECK_SEMCTL (&arg, semid, cmd)); } { int result; struct __old_semid_ds old; struct semid_ds *buf; #ifdef __NR_getuid32 if (__libc_missing_32bit_uids <= 0) { if (__libc_missing_32bit_uids < 0) { int save_errno = errno; /* Test presence of new IPC by testing for getuid32 syscall. */ result = INLINE_SYSCALL (getuid32, 0); if (result == -1 && errno == ENOSYS) __libc_missing_32bit_uids = 1; else __libc_missing_32bit_uids = 0; __set_errno(save_errno); } if (__libc_missing_32bit_uids <= 0) { result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64, CHECK_SEMCTL (&arg, semid, cmd | __IPC_64)); return result; } } #endif buf = arg.buf; arg.__old_buf = &old; if (cmd == IPC_SET) { old.sem_perm.uid = buf->sem_perm.uid; old.sem_perm.gid = buf->sem_perm.gid; old.sem_perm.mode = buf->sem_perm.mode; if (old.sem_perm.uid != buf->sem_perm.uid || old.sem_perm.gid != buf->sem_perm.gid) { __set_errno (EINVAL); return -1; } } result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd, CHECK_SEMCTL (&arg, semid, cmd)); if (result != -1 && cmd != IPC_SET) { memset(buf, 0, sizeof(*buf)); buf->sem_perm.__key = old.sem_perm.__key; buf->sem_perm.uid = old.sem_perm.uid; buf->sem_perm.gid = old.sem_perm.gid; buf->sem_perm.cuid = old.sem_perm.cuid; buf->sem_perm.cgid = old.sem_perm.cgid; buf->sem_perm.mode = old.sem_perm.mode; buf->sem_perm.__seq = old.sem_perm.__seq; buf->sem_otime = old.sem_otime; buf->sem_ctime = old.sem_ctime; buf->sem_nsems = old.sem_nsems; } return result; } #endif }
/* Create a one-way communication channel (__pipe). If successful, two file descriptors are stored in PIPEDES; bytes written on PIPEDES[1] can be read from PIPEDES[0]. Returns 0 if successful, -1 if not. */ int __pipe (int __pipedes[2]) { return INLINE_SYSCALL (pipe2, 2, __pipedes, 0); }
int __shmctl (int shmid, int cmd, struct shmid_ds *buf) { return INLINE_SYSCALL (shmctl, 3, shmid, cmd | __IPC_64, buf); }
/* Call kernel with additional two arguments the syscall requires. */ int reboot (int howto) { return INLINE_SYSCALL (reboot, 3, (int) 0xfee1dead, 672274793, howto); }
/* Create a directory named PATH with protections MODE. */ int __mkdir (const char *path, mode_t mode) { return INLINE_SYSCALL (mkdirat, 3, AT_FDCWD, path, mode); }
/* Get information about the file NAME in BUF. */ int __xstat (int vers, const char *name, struct stat *buf) { return INLINE_SYSCALL (stat, 2, name, buf); }
int __real_chown (const char *file, uid_t owner, gid_t group) { return INLINE_SYSCALL (chown32, 3, file, owner, group); }
/* Return information about the filesystem on which FD resides. */ int __fstatfs (int fd, struct statfs *buf) { int rc = INLINE_SYSCALL (fstatfs64, 3, fd, sizeof (*buf), buf); return rc ?: statfs_overflow (buf); }
int lockf64 (int fd, int cmd, off64_t len64) { #if __ASSUME_FCNTL64 == 0 struct flock fl; off_t len = (off_t) len64; #endif #ifdef __NR_fcntl64 struct flock64 fl64; int cmd64; #endif #if __ASSUME_FCNTL64 == 0 memset ((char *) &fl, '\0', sizeof (fl)); /* lockf is always relative to the current file position. */ fl.l_whence = SEEK_CUR; fl.l_start = 0; fl.l_len = len; #endif #ifdef __NR_fcntl64 # if __ASSUME_FCNTL64 == 0 if (!__have_no_fcntl64) { # endif memset ((char *) &fl64, '\0', sizeof (fl64)); fl64.l_whence = SEEK_CUR; fl64.l_start = 0; fl64.l_len = len64; # if __ASSUME_FCNTL64 == 0 } # endif #endif #if __ASSUME_FCNTL64 == 0 && !defined __NR_fcntl64 if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } #endif switch (cmd) { case F_TEST: /* Test the lock: return 0 if FD is unlocked or locked by this process; return -1, set errno to EACCES, if another process holds the lock. */ #if __ASSUME_FCNTL64 > 0 fl64.l_type = F_RDLCK; if (INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64) < 0) return -1; if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; #else # ifdef __NR_fcntl64 if (!__have_no_fcntl64) { int res; fl64.l_type = F_RDLCK; res = INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64); /* If errno == ENOSYS try the 32bit interface if len64 can be represented with 32 bits. */ if (res == 0) { if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; } else if (errno == ENOSYS) __have_no_fcntl64 = 1; else /* res < 0 && errno != ENOSYS. */ return -1; if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } } # endif fl.l_type = F_RDLCK; if (__fcntl (fd, F_GETLK, &fl) < 0) return -1; if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; #endif case F_ULOCK: #if __ASSUME_FCNTL64 == 0 fl.l_type = F_UNLCK; cmd = F_SETLK; #endif #ifdef __NR_fcntl64 fl64.l_type = F_UNLCK; cmd64 = F_SETLK64; #endif break; case F_LOCK: #if __ASSUME_FCNTL64 == 0 fl.l_type = F_WRLCK; cmd = F_SETLKW; #endif #ifdef __NR_fcntl64 fl64.l_type = F_WRLCK; cmd64 = F_SETLKW64; #endif break; case F_TLOCK: #if __ASSUME_FCNTL64 == 0 fl.l_type = F_WRLCK; cmd = F_SETLK; #endif #ifdef __NR_fcntl64 fl64.l_type = F_WRLCK; cmd64 = F_SETLK64; #endif break; default: __set_errno (EINVAL); return -1; } #if __ASSUME_FCNTL64 > 0 return INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64); #else # ifdef __NR_fcntl64 if (!__have_no_fcntl64) { int res = INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64); /* If errno == ENOSYS try the 32bit interface if len64 can be represented with 32 bits. */ if (res == 0 || errno != ENOSYS) return res; __have_no_fcntl64 = 1; if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } } # endif return __fcntl (fd, cmd, &fl); #endif }
/* For Linux we must convert the array of groups from the format that the kernel returns. */ int __getgroups (int n, gid_t *groups) { return INLINE_SYSCALL (getgroups32, 2, n, CHECK_N (groups, n)); }
ssize_t __libc_recv (int fd, void *buf, size_t n, int flags) { return INLINE_SYSCALL (recvfrom, 6, fd, buf, n, flags, NULL, NULL); }
int _DkVirtualMemoryFree (void * addr, int size) { int ret = INLINE_SYSCALL(munmap, 2, addr, size); return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : 0; }
int __new_shmctl (int shmid, int cmd, struct shmid_ds *buf) { #if __ASSUME_IPC64 > 0 return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0, CHECK_1 (buf)); #else switch (cmd) { case SHM_STAT: case IPC_STAT: case IPC_SET: #if __WORDSIZE != 32 case IPC_INFO: #endif break; default: return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, CHECK_1 (buf)); } { int save_errno = errno, result; union { struct __old_shmid_ds ds; struct __old_shminfo info; } old; /* Unfortunately there is no way how to find out for sure whether we should use old or new shmctl. */ result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0, CHECK_1 (buf)); if (result != -1 || errno != EINVAL) return result; __set_errno(save_errno); if (cmd == IPC_SET) { old.ds.shm_perm.uid = buf->shm_perm.uid; old.ds.shm_perm.gid = buf->shm_perm.gid; old.ds.shm_perm.mode = buf->shm_perm.mode; if (old.ds.shm_perm.uid != buf->shm_perm.uid || old.ds.shm_perm.gid != buf->shm_perm.gid) { __set_errno (EINVAL); return -1; } } result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, __ptrvalue (&old.ds)); if (result != -1 && (cmd == SHM_STAT || cmd == IPC_STAT)) { memset(buf, 0, sizeof(*buf)); buf->shm_perm.__key = old.ds.shm_perm.__key; buf->shm_perm.uid = old.ds.shm_perm.uid; buf->shm_perm.gid = old.ds.shm_perm.gid; buf->shm_perm.cuid = old.ds.shm_perm.cuid; buf->shm_perm.cgid = old.ds.shm_perm.cgid; buf->shm_perm.mode = old.ds.shm_perm.mode; buf->shm_perm.__seq = old.ds.shm_perm.__seq; buf->shm_atime = old.ds.shm_atime; buf->shm_dtime = old.ds.shm_dtime; buf->shm_ctime = old.ds.shm_ctime; buf->shm_segsz = old.ds.shm_segsz; buf->shm_nattch = old.ds.shm_nattch; buf->shm_cpid = old.ds.shm_cpid; buf->shm_lpid = old.ds.shm_lpid; } #if __WORDSIZE != 32 else if (result != -1 && cmd == IPC_INFO) { struct shminfo *i = (struct shminfo *)buf; memset(i, 0, sizeof(*i)); i->shmmax = old.info.shmmax; i->shmmin = old.info.shmmin; i->shmmni = old.info.shmmni; i->shmseg = old.info.shmseg; i->shmall = old.info.shmall; } #endif return result; } #endif }
pid_t __libc_fork (void) { pid_t pid; struct used_handler { struct fork_handler *handler; struct used_handler *next; } *allp = NULL; /* Run all the registered preparation handlers. In reverse order. While doing this we build up a list of all the entries. */ struct fork_handler *runp; while ((runp = __fork_handlers) != NULL) { /* Make sure we read from the current RUNP pointer. */ atomic_full_barrier (); unsigned int oldval = runp->refcntr; if (oldval == 0) /* This means some other thread removed the list just after the pointer has been loaded. Try again. Either the list is empty or we can retry it. */ continue; /* Bump the reference counter. */ if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr, oldval + 1, oldval)) /* The value changed, try again. */ continue; /* We bumped the reference counter for the first entry in the list. That means that none of the following entries will just go away. The unloading code works in the order of the list. While executing the registered handlers we are building a list of all the entries so that we can go backward later on. */ while (1) { /* Execute the handler if there is one. */ if (runp->prepare_handler != NULL) runp->prepare_handler (); /* Create a new element for the list. */ struct used_handler *newp = (struct used_handler *) alloca (sizeof (*newp)); newp->handler = runp; newp->next = allp; allp = newp; /* Advance to the next handler. */ runp = runp->next; if (runp == NULL) break; /* Bump the reference counter for the next entry. */ atomic_increment (&runp->refcntr); } /* We are done. */ break; } __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); #ifndef NDEBUG pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); #endif /* We need to prevent the getpid() code to update the PID field so that, if a signal arrives in the child very early and the signal handler uses getpid(), the value returned is correct. */ pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); THREAD_SETMEM (THREAD_SELF, pid, -parentpid); #ifdef ARCH_FORK pid = ARCH_FORK (); #else # error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used" pid = INLINE_SYSCALL (fork, 0); #endif if (pid == 0) { struct pthread *self = THREAD_SELF; assert (THREAD_GETMEM (self, tid) != ppid); if (__fork_generation_pointer != NULL) *__fork_generation_pointer += 4; /* Adjust the PID field for the new process. */ THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); #if HP_TIMING_AVAIL /* The CPU clock of the thread and process have to be set to zero. */ hp_timing_t now; HP_TIMING_NOW (now); THREAD_SETMEM (self, cpuclock_offset, now); GL(dl_cpuclock_offset) = now; #endif /* Reset the file list. These are recursive mutexes. */ fresetlockfiles (); /* Reset locks in the I/O code. */ STDIO_INIT_MUTEX(_stdio_openlist_add_lock); /* XXX reset any locks in dynamic loader */ /* Run the handlers registered for the child. */ while (allp != NULL) { if (allp->handler->child_handler != NULL) allp->handler->child_handler (); /* Note that we do not have to wake any possible waiter. This is the only thread in the new process. The count may have been bumped up by other threads doing a fork. We reset it to 1, to avoid waiting for non-existing thread(s) to release the count. */ allp->handler->refcntr = 1; /* XXX We could at this point look through the object pool and mark all objects not on the __fork_handlers list as unused. This is necessary in case the fork() happened while another thread called dlclose() and that call had to create a new list. */ allp = allp->next; } /* Initialize the fork lock. */ __fork_lock = LLL_LOCK_INITIALIZER; } else { assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); /* Restore the PID value. */ THREAD_SETMEM (THREAD_SELF, pid, parentpid); /* We execute this even if the 'fork' call failed. */ __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); /* Run the handlers registered for the parent. */ while (allp != NULL) { if (allp->handler->parent_handler != NULL) allp->handler->parent_handler (); if (atomic_decrement_and_test (&allp->handler->refcntr) && allp->handler->need_signal) lll_futex_wake (allp->handler->refcntr, 1, LLL_PRIVATE); allp = allp->next; } } return pid; }
time_t time(time_t *tp) { return INLINE_SYSCALL(time, 1, tp); }
int sys$testcode(void) { return INLINE_SYSCALL($setprn,0); }
int __libc_statfs(const char *path, struct statfs *buf) { int err = INLINE_SYSCALL(statfs64, 3, path, sizeof(*buf), buf); return err; }
int putmsg (int fildes, const struct strbuf *ctlptr, const struct strbuf *dataptr, int flags) { return INLINE_SYSCALL (putpmsg, 5, fildes, ctlptr, dataptr, -1, flags); }
/* Remove the link named NAME. */ int __unlink (const char *name) { return INLINE_SYSCALL (unlinkat, 3, AT_FDCWD, name, 0); }
/* Compiling under older kernels. */ int __chown_is_lchown (const char *file, uid_t owner, gid_t group) { return INLINE_SYSCALL (chown, 3, CHECK_STRING (file), owner, group); }
void _DkPrintConsole (const void * buf, int size) { INLINE_SYSCALL(write, 3, 2, buf, size); }
/* Make a link to FROM called TO. */ int __link (const char *from, const char *to) { return INLINE_SYSCALL (linkat, 5, AT_FDCWD, from, AT_FDCWD, to, 0); }
/* internally to wait for one object. Also used as a shortcut to wait on events and semaphores */ static int _DkObjectWaitOne (PAL_HANDLE handle, int timeout) { /* only for all these handle which has a file descriptor, or a eventfd. events and semaphores will skip this part */ if (handle->__in.flags & HAS_FDS) { struct pollfd fds[MAX_FDS]; int off[MAX_FDS]; int nfds = 0; for (int i = 0 ; i < MAX_FDS ; i++) { int events = 0; if ((handle->__in.flags & RFD(i)) && !(handle->__in.flags & ERROR(i))) events |= POLLIN; if ((handle->__in.flags & WFD(i)) && !(handle->__in.flags & WRITEABLE(i)) && !(handle->__in.flags & ERROR(i))) events |= POLLOUT; if (events) { fds[nfds].fd = handle->__in.fds[i]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; off[nfds] = i; nfds++; } } if (!nfds) return -PAL_ERROR_TRYAGAIN; int ret = INLINE_SYSCALL(poll, 3, &fds, nfds, timeout ? timeout : -1); if (IS_ERR(ret)) switch (ERRNO(ret)) { case EINTR: return -PAL_ERROR_INTERRUPTED; default: return unix_to_pal_error(ERRNO(ret)); } if (!ret) return -PAL_ERROR_TRYAGAIN; for (int i = 0 ; i < nfds ; i++) { if (!fds[i].revents) continue; if (fds[i].revents & POLLOUT) handle->__in.flags |= WRITEABLE(off[i]); if (fds[i].revents & (POLLHUP|POLLERR)) handle->__in.flags |= ERROR(off[i]); } return 0; } const struct handle_ops * ops = HANDLE_OPS(handle); if (!ops->wait) return -PAL_ERROR_NOTSUPPORT; return ops->wait(handle, timeout); }