ssize_t alcove_mk_error(char *buf, size_t len, const char *reason) { int index = 0; if (alcove_encode_version(buf, len, &index) < 0) return -1; if (alcove_encode_tuple_header(buf, len, &index, 2) < 0) return -1; if (alcove_encode_atom(buf, len, &index, "error") < 0) return -1; if (alcove_encode_atom(buf, len, &index, reason) < 0) return -1; return index; }
int alcove_encode_constant(char *buf, size_t len, int *index, char *name, const alcove_constant_t *constants) { long long val = 0; if (alcove_lookup_constant(name, &val, constants) < 0) return alcove_encode_atom(buf, len, index, "unknown"); return alcove_encode_ulonglong(buf, len, index, val); }
/* * getrlimit(2) * */ ssize_t alcove_sys_getrlimit(alcove_state_t *ap, const char *arg, size_t len, char *reply, size_t rlen) { int index = 0; int rindex = 0; int resource = 0; struct rlimit rlim = {0}; int rv = 0; /* resource */ switch (alcove_decode_define(arg, len, &index, &resource, alcove_rlimit_constants)) { case 0: break; case 1: return alcove_mk_error(reply, rlen, "unsupported"); default: return -1; } rv = getrlimit(resource, &rlim); if (rv < 0) return alcove_mk_errno(reply, rlen, errno); ALCOVE_ERR(alcove_encode_version(reply, rlen, &rindex)); ALCOVE_ERR(alcove_encode_tuple_header(reply, rlen, &rindex, 2)); ALCOVE_ERR(alcove_encode_atom(reply, rlen, &rindex, "ok")); ALCOVE_ERR(alcove_encode_tuple_header(reply, rlen, &rindex, 3)); ALCOVE_ERR(alcove_encode_atom(reply, rlen, &rindex, "alcove_rlimit")); ALCOVE_ERR(alcove_encode_ulonglong(reply, rlen, &rindex, rlim.rlim_cur)); ALCOVE_ERR(alcove_encode_ulonglong(reply, rlen, &rindex, rlim.rlim_max)); return rindex; }
int alcove_encode_cstruct(char *reply, size_t rlen, int *rindex, const char *buf, size_t len, alcove_alloc_t *ptr, ssize_t nptr) { int i = 0; size_t offset = 0; if (alcove_encode_list_header(reply, rlen, rindex, nptr) < 0) return -1; for ( ; i < nptr; i++) { if (ptr[i].p) { if (offset + sizeof(void *) > len) return -1; /* Allocated buffer */ if (alcove_encode_tuple_header(reply, rlen, rindex, 2) < 0) return -1; if (alcove_encode_atom(reply, rlen, rindex, "ptr") < 0) return -1; if (alcove_encode_binary(reply, rlen, rindex, ptr[i].p, ptr[i].len) < 0) return -1; free(ptr[i].p); offset += sizeof(void *); } else { if (offset + ptr[i].len > len) return -1; /* Static binary */ if (alcove_encode_binary(reply, rlen, rindex, buf+offset, ptr[i].len) < 0) return -1; offset += ptr[i].len; } } if (alcove_encode_empty_list(reply, rlen, rindex) < 0) return -1; free(ptr); ptr = NULL; return 0; }
/* * readdir(3) * */ ssize_t alcove_sys_readdir(alcove_state_t *ap, const char *arg, size_t len, char *reply, size_t rlen) { int index = 0; int rindex = 0; char name[PATH_MAX] = {0}; size_t namelen = sizeof(name)-1; DIR *dirp = NULL; struct dirent *dent = NULL; UNUSED(ap); /* name */ if (alcove_decode_iolist(arg, len, &index, name, &namelen) < 0 || namelen == 0) return -1; dirp = opendir(name); if (dirp == NULL) return alcove_mk_errno(reply, rlen, errno); ALCOVE_ERR(alcove_encode_version(reply, rlen, &rindex)); ALCOVE_ERR(alcove_encode_tuple_header(reply, rlen, &rindex, 2)); ALCOVE_ERR(alcove_encode_atom(reply, rlen, &rindex, "ok")); errno = 0; while ( (dent = readdir(dirp))) { ALCOVE_ERR(alcove_encode_list_header(reply, rlen, &rindex, 1)); ALCOVE_ERR(alcove_encode_binary(reply, rlen, &rindex, dent->d_name, strlen(dent->d_name))); } if (errno != 0) return alcove_mk_errno(reply, rlen, errno); if (closedir(dirp) < 0) return alcove_mk_errno(reply, rlen, errno); ALCOVE_ERR(alcove_encode_empty_list(reply, rlen, &rindex)); return rindex; }
/* * ptrace(2) * */ ssize_t alcove_sys_ptrace(alcove_state_t *ap, const char *arg, size_t len, char *reply, size_t rlen) { #if defined(__linux__) int index = 0; int rindex = 0; int type = 0; int arity = 0; int request = 0; pid_t pid = 0; alcove_ptrace_arg_t addr = {0}; alcove_ptrace_arg_t data = {0}; alcove_alloc_t *elem = NULL; ssize_t nelem = 0; long rv = 0; UNUSED(ap); /* request */ switch (alcove_decode_constant(arg, len, &index, &request, alcove_ptrace_constants)) { case 0: break; case 1: return alcove_mk_error(reply, rlen, "enotsup"); default: return -1; } /* pid */ if (alcove_decode_int(arg, len, &index, &pid) < 0) return -1; /* addr */ if (alcove_get_type(arg, len, &index, &type, &arity) < 0) return -1; switch (type) { case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: addr.type = ALCOVE_PTRACEARG_INT; if (alcove_decode_ulong(arg, len, &index, &addr.arg) < 0) return -1; break; case ERL_LIST_EXT: addr.type = ALCOVE_PTRACEARG_CSTRUCT; addr.len = sizeof(addr.data); if (alcove_decode_cstruct(arg, len, &index, addr.data, &(addr.len), &elem, &nelem) < 0) return -1; break; case ERL_BINARY_EXT: addr.type = ALCOVE_PTRACEARG_BINARY; if (arity > sizeof(addr.data)) return -1; if (alcove_decode_binary(arg, len, &index, addr.data, &addr.len) < 0) return -1; break; default: return -1; } /* data */ if (alcove_get_type(arg, len, &index, &type, &arity) < 0) return -1; switch (type) { case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: data.type = ALCOVE_PTRACEARG_INT; if (alcove_decode_ulong(arg, len, &index, &data.arg) < 0) return -1; break; case ERL_LIST_EXT: data.type = ALCOVE_PTRACEARG_CSTRUCT; data.len = sizeof(data.data); if (alcove_decode_cstruct(arg, len, &index, data.data, &(data.len), &elem, &nelem) < 0) return -1; break; case ERL_BINARY_EXT: data.type = ALCOVE_PTRACEARG_BINARY; if (arity > sizeof(data.data)) return -1; if (alcove_decode_binary(arg, len, &index, data.data, &data.len) < 0) return -1; break; default: return -1; } errno = 0; rv = ptrace(request, pid, PRTRACEARG(addr), PRTRACEARG(data)); if (errno) return alcove_mk_errno(reply, rlen, errno); ALCOVE_ERR(alcove_encode_version(reply, rlen, &rindex)); ALCOVE_ERR(alcove_encode_tuple_header(reply, rlen, &rindex, 4)); ALCOVE_ERR(alcove_encode_atom(reply, rlen, &rindex, "ok")); ALCOVE_ERR(alcove_encode_long(reply, rlen, &rindex, rv)); switch (addr.type) { case ALCOVE_PTRACEARG_CSTRUCT: ALCOVE_ERR(alcove_encode_cstruct(reply, rlen, &rindex, addr.data, addr.len, elem, nelem)); break; case ALCOVE_PTRACEARG_INT: /* return an empty binary */ case ALCOVE_PTRACEARG_BINARY: ALCOVE_ERR(alcove_encode_binary(reply, rlen, &rindex, addr.data, addr.len)); break; default: return -1; } switch (data.type) { case ALCOVE_PTRACEARG_CSTRUCT: ALCOVE_ERR(alcove_encode_cstruct(reply, rlen, &rindex, data.data, data.len, elem, nelem)); break; case ALCOVE_PTRACEARG_INT: /* return an empty binary */ case ALCOVE_PTRACEARG_BINARY: ALCOVE_ERR(alcove_encode_binary(reply, rlen, &rindex, data.data, data.len)); break; default: return -1; } return rindex; #else UNUSED(ap); UNUSED(arg); UNUSED(len); return alcove_mk_atom(reply, rlen, "undef"); #endif }