/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * shim_fcntl.c * * Implementation of system call "fcntl". */ #include #include #include #include #include #include #include #include #include #include int shim_do_fcntl (int fd, int cmd, unsigned long arg) { struct shim_handle_map * handle_map = get_cur_handle_map(NULL); int flags; int ret = -ENOSYS; struct shim_handle * hdl = get_fd_handle(fd, &flags, handle_map); if (!hdl) return -EBADF; switch (cmd) { /* F_DUPFD (long) * Find the lowest numbered available file descriptor greater than or * equal to arg and make it be a copy of fd. This is different from * dup2(2), which uses exactly the descriptor specified. * On success, the new descriptor is returned. */ case F_DUPFD: { int vfd = arg; while(1) { if (set_new_fd_handle_by_fd(vfd, hdl, flags, handle_map) == vfd) break; vfd++; }; ret = vfd; break; } /* F_DUPFD_CLOEXEC (long; since Linux 2.6.24) * As for F_DUPFD, but additionally set the close-on-exec flag for * the duplicate descriptor. Specifying this flag permits a * program to avoid an additional fcntl() F_SETFD operation to set * the FD_CLOEXEC flag. For an explanation of why this flag is * useful, see the description of O_CLOEXEC in open(2). */ case F_DUPFD_CLOEXEC: { int vfd = arg; flags |= FD_CLOEXEC; while(1) { if (set_new_fd_handle_by_fd(vfd, hdl, flags, handle_map) == vfd) break; vfd++; }; ret = vfd; break; } /* File descriptor flags * The following commands manipulate the flags associated with a file * descriptor. Currently, only one such flag is defined: FD_CLOEXEC, * the close-on-exec flag. If the FD_CLOEXEC bit is 0, the file * descriptor will * remain open across an execve(2), otherwise it will be closed. * * F_GETFD (void) * Read the file descriptor flags; arg is ignored. */ case F_GETFD: ret = flags & FD_CLOEXEC; break; /* F_SETFD (long) * Set the file descriptor flags to the value specified by arg. */ case F_SETFD: lock(handle_map->lock); if (HANDLE_ALLOCATED(handle_map->map[fd])) handle_map->map[fd]->flags = arg & FD_CLOEXEC; unlock(handle_map->lock); ret = 0; break; /* File status flags * Each open file description has certain associated status flags, * initialized by open(2) and possibly modified by fcntl(). * Duplicated file descriptors (made with dup(2), fcntl(F_DUPFD), * fork(2), etc.) refer to the same open file description, and thus * share the same file status flags. * The file status flags and their semantics are described in open(2). * * F_GETFL (void) * Read the file status flags; arg is ignored. */ case F_GETFL: lock(hdl->lock); flags = hdl->flags; unlock(hdl->lock); ret = flags; break; /* F_SETFL (long) * Set the file status flags to the value specified by arg. File * access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags * (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. On * Linux this command can only change the O_APPEND, O_DIRECT, * O_NOATIME, and O_NONBLOCK flags. */ #define FCNTL_SETFL_MASK (O_APPEND|O_NONBLOCK) case F_SETFL: lock(hdl->lock); if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->setflags) hdl->fs->fs_ops->setflags(hdl, arg & FCNTL_SETFL_MASK); hdl->flags = (hdl->flags & ~FCNTL_SETFL_MASK) | (arg & FCNTL_SETFL_MASK); unlock(hdl->lock); ret = 0; break; /* Advisory locking * F_GETLK, F_SETLK and F_SETLKW are used to acquire, release, and * test for the existence of record locks (also known as file-segment * or file-region locks). The third argument, lock, is a pointer to * a structure that has at least the following fields (in unspecified * order). * * F_SETLK (struct flock *) * Acquire a lock (when l_type is F_RDLCK or F_WRLCK) or release a * lock (when l_type is F_UNLCK) on the bytes specified by the * l_whence, l_start, and l_len fields of lock. If a conflicting lock * is held by another process, this call returns -1 and sets errno to * EACCES or EAGAIN. */ case F_SETLK: ret = -ENOSYS; break; /* F_SETLKW (struct flock *) * As for F_SETLK, but if a conflicting lock is held on the file, * then wait for that lock to be released. If a signal is caught while * waiting, then the call is interrupted and (after the signal handler * has returned) returns immediately (with return value -1 and errno * set to EINTR; see signal(7)). */ case F_SETLKW: ret = -ENOSYS; break; /* F_GETLK (struct flock *) * On input to this call, lock describes a lock we would like to place * on the file. If the lock could be placed, fcntl() does not * actually place it, but returns F_UNLCK in the l_type field of lock * and leaves the other fields of the structure unchanged. If one or * more incompatible locks would prevent this lock being placed, then * fcntl() returns details about one of these locks in the l_type, * l_whence, l_start, and l_len fields of lock and sets l_pid to be * the PID of the process holding that lock. */ case F_GETLK: ret = -ENOSYS; break; /* F_SETOWN (int) * Set the process ID or process group ID that will receive SIGIO * and SIGURG signals for events on file descriptor fd to the ID given * in arg. A process ID is specified as a positive value; a process * group ID is specified as a negative value. Most commonly, the * calling process specifies itself as the owner (that is, arg is * specified as getpid(2)). */ case F_SETOWN: ret = 0; /* XXX: DUMMY for now */ break; } put_handle(hdl); return ret; }