Esempio n. 1
0
static int sys_ioctl(__user void * user_args)
{
    struct _ioctl_get_args args;
    file_t * file;
    void * ioargs = NULL;
    int err, retval = -1;

    err = copyin(user_args, &args, sizeof(args));
    if (err) {
        set_errno(EFAULT);
        return -1;
    }

    file = fs_fildes_ref(curproc->files, args.fd, 1);
    if (!file) {
        set_errno(EBADF);
        return -1;
    }

    if (args.arg) {
        ioargs = kmalloc(args.arg_len);
        if (!ioargs) {
            set_errno(ENOMEM);
            goto out;
        }

        if (args.request & 1) { /* Get request */
            if (!useracc((__user void *)args.arg, args.arg_len,
                         VM_PROT_WRITE)) {
                set_errno(EFAULT);
                goto out;
            }
            /* Get request doesn't need copyin */
        } else { /* Set request */
            /* Set operation needs copyin */
            err = copyin((__user void *)args.arg, ioargs, args.arg_len);
            if (err) {
                set_errno(EFAULT);
                goto out;
            }
        }
    }

    /* Actual ioctl call */
    retval = file->vnode->vnode_ops->ioctl(file, args.request,
                                           ioargs, args.arg_len);
    if (retval < 0)
        set_errno(-retval);

    /* Copyout if request type was get. */
    if (args.request & 1)
        copyout(ioargs, (__user void *)args.arg, args.arg_len);

out:
    kfree(ioargs);
    fs_fildes_ref(curproc->files, args.fd, -1);
    return retval;
}
Esempio n. 2
0
static int sys_lseek(void * user_args)
{
    struct _fs_lseek_args args;
    file_t * file;
    int retval = 0;

    if (!useracc(user_args, sizeof(args), VM_PROT_WRITE)) {
        /* No permission to read/write */
        set_errno(EFAULT);
        return -1;
    }
    copyin(user_args, &args, sizeof(args));

    /* Increment refcount for the file pointed by fd */
    file = fs_fildes_ref(curproc->files, args.fd, 1);
    if (!file) {
        set_errno(EBADF);
        return -1;
    }

    if (args.whence == SEEK_SET)
        file->seek_pos = args.offset;
    else if (args.whence == SEEK_CUR)
        file->seek_pos += args.offset;
    else if (args.whence == SEEK_END) {
        struct stat stat_buf;
        int err;

        err = file->vnode->vnode_ops->stat(file->vnode, &stat_buf);
        if (!err) {
            const off_t new_offset = stat_buf.st_size + args.offset;

            if (new_offset >= stat_buf.st_size)
                file->seek_pos = new_offset;
            else {
                set_errno(EOVERFLOW);
                retval = -1;
            }
        } else {
            set_errno(EBADF);
            retval = -1;
        }
    } else {
        set_errno(EINVAL);
        retval = -1;
    }

    /* Resulting offset is stored to args */
    args.offset = file->seek_pos;

    /* Decrement refcount for the file pointed by fd */
    fs_fildes_ref(curproc->files, args.fd, -1);

    copyout(&args, user_args, sizeof(args));
    return retval;
}
Esempio n. 3
0
File: mbr.c Progetto: htchiang/zeke
int mbr_register(int fd, int * part_count)
{
    file_t * file;
    vnode_t * parent_vnode;
    struct dev_info * parent;
    uint8_t * block_0 = NULL;
    int parts = 0;
    int retval = 0;

#ifdef configMBR_DEBUG
    KERROR(KERROR_DEBUG, "%s(fd: %d, part_count: %p)\n", __func__,
           fd, part_count);
#endif

    file = fs_fildes_ref(curproc->files, fd, 1);

    parent_vnode = file->vnode;
    parent = (struct dev_info *)parent_vnode->vn_specinfo;
    if (!(S_ISBLK(parent_vnode->vn_mode) || S_ISCHR(parent_vnode->vn_mode))) {
        KERROR(KERROR_ERR, "MBR: not a device\n");

        retval = -ENODEV;
        goto fail;
    }

    /* Check the validity of the parent device. */
    if (!parent) {
        KERROR(KERROR_ERR, "MBR: invalid parent device\n");

        retval = -ENODEV;
        goto fail;
    }

    block_0 = kmalloc(MBR_SIZE);
    if (!block_0) {
        retval = -ENOMEM;
        goto fail;
    }

#ifdef configMBR_DEBUG
    KERROR(KERROR_DEBUG,
           "MBR: reading block 0 from device %s\n",
           parent->dev_name);
#endif

    retval = read_block_0(block_0, file);
    if (retval)
        goto fail;
    retval = check_signature(block_0);
    if (retval)
        goto fail;

#ifdef configMBR_DEBUG
    KERROR(KERROR_DEBUG,
             "MBR: found valid MBR on device %s\n", parent->dev_name);
#endif

    /*
     * If parent block size is not MBR_SIZE, we have to coerce start_block
     * and blocks to fit.
     */
    if (parent->block_size < MBR_SIZE) {
        /* We do not support parent device block sizes < 512 */
        KERROR(KERROR_ERR,
                 "MBR: block size of %s is too small (%i)\n",
                 parent->dev_name, parent->block_size);

        retval = -ENOTSUP;
        goto fail;
    }

    uint32_t block_size_adjust = parent->block_size / MBR_SIZE;
    if (parent->block_size % MBR_SIZE) {
        /*
         * We do not support parent device block sizes that are not
         * multiples of 512.
         */
        KERROR(KERROR_ERR,
               "MBR: block size of %s is not a multiple of 512 (%i)\n",
               parent->dev_name, parent->block_size);

        retval = -ENOTSUP;
        goto fail;
    }

#ifdef configMBR_DEBUG
    if (block_size_adjust > 1) {
        KERROR(KERROR_DEBUG, "MBR: block_size_adjust: %i\n",
                 block_size_adjust);
    }
#endif

    int major_num = DEV_MAJOR(parent->dev_id) + 1;
    for (size_t i = 0; i < 4; i++) {
        size_t p_offset = 0x1be + (i * 0x10);
        struct mbr_dev * d;

        if (block_0[p_offset + 4] == 0x00) {
            /* Invalid partition */
            continue;
        }

        d = kzalloc(sizeof(struct mbr_dev));
        if (!d) {
            KERROR(KERROR_ERR, "MBR: Out of memory");

            retval = -ENOMEM;
            break;
        }

        d->dev.dev_id = DEV_MMTODEV(major_num, mbr_dev_count);
        d->dev.drv_name = driver_name;
        ksprintf(d->dev.dev_name, sizeof(d->dev.dev_name), "%sp%u",
                 parent->dev_name, i);
        d->dev.read = mbr_read;
        d->dev.write = (parent->write) ? mbr_write : NULL;
        d->dev.block_size = parent->block_size;
        d->dev.flags = parent->flags;
        d->part_no = i;
        d->part_id = block_0[p_offset + 4];
        d->start_block = read_word(block_0, p_offset + 8);
        d->blocks = read_word(block_0, p_offset + 12);
        d->parent = parent;

        /* Adjust start_block and blocks to the parent block size */
        if (d->start_block % block_size_adjust) {
            KERROR(KERROR_ERR,
                   "MBR: partition number %i on %s does not start on a block "
                   "boundary (%i).\n",
                   d->part_no, parent->dev_name, d->start_block);

            retval = -EFAULT;
            goto fail;
        }
        d->start_block /= block_size_adjust;

        if (d->blocks % block_size_adjust) {
            KERROR(KERROR_ERR,
                   "MBR: partition number %i on %s does not have a length "
                   "that is an exact multiple of the block length (%i).\n",
                   d->part_no, parent->dev_name, d->start_block);

            retval = -EFAULT;
            goto fail;
        }
        d->blocks /= block_size_adjust;
        d->dev.num_blocks = d->blocks;

#ifdef configMBR_DEBUG
        KERROR(KERROR_DEBUG,
               "MBR: partition number %i (%s) of type %x, "
               "start sector %u, sector count %u, p_offset %03x\n",
               d->part_no, d->dev.dev_name, d->part_id,
               d->start_block, d->blocks, p_offset);
#endif

        make_dev(&d->dev, 0, 0, 0666, NULL);
        mbr_dev_count++;
        parts++;

        /* Register the fs */
        //register_fs__((struct dev_info *)d, d->part_id);
        /* TODO Register the fs dev with devfs */
    }

    KERROR(KERROR_INFO, "MBR: found total of %i partition(s)\n",
           parts);

fail:
    kfree(block_0);
    fs_fildes_ref(curproc->files, fd, -1);

    if (retval != 0) {
        KERROR(KERROR_ERR, "MBR registration failed on device: \"%s\"\n",
               parent->dev_name);
    }

    return retval;
}
Esempio n. 4
0
pid_t proc_fork(void)
{
    /*
     * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
     */

    KERROR_DBG("%s(%u)\n", __func__, curproc->pid);

    struct proc_info * const old_proc = curproc;
    struct proc_info * new_proc;
    pid_t retval = 0;

    /* Check that the old process is in valid state. */
    if (!old_proc || old_proc->state == PROC_STATE_INITIAL)
        return -EINVAL;

    new_proc = clone_proc_info(old_proc);
    if (!new_proc)
        return -ENOMEM;

    /* Clear some things required to be zeroed at this point */
    new_proc->state = PROC_STATE_INITIAL;
    new_proc->files = NULL;
    new_proc->pgrp = NULL; /* Must be NULL so we don't free the old ref. */
    memset(&new_proc->tms, 0, sizeof(new_proc->tms));
    /* ..and then start to fix things. */

    /*
     * Process group.
     */
    PROC_LOCK();
    proc_pgrp_insert(old_proc->pgrp, new_proc);
    PROC_UNLOCK();

    /*
     *  Initialize the mm struct.
     */
    retval = vm_mm_init(&new_proc->mm, old_proc->mm.nr_regions);
    if (retval)
        goto out;

    /*
     * Clone the master page table.
     * This is probably something we would like to get rid of but we are
     * stuck with because it's the easiest way to keep some static kernel
     * mappings valid between processes.
     */
    if (mmu_ptcpy(&new_proc->mm.mpt, &old_proc->mm.mpt)) {
        retval = -EAGAIN;
        goto out;
    }

    /*
     * Clone L2 page tables.
     */
    if (vm_ptlist_clone(&new_proc->mm.ptlist_head, &new_proc->mm.mpt,
                        &old_proc->mm.ptlist_head) < 0) {
        retval = -ENOMEM;
        goto out;
    }

    retval = clone_code_region(new_proc, old_proc);
    if (retval)
        goto out;

    /*
     * Clone stack region.
     */
    retval = clone_stack(new_proc, old_proc);
    if (retval) {
        KERROR_DBG("Cloning stack region failed.\n");
        goto out;
    }

    /*
     *  Clone other regions.
     */
    retval = clone_regions_from(new_proc, old_proc, MM_HEAP_REGION);
    if (retval)
        goto out;

    /*
     * Set break values.
     */
    new_proc->brk_start = (void *)(
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_mmu.vaddr +
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_bcount);
    new_proc->brk_stop = (void *)(
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_mmu.vaddr +
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_bufsize);

    /* fork() signals */
    ksignal_signals_fork_reinit(&new_proc->sigs);

    /*
     * Copy file descriptors.
     */
    KERROR_DBG("Copy file descriptors\n");
    int nofile_max = old_proc->rlim[RLIMIT_NOFILE].rlim_max;
    if (nofile_max < 0) {
#if configRLIMIT_NOFILE < 0
#error configRLIMIT_NOFILE can't be negative.
#endif
        nofile_max = configRLIMIT_NOFILE;
    }
    new_proc->files = fs_alloc_files(nofile_max, nofile_max);
    if (!new_proc->files) {
        KERROR_DBG(
               "\tENOMEM when tried to allocate memory for file descriptors\n");
        retval = -ENOMEM;
        goto out;
    }
    /* Copy and ref old file descriptors */
    for (int i = 0; i < old_proc->files->count; i++) {
        new_proc->files->fd[i] = old_proc->files->fd[i];
        fs_fildes_ref(new_proc->files, i, 1); /* null pointer safe */
    }
    KERROR_DBG("All file descriptors copied\n");

    /*
     * Select PID.
     */
    if (likely(nprocs != 1)) { /* Tecnically it would be good idea to have lock
                                * on nprocs before reading it but I think this
                                * should work fine... */
        new_proc->pid = proc_get_random_pid();
    } else { /* Proc is init */
        KERROR_DBG("Assuming this process to be init\n");
        new_proc->pid = 1;
    }

    if (new_proc->cwd) {
        KERROR_DBG("Increment refcount for the cwd\n");
        vref(new_proc->cwd); /* Increment refcount for the cwd */
    }

    /* Update inheritance attributes */
    set_proc_inher(old_proc, new_proc);

    /* Insert the new process into the process array */
    procarr_insert(new_proc);

    /*
     * A process shall be created with a single thread. If a multi-threaded
     * process calls fork(), the new process shall contain a replica of the
     * calling thread.
     * We left main_thread null if calling process has no main thread.
     */
    KERROR_DBG("Handle main_thread\n");
    if (old_proc->main_thread) {
        KERROR_DBG("Call thread_fork() to get a new main thread for the fork.\n");
        if (!(new_proc->main_thread = thread_fork(new_proc->pid))) {
            KERROR_DBG("\tthread_fork() failed\n");
            retval = -EAGAIN;
            goto out;
        }

        KERROR_DBG("\tthread_fork() fork OK\n");

        /*
         * We set new proc's mpt as the current mpt because the new main thread
         * is going to return directly to the user space.
         */
        new_proc->main_thread->curr_mpt = &new_proc->mm.mpt;
    } else {
        KERROR_DBG("No thread to fork.\n");
        new_proc->main_thread = NULL;
    }
    retval = new_proc->pid;

    new_proc->state = PROC_STATE_READY;

#ifdef configPROCFS
    procfs_mkentry(new_proc);
#endif

    if (new_proc->main_thread) {
        KERROR_DBG("Set the new main_thread (%d) ready\n",
                   new_proc->main_thread->id);
        thread_ready(new_proc->main_thread->id);
    }

    KERROR_DBG("Fork %d -> %d created.\n", old_proc->pid, new_proc->pid);

out:
    if (unlikely(retval < 0)) {
        _proc_free(new_proc);
    }
    return retval;
}
Esempio n. 5
0
static int sys_filestat(void * user_args)
{
    struct _fs_stat_args * args = 0;
    vnode_t * vnode;
    struct stat stat_buf;
    int err, retval = -1;

    err = copyinstruct(user_args, (void **)(&args),
            sizeof(struct _fs_stat_args),
            GET_STRUCT_OFFSETS(struct _fs_stat_args,
                path, path_len));
    if (err) {
        set_errno(-err);
        goto out;
    }

    if (!useracc(args->buf, sizeof(struct stat), VM_PROT_WRITE)) {
        set_errno(EFAULT);
        goto out;
    }

    /* Validate path string */
    if (!strvalid(args->path, args->path_len)) {
        set_errno(ENAMETOOLONG);
        goto out;
    }

    if (args->flags & AT_FDARG) { /* by fildes */
        file_t * fildes;
        /* Note: AT_SYMLINK_NOFOLLOW == O_NOFOLLOW */
        const int ofalgs = (args->flags & AT_SYMLINK_NOFOLLOW);

        fildes = fs_fildes_ref(curproc->files, args->fd, 1);
        if (!fildes) {
            set_errno(EBADF);
            goto out;
        }

        err = fildes->vnode->vnode_ops->stat(fildes->vnode, &stat_buf);
        if (!err) {
            /* Check if fildes was opened with O_SEARCH or if not then if we
             * have a permission to search by file permissions. */
            if (fildes->oflags & O_SEARCH || chkperm_cproc(&stat_buf, O_EXEC))
                err = lookup_vnode(&vnode, fildes->vnode, args->path, ofalgs);
            else /* No permission to search */
                err = -EACCES;
        }

        fs_fildes_ref(curproc->files, args->fd, -1);
        if (err) { /* Handle previous error */
            set_errno(-err);
            goto out;
        }
    } else { /* search by path */
        if (fs_namei_proc(&vnode, -1, (char *)args->path, AT_FDCWD)) {
            set_errno(ENOENT);
            goto out;
        }
    }

    if ((args->flags & AT_FDARG) &&
        (args->flags & O_EXEC)) { /* Get stat of given fildes, which we have
                                   * have in stat_buf. */
        goto ready;
    }

    err = vnode->vnode_ops->stat(vnode, &stat_buf);
    if (err) {
        set_errno(-err);
        goto out;
    }

ready:
    copyout(&stat_buf, args->buf, sizeof(struct stat));
    retval = 0;
out:
    freecpystruct(args);
    return retval;
}
Esempio n. 6
0
static int sys_fcntl(void * user_args)
{
    struct _fs_fcntl_args args;
    file_t * file;
    int err, retval = -1;

    err = copyin(user_args, &args, sizeof(args));
    if (err) {
        set_errno(EFAULT);
        return -1;
    }

    file = fs_fildes_ref(curproc->files, args.fd, 1);
    if (!file) {
        set_errno(EBADF);
        return -1;
    }

    switch (args.cmd) {
    case F_DUPFD_CLOEXEC:
        file->fdflags = FD_CLOEXEC;
    case F_DUPFD:
    {
        int new_fd;

        new_fd = fs_fildes_cproc_next(file, args.third.ival);
        if (new_fd < 0) {
            set_errno(-new_fd);
            goto out;
        }

        fs_fildes_ref(curproc->files, new_fd, 1);
        retval = new_fd;
        break;
    }
    case F_DUP2FD:
    {
        int new_fd = args.third.ival;

        if (args.fd == new_fd) {
            retval = new_fd;
            goto out;
        }

        if (curproc->files->fd[new_fd]) {
            if (fs_fildes_close_cproc(new_fd)) {
                set_errno(EIO);
                goto out;
            }
        }

        new_fd = fs_fildes_cproc_next(file, new_fd);
        if (new_fd < 0) {
            set_errno(-new_fd);
            goto out;
        }
        if (new_fd != args.third.ival ||
            !fs_fildes_ref(curproc->files, new_fd, 1)) {
            fs_fildes_close_cproc(new_fd);
            set_errno(EIO);
            goto out;
        }

        retval = new_fd;
        break;
    }
    case F_GETFD:
        retval = file->fdflags;
        break;
    case F_SETFD:
        file->fdflags = args.third.ival;
        break;
    case F_GETFL:
        retval = file->oflags;
        break;
    case F_SETFL:
        /* TODO sync will need some operations to be done */
        file->oflags = args.third.ival & (O_APPEND | O_SYNC | O_NONBLOCK);
        retval = 0;
        break;
    case F_GETOWN:
        /* TODO */
    case F_SETOWN:
        /* TODO */
    case F_GETLK:
        /* TODO */
    case F_SETLK:
        /* TODO */
    case F_SETLKW:
        /* TODO */
    default:
        set_errno(EINVAL);
    }

out:
    fs_fildes_ref(curproc->files, args.fd, -1);
    return retval;
}
Esempio n. 7
0
static int sys_getdents(void * user_args)
{
    struct _ds_getdents_args args;
    struct dirent * dents;
    size_t bytes_left;
    file_t * fildes;
    struct dirent d; /* Temp storage */
    int err, count = 0;

    err = copyin(user_args, &args, sizeof(args));
    if (err) {
        set_errno(EFAULT);
        return -1;
    }

    /* We must have a write access to the given buffer. */
    if (!useracc(args.buf, args.nbytes, VM_PROT_WRITE)) {
        set_errno(EFAULT);
        return -1;
    }

    fildes = fs_fildes_ref(curproc->files, args.fd, 1);
    if (!fildes) {
        set_errno(EBADF);
        return -1;
    }

    if (!S_ISDIR(fildes->vnode->vn_mode)) {
        count = -1;
        set_errno(ENOTDIR);
        goto out;
    }

    dents = kmalloc(args.nbytes);
    if (!dents) {
        count = -1;
        set_errno(ENOMEM);
        goto out;
    }

    /*
     * This is a bit tricky, if we are here for the first time there should be a
     * magic value 0x00000000FFFFFFFF set to seek_pos but we can't do a thing if
     * fildes was initialized incorrectly, so lets cross our fingers.
     */
    d.d_off = fildes->seek_pos;
    bytes_left = args.nbytes;
    while (bytes_left >= sizeof(struct dirent)) {
        vnode_t * vnode = fildes->vnode;
        if (vnode->vnode_ops->readdir(vnode, &d))
            break;
        dents[count++] = d;

        bytes_left -= (sizeof(struct dirent));
    }
    fildes->seek_pos = d.d_off;

    copyout(dents, args.buf, count * sizeof(struct dirent));
    kfree(dents);

out:
    fs_fildes_ref(curproc->files, args.fd, -1);
    return count;
}