a5648b8094
chase_symlinks() would return negative on error, and either a non-negative status or a non-negative fd when CHASE_OPEN was given. This made the interface quite complicated, because dependning on the flags used, we would get two different "types" of return object. Coverity was always confused by this, and flagged every use of chase_symlinks() without CHASE_OPEN as a resource leak (because it would this that an fd is returned). This patch uses a saparate output parameter, so there is no confusion. (I think it is OK to have functions which return either an error or an fd. It's only returning *either* an fd or a non-fd that is confusing.)
118 lines
3.8 KiB
C
118 lines
3.8 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
#include <getopt.h>
|
|
|
|
#include "fd-util.h"
|
|
#include "fs-util.h"
|
|
#include "log.h"
|
|
#include "main-func.h"
|
|
|
|
static char *arg_root = NULL;
|
|
static int arg_flags = 0;
|
|
static bool arg_open = false;
|
|
|
|
static int parse_argv(int argc, char *argv[]) {
|
|
enum {
|
|
ARG_ROOT = 0x1000,
|
|
ARG_OPEN,
|
|
};
|
|
|
|
static const struct option options[] = {
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ "root", required_argument, NULL, ARG_ROOT },
|
|
{ "open", no_argument, NULL, ARG_OPEN },
|
|
|
|
{ "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT },
|
|
{ "nonexistent", no_argument, NULL, CHASE_NONEXISTENT },
|
|
{ "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS },
|
|
{ "safe", no_argument, NULL, CHASE_SAFE },
|
|
{ "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH },
|
|
{ "step", no_argument, NULL, CHASE_STEP },
|
|
{ "nofollow", no_argument, NULL, CHASE_NOFOLLOW },
|
|
{ "warn", no_argument, NULL, CHASE_WARN },
|
|
{}
|
|
};
|
|
|
|
int c;
|
|
|
|
assert(argc >= 0);
|
|
assert(argv);
|
|
|
|
while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
|
|
switch (c) {
|
|
|
|
case 'h':
|
|
printf("Syntax:\n"
|
|
" %s [OPTION...] path...\n"
|
|
"Options:\n"
|
|
, argv[0]);
|
|
for (size_t i = 0; i < ELEMENTSOF(options) - 1; i++)
|
|
printf(" --%s\n", options[i].name);
|
|
return 0;
|
|
|
|
case ARG_ROOT:
|
|
arg_root = optarg;
|
|
break;
|
|
|
|
case ARG_OPEN:
|
|
arg_open = true;
|
|
break;
|
|
|
|
case CHASE_PREFIX_ROOT:
|
|
case CHASE_NONEXISTENT:
|
|
case CHASE_NO_AUTOFS:
|
|
case CHASE_SAFE:
|
|
case CHASE_TRAIL_SLASH:
|
|
case CHASE_STEP:
|
|
case CHASE_NOFOLLOW:
|
|
case CHASE_WARN:
|
|
arg_flags |= c;
|
|
break;
|
|
|
|
case '?':
|
|
return -EINVAL;
|
|
|
|
default:
|
|
assert_not_reached("Unhandled option");
|
|
}
|
|
|
|
if (optind == argc)
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "At least one argument is required.");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int run(int argc, char **argv) {
|
|
int r;
|
|
|
|
log_show_color(true);
|
|
log_parse_environment();
|
|
log_open();
|
|
|
|
r = parse_argv(argc, argv);
|
|
if (r <= 0)
|
|
return r;
|
|
|
|
for (int i = optind; i < argc; i++) {
|
|
_cleanup_free_ char *p = NULL;
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
printf("%s ", argv[i]);
|
|
fflush(stdout);
|
|
|
|
r = chase_symlinks(argv[i], arg_root, arg_flags, &p, arg_open ? &fd : NULL);
|
|
if (r < 0)
|
|
log_error_errno(r, "failed: %m");
|
|
else {
|
|
log_info("→ %s", p);
|
|
if (arg_open)
|
|
assert(fd >= 0);
|
|
else
|
|
assert(fd == -1);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|