/* If *phdl is returned on success, the ref count is incremented */ static int parse_thread_fd (const char * name, const char ** rest, struct shim_handle ** phdl) { const char * next, * nextnext; int next_len; int pid = parse_thread_name(name, &next, &next_len, &nextnext); if (!pid) return pid; if (!next || !nextnext || memcmp(next, "fd", next_len)) return -EINVAL; const char * p = nextnext; int fd = 0; for ( ; *p && *p != '/' ; p++) { if (*p < '0' || *p > '9') return -ENOENT; fd = fd * 10 + *p - '0'; if (fd >= __rlim[RLIMIT_NOFILE].rlim_cur) return -ENOENT; } struct shim_thread * thread = lookup_thread(pid); if (!thread) return -ENOENT; struct shim_handle_map * handle_map = get_cur_handle_map(thread); lock(&handle_map->lock); if (fd >= handle_map->fd_top || handle_map->map[fd] == NULL || handle_map->map[fd]->handle == NULL) { unlock(&handle_map->lock); return -ENOENT; } if (phdl) { *phdl = handle_map->map[fd]->handle; get_handle(*phdl); } unlock(&handle_map->lock); if (rest) *rest = *p ? p + 1 : NULL; return 0; }
struct shim_handle * get_fd_handle (FDTYPE fd, int * flags, struct shim_handle_map * map) { if (!map) map = get_cur_handle_map(NULL); struct shim_handle * hdl = NULL; lock(map->lock); if ((hdl = __get_fd_handle(fd, flags, map))) get_handle(hdl); unlock(map->lock); return hdl; }
int set_new_fd_handle (struct shim_handle * hdl, int flags, struct shim_handle_map * handle_map) { FDTYPE fd = 0; int new_size = 0; int ret = 0; if (!handle_map && !(handle_map = get_cur_handle_map(NULL))) return -EBADF; lock(handle_map->lock); if (!handle_map->map || handle_map->fd_size < INIT_HANDLE_MAP_SIZE) new_size = INIT_HANDLE_MAP_SIZE; if (!handle_map->map) goto extend; if (handle_map->fd_top != FD_NULL) do { ++fd; if (fd == handle_map->fd_size) { new_size = handle_map->fd_size < new_size ? new_size : handle_map->fd_size * 2; extend: if (!__enlarge_handle_map(handle_map, new_size)) { ret = -ENOMEM; goto out; } } } while (handle_map->fd_top != FD_NULL && fd <= handle_map->fd_top && HANDLE_ALLOCATED(handle_map->map[fd])); if (handle_map->fd_top == FD_NULL || fd > handle_map->fd_top) handle_map->fd_top = fd; ret = __set_new_fd_handle(&handle_map->map[fd], fd, hdl, flags); if (ret < 0) { if (fd == handle_map->fd_top) handle_map->fd_top = fd ? fd - 1 : FD_NULL; } else ret = fd; out: unlock(handle_map->lock); return ret; }
struct shim_handle * detach_fd_handle (FDTYPE fd, int * flags, struct shim_handle_map * handle_map) { struct shim_handle * handle = NULL; if (!handle_map && !(handle_map = get_cur_handle_map(NULL))) return NULL; lock(handle_map->lock); if (fd < handle_map->fd_size) handle = __detach_fd_handle(handle_map->map[fd], flags, handle_map); unlock(handle_map->lock); return handle; }
static int proc_list_thread_each_fd (const char * name, struct shim_dirent ** buf, int count) { const char * next; int next_len; int pid = parse_thread_name(name, &next, &next_len, NULL); if (!pid) return pid; if (!next || memcmp(next, "fd", next_len)) return -EINVAL; struct shim_thread * thread = lookup_thread(pid); if (!thread) return -ENOENT; struct shim_handle_map * handle_map = get_cur_handle_map(thread); int err = 0, bytes = 0; struct shim_dirent * dirent = *buf, ** last = NULL; lock(&handle_map->lock); for (int i = 0 ; i < handle_map->fd_size ; i++) if (handle_map->map[i] && handle_map->map[i]->handle) { int d = i, l = 0; for ( ; d ; d /= 10, l++); l = l ? : 1; bytes += sizeof(struct shim_dirent) + l + 1; if (bytes > count) { err = -ENOMEM; break; } dirent->next = (void *) (dirent + 1) + l + 1; dirent->ino = 1; dirent->type = LINUX_DT_LNK; dirent->name[0] = '0'; dirent->name[l--] = 0; for (d = i ; d ; d /= 10) dirent->name[l--] = '0' + d % 10; last = &dirent->next; dirent = dirent->next; }
int set_new_fd_handle_by_fd (FDTYPE fd, struct shim_handle * hdl, int flags, struct shim_handle_map * handle_map) { int new_size = 0; int ret = 0; if (!handle_map && !(handle_map = get_cur_handle_map(NULL))) return -EBADF; lock(handle_map->lock); if (!handle_map->map || handle_map->fd_size < INIT_HANDLE_MAP_SIZE) new_size = INIT_HANDLE_MAP_SIZE; if (!handle_map->map) goto extend; if (fd >= handle_map->fd_size) { new_size = handle_map->fd_size < new_size ? new_size : handle_map->fd_size; extend: while (new_size <= fd) new_size *= 2; if (!__enlarge_handle_map(handle_map, new_size)) { ret = -ENOMEM; goto out; } } if (handle_map->fd_top != FD_NULL && fd <= handle_map->fd_top && HANDLE_ALLOCATED(handle_map->map[fd])) { ret = -EBADF; goto out; } if (handle_map->fd_top == FD_NULL || fd > handle_map->fd_top) handle_map->fd_top = fd; struct shim_fd_handle * new_handle = handle_map->map[fd]; if (!new_handle) { new_handle = malloc(sizeof(struct shim_fd_handle)); if (!new_handle) { ret = -ENOMEM; goto out; } handle_map->map[fd] = new_handle; } ret = __set_new_fd_handle(&handle_map->map[fd], fd, hdl, flags); if (ret < 0) { if (fd == handle_map->fd_top) handle_map->fd_top = fd ? fd - 1 : FD_NULL; } else ret = fd; out: unlock(handle_map->lock); return fd; }
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; }