2020-07-15 22:29 UTC-0700 ~ Tony Ambardar <tony.ambardar@xxxxxxxxx> > The bpftool sources include code to walk file trees, but use multiple > frameworks to do so: nftw and fts. While nftw conforms to POSIX/SUSv3 and > is widely available, fts is not conformant and less common, especially on > non-glibc systems. The inconsistent framework usage hampers maintenance > and portability of bpftool, in particular for embedded systems. > > Standardize code usage by rewriting one fts-based function to use nftw. > Clean up related function warnings by using "const char *" arguments and > fixing an unsafe call to dirname(). > > These changes help in building bpftool against musl for OpenWrt. Could you please add a line to the log about the reason for the path copy in open_obj_pinned()? > > Signed-off-by: Tony Ambardar <Tony.Ambardar@xxxxxxxxx> > --- > > V2: > * use _GNU_SOURCE to pull in getpagesize(), getline(), nftw() definitions > * use "const char *" in open_obj_pinned() and open_obj_pinned_any() > * make dirname() safely act on a string copy > > --- > tools/bpf/bpftool/common.c | 129 +++++++++++++++++++++---------------- > tools/bpf/bpftool/main.h | 4 +- > 2 files changed, 76 insertions(+), 57 deletions(-) > > diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c > index 29f4e7611ae8..7c2e52fc5784 100644 > --- a/tools/bpf/bpftool/common.c > +++ b/tools/bpf/bpftool/common.c > @@ -1,10 +1,11 @@ > // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ > > +#define _GNU_SOURCE > #include <ctype.h> > #include <errno.h> > #include <fcntl.h> > -#include <fts.h> > +#include <ftw.h> > #include <libgen.h> > #include <mntent.h> > #include <stdbool.h> > @@ -160,24 +161,36 @@ int mount_tracefs(const char *target) > return err; > } > > -int open_obj_pinned(char *path, bool quiet) > +int open_obj_pinned(const char *path, bool quiet) > { > - int fd; > + char *pname; > + int fd = -1; > + > + pname = strdup(path); > + if (pname == NULL) { Simply "if (!pname) {" > + if (!quiet) > + p_err("bpf obj get (%s): %s", path, strerror(errno)); Please update the error message, this one was for a failure on bpf_obj_get(). > + goto out_ret; > + } > + You're adding a second blank line here, please fix. > > - fd = bpf_obj_get(path); > + fd = bpf_obj_get(pname); > if (fd < 0) { > if (!quiet) > - p_err("bpf obj get (%s): %s", path, > - errno == EACCES && !is_bpffs(dirname(path)) ? > + p_err("bpf obj get (%s): %s", pname, > + errno == EACCES && !is_bpffs(dirname(pname)) ? > "directory not in bpf file system (bpffs)" : > strerror(errno)); > - return -1; > + goto out_free; > } > > +out_free: > + free(pname); > +out_ret: > return fd; > } > > -int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) > +int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type) > { > enum bpf_obj_type type; > int fd; > @@ -367,68 +380,74 @@ void print_hex_data_json(uint8_t *data, size_t len) > jsonw_end_array(json_wtr); > } > > -int build_pinned_obj_table(struct pinned_obj_table *tab, > - enum bpf_obj_type type) > +static struct pinned_obj_table *build_fn_table; /* params for nftw cb*/ > +static enum bpf_obj_type build_fn_type; I would move the comments above the lines, since it applies to both of them. > + > +static int do_build_table_cb(const char *fpath, const struct stat *sb, > + int typeflag, struct FTW *ftwbuf) Please align the second line on the open parenthesis. > { > struct bpf_prog_info pinned_info = {}; A few suggestions on this code, even though I realise you simply moved some parts. We can skip zero-initialising here (" = {}") because we memset() it below before using it anyway. > struct pinned_obj *obj_node = NULL; > __u32 len = sizeof(pinned_info); > - struct mntent *mntent = NULL; > enum bpf_obj_type objtype; > + int fd, err = 0; > + > + if (typeflag != FTW_F) > + goto out_ret; > + fd = open_obj_pinned(fpath, true); > + if (fd < 0) > + goto out_ret; > + > + objtype = get_fd_type(fd); > + if (objtype != build_fn_type) > + goto out_close; > + > + memset(&pinned_info, 0, sizeof(pinned_info)); > + if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len)) { > + p_err("can't get obj info: %s", strerror(errno)); We are simply building a table here to show the paths where objects are pinned when listing progs/maps/etc., and I don't believe we want to print an error in that case. And with such a message I would expect the function to return and bpftool to stop, but again I don't believe this is necessary here and we can just go on listing objects, even if we fail to show their pinned paths. > + goto out_close; > + } > + > + obj_node = malloc(sizeof(*obj_node)); > + if (!obj_node) { > + p_err("mem alloc failed"); Same here, let's not add an error message. > + err = -1; > + goto out_close; > + } > + > + memset(obj_node, 0, sizeof(*obj_node)); Instead of malloc() + memset(), we could simply use calloc(). > + obj_node->id = pinned_info.id; > + obj_node->path = strdup(fpath); > + hash_add(build_fn_table->table, &obj_node->hash, obj_node->id); > + > +out_close: > + close(fd); > +out_ret: > + return err; > +} > + > +int build_pinned_obj_table(struct pinned_obj_table *tab, > + enum bpf_obj_type type) > +{ The end looks good. Apart from the minor points mentioned above, the patch is good, copying the string in open_obj_pinned() looks like the right approach. It does compile (with no warnings) and works as intended on my machine :). Thanks, Quentin