/* Write up to N chars from BUF to COOKIE. Return how many chars were written or -1 for error. */ static ssize_t writeio (void *cookie, const char *buf, size_t n) { mach_msg_type_number_t wrote; error_t err; if (err = __io_write ((io_t) cookie, buf, n, -1, &wrote)) return __hurd_fail (err); return wrote; }
/* Return the number of available physical pages */ long int __get_avphys_pages () { vm_statistics_data_t vs; kern_return_t err; err = __vm_statistics (__mach_task_self (), &vs); if (err) return __hurd_fail (err); return vs.free_count; }
ssize_t setxattr (const char *path, const char *name, const void *value, size_t size, int flags) { error_t err; file_t port = __file_name_lookup (path, 0, 0); if (port == MACH_PORT_NULL) return -1; err = _hurd_xattr_set (port, name, value, size, flags); __mach_port_deallocate (__mach_task_self (), port); return __hurd_fail (err); }
/* Move COOKIE's file position *POS bytes, according to WHENCE. The current file position is stored in *POS. Returns zero if successful, nonzero if not. */ static int seekio (void *cookie, #ifdef USE_IN_LIBIO _IO_off64_t *pos, #else fpos_t *pos, #endif int whence) { error_t err = __io_seek ((file_t) cookie, *pos, whence, pos); return err ? __hurd_fail (err) : 0; }
int fchmodat (int fd, const char *file, mode_t mode, int flag) { error_t err; file_t port = __file_name_lookup_at (fd, flag, file, 0, 0); if (port == MACH_PORT_NULL) return -1; err = __file_chmod (port, mode); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
/* Make PATH be the root directory (the starting point for absolute paths). Note that while on traditional UNIX systems this call is restricted to the super-user, it isn't on the Hurd. */ int chroot (const char *path) { const char *lookup; size_t len; file_t dir, root; error_t err; /* Append trailing "/." to directory name to force ENOTDIR if it's not a directory and EACCES if we don't have search permission. */ len = strlen (path); if (len >= 2 && path[len - 2] == '/' && path[len - 1] == '.') lookup = path; else if (len == 0) /* Special-case empty file name according to POSIX. */ return __hurd_fail (ENOENT); else { char *n = alloca (len + 3); memcpy (n, path, len); n[len] = '/'; n[len + 1] = '.'; n[len + 2] = '\0'; lookup = n; } dir = __file_name_lookup (lookup, 0, 0); if (dir == MACH_PORT_NULL) return -1; /* Prevent going through DIR's .. */ err = __file_reparent (dir, MACH_PORT_NULL, &root); __mach_port_deallocate (__mach_task_self (), dir); if (err) return __hurd_fail (err); _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], root); return 0; }
/* Change the owner and group of FILE; if it's a link, do the link and not the target. */ int __lchown (const char *file, uid_t owner, gid_t group) { error_t err; file_t port = __file_name_lookup (file, O_NOLINK, 0); if (port == MACH_PORT_NULL) return -1; err = __file_chown (port, owner, group); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
/* Change the protections of FILE to MODE. */ int lchmod (const char *file, mode_t mode) { error_t err; file_t port = __file_name_lookup (file, O_NOLINK, 0); if (port == MACH_PORT_NULL) return -1; err = __file_chmod (port, mode); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
int getloadavg (double loadavg[], int nelem) { host_load_info_data_t info; mach_msg_type_number_t size = HOST_LOAD_INFO_COUNT; error_t err; int i; err = __host_info (__mach_host_self (), HOST_LOAD_INFO, (host_info_t) &info, &size); if (err) return __hurd_fail (err); if (size < HOST_LOAD_INFO_COUNT) return __hurd_fail (EGRATUITOUS); if (nelem > 3) nelem = 3; for (i = 0; i < nelem; ++i) loadavg[i] = (double) info.avenrun[i] / (double) LOAD_SCALE; return i; }
/* XXX shouldn't this be __chflags? */ int chflags (const char *file, int flags) { error_t err; file_t port = __file_name_lookup (file, 0, 0); if (port == MACH_PORT_NULL) return -1; err = __file_chflags (port, flags); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
/* Get information about the file descriptor FD in BUF. */ int __fxstat64 (int vers, int fd, struct stat64 *buf) { error_t err; if (vers != _STAT_VER) return __hurd_fail (EINVAL); if (err = HURD_DPORT_USE (fd, __io_stat (port, buf))) return __hurd_dfail (fd, err); return 0; }
file_t __file_name_lookup_at (int fd, int at_flags, const char *file_name, int flags, mode_t mode) { error_t err; file_t result; int empty = at_flags & AT_EMPTY_PATH; at_flags &= ~AT_EMPTY_PATH; err = __hurd_at_flags (&at_flags, &flags); if (err) return (__hurd_fail (err), MACH_PORT_NULL); if (fd == AT_FDCWD || file_name[0] == '/') return __file_name_lookup (file_name, flags, mode); if (empty != 0 && file_name[0] == '\0') { enum retry_type doretry; char retryname[1024]; /* XXX string_t LOSES! */ err = HURD_DPORT_USE (fd, __dir_lookup (port, "", flags, mode, &doretry, retryname, &result)); if (! err) err = __hurd_file_name_lookup_retry (&_hurd_ports_use, &__getdport, NULL, doretry, retryname, flags, mode, &result); return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result; } file_t startdir; error_t use_init_port (int which, error_t (*operate) (mach_port_t)) { return (which == INIT_PORT_CWDIR ? (*operate) (startdir) : _hurd_ports_use (which, operate)); } err = HURD_DPORT_USE (fd, (startdir = port, __hurd_file_name_lookup (&use_init_port, &__getdport, NULL, file_name, flags, mode & ~_hurd_umask, &result))); return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result; }
/* Store the CPU time used by this process and all its dead children (and their dead children) in BUFFER. Return the elapsed real time, or (clock_t) -1 for errors. All times are in CLK_TCKths of a second. */ clock_t __times (struct tms *tms) { struct task_basic_info bi; struct task_thread_times_info tti; mach_msg_type_number_t count; union { time_value_t tvt; struct timeval tv; } now; error_t err; count = TASK_BASIC_INFO_COUNT; err = __task_info (__mach_task_self (), TASK_BASIC_INFO, (task_info_t) &bi, &count); if (err) return __hurd_fail (err); count = TASK_THREAD_TIMES_INFO_COUNT; err = __task_info (__mach_task_self (), TASK_THREAD_TIMES_INFO, (task_info_t) &tti, &count); if (err) return __hurd_fail (err); tms->tms_utime = (clock_from_time_value (&bi.user_time) + clock_from_time_value (&tti.user_time)); tms->tms_stime = (clock_from_time_value (&bi.system_time) + clock_from_time_value (&tti.system_time)); /* XXX This can't be implemented until getrusage(RUSAGE_CHILDREN) can be. */ tms->tms_cutime = tms->tms_cstime = 0; if (__gettimeofday (&now.tv, NULL) < 0) return -1; return (clock_from_time_value (&now.tvt) - clock_from_time_value (&bi.creation_time)); }
file_t __file_name_lookup_at (int fd, int at_flags, const char *file_name, int flags, mode_t mode) { error_t err; file_t result; if ((at_flags & AT_SYMLINK_FOLLOW) && (at_flags & AT_SYMLINK_NOFOLLOW)) return (__hurd_fail (EINVAL), MACH_PORT_NULL); flags |= (at_flags & AT_SYMLINK_NOFOLLOW) ? O_NOLINK : 0; at_flags &= ~AT_SYMLINK_NOFOLLOW; if (at_flags & AT_SYMLINK_FOLLOW) flags &= ~O_NOLINK; at_flags &= ~AT_SYMLINK_FOLLOW; if (at_flags != 0) return (__hurd_fail (EINVAL), MACH_PORT_NULL); if (fd == AT_FDCWD || file_name[0] == '/') return __file_name_lookup (file_name, flags, mode); file_t startdir; error_t use_init_port (int which, error_t (*operate) (mach_port_t)) { return (which == INIT_PORT_CWDIR ? (*operate) (startdir) : _hurd_ports_use (which, operate)); } err = HURD_DPORT_USE (fd, (startdir = port, __hurd_file_name_lookup (&use_init_port, &__getdport, NULL, file_name, flags, mode & ~_hurd_umask, &result))); return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result; }
/* Remove the directory FILE_NAME. */ int __rmdir (const char *file_name) { error_t err; const char *name; file_t parent = __directory_name_split (file_name, (char **) &name); if (parent == MACH_PORT_NULL) return -1; err = __dir_rmdir (parent, name); __mach_port_deallocate (__mach_task_self (), parent); if (err) return __hurd_fail (err); return 0; }
pid_t getsid (pid_t pid) { error_t err; pid_t sid; if (pid == 0) pid = _hurd_pid; err = __USEPORT (PROC, __proc_getsid (port, pid, &sid)); if (err) return (pid_t) __hurd_fail (err); return sid; }
/* Fetch a thread state structure from PID and store it at ADDR. */ int get_regs (int flavor, mach_msg_type_number_t count) { error_t err; task_t task = __pid2task (pid); thread_t thread; if (task == MACH_PORT_NULL) return -1; err = fetch_user_thread (task, &thread); __mach_port_deallocate (__mach_task_self (), task); if (!err) err = __thread_get_state (thread, flavor, addr, &count); __mach_port_deallocate (__mach_task_self (), thread); return err ? __hurd_fail (err) : 0; }
/* Get file-specific information about FILE. */ long int __pathconf (const char *file, int name) { error_t err; int value; /* RPC returns an `int', not a `long int'. */ file_t port = __file_name_lookup (file, 0, 0); if (port == MACH_PORT_NULL) return -1L; err = __io_pathconf (port, name, &value); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err), -1L; return value; }
/* Return information about the filesystem on which FILE resides. */ int __statfs64 (const char *file, struct statfs64 *buf) { error_t err; file_t port; port = __file_name_lookup (file, 0, 0); if (port == MACH_PORT_NULL) return -1; err = __file_statfs (port, buf); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
/* Adjust the current time of day by the amount in DELTA. If OLDDELTA is not NULL, it is filled in with the amount of time adjustment remaining to be done from the last `__adjtime' call. This call is restricted to the super-user. */ int __adjtime (const struct timeval *delta, struct timeval *olddelta) { error_t err; mach_port_t hostpriv; hostpriv = __pid2task (-1); if (hostpriv == MACH_PORT_NULL) return -1; err = __host_adjust_time (hostpriv, delta, olddelta); __mach_port_deallocate (__mach_task_self (), hostpriv); if (err) return __hurd_fail (err); return 0; }
int revoke (const char *file_name) { error_t err; file_t file = __file_name_lookup (file_name, 0, 0); if (file == MACH_PORT_NULL) return -1; err = __io_revoke (file); __mach_port_deallocate (__mach_task_self (), file); if (err) return __hurd_fail (err); return 0; }
/* Truncate FILE_NAME to LENGTH bytes. */ int __truncate64 (const char *file_name, off64_t length) { error_t err; file_t file = __file_name_lookup (file_name, O_WRITE, 0); if (file == MACH_PORT_NULL) return -1; err = __file_set_size (file, length); __mach_port_deallocate (__mach_task_self (), file); if (err) return __hurd_fail (err); return 0; }
/* Change the access time of FILE to TVP[0] and the modification time of FILE to TVP[1]. */ int __lutimes (const char *file, const struct timeval tvp[2]) { error_t err; file_t port; port = __file_name_lookup (file, O_NOLINK, 0); if (port == MACH_PORT_NULL) return -1; err = hurd_futimes (port, tvp); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
/* Replace the current process, executing FILE_NAME with arguments ARGV and environment ENVP. ARGV and ENVP are terminated by NULL pointers. */ int __execve (const char *file_name, char *const argv[], char *const envp[]) { error_t err; file_t file = __file_name_lookup (file_name, O_EXEC, 0); if (file == MACH_PORT_NULL) return -1; /* Hopefully this will not return. */ err = _hurd_exec (__mach_task_self (), file, argv, envp); /* Oh well. Might as well be tidy. */ __mach_port_deallocate (__mach_task_self (), file); return __hurd_fail (err); }
/* Remove the link named NAME. */ int __unlink (const char *name) { error_t err; file_t dir; const char *file; dir = __directory_name_split (name, (char **) &file); if (dir == MACH_PORT_NULL) return -1; err = __dir_unlink (dir, file); __mach_port_deallocate (__mach_task_self (), dir); if (err) return __hurd_fail (err); return 0; }
/* Create a new session with the calling process as its leader. The process group IDs of the session and the calling process are set to the process ID of the calling process, which is returned. */ pid_t __setsid (void) { error_t err; unsigned int stamp; HURD_CRITICAL_BEGIN; __mutex_lock (&_hurd_dtable_lock); stamp = _hurd_pids_changed_stamp; /* Atomic fetch. */ /* Tell the proc server we want to start a new session. */ err = __USEPORT (PROC, __proc_setsid (port)); if (err) __mutex_unlock (&_hurd_dtable_lock); else { /* Punt our current ctty, and update the dtable accordingly. We hold the dtable lock from before the proc_setsid call through clearing the cttyid port and processing the dtable, so that we can be sure that it's all done by the time the signal thread processes the pgrp change notification. */ _hurd_locked_install_cttyid (MACH_PORT_NULL); /* Synchronize with the signal thread to make sure we have received and processed proc_newids before returning to the user. This is necessary to ensure that _hurd_pgrp (and thus the value returned by `getpgrp ()' in other threads) has been updated before we return. */ while (_hurd_pids_changed_stamp == stamp) { #ifdef noteven /* XXX we have no need for a mutex, but cthreads demands one. */ __condition_wait (&_hurd_pids_changed_sync, NULL); #else __swtch_pri (0); #endif } } HURD_CRITICAL_END; return err ? __hurd_fail (err) : _hurd_pgrp; }
/* Make a link to FROM called TO. */ int __symlink (const char *from, const char *to) { error_t err; file_t dir, node; char *name; const size_t len = strlen (from) + 1; char buf[sizeof (_HURD_SYMLINK) + len]; /* A symlink is a file whose translator is "/hurd/symlink\0target\0". */ memcpy (buf, _HURD_SYMLINK, sizeof (_HURD_SYMLINK)); memcpy (&buf[sizeof (_HURD_SYMLINK)], from, len); dir = __file_name_split (to, &name); if (dir == MACH_PORT_NULL) return -1; /* Create a new, unlinked node in the target directory. */ err = __dir_mkfile (dir, O_WRITE, 0777 & ~_hurd_umask, &node); if (! err) { /* Set the node's translator to make it a symlink. */ err = __file_set_translator (node, FS_TRANS_EXCL|FS_TRANS_SET, FS_TRANS_EXCL|FS_TRANS_SET, 0, buf, sizeof (_HURD_SYMLINK) + len, MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); if (! err) /* Link the node, now a valid symlink, into the target directory. */ err = __dir_link (dir, node, name, 1); __mach_port_deallocate (__mach_task_self (), node); } __mach_port_deallocate (__mach_task_self (), dir); if (err) return __hurd_fail (err); return 0; }
int mlock (const void *addr, size_t len) { mach_port_t host; vm_address_t page; error_t err; err = __get_privileged_ports (&host, NULL); if (err) host = __mach_host_self(); page = trunc_page ((vm_address_t) addr); len = round_page ((vm_address_t) addr + len) - page; err = __vm_wire (host, __mach_task_self (), page, len, VM_PROT_READ); if (host != __mach_host_self()) __mach_port_deallocate (__mach_task_self (), host); return err ? __hurd_fail (err) : 0; }
/* Read up to N chars into BUF from COOKIE. Return how many chars were read, 0 for EOF or -1 for error. */ static ssize_t readio (void *cookie, char *buf, size_t n) { mach_msg_type_number_t nread; error_t err; char *bufp = buf; nread = n; if (err = __io_read ((io_t) cookie, &bufp, &nread, -1, n)) return __hurd_fail (err); if (bufp != buf) { memcpy (buf, bufp, nread); __vm_deallocate (__mach_task_self (), (vm_address_t) bufp, (vm_size_t) nread); } return nread; }
int geteuids (int n, uid_t *uidset) { error_t err; int nuids; void *crit; crit = _hurd_critical_section_lock (); __mutex_lock (&_hurd_id.lock); if (err = _hurd_check_ids ()) { __mutex_unlock (&_hurd_id.lock); _hurd_critical_section_unlock (crit); return __hurd_fail (err); } nuids = _hurd_id.gen.nuids; if (n != 0) { /* Copy the uids onto stack storage and then release the idlock. */ uid_t uids[nuids]; memcpy (uids, _hurd_id.gen.uids, sizeof (uids)); __mutex_unlock (&_hurd_id.lock); _hurd_critical_section_unlock (crit); /* Now that the lock is released, we can safely copy the uid set into the user's array, which might fault. */ if (nuids > n) nuids = n; memcpy (uidset, uids, nuids * sizeof (uid_t)); } else { __mutex_unlock (&_hurd_id.lock); _hurd_critical_section_unlock (crit); } return nuids; }