update
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int
|
||||
parse_errno(const char *text)
|
||||
{
|
||||
char *end;
|
||||
long value;
|
||||
|
||||
errno = 0;
|
||||
value = strtol(text, &end, 0);
|
||||
if (errno != 0 || *text == '\0' || *end != '\0' || value <= 0 ||
|
||||
value > 255)
|
||||
errx(2, "invalid errno: %s", text);
|
||||
return ((int)value);
|
||||
}
|
||||
|
||||
static int
|
||||
run_operation(const char *operation, const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
int fd;
|
||||
|
||||
if (strcmp(operation, "stat") == 0)
|
||||
return (stat(path, &sb));
|
||||
if (strcmp(operation, "lstat") == 0)
|
||||
return (lstat(path, &sb));
|
||||
if (strcmp(operation, "open-read") == 0) {
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return (-1);
|
||||
return (close(fd));
|
||||
}
|
||||
if (strcmp(operation, "open-rdwr") == 0) {
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0)
|
||||
return (-1);
|
||||
return (close(fd));
|
||||
}
|
||||
if (strcmp(operation, "access-read") == 0)
|
||||
return (access(path, R_OK));
|
||||
if (strcmp(operation, "access-write") == 0)
|
||||
return (access(path, W_OK));
|
||||
if (strcmp(operation, "access-exec") == 0)
|
||||
return (access(path, X_OK));
|
||||
if (strcmp(operation, "chmod") == 0)
|
||||
return (chmod(path, 0777));
|
||||
if (strcmp(operation, "chown") == 0)
|
||||
return (chown(path, 65534, 65534));
|
||||
if (strcmp(operation, "truncate") == 0)
|
||||
return (truncate(path, 0));
|
||||
if (strcmp(operation, "create") == 0) {
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0)
|
||||
return (-1);
|
||||
if (close(fd) != 0)
|
||||
return (-1);
|
||||
return (unlink(path));
|
||||
}
|
||||
errx(2, "unknown operation: %s", operation);
|
||||
}
|
||||
|
||||
static void
|
||||
expect_result(const char *operation, const char *path, int expected_errno)
|
||||
{
|
||||
int error, result;
|
||||
|
||||
errno = 0;
|
||||
result = run_operation(operation, path);
|
||||
error = errno;
|
||||
if (expected_errno == 0) {
|
||||
if (result != 0)
|
||||
errx(1, "%s %s returned errno %d (%s)", operation, path,
|
||||
error, strerror(error));
|
||||
printf("op=%s result=success errno=0\n", operation);
|
||||
return;
|
||||
}
|
||||
if (result == 0)
|
||||
errx(1, "%s %s unexpectedly succeeded", operation, path);
|
||||
if (error != expected_errno)
|
||||
errx(1, "%s %s returned errno %d (%s), expected %d", operation,
|
||||
path, error, strerror(error), expected_errno);
|
||||
printf("op=%s result=error errno=%d message=%s\n", operation,
|
||||
error, strerror(error));
|
||||
}
|
||||
|
||||
static long
|
||||
checked_pathconf(const char *path, int name, const char *label, int *errorp)
|
||||
{
|
||||
long value;
|
||||
|
||||
errno = 0;
|
||||
value = pathconf(path, name);
|
||||
*errorp = value == -1 ? errno : 0;
|
||||
if (*errorp != 0)
|
||||
printf("%s=error:%d ", label, *errorp);
|
||||
else
|
||||
printf("%s=%ld ", label, value);
|
||||
return (value);
|
||||
}
|
||||
|
||||
static void
|
||||
show_pathconf(const char *path)
|
||||
{
|
||||
int chown_error, filesizebits_error, link_error, name_error,
|
||||
no_trunc_error, path_error;
|
||||
long chown_restricted, filesizebits, link_max, name_max, no_trunc,
|
||||
path_max;
|
||||
|
||||
name_max = checked_pathconf(path, _PC_NAME_MAX, "name_max",
|
||||
&name_error);
|
||||
path_max = checked_pathconf(path, _PC_PATH_MAX, "path_max",
|
||||
&path_error);
|
||||
filesizebits = checked_pathconf(path, _PC_FILESIZEBITS, "filesizebits",
|
||||
&filesizebits_error);
|
||||
link_max = checked_pathconf(path, _PC_LINK_MAX, "link_max",
|
||||
&link_error);
|
||||
no_trunc = checked_pathconf(path, _PC_NO_TRUNC, "no_trunc",
|
||||
&no_trunc_error);
|
||||
chown_restricted = checked_pathconf(path, _PC_CHOWN_RESTRICTED,
|
||||
"chown_restricted", &chown_error);
|
||||
putchar('\n');
|
||||
if (name_error != 0 || path_error != 0 || filesizebits_error != 0 ||
|
||||
link_error != 0 || no_trunc_error != 0 || chown_error != 0 ||
|
||||
name_max != 255 || path_max <= 0 || filesizebits != 64 ||
|
||||
link_max <= 0 || no_trunc != 1 || chown_restricted != 1)
|
||||
errx(1, "unexpected EROFS pathconf values");
|
||||
}
|
||||
|
||||
static void
|
||||
show_readlink(const char *path)
|
||||
{
|
||||
unsigned char target[4096];
|
||||
uint64_t hash;
|
||||
ssize_t length;
|
||||
|
||||
length = readlink(path, (char *)target, sizeof(target));
|
||||
if (length < 0)
|
||||
err(1, "readlink %s", path);
|
||||
if ((size_t)length == sizeof(target))
|
||||
errx(1, "symlink target is too long");
|
||||
hash = UINT64_C(14695981039346656037);
|
||||
for (ssize_t index = 0; index < length; index++) {
|
||||
hash ^= target[index];
|
||||
hash *= UINT64_C(1099511628211);
|
||||
}
|
||||
target[length] = '\0';
|
||||
printf("length=%zd fnv1a64=%016" PRIx64 " target=%s\n", length,
|
||||
hash, target);
|
||||
}
|
||||
|
||||
static void
|
||||
show_stat(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (lstat(path, &sb) != 0)
|
||||
err(1, "lstat %s", path);
|
||||
printf("ino=%ju mode=%#jo uid=%ju gid=%ju nlink=%ju size=%jd "
|
||||
"blocks=%jd blksize=%jd",
|
||||
(uintmax_t)sb.st_ino, (uintmax_t)sb.st_mode,
|
||||
(uintmax_t)sb.st_uid, (uintmax_t)sb.st_gid,
|
||||
(uintmax_t)sb.st_nlink, (intmax_t)sb.st_size,
|
||||
(intmax_t)sb.st_blocks, (intmax_t)sb.st_blksize);
|
||||
#ifdef __FreeBSD__
|
||||
printf(" gen=%ju", (uintmax_t)sb.st_gen);
|
||||
#endif
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 5 && strcmp(argv[1], "expect-error") == 0) {
|
||||
expect_result(argv[2], argv[3], parse_errno(argv[4]));
|
||||
return (0);
|
||||
}
|
||||
if (argc == 4 && strcmp(argv[1], "expect-success") == 0) {
|
||||
expect_result(argv[2], argv[3], 0);
|
||||
return (0);
|
||||
}
|
||||
if (argc == 3 && strcmp(argv[1], "pathconf") == 0) {
|
||||
show_pathconf(argv[2]);
|
||||
return (0);
|
||||
}
|
||||
if (argc == 3 && strcmp(argv[1], "readlink") == 0) {
|
||||
show_readlink(argv[2]);
|
||||
return (0);
|
||||
}
|
||||
if (argc == 3 && strcmp(argv[1], "stat") == 0) {
|
||||
show_stat(argv[2]);
|
||||
return (0);
|
||||
}
|
||||
errx(2, "usage: %s expect-error OP PATH ERRNO | "
|
||||
"expect-success OP PATH | pathconf PATH | readlink PATH | stat PATH",
|
||||
argv[0]);
|
||||
}
|
||||
Reference in New Issue
Block a user