HelenOS sources

root/uspace/lib/posix/src/unistd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sleep
  2. getlogin
  3. getlogin_r
  4. isatty
  5. getcwd
  6. chdir
  7. getpagesize
  8. getpid
  9. getuid
  10. getgid
  11. close
  12. read
  13. write
  14. _lseek
  15. _lseek64
  16. lseek64
  17. lseek
  18. fsync
  19. ftruncate
  20. ftruncate64
  21. rmdir
  22. unlink
  23. dup
  24. dup2
  25. access
  26. sysconf
  27. pathconf
  28. fork
  29. execv
  30. execvp
  31. pipe
  32. alarm

/*
 * Copyright (c) 2011 Jiri Zarevucky
 * Copyright (c) 2011 Petr Koupy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup libposix
 * @{
 */
/** @file Miscellaneous standard definitions.
 */

#define _LARGEFILE64_SOURCE
#undef _FILE_OFFSET_BITS

#include "internal/common.h"
#include <unistd.h>

#include <errno.h>

#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>

#include <fibril.h>
#include <task.h>
#include <stats.h>
#include <stdlib.h>
#include <vfs/vfs.h>

#include <libarch/config.h>

// FIXME: replace with a hash table
aoff64_t posix_pos[VFS_MAX_OPEN_FILES];

/* Array of environment variable strings (NAME=VALUE). */
char **environ = NULL;

/**
 * Sleep for the specified number of seconds.
 *
 * Note that POSIX allows this call to be interrupted and then the return
 * value represents remaining seconds for the sleep. HelenOS does not offer
 * such functionality and thus always the whole sleep is taken.
 *
 * @param seconds Number of seconds to sleep.
 * @return Always 0 on HelenOS.
 */
unsigned int sleep(unsigned int seconds)
{
        fibril_sleep(seconds);
        return 0;
}

/**
 * Get current user name.
 *
 * @return User name (static) string or NULL if not found.
 */
char *getlogin(void)
{
        /* There is currently no support for user accounts in HelenOS. */
        return (char *) "user";
}

/**
 * Get current user name.
 *
 * @param name Pointer to a user supplied buffer.
 * @param namesize Length of the buffer.
 * @return Zero on success, error code otherwise.
 */
int getlogin_r(char *name, size_t namesize)
{
        /* There is currently no support for user accounts in HelenOS. */
        if (namesize >= 5) {
                strcpy(name, (char *) "user");
                return 0;
        } else {
                errno = ERANGE;
                return -1;
        }
}

/**
 * Test whether open file descriptor is associated with a terminal.
 *
 * @param fd Open file descriptor to test.
 * @return Boolean result of the test.
 */
int isatty(int fd)
{
        // TODO
        /*
         * Always returns false, because there is no easy way to find
         * out under HelenOS.
         */
        return 0;
}

/**
 * Get the pathname of the current working directory.
 *
 * @param buf Buffer into which the pathname shall be put.
 * @param size Size of the buffer.
 * @return Buffer pointer on success, NULL on failure.
 */
char *getcwd(char *buf, size_t size)
{
        if (failed(vfs_cwd_get(buf, size)))
                return NULL;
        return buf;
}

/**
 * Change the current working directory.
 *
 * @param path New working directory.
 */
int chdir(const char *path)
{
        if (failed(vfs_cwd_set(path)))
                return -1;
        return 0;
}

/**
 * Determine the page size of the current run of the process.
 *
 * @return Page size of the process.
 */
int getpagesize(void)
{
        return PAGE_SIZE;
}

/**
 * Get the process ID of the calling process.
 *
 * @return Process ID.
 */
pid_t getpid(void)
{
        return task_get_id();
}

/**
 * Get the real user ID of the calling process.
 *
 * @return User ID.
 */
uid_t getuid(void)
{
        /* There is currently no support for user accounts in HelenOS. */
        return 0;
}

/**
 * Get the real group ID of the calling process.
 *
 * @return Group ID.
 */
gid_t getgid(void)
{
        /* There is currently no support for user accounts in HelenOS. */
        return 0;
}

/**
 * Close a file.
 *
 * @param fildes File descriptor of the opened file.
 * @return 0 on success, -1 on error.
 */
int close(int fildes)
{
        posix_pos[fildes] = 0;
        if (failed(vfs_put(fildes)))
                return -1;
        else
                return 0;
}

/**
 * Read from a file.
 *
 * @param fildes File descriptor of the opened file.
 * @param buf Buffer to which the read bytes shall be stored.
 * @param nbyte Upper limit on the number of read bytes.
 * @return Number of read bytes on success, -1 otherwise.
 */
ssize_t read(int fildes, void *buf, size_t nbyte)
{
        size_t nread;
        if (failed(vfs_read(fildes, &posix_pos[fildes], buf, nbyte, &nread)))
                return -1;
        return (ssize_t) nread;
}

/**
 * Write to a file.
 *
 * @param fildes File descriptor of the opened file.
 * @param buf Buffer to write.
 * @param nbyte Size of the buffer.
 * @return Number of written bytes on success, -1 otherwise.
 */
ssize_t write(int fildes, const void *buf, size_t nbyte)
{
        size_t nwr;
        if (failed(vfs_write(fildes, &posix_pos[fildes], buf, nbyte, &nwr)))
                return -1;
        return nwr;
}

static off64_t _lseek(int fildes, off64_t offset, off64_t max_pos, int whence)
{
        vfs_stat_t st;
        off64_t new_pos;

        switch (whence) {
        case SEEK_SET:
                new_pos = offset;
                break;
        case SEEK_CUR:
                if (__builtin_add_overflow(posix_pos[fildes], offset, &new_pos)) {
                        errno = EOVERFLOW;
                        return -1;
                }
                break;
        case SEEK_END:
                if (failed(vfs_stat(fildes, &st)))
                        return -1;

                if (__builtin_add_overflow(st.size, offset, &new_pos)) {
                        errno = EOVERFLOW;
                        return -1;
                }
                break;
        default:
                errno = EINVAL;
                return -1;
        }

        if (new_pos < 0) {
                errno = EINVAL;
                return -1;
        }

        if (new_pos > max_pos) {
                /* The resulting file offset is too large for the interface. */
                errno = EOVERFLOW;
                return -1;
        }

        posix_pos[fildes] = new_pos;
        return new_pos;
}

static off64_t _lseek64(int fildes, off64_t offset, int whence)
{
        return _lseek(fildes, offset, INT64_MAX, whence);
}

off64_t lseek64(int fildes, off64_t offset, int whence)
{
        return _lseek64(fildes, offset, whence);
}

/**
 * Reposition read/write file offset
 *
 * @param fildes File descriptor of the opened file.
 * @param offset New offset in the file.
 * @param whence The position from which the offset argument is specified.
 * @return Upon successful completion, returns the resulting offset
 *         as measured in bytes from the beginning of the file, -1 otherwise.
 */
off_t lseek(int fildes, off_t offset, int whence)
{
#if LONG_MAX == INT_MAX
        return _lseek(fildes, offset, LONG_MAX, whence);
#else
        return _lseek64(fildes, offset, whence);
#endif
}

/**
 * Requests outstanding data to be written to the underlying storage device.
 *
 * @param fildes File descriptor of the opened file.
 * @return Zero on success, -1 otherwise.
 */
int fsync(int fildes)
{
        if (failed(vfs_sync(fildes)))
                return -1;
        else
                return 0;
}

/**
 * Truncate a file to a specified length.
 *
 * @param fildes File descriptor of the opened file.
 * @param length New length of the file.
 * @return Zero on success, -1 otherwise.
 */
int ftruncate(int fildes, off_t length)
{
        return ftruncate64(fildes, length);
}

int ftruncate64(int fildes, off64_t length)
{
        if (failed(vfs_resize(fildes, (aoff64_t) length)))
                return -1;
        else
                return 0;
}

/**
 * Remove a directory.
 *
 * @param path Directory pathname.
 * @return Zero on success, -1 otherwise.
 */
int rmdir(const char *path)
{
        if (failed(vfs_unlink_path(path)))
                return -1;
        else
                return 0;
}

/**
 * Remove a link to a file.
 *
 * @param path File pathname.
 * @return Zero on success, -1 otherwise.
 */
int unlink(const char *path)
{
        if (failed(vfs_unlink_path(path)))
                return -1;
        else
                return 0;
}

/**
 * Duplicate an open file descriptor.
 *
 * @param fildes File descriptor to be duplicated.
 * @return On success, new file descriptor for the same file, otherwise -1.
 */
int dup(int fildes)
{
        return fcntl(fildes, F_DUPFD, 0);
}

/**
 * Duplicate an open file descriptor.
 *
 * @param fildes File descriptor to be duplicated.
 * @param fildes2 File descriptor to be paired with the same file description
 *     as is paired fildes.
 * @return fildes2 on success, -1 otherwise.
 */
int dup2(int fildes, int fildes2)
{
        int file;
        if (failed(vfs_clone(fildes, fildes2, false, &file))) {
                return -1;
        }
        return file;
}

/**
 * Determine accessibility of a file.
 *
 * @param path File to check accessibility for.
 * @param amode Either check for existence or intended access mode.
 * @return Zero on success, -1 otherwise.
 */
int access(const char *path, int amode)
{
        if (amode == F_OK || (amode & (X_OK | W_OK | R_OK))) {
                /*
                 * HelenOS doesn't support permissions, permission checks
                 * are equal to existence check.
                 *
                 * Check file existence by attempting to open it.
                 */
                int fd = open(path, O_RDONLY);
                if (fd >= 0) {
                        close(fd);
                        return 0;
                }
                DIR *dir = opendir(path);
                if (dir != NULL) {
                        closedir(dir);
                        return 0;
                }
                return -1;
        } else {
                /* Invalid amode argument. */
                errno = EINVAL;
                return -1;
        }
}

/**
 * Get configurable system variables.
 *
 * @param name Variable name.
 * @return Variable value.
 */
long sysconf(int name)
{
        long clk_tck = 0;
        size_t cpu_count = 0;
        stats_cpu_t *cpu_stats = stats_get_cpus(&cpu_count);
        if (cpu_stats && cpu_count > 0) {
                clk_tck = ((long) cpu_stats[0].frequency_mhz) * 1000000L;
        }
        if (cpu_stats) {
                free(cpu_stats);
                cpu_stats = 0;
        }

        long phys_pages = 0;
        long avphys_pages = 0;
        stats_physmem_t *mem_stats = stats_get_physmem();
        if (mem_stats) {
                phys_pages = (long) (mem_stats->total / getpagesize());
                avphys_pages = (long) (mem_stats->free / getpagesize());
                free(mem_stats);
                mem_stats = 0;
        }

        switch (name) {
        case _SC_PHYS_PAGES:
                return phys_pages;
        case _SC_AVPHYS_PAGES:
                return avphys_pages;
        case _SC_PAGESIZE:
                return getpagesize();
        case _SC_CLK_TCK:
                return clk_tck;
        default:
                errno = EINVAL;
                return -1;
        }
}

/**
 *
 * @param path
 * @param name
 * @return
 */
long pathconf(const char *path, int name)
{
        // TODO: low priority, just a compile-time dependency of binutils
        not_implemented();
        return -1;
}

/**
 *
 * @return
 */
pid_t fork(void)
{
        // TODO: low priority, just a compile-time dependency of binutils
        not_implemented();
        return -1;
}

/**
 *
 * @param path
 * @param argv
 * @return
 */
int execv(const char *path, char *const argv[])
{
        // TODO: low priority, just a compile-time dependency of binutils
        not_implemented();
        return -1;
}

/**
 *
 * @param file
 * @param argv
 * @return
 */
int execvp(const char *file, char *const argv[])
{
        // TODO: low priority, just a compile-time dependency of binutils
        not_implemented();
        return -1;
}

/**
 *
 * @param fildes
 * @return
 */
int pipe(int fildes[2])
{
        // TODO: low priority, just a compile-time dependency of binutils
        not_implemented();
        return -1;
}

unsigned int alarm(unsigned int seconds)
{
        not_implemented();
        return 0;
}

/** @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub