On Tue, 2010-01-26 at 17:08 -0500, Caleb Case wrote: > This provides the basic compilation function semanage_compile_hll that > is called during module installation. semanage_exec is a helper function > which sets up the redirected io for the child process, executes it, > waits for the child to exit, and then propagates the child's exit > status. An additional helper function semanage_fd_to_data reads a given > file descriptor into a buffer (unzipping it if necessary). The > compilation messages are stored in > /var/lib/selinux/.../modules/<priority>/<module>/log. > diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c > index 2bda1e2..dd96a75 100644 > --- a/libsemanage/src/semanage_store.c > +++ b/libsemanage/src/semanage_store.c > @@ -3034,3 +3034,357 @@ int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len, > > return 0; > } > + > +/* Execute @cmd with @args and redirect the @io. > + * > + * @io is an array of fd's to redirect. Indices correspond to fds. The fds > + * are not closed. Indices set to -1 are ignored, otherwise they are > + * dup2'd. > + * > + * Returns: > + * 0 success > + * -1 failure, error outside HLL compiler > + * +N failure, HLL compiler exit status N > + */ > +static int semanage_exec(semanage_handle_t *sh, > + const char *cmd, > + char *argv[], > + int io[], > + int io_len) Can this function be unified with the already existing semanage_exec_prog()? Likely by making the latter call this one after splitting args? > +int semanage_fd_to_data(semanage_handle_t *sh, > + int fd, > + char **data, > + size_t *data_len) > +{ > + assert(sh); > + assert(data); > + assert(data_len); > + > + int status = 0; > + int ret = 0; > + > + *data = NULL; > + *data_len = 0; > + > + FILE *fp = NULL; > + struct stat sb; > + sb.st_size = 0; > + ssize_t nread = 0; > + char *data_tmp = NULL; > + > + /* Find out how big it is. */ > + ret = fstat(fd, &sb); > + if (ret != 0) { > + ERR(sh, "Failed to stat file"); > + status = -2; > + goto cleanup; > + } > + *data_len = sb.st_size; > + > + /* Allocate a buffer for the file. */ > + *data = malloc(*data_len + 1); > + if (*data == NULL) { > + ERR(sh, "Out of memory!"); > + status = -1; > + goto cleanup; > + } > + (*data)[*data_len] = '\0'; Aren't we going to clobber this shortly? > + > + /* Read into the buffer. */ > + while((size_t)nread != *data_len) { > + nread = read(fd, *data + nread, *data_len - nread); > + if (nread < 0) { We should likely handle EINTR more cleanly throughout. > + ERR(sh, "Failed to read the file"); > + status = -1; > + goto cleanup; > + } > + } > + > + /* Try to bunzip. */ > + fp = fmemopen(*data, *data_len, "r"); > + if (fp == NULL) { > + ERR(sh, "Failed to open file for reading"); > + status = -1; > + goto cleanup; > + } I have a patch to eliminate use of fmemopen() in libsemanage as it doesn't handle binary files correctly for glibc < 2.9; see the other discussion. Maybe this is ok due to only acting on text files? > + > + nread = bunzip(sh, fp, &data_tmp); > + if (nread > 0) { > + free(*data); > + *data = data_tmp; > + *data_len = (size_t)nread; > + } > + > +cleanup: > + if (status != 0) { > + free(*data); > + *data = NULL; > + *data_len = 0; > + } > + > + if (fp != NULL) fclose(fp); > + > + return status; > +} > + > +int semanage_compile_hll(semanage_handle_t *sh, > + const semanage_module_info_t *modinfo) > +{ > + int status = 0; > + int ret = 0; > + > + char hll_path[PATH_MAX]; > + char cil_path[PATH_MAX]; > + char ver_path[PATH_MAX]; > + char log_path[PATH_MAX]; > + > + char tmp[] = "/tmp/libsemanage-XXXXXX"; > + int tmp_fd = -1; > + ssize_t nwrite = 0; > + > + int io[4]; > + int io_len = 4; > + > + const semanage_lang_conf_t *conf = NULL; > + > + int i; > + > + char **argv = NULL; > + > + char *data = NULL; > + size_t data_len = 0; > + > + /* determine paths and setup io: > + * > + * 0 hll > + * 1 cil > + * 2 log > + * 3 version > + */ > + > + /* 0 hll */ > + ret = semanage_module_get_path(sh, > + modinfo, > + SEMANAGE_MODULE_PATH_HLL, > + hll_path, > + sizeof(hll_path)); > + if (ret != 0) { > + status = -1; > + goto cleanup; > + } > + > + /* open hll, read in (which will bunzip if necessary) */ > + tmp_fd = open(hll_path, O_RDONLY); > + if (tmp_fd < 0) { > + ERR(sh, "Failed to open %s", hll_path); > + status = -1; > + goto cleanup; > + } > + > + ret = semanage_fd_to_data(sh, tmp_fd, &data, &data_len); > + if (ret != 0) { > + ERR(sh, "Failed to read %s", hll_path); > + status = -1; > + goto cleanup; > + } > + > + close(tmp_fd); > + tmp_fd = mkstemp(tmp); > + if (tmp_fd < 0) { > + ERR(sh, > + "Failed to create tmp file for module %s.", > + modinfo->name); > + status = -1; > + goto cleanup; > + } > + > + while((size_t)nwrite != data_len) { > + nwrite = write(tmp_fd, data + nwrite, data_len - nwrite); > + if (nwrite < 0) { EINTR handling. Need to check that the expected length was written, not just < 0. >From the man page: If a write() is interrupted by a signal handler before any bytes are written, then the call fails with the error EINTR; if it is interrupted after at least one byte has been written, the call succeeds, and returns the number of bytes written. > + ERR(sh, > + "Failed to write data to tmp file for module %s.", > + modinfo->name); > + status = -1; > + goto cleanup; > + } > + } > + > + ret = fsync(tmp_fd); fdatasync(), maybe? -- Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with the words "unsubscribe selinux" without quotes as the message.