1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
/* SPDX-License-Identifier: MIT */
/* SPDX-FileCopyrightText: (c) Copyright 2024 Andrew Bower <andrew@bower.uk> */
/* xchpst: eXtended Change Process State
* A tool that is backwards compatible with chpst(8) from runit(8),
* offering additional options to harden process with namespace isolation
* and more. */
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "xchpst.h"
#include "caps.h"
#include "options.h"
bool read_env_dir(const char *dir_name) {
int dir1 = -1;
int dir2 = -1;
int file = -1;
DIR *dir = NULL;
const char *entity;
const struct dirent *de;
bool success = false;
struct stat statbuf;
char *data = NULL;
ssize_t data_sz = -1;
ssize_t buffered;
ssize_t end;
ssize_t ptr;
int rc;
if ((dir1 = open(entity = dir_name, O_RDONLY | O_DIRECTORY)) == -1)
goto fail;
if ((dir2 = openat(dir1, "./", O_RDONLY | O_DIRECTORY)) == -1)
goto fail;
if ((dir = fdopendir(dir1)) == NULL)
goto fail;
for (errno = 0; (de = readdir(dir));) {
if (de->d_type == DT_DIR)
continue;
if ((file = openat(dir2, entity = de->d_name, O_RDONLY)) == -1)
goto fail;
if ((rc = fstat(file, &statbuf)) == -1)
goto fail;
assert(statbuf.st_size >= 0); /* educate gcc -fanalyzer */
if ((ssize_t) statbuf.st_size > data_sz) {
data_sz = statbuf.st_size;
free(data);
data = malloc(data_sz + 1);
if (data == NULL)
goto fail;
}
for (ptr = 0, buffered = 0, end = statbuf.st_size; ptr < end; ptr++) {
/* Slurp chunks of data */
if (ptr == buffered) {
if ((rc = read(file, data + ptr, end - ptr)) == -1)
goto fail;
else
buffered += rc;
}
/* Terminate at first LF; turn NUL within value into LF */
if (data[ptr] == '\n')
end = ptr;
else if (data[ptr] == '\0')
data[ptr] = '\n';
}
/* Remove trailing whitespace */
for (ptr = end - 1; ptr >= 0; ptr--)
if (data[ptr] == ' ' || data[ptr] == '\t')
data[ptr] = '\0';
else
break;
close(file);
file = -1;
if (statbuf.st_size != 0) {
data[end] = '\0';
if (is_verbose())
fprintf(stderr, "setting %s=%s\n", de->d_name, data);
setenv(de->d_name, data, 1);
} else {
if (is_verbose())
fprintf(stderr, "unsetting %s\n", de->d_name);
unsetenv(de->d_name);
}
}
success = errno == 0 ? true : false;
fail:
if (!success)
fprintf(stderr, "error reading environment \"%s\", %s\n", entity, strerror(errno));
free(data);
if (file != -1)
close(file);
if (dir != NULL)
closedir(dir);
/* if fdopendir(dir1) succeeded, then don't close dir1 */
else if (dir1 != -1)
close(dir1);
if (dir2 != -1)
close(dir2);
return success;
}
|