Ejemplo n.º 1
0
static int __del_msg_handle (struct shim_msg_handle * msgq)
{
    if (msgq->deleted)
        return -EIDRM;

    msgq->deleted = true;
    free(msgq->queue);
    msgq->queuesize = 0;
    msgq->queueused = 0;
    free(msgq->types);
    msgq->ntypes = 0;

    struct shim_handle * hdl = MSG_TO_HANDLE(msgq);

    lock(msgq_list_lock);
    list_del_init(&msgq->list);
    put_handle(hdl);
    if (!hlist_unhashed(&msgq->key_hlist)) {
        hlist_del_init(&msgq->key_hlist);
        put_handle(hdl);
    }
    if (!hlist_unhashed(&msgq->qid_hlist)) {
        hlist_del_init(&msgq->qid_hlist);
        put_handle(hdl);
    }
    unlock(msgq_list_lock);
    return 0;
}
Ejemplo n.º 2
0
int shim_do_pipe2 (int * filedes, int flags)
{
    if (!filedes)
        return -EINVAL;

    int ret = 0;

    struct shim_handle * hdl1 = get_new_handle();
    struct shim_handle * hdl2 = get_new_handle();

    if (!hdl1 || !hdl2) {
        ret = -ENOMEM;
        goto out;
    }

    hdl1->type       = TYPE_PIPE;
    set_handle_fs(hdl1, &pipe_builtin_fs);
    hdl1->flags      = O_RDONLY;
    hdl1->acc_mode   = MAY_READ;

    hdl2->type       = TYPE_PIPE;
    set_handle_fs(hdl2, &pipe_builtin_fs);
    hdl2->flags      = O_WRONLY;
    hdl2->acc_mode   = MAY_WRITE;

    if ((ret = create_pipes(&hdl1->info.pipe.pipeid,
                            &hdl1->pal_handle, &hdl2->pal_handle,
                            &hdl1->uri, flags)) < 0)
        goto out;

    qstrcopy(&hdl2->uri, &hdl2->uri);

    flags = flags & O_CLOEXEC ? FD_CLOEXEC : 0;
    int vfd1 = set_new_fd_handle(hdl1, flags, NULL);
    int vfd2 = set_new_fd_handle(hdl2, flags, NULL);

    if (vfd1 < 0 || vfd2 < 0) {
        if (vfd1 >= 0) {
            struct shim_handle * tmp = detach_fd_handle(vfd1, NULL, NULL);
            if (tmp)
                close_handle(tmp);
        }
        if (vfd2 >= 0) {
            struct shim_handle * tmp = detach_fd_handle(vfd2, NULL, NULL);
            if (tmp)
                close_handle(tmp);
        }
        goto out;
    }

    filedes[0] = vfd1;
    filedes[1] = vfd2;
out:
    if (hdl1)
        put_handle(hdl1);
    if (hdl2)
        put_handle(hdl2);
    return ret;
}
Ejemplo n.º 3
0
int shim_do_ftruncate (int fd, loff_t length)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    struct shim_mount * fs = hdl->fs;
    int ret = -EACCES;

    if (!fs || !fs->fs_ops)
        goto out;

    if (hdl->type == TYPE_DIR)
        goto out;

    if (!fs->fs_ops->truncate) {
        ret = -EROFS;
        goto out;
    }

    ret = fs->fs_ops->truncate(hdl, length);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 4
0
/* lseek is simply doing arithmetic on the offset, no PAL call here */
off_t shim_do_lseek (int fd, off_t offset, int origin)
{
    if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END)
        return -EINVAL;

    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = 0;
    struct shim_mount * fs = hdl->fs;
    assert(fs && fs->fs_ops);

    if (!fs->fs_ops->seek) {
        ret = -ESPIPE;
        goto out;
    }

    if (hdl->type == TYPE_DIR) {
        /* TODO: handle lseek'ing of directories */
        ret = -ENOSYS;
        goto out;
    }

    ret = fs->fs_ops->seek(hdl, offset, origin);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 5
0
int shim_do_fsync (int fd)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = -EACCES;
    struct shim_mount * fs = hdl->fs;

    if (!fs || !fs->fs_ops)
        goto out;

    if (hdl->type == TYPE_DIR)
        goto out;

    if (!fs->fs_ops->flush) {
        ret = -EROFS;
        goto out;
    }

    ret = fs->fs_ops->flush(hdl);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 6
0
int shim_do_openat (int dfd, const char * filename, int flags, int mode)
{
    if (!filename || test_user_string(filename))
        return -EFAULT;

    if (*filename == '/')
        return shim_do_open(filename, flags, mode);

    struct shim_dentry * dir = NULL;
    int ret = 0;

    if ((ret = path_startat(dfd, &dir)) < 0)
        return ret;

    struct shim_handle * hdl = get_new_handle();
    if (!hdl) {
        ret = -ENOMEM;
        goto out;
    }

    ret = open_namei(hdl, dir, filename, flags, mode, NULL);
    if (ret < 0)
        goto out_hdl;

    ret = set_new_fd_handle(hdl, flags & O_CLOEXEC ? FD_CLOEXEC : 0, NULL);

out_hdl:
    put_handle(hdl);
out:
    put_dentry(dir);
    return ret;
}
Ejemplo n.º 7
0
size_t shim_do_read (int fd, void * buf, size_t count)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;
    int ret = do_handle_read(hdl, buf, count);
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 8
0
size_t shim_do_read (int fd, void * buf, size_t count)
{
    if (!buf || test_user_memory(buf, count, true))
        return -EFAULT;

    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = do_handle_read(hdl, buf, count);
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 9
0
size_t shim_do_write (int fd, const void * buf, size_t count)
{
    if (!buf || test_user_memory((void *) buf, count, false))
        return -EFAULT;

    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = do_handle_write(hdl, buf, count);
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 10
0
ssize_t shim_do_pwrite64 (int fd, char * buf, size_t count, loff_t pos)
{
    if (!buf || test_user_memory(buf, count, false))
        return -EFAULT;

    if (pos < 0)
        return -EINVAL;

    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    struct shim_mount * fs = hdl->fs;
    ssize_t ret = -EACCES;

    if (!fs || !fs->fs_ops)
        goto out;

    if (!fs->fs_ops->seek) {
        ret = -ESPIPE;
        goto out;
    }

    if (!fs->fs_ops->write)
        goto out;

    if (hdl->type == TYPE_DIR)
        goto out;

    int offset = fs->fs_ops->seek(hdl, 0, SEEK_CUR);
    if (offset < 0) {
        ret = offset;
        goto out;
    }

    ret = fs->fs_ops->seek(hdl, pos, SEEK_SET);
    if (ret < 0)
        goto out;

    int bytes = fs->fs_ops->write(hdl, buf, count);

    ret = fs->fs_ops->seek(hdl, offset, SEEK_SET);
    if (ret < 0)
        goto out;

    ret = bytes;
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 11
0
PyObject *
py_guestfs_create (PyObject *self, PyObject *args)
{
  guestfs_h *g;

  g = guestfs_create ();
  if (g == NULL) {
    PyErr_SetString (PyExc_RuntimeError,
                     "guestfs.create: failed to allocate handle");
    return NULL;
  }
  guestfs_set_error_handler (g, NULL, NULL);
  /* This can return NULL, but in that case put_handle will have
   * set the Python error string.
   */
  return put_handle (g);
}
Ejemplo n.º 12
0
size_t shim_do_pread64 (int fd, char * buf, size_t count, loff_t pos)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    struct shim_mount * fs = hdl->fs;
    size_t ret = -EACCES;

    if (!fs || !fs->fs_ops)
        goto out;

    if (!fs->fs_ops->seek) {
        ret = -ESPIPE;
        goto out;
    }

    if (!fs->fs_ops->read)
        goto out;

    if (hdl->type == TYPE_DIR)
        goto out;

    int offset = fs->fs_ops->seek(hdl, 0, SEEK_CUR);
    if (offset < 0) {
        ret = offset;
        goto out;
    }

    ret = fs->fs_ops->seek(hdl, pos, SEEK_SET);
    if (ret < 0)
        goto out;

    int bytes = fs->fs_ops->read(hdl, buf, count);

    ret = fs->fs_ops->seek(hdl, offset, SEEK_SET);
    if (ret < 0)
        goto out;

    ret = bytes;
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 13
0
int shim_do_open (const char * file, int flags, mode_t mode)
{
    if (!file || !(*file))
        return -EINVAL;

    struct shim_handle * hdl = get_new_handle();
    if (!hdl)
        return -ENOMEM;

    int ret = 0;
    ret = open_namei(hdl, NULL, file, flags, mode, NULL);
    if (ret < 0)
        goto out;

    ret = set_new_fd_handle(hdl, flags & O_CLOEXEC ? FD_CLOEXEC : 0, NULL);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 14
0
int shim_do_truncate (const char * path, loff_t length)
{
    struct shim_dentry * dent = NULL;
    int ret = 0;

    if (!path || test_user_string(path))
        return -EFAULT;

    if ((ret = path_lookupat(NULL, path, 0, &dent, NULL)) < 0)
        return ret;

    struct shim_mount * fs = dent->fs;

    if (!fs || !fs->d_ops || !fs->d_ops->open) {
        ret = -EBADF;
        goto out;
    }

    if (!fs->fs_ops->truncate) {
        ret = -EROFS;
        goto out;
    }

    struct shim_handle * hdl = get_new_handle();

    if (!hdl) {
        ret = -ENOMEM;
        goto out;
    }

    hdl->fs = fs;

    if ((ret = fs->d_ops->open(hdl, dent, O_WRONLY)) < 0)
        goto out_handle;

    ret = fs->fs_ops->truncate(hdl, length);
    flush_handle(hdl);
out_handle:
    put_handle(hdl);
out:
    return ret;
}
Ejemplo n.º 15
0
static PyObject *
py_hivex_open (PyObject *self, PyObject *args)
{
  PyObject *py_r;
  hive_h *r;
  char *filename;
  int flags;

  if (!PyArg_ParseTuple (args, (char *) "si:hivex_open", &filename, &flags))
    return NULL;
  r = hivex_open (filename, flags);
  if (r == NULL) {
    PyErr_SetString (PyExc_RuntimeError,
                     strerror (errno));
    return NULL;
  }

  py_r = put_handle (r);
  return py_r;
}
Ejemplo n.º 16
0
int shim_do_fstat (int fd, struct stat * stat)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = -EACCES;
    struct shim_mount * fs = hdl->fs;

    if (!fs || !fs->fs_ops)
        goto out;

    if (!fs->fs_ops->hstat)
        goto out;

    ret = fs->fs_ops->hstat(hdl, stat);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 17
0
void close_handle (struct shim_handle * hdl)
{
    int opened = REF_DEC(hdl->opened);

#ifdef DEBUG_REF
    debug("close handle %p(%s) (opened = %d)\n", hdl, __handle_name(hdl),
          opened);
#endif

    if (!opened) {
        if (hdl->type == TYPE_DIR) {
            struct shim_dir_handle * dir = &hdl->info.dir;

            if (dir->dot) {
                put_dentry(dir->dot);
                dir->dot = NULL;
            }

            if (dir->dotdot) {
                put_dentry(dir->dotdot);
                dir->dotdot = NULL;
            }

            while (*dir->ptr) {
                struct shim_dentry * dent = *dir->ptr;
                put_dentry(dent);
                *(dir->ptr++) = NULL;
            }
        } else {
            if (hdl->fs && hdl->fs->fs_ops &&
                hdl->fs->fs_ops->close)
                hdl->fs->fs_ops->close(hdl);
        }
    }

    put_handle(hdl);
}
Ejemplo n.º 18
0
int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
                         const char ** envp)
{
    BEGIN_PROFILE_INTERVAL();

    struct shim_thread * cur_thread = get_cur_thread();
    int ret;

    if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0)
        return ret;

    SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec);

    void * tcb = malloc(sizeof(__libc_tcb_t));
    if (!tcb)
        return -ENOMEM;

    populate_tls(tcb, false);
    __disable_preempt(&((__libc_tcb_t *) tcb)->shim_tcb); // Temporarily disable preemption
                                                          // during execve().
    debug("set tcb to %p\n", tcb);

    put_handle(cur_thread->exec);
    get_handle(hdl);
    cur_thread->exec = hdl;

    old_stack_top = cur_thread->stack_top;
    old_stack     = cur_thread->stack;
    old_stack_red = cur_thread->stack_red;
    cur_thread->stack_top = NULL;
    cur_thread->stack     = NULL;
    cur_thread->stack_red = NULL;

    initial_envp = NULL;
    new_argc = 0;
    for (const char ** a = argv ; *a ; a++, new_argc++);

    new_argcp = &new_argc;
    if ((ret = init_stack(argv, envp, &new_argcp, &new_argp,
                          REQUIRED_ELF_AUXV, &new_auxp)) < 0)
        return ret;

    SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec);

    SWITCH_STACK(new_argp);
    cur_thread = get_cur_thread();

    UPDATE_PROFILE_INTERVAL();

    DkVirtualMemoryFree(old_stack, old_stack_top - old_stack);
    DkVirtualMemoryFree(old_stack_red, old_stack - old_stack_red);

    if (bkeep_munmap(old_stack, old_stack_top - old_stack, 0) < 0 ||
        bkeep_munmap(old_stack_red, old_stack - old_stack_red, 0) < 0)
        BUG();

    remove_loaded_libraries();
    clean_link_map_list();
    SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec);

    reset_brk();

    size_t count = DEFAULT_VMA_COUNT;
    struct shim_vma_val * vmas = malloc(sizeof(struct shim_vma_val) * count);

    if (!vmas)
        return -ENOMEM;

retry_dump_vmas:
    ret = dump_all_vmas(vmas, count);

    if (ret == -EOVERFLOW) {
        struct shim_vma_val * new_vmas
                = malloc(sizeof(struct shim_vma_val) * count * 2);
        if (!new_vmas) {
            free(vmas);
            return -ENOMEM;
        }
        free(vmas);
        vmas = new_vmas;
        count *= 2;
        goto retry_dump_vmas;
    }

    if (ret < 0) {
        free(vmas);
        return ret;
    }

    count = ret;
    for (struct shim_vma_val * vma = vmas ; vma < vmas + count ; vma++) {
        /* Don't free the current stack */
        if (vma->addr == cur_thread->stack)
            continue;

        /* Free all the mapped VMAs */
        if (!(vma->flags & VMA_UNMAPPED))
            DkVirtualMemoryFree(vma->addr, vma->length);

        /* Remove the VMAs */
        bkeep_munmap(vma->addr, vma->length, vma->flags);
    }

    free_vma_val_array(vmas, count);

    SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec);

    if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0)
        shim_terminate(ret);

    init_brk_from_executable(cur_thread->exec);
    load_elf_interp(cur_thread->exec);

    SAVE_PROFILE_INTERVAL(load_new_executable_for_exec);

    cur_thread->robust_list = NULL;

#ifdef PROFILE
    if (ENTER_TIME)
        SAVE_PROFILE_INTERVAL_SINCE(syscall_execve, ENTER_TIME);
#endif

    debug("execve: start execution\n");
    execute_elf_object(cur_thread->exec, new_argcp, new_argp,
                       REQUIRED_ELF_AUXV, new_auxp);

    return 0;
}
Ejemplo n.º 19
0
int shim_do_ioctl (int fd, int cmd, unsigned long arg)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = -EAGAIN;
    switch(cmd) {
        /* <include/asm/termios.h> */
        case TCGETS:
        case TCSETS:
        case TCSETSW:
        case TCSETSF:
        case TCGETA:
        case TCSETA:
        case TCSETAW:
        case TCSETAF:
        case TCSBRK:
        case TCXONC:
        case TCFLSH:
        case TIOCEXCL:
        case TIOCNXCL:
        case TIOCSCTTY:
        case TIOCGPGRP:
        case TIOCSPGRP:
        case TIOCOUTQ:
        case TIOCSTI:
        case TIOCGWINSZ:
        case TIOCMGET:
        case TIOCMBIS:
        case TIOCMBIC:
        case TIOCMSET:
        case TIOCGSOFTCAR:
        case TIOCSSOFTCAR:
        /* case TIOCINQ = FIONREAD */
        case TIOCLINUX:
        case TIOCCONS:
        case TIOCGSERIAL:
        case TIOCSSERIAL:
        case TIOCPKT:
        case TIOCNOTTY:
        case TIOCSETD:
        case TIOCGETD:
        case TCSBRKP:
            ret = ioctl_termios(hdl, cmd, arg);
            break;
        case FIONBIO:
            if (hdl->fs && hdl->fs->fs_ops &&
                hdl->fs->fs_ops->setflags)
                hdl->fs->fs_ops->setflags(hdl, hdl->flags | O_NONBLOCK);
            hdl->flags |= O_NONBLOCK;
            ret = 0;
            break;
        case FIONCLEX:
            hdl->flags &= ~FD_CLOEXEC;
            ret = 0;
            break;
        case FIOCLEX:
            hdl->flags |= FD_CLOEXEC;
            ret = 0;
            break;
        case FIOASYNC:
            ret = install_async_event(hdl->pal_handle, 0, &signal_io, NULL);
            break;
        case TIOCSERCONFIG:
        case TIOCSERGWILD:
        case TIOCSERSWILD:
        case TIOCGLCKTRMIOS:
        case TIOCSLCKTRMIOS:
        case TIOCSERGSTRUCT:
        case TIOCSERGETLSR:
        case TIOCSERGETMULTI:
        case TIOCSERSETMULTI:
            ret = ioctl_termios(hdl, cmd, arg);
            break;

        case FDCLRPRM:
        case FDSETPRM:
        case FDDEFPRM:
        case FDGETPRM:
        case FDMSGON:
        case FDMSGOFF:
        case FDFMTBEG:
        case FDFMTTRK:
        case FDFMTEND:
        case FDSETEMSGTRESH:
        case FDFLUSH:
        case FDSETMAXERRS:
        case FDGETMAXERRS:
        case FDGETDRVTYP:
        case FDSETDRVPRM:
        case FDGETDRVPRM:
        case FDGETDRVSTAT:
        case FDPOLLDRVSTAT:
        case FDRESET:
        case FDGETFDCSTAT:
        case FDWERRORCLR:
        case FDWERRORGET:
        case FDRAWCMD:
        case FDTWADDLE:
            ret = ioctl_fd(hdl, cmd, arg);
            break;

        case FIONREAD: {
            struct shim_mount * fs = hdl->fs;
            int size = 0;
            int offset = 0;

            if (!fs || !fs->fs_ops) {
                ret = -EACCES;
                break;
            }

            if (fs->fs_ops->hstat) {
                struct stat stat;
                ret = fs->fs_ops->hstat(hdl, &stat);
                if (ret < 0)
                    break;

                size = stat.st_size;
                goto done_fioread;
            }

            if (hdl->pal_handle) {
                PAL_STREAM_ATTR attr;
                if (!DkStreamAttributesQueryByHandle(hdl->pal_handle, &attr)) {
                    ret = -PAL_ERRNO;
                    break;
                }
                size = attr.pending_size;
                goto done_fioread;
            }

done_fioread:
            if (fs->fs_ops->seek) {
                ret = fs->fs_ops->seek(hdl, 0, SEEK_CUR);
                if (ret < 0)
                    break;
                offset = ret;
            }

            *(int *) arg = size - offset;
            ret = 0;
            break;
        }

        /* Socket configuration controls. */
        case SIOCGIFNAME:       /* 0x8910 get iface name */
        case SIOCSIFLINK:       /* 0x8911 set iface channel */
        case SIOCGIFCONF:       /* 0x8912 get iface list */
        case SIOCGIFFLAGS:      /* 0x8913 get flags */
        case SIOCSIFFLAGS:      /* 0x8914 set flags */
        case SIOCGIFADDR:       /* 0x8915 get PA address */
        case SIOCSIFADDR:       /* 0x8916 set PA address */
        case SIOCGIFDSTADDR:    /* 0x8917 get remote PA address */
        case SIOCSIFDSTADDR:    /* 0x8918 set remote PA address */
        case SIOCGIFBRDADDR:    /* 0x8919 get broadcast PA address */
        case SIOCSIFBRDADDR:    /* 0x891a set broadcast PA address */
        case SIOCGIFNETMASK:    /* 0x891b get network PA mask */
        case SIOCSIFNETMASK:    /* 0x891c set network PA mask */
        case SIOCGIFMETRIC:     /* 0x891d get metric */
        case SIOCSIFMETRIC:     /* 0x891e set metric */
        case SIOCGIFMEM:        /* 0x891f get memory address (BSD) */
        case SIOCSIFMEM:        /* 0x8920 set memory address (BSD) */
        case SIOCGIFMTU:        /* 0x8921 get MTU size */
        case SIOCSIFMTU:        /* 0x8922 set MTU size */
        case SIOCSIFNAME:       /* 0x8923 set interface name */
        case SIOCSIFHWADDR:     /* 0x8924 set hardware address */
        case SIOCGIFENCAP:      /* 0x8925 get/set encapsulations       */
        case SIOCSIFENCAP:      /* 0x8926 */
        case SIOCGIFHWADDR:     /* 0x8927 Get hardware address */
        case SIOCGIFSLAVE:      /* 0x8929 Driver slaving support */
        case SIOCSIFSLAVE:      /* 0x8930 */
        case SIOCADDMULTI:      /* 0x8931 Multicast address lists */
        case SIOCDELMULTI:      /* 0x8932 */
        case SIOCGIFINDEX:      /* 0x8933 name -> if_index mapping */
        /* SIOGIFINDEX = SIOCGIFINDEX misprint compatibility :-) */
        case SIOCSIFPFLAGS:     /* 0x8934 set/get extended flags set */
        case SIOCGIFPFLAGS:     /* 0x8935 */
        case SIOCDIFADDR:       /* 0x8936 delete PA address */
        case SIOCSIFHWBROADCAST: /* 0x8937 set hardware broadcast addr */
        case SIOCGIFCOUNT:      /* 0x8938 get number of devices */
        case SIOCGIFBR:         /* 0x8940 Bridging support */
        case SIOCSIFBR:         /* 0x8941 Set bridging options  */
        case SIOCGIFTXQLEN:     /* 0x8942 Get the tx queue length */
        case SIOCSIFTXQLEN:     /* 0x8943 Set the tx queue length  */
            ret = ioctl_netdevice(hdl, cmd, arg);
            break;

        default:
            ret = -ENOSYS;
            break;
    }

    put_handle(hdl);
    return ret;
}
Ejemplo n.º 20
0
Archivo: read.c Proyecto: Hooman3/minix
/*===========================================================================*
 *				do_getdents				     *
 *===========================================================================*/
ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
	off_t *posp)
{
/* Retrieve directory entries.
 */
  struct fsdriver_dentry fsdentry;
  char name[NAME_MAX+1];
  struct inode *ino, *child;
  struct sffs_attr attr;
  off_t pos;
  int r;
  /* must be at least sizeof(struct dirent) + NAME_MAX */
  static char buf[BLOCK_SIZE];

  if ((ino = find_inode(ino_nr)) == NULL)
	return EINVAL;

  if (!IS_DIR(ino)) return ENOTDIR;

  if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL;

  /* We are going to need at least one free inode to store children in. */
  if (!have_free_inode()) return ENFILE;

  /* If we don't have a directory handle yet, get one now. */
  if ((r = get_handle(ino)) != OK)
	return r;

  fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf));

  /* We use the seek position as file index number. The first position is for
   * the "." entry, the second position is for the ".." entry, and the next
   * position numbers each represent a file in the directory.
   */
  do {
	/* Determine which inode and name to use for this entry.
	 * We have no idea whether the host will give us "." and/or "..",
	 * so generate our own and skip those from the host.
	 */
	pos = (*posp)++;

	if (pos == 0) {
		/* Entry for ".". */
		child = ino;

		strcpy(name, ".");

		get_inode(child);
	}
	else if (pos == 1) {
		/* Entry for "..", but only when there is a parent. */
		if (ino->i_parent == NULL)
			continue;

		child = ino->i_parent;

		strcpy(name, "..");

		get_inode(child);
	}
	else {
		/* Any other entry, not being "." or "..". */
		attr.a_mask = SFFS_ATTR_MODE;

		r = sffs_table->t_readdir(ino->i_dir, pos - 2, name,
			sizeof(name), &attr);

		if (r != OK) {
			/* No more entries? Then close the handle and stop. */
			if (r == ENOENT) {
				put_handle(ino);

				break;
			}

			/* FIXME: what if the error is ENAMETOOLONG? */
			return r;
		}

		if (!strcmp(name, ".") || !strcmp(name, ".."))
			continue;

		if ((child = lookup_dentry(ino, name)) == NULL) {
			child = get_free_inode();

			/* We were promised a free inode! */
			assert(child != NULL);

			child->i_flags = MODE_TO_DIRFLAG(attr.a_mode);

			add_dentry(ino, name, child);
		}
	}

	r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name),
		IS_DIR(child) ? DT_DIR : DT_REG);

	put_inode(child);

	if (r < 0)
		return r;
  } while (r > 0);

  return fsdriver_dentry_finish(&fsdentry);
}
Ejemplo n.º 21
0
size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count)
{
    if (!buf || test_user_memory(buf, count, true))
        return -EFAULT;

    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = -EACCES;

    if (hdl->type != TYPE_DIR) {
        ret = -ENOTDIR;
        goto out;
    }

    /* DEP 3/3/17: Properly handle an unlinked directory */
    if (hdl->dentry->state & DENTRY_NEGATIVE) {
        ret = -ENOENT;
        goto out;
    }

    lock(&hdl->lock);

    struct shim_dir_handle * dirhdl = &hdl->info.dir;
    struct shim_dentry * dent = hdl->dentry;
    struct linux_dirent64 * b = buf;
    int bytes = 0;

    /* If we haven't listed the directory, do this first */
    if (!(dent->state & DENTRY_LISTED)) {
        ret = list_directory_dentry(dent);
        if (ret) goto out;
    }

#define DIRENT_SIZE(len)  (sizeof(struct linux_dirent64) + (len) + 1)

#define ASSIGN_DIRENT(dent, name, type)                                 \
        do {                                                            \
            int len = strlen(name);                                     \
            if (bytes + DIRENT_SIZE(len) > count)                       \
                goto done;                                              \
                                                                        \
            b->d_ino = (dent)->ino;                                     \
            b->d_off = ++dirhdl->offset;                                \
            b->d_reclen = DIRENT_SIZE(len);                             \
            b->d_type = (type);                                         \
                                                                        \
            memcpy(b->d_name, name, len + 1);                           \
                                                                        \
            b = (void *) b + DIRENT_SIZE(len);                          \
            bytes += DIRENT_SIZE(len);                                  \
        } while(0)

    if (dirhdl->dot) {
        ASSIGN_DIRENT(dirhdl->dot, ".", LINUX_DT_DIR);
        put_dentry(dirhdl->dot);
        dirhdl->dot = NULL;
    }

    if (dirhdl->dotdot) {
        ASSIGN_DIRENT(dirhdl->dotdot, "..", LINUX_DT_DIR);
        put_dentry(dirhdl->dotdot);
        dirhdl->dotdot = NULL;
    }

    if (dirhdl->ptr == (void *) -1) {
        ret = list_directory_handle(dent, hdl);
        if (ret) goto out;
    }

    while (dirhdl->ptr && *dirhdl->ptr) {
        dent = *dirhdl->ptr;
        /* DEP 3/3/17: We need to filter negative dentries */
        if (!(dent->state & DENTRY_NEGATIVE))
            ASSIGN_DIRENT(dent, dentry_get_name(dent), get_dirent_type(dent->type));
        put_dentry(dent);
        *(dirhdl->ptr++) = NULL;
    }

#undef DIRENT_SIZE
#undef ASSIGN_DIRENT

done:
    ret = bytes;
    /* DEP 3/3/17: Properly detect EINVAL case, where buffer is too small to
     * hold anything */
    if (bytes == 0 && (dirhdl->dot || dirhdl->dotdot ||
                       (dirhdl->ptr && *dirhdl->ptr)))
        ret = -EINVAL;
    unlock(&hdl->lock);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 22
0
size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count)
{
    struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
    if (!hdl)
        return -EBADF;

    int ret = -EACCES;

    if (hdl->type != TYPE_DIR) {
        ret = -ENOTDIR;
        goto out;
    }

    lock(hdl->lock);

    struct shim_dir_handle * dirhdl = &hdl->info.dir;
    struct shim_dentry * dent = hdl->dentry;
    struct linux_dirent64 * b = buf;
    int bytes = 0;

#define DIRENT_SIZE(len)  (sizeof(struct linux_dirent64) + (len) + 1)

#define ASSIGN_DIRENT(dent, name, type)                                 \
        do {                                                            \
            int len = strlen(name);                                     \
            if (bytes + DIRENT_SIZE(len) > count)                       \
                goto done;                                              \
                                                                        \
            b->d_ino = dent->ino;                                       \
            b->d_off = ++dirhdl->offset;                                \
            b->d_reclen = DIRENT_SIZE(len);                             \
            b->d_type = type ? : get_dirent_type(dent->mode);           \
                                                                        \
            memcpy(b->d_name, name, len + 1);                           \
                                                                        \
            b = (void *) b + DIRENT_SIZE(len);                          \
            bytes += DIRENT_SIZE(len);                                  \
        } while(0)

    if (dirhdl->dot) {
        ASSIGN_DIRENT(dirhdl->dot, ".", LINUX_DT_DIR);
        put_dentry(dirhdl->dot);
        dirhdl->dot = NULL;
    }

    if (dirhdl->dotdot) {
        ASSIGN_DIRENT(dirhdl->dotdot, "..", LINUX_DT_DIR);
        put_dentry(dirhdl->dotdot);
        dirhdl->dotdot = NULL;
    }

    while (*dirhdl->ptr) {
        dent = *dirhdl->ptr;
        ASSIGN_DIRENT(dent, dentry_get_name(dent), 0);
        put_dentry(dent);
        *(dirhdl->ptr++) = NULL;
    }

#undef DIRENT_SIZE
#undef ASSIGN_DIRENT

done:
    ret = bytes;
    unlock(hdl->lock);
out:
    put_handle(hdl);
    return ret;
}
Ejemplo n.º 23
0
int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv,
                         const char ** envp)
{
    BEGIN_PROFILE_INTERVAL();

    struct shim_thread * cur_thread = get_cur_thread();
    int ret;

    if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0)
        return ret;

    SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec);

    void * tcb = malloc(sizeof(__libc_tcb_t));
    if (!tcb)
        return -ENOMEM;

    populate_tls(tcb);

    put_handle(cur_thread->exec);
    get_handle(hdl);
    cur_thread->exec = hdl;

    old_stack_top = cur_thread->stack_top;
    old_stack     = cur_thread->stack;
    old_stack_red = cur_thread->stack_red;
    cur_thread->stack_top = NULL;
    cur_thread->stack     = NULL;
    cur_thread->stack_red = NULL;

    initial_envp = NULL;
    new_argc = 0;
    for (const char ** a = argv ; *a ; a++, new_argc++);

    if ((ret = init_stack(argv, envp, &new_argp,
                          REQUIRED_ELF_AUXV, &new_auxp)) < 0)
        return ret;

    SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec);

    switch_stack(new_argp);
    cur_thread = get_cur_thread();

    UPDATE_PROFILE_INTERVAL();

    DkVirtualMemoryFree(old_stack, old_stack_top - old_stack);
    DkVirtualMemoryFree(old_stack_red, old_stack - old_stack_red);
    int flags = VMA_INTERNAL;
    bkeep_munmap(old_stack, old_stack_top - old_stack, &flags);
    bkeep_munmap(old_stack_red, old_stack - old_stack_red, &flags);

    remove_loaded_libraries();
    clean_link_map_list();
    SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec);

    init_brk();
    unmap_all_vmas();
    SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec);

    if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0)
        shim_terminate();

    load_elf_interp(cur_thread->exec);

    SAVE_PROFILE_INTERVAL(load_new_executable_for_exec);

    debug("execve: start execution\n");
    execute_elf_object(cur_thread->exec, new_argc, new_argp,
                       REQUIRED_ELF_AUXV, new_auxp);

    return 0;
}
Ejemplo n.º 24
0
Archivo: read.c Proyecto: Sciumo/minix
/*===========================================================================*
 *				do_getdents				     *
 *===========================================================================*/
int do_getdents()
{
/* Retrieve directory entries.
 */
  char name[NAME_MAX+1];
  struct inode *ino, *child;
  struct dirent *dent;
  struct sffs_attr attr;
  size_t len, off, user_off, user_left;
  off_t pos;
  int r;
  /* must be at least sizeof(struct dirent) + NAME_MAX */
  static char buf[BLOCK_SIZE];

  attr.a_mask = SFFS_ATTR_MODE;

  if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
	return EINVAL;

  if (m_in.REQ_SEEK_POS_HI != 0) return EINVAL;

  if (!IS_DIR(ino)) return ENOTDIR;

  /* We are going to need at least one free inode to store children in. */
  if (!have_free_inode()) return ENFILE;

  /* If we don't have a directory handle yet, get one now. */
  if ((r = get_handle(ino)) != OK)
	return r;

  off = 0;
  user_off = 0;
  user_left = m_in.REQ_MEM_SIZE;

  /* We use the seek position as file index number. The first position is for
   * the "." entry, the second position is for the ".." entry, and the next
   * position numbers each represent a file in the directory.
   */
  for (pos = m_in.REQ_SEEK_POS_LO; ; pos++) {
	/* Determine which inode and name to use for this entry.
	 * We have no idea whether the host will give us "." and/or "..",
	 * so generate our own and skip those from the host.
	 */
	if (pos == 0) {
		/* Entry for ".". */
		child = ino;

		strcpy(name, ".");

		get_inode(child);
	}
	else if (pos == 1) {
		/* Entry for "..", but only when there is a parent. */
		if (ino->i_parent == NULL)
			continue;

		child = ino->i_parent;

		strcpy(name, "..");

		get_inode(child);
	}
	else {
		/* Any other entry, not being "." or "..". */
		r = sffs_table->t_readdir(ino->i_dir, pos - 2, name,
			sizeof(name), &attr);

		if (r != OK) {
			/* No more entries? Then close the handle and stop. */
			if (r == ENOENT) {
				put_handle(ino);

				break;
			}

			/* FIXME: what if the error is ENAMETOOLONG? */
			return r;
		}

		if (!strcmp(name, ".") || !strcmp(name, ".."))
			continue;

		if ((child = lookup_dentry(ino, name)) == NULL) {
			child = get_free_inode();

			/* We were promised a free inode! */
			assert(child != NULL);

			child->i_flags = MODE_TO_DIRFLAG(attr.a_mode);

			add_dentry(ino, name, child);
		}
	}

	len = DWORD_ALIGN(sizeof(struct dirent) + strlen(name));

	/* Is the user buffer too small to store another record?
	 * Note that we will be rerequesting the same dentry upon a subsequent
	 * getdents call this way, but we really need the name length for this.
	 */
	if (user_off + off + len > user_left) {
		put_inode(child);

		/* Is the user buffer too small for even a single record? */
		if (user_off == 0 && off == 0)
			return EINVAL;

		break;
	}

	/* If our own buffer cannot contain the new record, copy out first. */
	if (off + len > sizeof(buf)) {
		r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT,
			user_off, (vir_bytes) buf, off, D);

		if (r != OK) {
			put_inode(child);

			return r;
		}

		user_off += off;
		user_left -= off;
		off = 0;
	}

	/* Fill in the actual directory entry. */
	dent = (struct dirent *) &buf[off];
	dent->d_ino = INODE_NR(child);
	dent->d_off = pos;
	dent->d_reclen = len;
	strcpy(dent->d_name, name);

	off += len;

	put_inode(child);
  }

  /* If there is anything left in our own buffer, copy that out now. */
  if (off > 0) {
	r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, user_off,
		(vir_bytes) buf, off, D);

	if (r != OK)
		return r;

	user_off += off;
  }

  m_out.RES_SEEK_POS_HI = 0;
  m_out.RES_SEEK_POS_LO = pos;
  m_out.RES_NBYTES = user_off;

  return OK;
}
Ejemplo n.º 25
0
int shim_do_socketpair (int domain, int type, int protocol, int * sv)
{
    if (domain != AF_UNIX)
        return -EAFNOSUPPORT;

    if (type != SOCK_STREAM)
        return -EPROTONOSUPPORT;

    if (!sv)
        return -EINVAL;

    int ret = 0;
    struct shim_handle * hdl1 = get_new_handle();
    struct shim_handle * hdl2 = get_new_handle();

    if (!hdl1 || !hdl2) {
        ret = -ENOMEM;
        goto out;
    }

    struct shim_sock_handle * sock1 = &hdl1->info.sock;
    struct shim_sock_handle * sock2 = &hdl2->info.sock;

    hdl1->type          = TYPE_SOCK;
    set_handle_fs(hdl1, &socket_builtin_fs);
    hdl1->flags         = O_RDONLY;
    hdl1->acc_mode      = MAY_READ|MAY_WRITE;
    sock1->domain       = domain;
    sock1->sock_type    = type & ~(SOCK_NONBLOCK|SOCK_CLOEXEC);
    sock1->protocol     = protocol;
    sock1->sock_state   = SOCK_ACCEPTED;

    hdl2->type          = TYPE_SOCK;
    set_handle_fs(hdl2, &socket_builtin_fs);
    hdl1->flags         = O_WRONLY;
    hdl2->acc_mode      = MAY_READ|MAY_WRITE;
    sock2->domain       = domain;
    sock2->sock_type    = type & ~(SOCK_NONBLOCK|SOCK_CLOEXEC);
    sock2->protocol     = protocol;
    sock2->sock_state   = SOCK_CONNECTED;

    if ((ret = create_pipes(&sock1->addr.un.pipeid, &hdl1->pal_handle,
                            &hdl2->pal_handle, &hdl1->uri,
                            type & SOCK_NONBLOCK ? O_NONBLOCK : 0)) < 0)
        goto out;

    sock2->addr.un.pipeid = sock1->addr.un.pipeid;
    qstrcopy(&hdl2->uri, &hdl1->uri);

    int flags = type & SOCK_CLOEXEC ? FD_CLOEXEC : 0;
    int vfd1 = set_new_fd_handle(hdl1, flags, NULL);
    int vfd2 = set_new_fd_handle(hdl2, flags, NULL);

    if (vfd1 < 0 || vfd2 < 0) {
        if (vfd1 >= 0) {
            struct shim_handle * tmp = detach_fd_handle(vfd1, NULL, NULL);
            if (tmp)
                close_handle(tmp);
        }
        if (vfd2 >= 0) {
            struct shim_handle * tmp = detach_fd_handle(vfd2, NULL, NULL);
            if (tmp)
                close_handle(tmp);
        }
        goto out;
    }

    sv[0] = vfd1;
    sv[1] = vfd2;
out:
    if (hdl1)
        put_handle(hdl1);
    if (hdl2)
        put_handle(hdl2);
    return ret;
}
Ejemplo n.º 26
0
int init_important_handles (void)
{
    struct shim_thread * thread = get_cur_thread();

    if (thread->handle_map)
        goto done;

    struct shim_handle_map * handle_map = get_cur_handle_map(thread);

    if (!handle_map) {
        handle_map = get_new_handle_map(INIT_HANDLE_MAP_SIZE);
        if (!handle_map)
            return -ENOMEM;

        set_handle_map(thread, handle_map);
    }

    lock(handle_map->lock);

    if (handle_map->fd_size < 3) {
        if (!__enlarge_handle_map(handle_map, INIT_HANDLE_MAP_SIZE)) {
            unlock(handle_map->lock);
            return -ENOMEM;
        }
    }

    struct shim_handle * hdl = NULL;
    int ret;

    for (int fd = 0 ; fd < 3 ; fd++)
        if (!HANDLE_ALLOCATED(handle_map->map[fd])) {
            if (!hdl) {
                hdl = get_new_handle();
                if (!hdl)
                    return -ENOMEM;

                if ((ret = init_tty_handle(hdl, fd)) < 0) {
                    put_handle(hdl);
                    return ret;
                }
            } else {
                get_handle(hdl);
            }

            __set_new_fd_handle(&handle_map->map[fd], fd, hdl, 0);
            put_handle(hdl);
            if (fd != 1)
                hdl = NULL;
        } else {
            if (fd == 1)
                hdl = handle_map->map[fd]->handle;
        }

    if (handle_map->fd_top == FD_NULL || handle_map->fd_top < 2)
        handle_map->fd_top = 2;

    unlock(handle_map->lock);

done:
    init_exec_handle(thread);
    return 0;
}
Ejemplo n.º 27
0
void put_msg_handle (struct shim_msg_handle * msgq)
{
    put_handle(MSG_TO_HANDLE(msgq));
}
Ejemplo n.º 28
0
static int __add_msg_handle (unsigned long key, IDTYPE msqid, bool owned,
                             struct shim_msg_handle ** msghdl)
{
    struct hlist_head * key_head = (key != IPC_PRIVATE) ?
                                   &msgq_key_hlist[MSGQ_HASH(key)] :
                                   NULL;
    struct hlist_head * qid_head = msqid ?
                                   &msgq_qid_hlist[MSGQ_HASH(msqid)] :
                                   NULL;

    struct shim_msg_handle * tmp;
    struct hlist_node * pos;

    if (key_head)
        hlist_for_each_entry(tmp, pos, key_head, key_hlist)
            if (tmp->msqkey == key) {
                if (tmp->msqid == msqid) {
                    if (msghdl)
                        *msghdl = tmp;
                    return 0;
                }
                return -EEXIST;
            }

    if (qid_head)
        hlist_for_each_entry(tmp, pos, qid_head, qid_hlist)
            if (tmp->msqid == msqid) {
                if (key)
                    tmp->msqkey = key;
                if (msghdl)
                    *msghdl = tmp;
                return 0;
            }

    struct shim_handle * hdl = get_new_handle();
    if (!hdl)
        return -ENOMEM;

    struct shim_msg_handle * msgq = &hdl->info.msg;

    hdl->type       = TYPE_MSG;
    msgq->msqkey    = key;
    msgq->msqid     = msqid;
    msgq->owned     = owned;
    msgq->deleted   = false;
    msgq->currentsize = 0;
    msgq->event     = DkSynchronizationEventCreate(0);

    msgq->queue     = malloc(MSG_QOBJ_SIZE * DEFAULT_MSG_QUEUE_SIZE);
    msgq->queuesize = DEFAULT_MSG_QUEUE_SIZE;
    msgq->queueused = 0;
    msgq->freed     = NULL;

    msgq->ntypes    = 0;
    msgq->maxtypes  = INIT_MSG_TYPE_SIZE;
    msgq->types     = malloc(sizeof(struct msg_type) * INIT_MSG_TYPE_SIZE);

    INIT_LIST_HEAD(&msgq->list);
    get_handle(hdl);
    list_add_tail(&msgq->list, &msgq_list);

    INIT_HLIST_NODE(&msgq->key_hlist);
    if (key_head) {
        get_handle(hdl);
        hlist_add_head(&msgq->key_hlist, key_head);
    }
    INIT_HLIST_NODE(&msgq->qid_hlist);
    if (qid_head) {
        get_handle(hdl);
        hlist_add_head(&msgq->qid_hlist, qid_head);
    }

    if (!msghdl) {
        put_handle(hdl);
        return 0;
    }

    *msghdl = msgq;
    return 0;
}
Ejemplo n.º 29
0
int thread_exit(struct shim_thread * self, bool send_ipc)
{
    /* Chia-Che: Broadcast exit message as early as possible,
       so other process can start early on responding. */
    if (self->in_vm && send_ipc)
        ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal);

    lock(&self->lock);

    if (!self->is_alive) {
        debug("thread %d is dead\n", self->tid);
    out:
        unlock(&self->lock);
        return 0;
    }

    #ifdef PROFILE
    self->exit_time = GET_PROFILE_INTERVAL();
    #endif

    int exit_code = self->exit_code;
    self->is_alive = false;

    if (is_internal(self))
        goto out;

    struct shim_handle_map * handle_map = self->handle_map;
    struct shim_handle * exec = self->exec;
    struct shim_thread * parent = self->parent;
    self->handle_map = NULL;
    self->exec = NULL;

    if (parent) {
        assert(parent != self);
        assert(parent->child_exit_event);
        debug("thread exits, notifying thread %d\n", parent->tid);

        lock(&parent->lock);
        LISTP_DEL_INIT(self, &parent->children, siblings);
        LISTP_ADD_TAIL(self, &parent->exited_children, siblings);

        if (!self->in_vm) {
            debug("deliver SIGCHLD (thread = %d, exitval = %d)\n",
                  self->tid, exit_code);

            siginfo_t info;
            memset(&info, 0, sizeof(siginfo_t));
            info.si_signo = SIGCHLD;
            info.si_pid   = self->tid;
            info.si_uid   = self->uid;
            info.si_status = (exit_code & 0xff) << 8;

            append_signal(parent, SIGCHLD, &info, true);
        }
        unlock(&parent->lock);

        DkEventSet(parent->child_exit_event);
    } else {
        debug("parent not here, need to tell another process\n");
        ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal);
    }

    struct robust_list_head * robust_list = (void *) self->robust_list;
    self->robust_list = NULL;

    unlock(&self->lock);

    if (handle_map)
        put_handle_map(handle_map);

    if (exec)
        put_handle(exec);

    if (robust_list)
        release_robust_list(robust_list);

    if (self->clear_child_tid)
        release_clear_child_id (self->clear_child_tid);

    DkEventSet(self->exit_event);
    return 0;
}