diff --git a/0001-Use-mountinfo-to-be-able-to-use-the-mount-identity.patch b/0001-Use-mountinfo-to-be-able-to-use-the-mount-identity.patch index 291f264..ef8586b 100644 --- a/0001-Use-mountinfo-to-be-able-to-use-the-mount-identity.patch +++ b/0001-Use-mountinfo-to-be-able-to-use-the-mount-identity.patch @@ -1,6 +1,6 @@ -From 1066ab018235e9981d8770f6c94b294f8b16c7fe Mon Sep 17 00:00:00 2001 +From e5ba304260af6a93c7af03f6bc29e1d3472ef442 Mon Sep 17 00:00:00 2001 From: Werner Fink -Date: Wed, 23 Feb 2022 13:58:32 +0100 +Date: Wed, 23 Nov 2022 14:51:53 +0100 Subject: [PATCH] Use mountinfo to be able to use the mount identity which allows to distinguish different mounts with the @@ -28,21 +28,31 @@ up the parsing of fdinfo. Add a fallback if the system call name_to_handle_at() is not supported by the used file system. +Avoid foreign namespaces as well as mount IDs for +sockets. Expand paths also for named sockets. + Signed-off-by: Werner Fink --- - configure.ac | 15 +- - src/fuser.c | 734 +++++++++++++++++++++++++++++++++++++++----------- - src/fuser.h | 25 +- - src/timeout.c | 5 +- - 4 files changed, 618 insertions(+), 161 deletions(-) + configure.ac | 18 +- + src/fuser.c | 763 +++++++++++++++++++++++++++++++++++++++++++++------ + src/fuser.h | 26 +- + 3 files changed, 721 insertions(+), 86 deletions(-) diff --git configure.ac configure.ac -index 182a0df..d4dee51 100644 +index 723cf02..3599fea 100644 --- configure.ac +++ configure.ac -@@ -60,6 +60,19 @@ if test "$enable_timeout_stat" = "static"; then +@@ -12,6 +12,7 @@ AC_USE_SYSTEM_EXTENSIONS(_GNU_SOURCE) + AC_PROG_CXX + AC_PROG_LN_S + AC_PROG_CC ++AC_PROG_CC_STDC + + AC_DEFUN([PSMISC_PROG_PO4A], [ + AC_REQUIRE([AM_NLS]) +@@ -62,6 +63,19 @@ if test "$enable_apparmor" = "yes"; then fi - AM_CONDITIONAL([WANT_TIMEOUT_STAT], [test "$enable_timeout_stat" = "static"]) + AC_SUBST([DL_LIB]) +# Use /proc/self/mountinfo if available +if test -e /proc/self/mountinfo ; then @@ -57,12 +67,15 @@ index 182a0df..d4dee51 100644 +AC_CHECK_FUNC([name_to_handle_at],[ + AC_DEFINE([HAS_NAME_TO_HANDLE_AT], [1], [System has name_to_handle_at(2) system call])]) + - # Use string search for network based file systems but only if the system - # has /proc/self/mountinfo - AC_SUBST([WITH_MOUNTINFO_LIST]) -@@ -101,7 +114,7 @@ dnl Checks for header files. + AC_CHECK_HEADERS([sys/syscall.h]) + AC_CHECK_DECLS([SYS_statx], + [has_syscall_statx="yes"], +@@ -105,9 +119,9 @@ AC_SUBST([TERMCAP_LIB]) + + dnl Checks for header files. AC_HEADER_DIRENT - AC_HEADER_STDC +- ++AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([arpa/inet.h fcntl.h langinfo.h libintl.h limits.h locale.h mntent.h netdb.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h termios.h unistd.h]) +AC_CHECK_HEADERS([arpa/inet.h fcntl.h langinfo.h libintl.h limits.h locale.h mntent.h netdb.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/mount.h sys/param.h sys/stat.h sys/socket.h sys/types.h termios.h unistd.h]) @@ -70,7 +83,7 @@ index 182a0df..d4dee51 100644 dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git src/fuser.c src/fuser.c -index 03e6237..ee2ba15 100644 +index f2bd3e9..8e4c853 100644 --- src/fuser.c +++ src/fuser.c @@ -32,6 +32,8 @@ @@ -83,1095 +96,1088 @@ index 03e6237..ee2ba15 100644 #include #include @@ -87,7 +89,7 @@ static void check_map(const pid_t pid, const char *filename, - struct device_list *dev_head, - struct inode_list *ino_head, const uid_t uid, - const char access); + struct device_list *dev_head, + struct inode_list *ino_head, const uid_t uid, + const char access); -static struct stat *get_pidstat(const pid_t pid, const char *filename); +static struct stat *get_pidstat(const pid_t pid, const char *filename, int *id); static uid_t getpiduid(const pid_t pid); static int print_matches(struct names *names_head, const opt_type opts, - const int sig_number); + const int sig_number); @@ -96,9 +98,9 @@ static int kill_matched_proc(struct procs *pptr, const opt_type opts, /*int parse_mount(struct names *this_name, struct device_list **dev_list);*/ static void add_device(struct device_list **dev_list, -- struct names *this_name, dev_t device); +- struct names *this_name, dev_t device); -void fill_unix_cache(struct unixsocket_list **unixsocket_head); -void clear_unix_cache(struct unixsocket_list **unixsocket_head); -+ struct names *this_name, dev_t device, dev_t subvol); ++ struct names *this_name, dev_t device, dev_t subvol); +static void fill_unix_cache(struct unixsocket_list **unixsocket_head); +static void clear_unix_cache(struct unixsocket_list **unixsocket_head); static void atexit_clear_unix_cache(); static dev_t find_net_dev(void); - static void scan_procs(struct names *names_head, struct inode_list *ino_head, -@@ -117,9 +119,16 @@ static void debug_match_lists(struct names *names_head, - struct device_list *dev_head); + static void scan_procs( +@@ -123,6 +125,15 @@ static void debug_match_lists( + struct device_list *dev_head); #endif --#if defined(WITH_MOUNTINFO_LIST) +static list_t mntinfo = { &mntinfo, &mntinfo }; - static void clear_mntinfo(void) __attribute__ ((__destructor__)); - static void init_mntinfo(void) __attribute__ ((__constructor__)); ++static void clear_mntinfo(void) __attribute__ ((__destructor__)); ++static void init_mntinfo(void) __attribute__ ((__constructor__)); +static int get_fdinfo(const pid_t pid, const char *fd, struct fdinfo *info, const ino_t ns); +#if defined(HAS_NAME_TO_HANDLE_AT) +static ino_t get_namespace(const pid_t pid); +static int get_mountid(const char *path); +#endif +static int find_mountpoint(const char *path, mntinfo_t **mountinfo); -+#if defined(WITH_MOUNTINFO_LIST) - static int mntstat(const char *path, struct stat *buf); + static char *expandpath(const char *path); + static struct unixsocket_list *unixsockets = NULL; + static struct names *names_head = NULL, *names_tail = NULL; +@@ -167,6 +178,7 @@ static void usage( + fprintf(stderr, _(" -4,--ipv4 search IPv4 sockets only\n" + " -6,--ipv6 search IPv6 sockets only\n")); #endif - static stat_t thestat = stat; -@@ -210,6 +219,7 @@ scan_procs(struct names *names_head, struct inode_list *ino_head, - struct stat *cwd_stat = NULL; - struct stat *exe_stat = NULL; - struct stat *root_stat = NULL; -+ int cwd_id, exe_id, root_id; - - if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */ - continue; -@@ -219,9 +229,9 @@ scan_procs(struct names *names_head, struct inode_list *ino_head, - continue; - uid = getpiduid(pid); - -- cwd_stat = get_pidstat(pid, "cwd"); -- exe_stat = get_pidstat(pid, "exe"); -- root_stat = get_pidstat(pid, "root"); -+ cwd_stat = get_pidstat(pid, "cwd", &cwd_id); -+ exe_stat = get_pidstat(pid, "exe", &exe_id); -+ root_stat = get_pidstat(pid, "root", &root_id); - cwd_dev = cwd_stat ? cwd_stat->st_dev : 0; - exe_dev = exe_stat ? exe_stat->st_dev : 0; - root_dev = root_stat ? root_stat->st_dev : 0; -@@ -229,39 +239,51 @@ scan_procs(struct names *names_head, struct inode_list *ino_head, - /* Scan the devices */ - for (dev_tmp = dev_head; dev_tmp != NULL; - dev_tmp = dev_tmp->next) { -- if (exe_dev == dev_tmp->device) -- add_matched_proc(dev_tmp->name, pid, uid, -- ACCESS_EXE); -- if (root_dev == dev_tmp->device) -- add_matched_proc(dev_tmp->name, pid, uid, -- ACCESS_ROOT); -- if (cwd_dev == dev_tmp->device) -- add_matched_proc(dev_tmp->name, pid, uid, -- ACCESS_CWD); -+ struct subvol *vol_tmp; -+ char access = 0; -+ if (exe_dev == dev_tmp->device && dev_tmp->mnt_id == exe_id) -+ access |= ACCESS_EXE; -+ if (root_dev == dev_tmp->device && dev_tmp->mnt_id == root_id) -+ access |= ACCESS_ROOT; -+ if (cwd_dev == dev_tmp->device && dev_tmp->mnt_id == cwd_id) -+ access |= ACCESS_CWD; -+ for (vol_tmp = dev_tmp->vol; vol_tmp != NULL; -+ vol_tmp = vol_tmp->next) { -+ /* For BtrFS sub volumes there are different -+ mount ids for the same device */ -+ if (exe_dev == vol_tmp->device && vol_tmp->mnt_id == exe_id) -+ access |= ACCESS_EXE; -+ if (root_dev == vol_tmp->device && vol_tmp->mnt_id == root_id) -+ access |= ACCESS_ROOT; -+ if (cwd_dev == vol_tmp->device && vol_tmp->mnt_id == cwd_id) -+ access |= ACCESS_CWD; -+ } -+ if (access) -+ add_matched_proc(dev_tmp->name, pid, uid, access); - } - for (ino_tmp = ino_head; ino_tmp != NULL; - ino_tmp = ino_tmp->next) { -- if (exe_dev == ino_tmp->device) { -+ if (exe_dev == ino_tmp->device && ino_tmp->mnt_id == exe_id) { - if (!exe_stat) -- exe_stat = get_pidstat(pid, "exe"); -+ exe_stat = get_pidstat(pid, "exe", NULL); - if (exe_stat - && exe_stat->st_dev == ino_tmp->device - && exe_stat->st_ino == ino_tmp->inode) - add_matched_proc(ino_tmp->name, pid, - uid, ACCESS_EXE); - } -- if (root_dev == ino_tmp->device) { -+ if (root_dev == ino_tmp->device && ino_tmp->mnt_id == root_id) { - if (!root_stat) -- root_stat = get_pidstat(pid, "root"); -+ root_stat = get_pidstat(pid, "root", NULL); - if (root_stat - && root_stat->st_dev == ino_tmp->device - && root_stat->st_ino == ino_tmp->inode) - add_matched_proc(ino_tmp->name, pid, - uid, ACCESS_ROOT); - } -- if (cwd_dev == ino_tmp->device) { -+ if (cwd_dev == ino_tmp->device && ino_tmp->mnt_id == cwd_id) { - if (!cwd_stat) -- cwd_stat = get_pidstat(pid, "cwd"); -+ cwd_stat = get_pidstat(pid, "cwd", NULL); - if (cwd_stat - && cwd_stat->st_dev == ino_tmp->device - && cwd_stat->st_ino == ino_tmp->inode) -@@ -302,18 +324,42 @@ add_inode(struct inode_list **ino_list, struct names *this_name, - ino_tmp->name = this_name; - ino_tmp->device = device; - ino_tmp->inode = inode; -+ ino_tmp->mnt_id = this_name->mnt_id; - ino_tmp->next = ino_head; - *ino_list = ino_tmp; ++ fprintf(stderr, _(" - reset options\n\n")); + fprintf(stderr, _(" udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n")); + exit(1); } -+ -+static void -+add_subvol(struct subvol **head, dev_t device, int mnt_id) +@@ -209,6 +221,7 @@ static void scan_procs( + struct stat *cwd_stat = NULL; + struct stat *exe_stat = NULL; + struct stat *root_stat = NULL; ++ int cwd_id, exe_id, root_id; + + if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */ + continue; +@@ -218,49 +231,64 @@ static void scan_procs( + continue; + uid = getpiduid(pid); + +- cwd_stat = get_pidstat(pid, "cwd"); +- exe_stat = get_pidstat(pid, "exe"); +- root_stat = get_pidstat(pid, "root"); ++ cwd_stat = get_pidstat(pid, "cwd", &cwd_id); ++ exe_stat = get_pidstat(pid, "exe", &exe_id); ++ root_stat = get_pidstat(pid, "root", &root_id); + cwd_dev = cwd_stat ? cwd_stat->st_dev : 0; + exe_dev = exe_stat ? exe_stat->st_dev : 0; + root_dev = root_stat ? root_stat->st_dev : 0; + + /* Scan the devices */ +- for (dev_tmp = dev_head; dev_tmp != NULL; +- dev_tmp = dev_tmp->next) { +- if (exe_dev == dev_tmp->device) +- add_matched_proc(dev_tmp->name, pid, uid, +- ACCESS_EXE); +- if (root_dev == dev_tmp->device) +- add_matched_proc(dev_tmp->name, pid, uid, +- ACCESS_ROOT); +- if (cwd_dev == dev_tmp->device) +- add_matched_proc(dev_tmp->name, pid, uid, +- ACCESS_CWD); ++ for (dev_tmp = dev_head; dev_tmp != NULL; dev_tmp = dev_tmp->next) ++ { ++ struct subvol *vol_tmp; ++ char access = 0; ++ if (exe_dev == dev_tmp->device && dev_tmp->mnt_id == exe_id) ++ access |= ACCESS_EXE; ++ if (root_dev == dev_tmp->device && dev_tmp->mnt_id == root_id) ++ access |= ACCESS_ROOT; ++ if (cwd_dev == dev_tmp->device && dev_tmp->mnt_id == cwd_id) ++ access |= ACCESS_CWD; ++ for (vol_tmp = dev_tmp->vol; vol_tmp != NULL; vol_tmp = vol_tmp->next) ++ { ++ /* For BtrFS sub volumes there are different ++ mount ids for the same device */ ++ if (exe_dev == vol_tmp->device && vol_tmp->mnt_id == exe_id) ++ access |= ACCESS_EXE; ++ if (root_dev == vol_tmp->device && vol_tmp->mnt_id == root_id) ++ access |= ACCESS_ROOT; ++ if (cwd_dev == vol_tmp->device && vol_tmp->mnt_id == cwd_id) ++ access |= ACCESS_CWD; ++ } ++ if (access) ++ add_matched_proc(dev_tmp->name, pid, uid, access); + } +- for (ino_tmp = ino_head; ino_tmp != NULL; +- ino_tmp = ino_tmp->next) { +- if (exe_dev == ino_tmp->device) { ++ for (ino_tmp = ino_head; ino_tmp != NULL; ino_tmp = ino_tmp->next) ++ { ++ if (exe_dev == ino_tmp->device && ino_tmp->mnt_id == exe_id) ++ { + if (!exe_stat) +- exe_stat = get_pidstat(pid, "exe"); ++ exe_stat = get_pidstat(pid, "exe", NULL); + if (exe_stat + && exe_stat->st_dev == ino_tmp->device + && exe_stat->st_ino == ino_tmp->inode) + add_matched_proc(ino_tmp->name, pid, + uid, ACCESS_EXE); + } +- if (root_dev == ino_tmp->device) { ++ if (root_dev == ino_tmp->device && ino_tmp->mnt_id == root_id) ++ { + if (!root_stat) +- root_stat = get_pidstat(pid, "root"); ++ root_stat = get_pidstat(pid, "root", NULL); + if (root_stat + && root_stat->st_dev == ino_tmp->device + && root_stat->st_ino == ino_tmp->inode) + add_matched_proc(ino_tmp->name, pid, + uid, ACCESS_ROOT); + } +- if (cwd_dev == ino_tmp->device) { ++ if (cwd_dev == ino_tmp->device && ino_tmp->mnt_id == cwd_id) ++ { + if (!cwd_stat) +- cwd_stat = get_pidstat(pid, "cwd"); ++ cwd_stat = get_pidstat(pid, "cwd", NULL); + if (cwd_stat + && cwd_stat->st_dev == ino_tmp->device + && cwd_stat->st_ino == ino_tmp->inode) +@@ -302,20 +330,48 @@ static void add_inode( + ino_tmp->name = this_name; + ino_tmp->device = device; + ino_tmp->inode = inode; ++ ino_tmp->mnt_id = this_name->mnt_id; + ino_tmp->next = ino_head; + *ino_list = ino_tmp; + } ++ ++static void add_subvol( ++ struct subvol **head, ++ dev_t device, ++ int mnt_id) +{ -+ struct subvol *vol_tmp, *vol_head; ++ struct subvol *vol_tmp, *vol_head; + -+ if ((vol_tmp = -+ (struct subvol *)malloc(sizeof(struct subvol))) == NULL) -+ return; -+ vol_head = *head; -+ vol_tmp->device = device; -+ vol_tmp->mnt_id = mnt_id; -+ vol_tmp->next = vol_head; -+ *head = vol_tmp; ++ if ((vol_tmp = ++ (struct subvol *)malloc(sizeof(struct subvol))) == NULL) ++ return; ++ vol_head = *head; ++ vol_tmp->device = device; ++ vol_tmp->mnt_id = mnt_id; ++ vol_tmp->next = vol_head; ++ *head = vol_tmp; +} - static void --add_device(struct device_list **dev_list, struct names *this_name, dev_t device) -+add_device(struct device_list **dev_list, struct names *this_name, dev_t device, dev_t subvol) + static void add_device( + struct device_list **dev_list, + struct names *this_name, +- dev_t device) ++ dev_t device, ++ dev_t subvol) { - struct device_list *dev_tmp, *dev_head; + struct device_list *dev_tmp, *dev_head; #ifdef DEBUG - fprintf(stderr, "add_device(%s %u\n", this_name->filename, - (unsigned int)device); - #endif /* DEBUG */ -+ /* For BtrFS there are many sub volumes all on the same block device */ -+ for (dev_tmp = *dev_list; dev_tmp != NULL; dev_tmp = dev_tmp->next) -+ if (dev_tmp->device == device) { -+ if (dev_tmp->device != subvol) -+ add_subvol(&dev_tmp->vol, subvol, this_name->mnt_id); -+ *dev_list = dev_tmp; -+ return; -+ } + fprintf(stderr, "add_device(%s %u\n", this_name->filename, +- (unsigned int)device); +-#endif /* DEBUG */ ++ (unsigned int)device); ++#endif /* DEBUG */ ++ /* For BtrFS there are many sub volumes all on the same block device */ ++ for (dev_tmp = *dev_list; dev_tmp != NULL; dev_tmp = dev_tmp->next) ++ if (dev_tmp->device == device) ++ { ++ if (dev_tmp->device != subvol) ++ add_subvol(&dev_tmp->vol, subvol, this_name->mnt_id); ++ *dev_list = dev_tmp; ++ return; ++ } - if ((dev_tmp = - (struct device_list *)malloc(sizeof(struct device_list))) == NULL) -@@ -321,6 +367,10 @@ add_device(struct device_list **dev_list, struct names *this_name, dev_t device) - dev_head = *dev_list; - dev_tmp->name = this_name; - dev_tmp->device = device; -+ dev_tmp->mnt_id = this_name->mnt_id; -+ dev_tmp->vol = NULL; -+ if (dev_tmp->device != subvol) -+ add_subvol(&dev_tmp->vol, subvol, this_name->mnt_id); - dev_tmp->next = dev_head; - *dev_list = dev_tmp; + if ((dev_tmp = + (struct device_list *)malloc(sizeof(struct device_list))) == NULL) +@@ -323,6 +379,10 @@ static void add_device( + dev_head = *dev_list; + dev_tmp->name = this_name; + dev_tmp->device = device; ++ dev_tmp->mnt_id = this_name->mnt_id; ++ dev_tmp->vol = NULL; ++ if (dev_tmp->device != subvol) ++ add_subvol(&dev_tmp->vol, subvol, this_name->mnt_id); + dev_tmp->next = dev_head; + *dev_list = dev_tmp; } -@@ -462,13 +512,15 @@ add_special_proc(struct names *name_list, const char ptype, const uid_t uid, - int parse_file(struct names *this_name, struct inode_list **ino_list, - const opt_type opts) +@@ -480,6 +540,7 @@ int parse_file( + struct inode_list **ino_list, + const opt_type opts) { -+ mntinfo_t *mountinfo; - char *new = expandpath(this_name->filename); - if (new) { - if (this_name->filename) - free(this_name->filename); - this_name->filename = strdup(new); - } -- if (timeout(thestat, this_name->filename, &(this_name->st), 5) != 0) { -+ if (timeout(thestat, this_name->filename, &(this_name->st), 5) != 0 || -+ find_mountpoint(this_name->filename, &mountinfo) != 0) { - if (errno == ENOENT) - fprintf(stderr, - _("Specified filename %s does not exist.\n"), -@@ -478,10 +530,12 @@ int parse_file(struct names *this_name, struct inode_list **ino_list, - this_name->filename, strerror(errno)); - return -1; - } -+ this_name->mnt_id = mountinfo->id; ++ mntinfo_t *mountinfo; + char *new = expandpath(this_name->filename); + if (new) + { +@@ -487,7 +548,8 @@ int parse_file( + free(this_name->filename); + this_name->filename = strdup(new); + } +- if (statn(this_name->filename, STATX_INO|STATX_TYPE, &(this_name->st)) != 0 ) ++ if (statn(this_name->filename, STATX_INO|STATX_TYPE, &(this_name->st)) != 0 || ++ find_mountpoint(this_name->filename, &mountinfo) != 0) + { + if (errno == ENOENT) + fprintf(stderr, +@@ -498,10 +560,12 @@ int parse_file( + this_name->filename, strerror(errno)); + return -1; + } ++ this_name->mnt_id = mountinfo->id; #ifdef DEBUG -- printf("adding file %s %lX %lX\n", this_name->filename, -+ printf("adding file %s %lX %lX %d nfs=%s\n", this_name->filename, - (unsigned long)this_name->st.st_dev, -- (unsigned long)this_name->st.st_ino); -+ (unsigned long)this_name->st.st_ino, -+ mountinfo->id, mountinfo->isremote ? "yes" : "no"); - #endif /* DEBUG */ - add_inode(ino_list, this_name, this_name->st.st_dev, - this_name->st.st_ino); -@@ -513,12 +567,43 @@ parse_mounts(struct names *this_name, struct device_list **dev_list, - const opt_type opts) +- printf("adding file %s %lX %lX\n", this_name->filename, ++ printf("adding file %s %lX %lX %d nfs=%s\n", this_name->filename, + (unsigned long)this_name->st.st_dev, +- (unsigned long)this_name->st.st_ino); ++ (unsigned long)this_name->st.st_ino, ++ mountinfo->id, mountinfo->isremote ? "yes" : "no"); + #endif /* DEBUG */ + add_inode(ino_list, this_name, this_name->st.st_dev, + this_name->st.st_ino); +@@ -537,12 +601,45 @@ int parse_mounts( + const opt_type opts) { - dev_t match_device; -+ list_t *ptr; -+ int count; + dev_t match_device; ++ list_t *ptr; ++ int count; - if (S_ISBLK(this_name->st.st_mode)) - match_device = this_name->st.st_rdev; - else - match_device = this_name->st.st_dev; -- add_device(dev_list, this_name, match_device); + if (S_ISBLK(this_name->st.st_mode)) + match_device = this_name->st.st_rdev; + else + match_device = this_name->st.st_dev; +- add_device(dev_list, this_name, match_device); + -+ count = 0; -+ list_for_each(ptr, &mntinfo) { -+ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); -+ if (match_device != mnt->dev) -+ continue; -+ if (S_ISBLK(this_name->st.st_mode)) { -+ /* Correct mount IDs check if a block device -+ * was specified */ -+ this_name->mnt_id = mnt->id; -+ add_device(dev_list, this_name, match_device, mnt->dev); -+ if (mnt->dev == mnt->vol) -+ count++; -+ else count = 1; -+ continue; -+ } -+ if (this_name->mnt_id != mnt->id) -+ continue; -+ count++; -+ } -+ if (count == 0) { -+ errno = ENOENT; -+ fprintf(stderr, -+ _("Specified filename %s has no mountpoint.\n"), -+ this_name->filename); -+ return -1; -+ } -+ if (S_ISBLK(this_name->st.st_mode)) -+ return 0; -+ add_device(dev_list, this_name, match_device, match_device); - return 0; ++ count = 0; ++ list_for_each(ptr, &mntinfo) ++ { ++ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); ++ if (match_device != mnt->dev) ++ continue; ++ if (S_ISBLK(this_name->st.st_mode)) ++ { ++ /* Correct mount IDs check if a block device ++ * was specified */ ++ this_name->mnt_id = mnt->id; ++ add_device(dev_list, this_name, match_device, mnt->dev); ++ if (mnt->dev == mnt->vol) ++ count++; ++ else count = 1; ++ continue; ++ } ++ if (this_name->mnt_id != mnt->id) ++ continue; ++ count++; ++ } ++ if (count == 0) ++ { ++ errno = ENOENT; ++ fprintf(stderr, _("Specified filename %s has no mountpoint.\n"), ++ this_name->filename); ++ return -1; ++ } ++ if (S_ISBLK(this_name->st.st_mode)) ++ return 0; ++ add_device(dev_list, this_name, match_device, match_device); + return 0; } -@@ -695,10 +780,12 @@ int parse_inet(struct names *this_name, struct ip_connections **ip_list) - break; - #endif - } -- } /*while */ -- freeaddrinfo(res); -+ } /* for (;;) */ -+ -+ freeaddrinfo(res); - return 0; -- } -+ -+ } /* if getaddrinfo */ - } - return 1; - } -@@ -965,6 +1052,21 @@ free_inodes(struct inode_list **match_inodes) +@@ -1010,6 +1107,22 @@ static void free_inodes( /* * Free up structures allocated in add_device */ + -+static void -+free_subvol(struct subvol **volumes) ++static void free_subvol( ++ struct subvol **volumes) +{ -+ struct subvol *vol_tmp, *vol_next; ++ struct subvol *vol_tmp, *vol_next; + -+ vol_tmp = *volumes; -+ while (vol_tmp != NULL) { -+ vol_next = vol_tmp->next; -+ free(vol_tmp); -+ vol_tmp = vol_next; -+ } -+ *volumes =NULL; ++ vol_tmp = *volumes; ++ while (vol_tmp != NULL) ++ { ++ vol_next = vol_tmp->next; ++ free(vol_tmp); ++ vol_tmp = vol_next; ++ } ++ *volumes =NULL; +} + - static void - free_devices(struct device_list **match_devices) + static void free_devices( + struct device_list **match_devices) { -@@ -972,6 +1074,8 @@ free_devices(struct device_list **match_devices) +@@ -1018,6 +1131,8 @@ static void free_devices( + device_tmp = *match_devices; + while(device_tmp != NULL) + { ++ if (device_tmp->vol) ++ free_subvol(&device_tmp->vol); + device_next = device_tmp->next; + free(device_tmp); + device_tmp = device_next; +@@ -1273,8 +1388,8 @@ int main(int argc, char *argv[]) + } - device_tmp = *match_devices; - while(device_tmp != NULL) { -+ if (device_tmp->vol) -+ free_subvol(&device_tmp->vol); - device_next = device_tmp->next; - free(device_tmp); - device_tmp = device_next; -@@ -1174,16 +1278,11 @@ int main(int argc, char *argv[]) - skip_argv = 1; - //while(option != '\0') option++; - if (strcmp(argv[argc_cnt], "tcp") == 0) -- default_namespace = -- NAMESPACE_TCP; -- else if (strcmp(argv[argc_cnt], "udp") -- == 0) -- default_namespace = -- NAMESPACE_UDP; -- else if (strcmp(argv[argc_cnt], "file") -- == 0) -- default_namespace = -- NAMESPACE_FILE; -+ default_namespace = NAMESPACE_TCP; -+ else if (strcmp(argv[argc_cnt], "udp") == 0) -+ default_namespace = NAMESPACE_UDP; -+ else if (strcmp(argv[argc_cnt], "file") == 0) -+ default_namespace = NAMESPACE_FILE; - else - usage(_ - ("Invalid namespace name")); -@@ -1223,7 +1322,7 @@ int main(int argc, char *argv[]) - } - - #if defined(WITH_MOUNTINFO_LIST) -- if ((opts & OPT_ALWAYSSTAT) == 0) -+ if ((opts & (OPT_MOUNTS|OPT_ALWAYSSTAT)) == OPT_MOUNTS) - thestat = mntstat; + #if defined(HAVE_DECL_SYS_STATX) && HAVE_DECL_SYS_STATX == 1 +- if ((opts & OPT_ALWAYSSTAT)) +- stat_flags = 0; /* Triggers sync with e.g. remote NFS server even on autofs */ ++ if ((opts & OPT_ALWAYSSTAT)) ++ stat_flags = 0; /* Triggers sync with e.g. remote NFS server even on autofs */ #endif - /* an option */ -@@ -1537,7 +1636,7 @@ print_matches(struct names *names_head, const opt_type opts, + /* an option */ + /* Not an option, must be a file specification */ +@@ -1589,7 +1704,8 @@ static int print_matches( - } - --static struct stat *get_pidstat(const pid_t pid, const char *filename) -+static struct stat *get_pidstat(const pid_t pid, const char *filename, int *id) + static struct stat *get_pidstat( + const pid_t pid, +- const char *filename) ++ const char *filename, ++ int *id) { - char pathname[PATH_MAX]; - struct stat *st; -@@ -1549,6 +1648,15 @@ static struct stat *get_pidstat(const pid_t pid, const char *filename) - free(st); - return NULL; - } + char pathname[PATH_MAX]; + struct stat *st; +@@ -1602,6 +1718,16 @@ static struct stat *get_pidstat( + free(st); + return NULL; + } + -+ if (id) { -+ mntinfo_t *info; -+ char *new = expandpath(pathname); -+ if (new && find_mountpoint(new, &info) == 0) -+ *id = info->id; -+ else *id = -1; -+ } ++ if (id) ++ { ++ mntinfo_t *info; ++ char *new = expandpath(pathname); ++ if (new && find_mountpoint(new, &info) == 0) ++ *id = info->id; ++ else *id = -1; ++ } + - return st; + return st; } -@@ -1563,10 +1671,11 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - struct inode_list *ino_tmp; - struct device_list *dev_tmp; - struct unixsocket_list *sock_tmp; -- struct stat st, lst; -+ struct stat st; - char *dirpath; - char filepath[PATH_MAX]; - char real_filepath[PATH_MAX]; -+ ino_t ns; +@@ -1621,10 +1747,11 @@ static void check_dir( + struct inode_list *ino_tmp; + struct device_list *dev_tmp; + struct unixsocket_list *sock_tmp; +- struct stat st, lst; ++ struct stat st; + char *dirpath; + char filepath[PATH_MAX]; + char real_filepath[PATH_MAX]; ++ ino_t ns; - if (asprintf(&dirpath, "/proc/%d/%s", pid, dirname) < 0) + if (asprintf(&dirpath, "/proc/%d/%s", pid, dirname) < 0) return; -@@ -1576,6 +1685,12 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, +@@ -1635,6 +1762,12 @@ static void check_dir( } free(dirpath); +#if defined(HAS_NAME_TO_HANDLE_AT) -+ ns = get_namespace(pid); ++ ns = get_namespace(pid); +#else -+ ns = -1; ++ ns = -1; +#endif + - while ((direntry = readdir(dirp)) != NULL) { - if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9') - continue; -@@ -1589,6 +1704,9 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - filepath, strerror(errno)); - } - } else { -+ struct fdinfo fd; -+ int fdret; -+ - thedev = st.st_dev; - if (thedev == netdev) { - for (sock_tmp = sockets; sock_tmp != NULL; -@@ -1601,10 +1719,29 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - } - } - } -+ -+ memset(&fd, 0, sizeof(struct fdinfo)); -+ fdret = get_fdinfo(pid, direntry->d_name, &fd, ns); -+ - for (dev_tmp = dev_head; dev_tmp != NULL; - dev_tmp = dev_tmp->next) { -- if (thedev != dev_tmp->device) -- continue; -+ -+ if (thedev != dev_tmp->device) { -+ struct subvol *vol_tmp; -+ int subvol_found = 0; -+ -+ for (vol_tmp = dev_tmp->vol; vol_tmp != NULL; -+ vol_tmp = vol_tmp->next) { -+ /* Check for BtrFS sub volumes as well */ -+ if (thedev == vol_tmp->device) { -+ subvol_found++; -+ break; -+ } -+ } -+ -+ if (!subvol_found) -+ continue; -+ } + while ((direntry = readdir(dirp)) != NULL) + { + if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9') +@@ -1643,7 +1776,7 @@ static void check_dir( + snprintf(filepath, sizeof filepath - 1, "/proc/%d/%s/%s", + pid, dirname, direntry->d_name); - /* check the paths match if it is not a block device */ - if (! S_ISBLK(dev_tmp->name->st.st_mode)) { -@@ -1616,9 +1753,14 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - continue; - } - } +- if (statn(filepath, STATX_INO, &st) != 0) ++ if (statn(filepath, STATX_INO, &st) != 0) + { + if (errno != ENOENT && errno != ENOTDIR) + { +@@ -1651,6 +1784,9 @@ static void check_dir( + filepath, strerror(errno)); + } + } else { ++ struct fdinfo fd; ++ int fdret; + -+ if (fdret != 0) -+ continue; -+ if (fd.mnt_id != dev_tmp->mnt_id) -+ continue; + thedev = st.st_dev; + if (thedev == netdev) + { +@@ -1666,11 +1802,32 @@ static void check_dir( + } + } + } + - if (access == ACCESS_FILE -- && (lstat(filepath, &lst) == 0) -- && (lst.st_mode & S_IWUSR)) { -+ && (fd.flags & (O_WRONLY|O_RDWR))) { - add_matched_proc(dev_tmp->name, - pid, uid, - ACCESS_FILEWR | -@@ -1640,9 +1782,10 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - continue; - } - if (st.st_ino == ino_tmp->inode) { -+ if (fdret != 0) -+ continue; - if (access == ACCESS_FILE -- && (lstat(filepath, &lst) == 0) -- && (lst.st_mode & S_IWUSR)) { -+ && (fd.flags & (O_WRONLY|O_RDWR))) { - add_matched_proc(ino_tmp->name, - pid, uid, - ACCESS_FILEWR | -@@ -1671,31 +1814,54 @@ check_map(const pid_t pid, const char *filename, - FILE *fp; - unsigned long long tmp_inode; - unsigned int tmp_maj, tmp_min; -- dev_t tmp_device; ++ memset(&fd, 0, sizeof(struct fdinfo)); ++ fdret = get_fdinfo(pid, direntry->d_name, &fd, ns); ++ + for (dev_tmp = dev_head; dev_tmp != NULL; + dev_tmp = dev_tmp->next) + { + if (thedev != dev_tmp->device) +- continue; ++ { ++ struct subvol *vol_tmp; ++ int subvol_found = 0; ++ ++ for (vol_tmp = dev_tmp->vol; vol_tmp != NULL; ++ vol_tmp = vol_tmp->next) ++ { ++ /* Check for BtrFS sub volumes as well */ ++ if (thedev == vol_tmp->device) ++ { ++ subvol_found++; ++ break; ++ } ++ } ++ ++ if (!subvol_found) ++ continue; ++ } - if (asprintf(&pathname, "/proc/%d/%s", pid, filename) < 0) + /* check the paths match if it is not a block device or socket */ + if (! S_ISBLK(dev_tmp->name->st.st_mode) +@@ -1686,10 +1843,14 @@ static void check_dir( + strlen(dev_tmp->name->filename)) != 0) + continue; + } ++ if (fdret != 0) ++ continue; ++ if (fd.mnt_id != dev_tmp->mnt_id) ++ continue; + } ++ + if (access == ACCESS_FILE +- && (lstat(filepath, &lst) == 0) +- && (lst.st_mode & S_IWUSR)) ++ && (fd.flags & (O_WRONLY|O_RDWR))) + { + add_matched_proc(dev_tmp->name, pid, uid, + ACCESS_FILEWR | access); +@@ -1709,9 +1870,10 @@ static void check_dir( + } + if (st.st_ino == ino_tmp->inode) + { ++ if (fdret != 0) ++ continue; + if (access == ACCESS_FILE +- && (lstat(filepath, &lst) == 0) +- && (lst.st_mode & S_IWUSR)) ++ && (fd.flags & (O_WRONLY|O_RDWR))) + { + add_matched_proc(ino_tmp->name, pid, uid, + ACCESS_FILEWR | access); +@@ -1740,7 +1902,6 @@ static void check_map( + FILE *fp; + unsigned long long tmp_inode; + unsigned int tmp_maj, tmp_min; +- dev_t tmp_device; + + if (asprintf(&pathname, "/proc/%d/%s", pid, filename) < 0) return; - if ((fp = fopen(pathname, "r")) == NULL) { -- free(pathname); -+ free(pathname); - return; -- } -- free(pathname); -+ } -+ free(pathname); - while (fgets(line, BUFSIZ, fp)) { -- if (sscanf(line, "%*s %*s %*s %x:%x %lld", -- &tmp_maj, &tmp_min, &tmp_inode) == 3) { -- tmp_device = tmp_maj * 256 + tmp_min; -+ char *scanned_path = NULL; -+ if (sscanf(line, "%*s %*s %*s %x:%x %lld %ms", -+ &tmp_maj, &tmp_min, &tmp_inode, &scanned_path) == 4) { -+ dev_t tmp_device = makedev(tmp_maj, tmp_min); -+ int mnt_id = -1; +@@ -1752,18 +1913,47 @@ static void check_map( + free(pathname); + while (fgets(line, BUFSIZ, fp)) + { +- if (sscanf(line, "%*s %*s %*s %x:%x %lld", +- &tmp_maj, &tmp_min, &tmp_inode) == 3) ++ char *scanned_path = NULL; ++ if (sscanf(line, "%*s %*s %*s %x:%x %lld %ms", ++ &tmp_maj, &tmp_min, &tmp_inode, &scanned_path) == 4) + { +- tmp_device = tmp_maj * 256 + tmp_min; ++ dev_t tmp_device = makedev(tmp_maj, tmp_min); ++ int mnt_id = -1; + -+ if (scanned_path) { -+ if (*scanned_path == '/') { -+ mntinfo_t *mountinfo; -+ if (find_mountpoint(scanned_path, &mountinfo) == 0) -+ mnt_id = mountinfo->id; -+ } -+ free(scanned_path); -+ } ++ if (scanned_path) ++ { ++ if (*scanned_path == '/') ++ { ++ mntinfo_t *mountinfo; ++ if (find_mountpoint(scanned_path, &mountinfo) == 0) ++ mnt_id = mountinfo->id; ++ } ++ free(scanned_path); ++ } + - for (dev_tmp = dev_head; dev_tmp != NULL; -- dev_tmp = dev_tmp->next) -- if (dev_tmp->device == tmp_device) -+ dev_tmp = dev_tmp->next) { -+ struct subvol *vol_tmp; -+ if (dev_tmp->device == tmp_device && -+ mnt_id == dev_tmp->mnt_id) - add_matched_proc(dev_tmp->name, pid, - uid, access); -+ for (vol_tmp = dev_tmp->vol; vol_tmp != NULL; -+ vol_tmp = vol_tmp->next) { -+ /* For BtrFS sub volumes there are different -+ mount ids for the same device */ -+ if (vol_tmp->device == tmp_device && mnt_id == vol_tmp->mnt_id) -+ add_matched_proc(dev_tmp->name, pid, -+ uid, access); -+ } -+ } - for (ino_tmp = ino_head; ino_tmp != NULL; - ino_tmp = ino_tmp->next) - if (ino_tmp->device == tmp_device - && ino_tmp->inode == tmp_inode) - add_matched_proc(ino_tmp->name, pid, - uid, access); -- } -+ } else if (scanned_path) -+ free(scanned_path); - } - fclose(fp); + for (dev_tmp = dev_head; dev_tmp != NULL; dev_tmp = dev_tmp->next) +- if (dev_tmp->device == tmp_device) ++ { ++ struct subvol *vol_tmp; ++ ++ if (dev_tmp->device == tmp_device && mnt_id == dev_tmp->mnt_id) + add_matched_proc(dev_tmp->name, pid, uid, access); ++ ++ for (vol_tmp = dev_tmp->vol; vol_tmp != NULL; vol_tmp = vol_tmp->next) ++ { ++ /* For BtrFS sub volumes there are different ++ mount ids for the same device */ ++ if (vol_tmp->device == tmp_device ++ && mnt_id == vol_tmp->mnt_id) ++ ++ add_matched_proc(dev_tmp->name, pid, uid, access); ++ } ++ } + for (ino_tmp = ino_head; ino_tmp != NULL; ino_tmp = ino_tmp->next) + if (ino_tmp->device == tmp_device + && ino_tmp->inode == tmp_inode) + add_matched_proc(ino_tmp->name, pid, uid, access); +- } ++ } else if (scanned_path) ++ free(scanned_path); + } + fclose(fp); } -@@ -1719,6 +1885,7 @@ static uid_t getpiduid(const pid_t pid) +@@ -1789,7 +1979,7 @@ static uid_t getpiduid( * fill_unix_cache : Create a list of Unix sockets * This list is used later for matching purposes */ -+static - void fill_unix_cache(struct unixsocket_list **unixsocket_head) +-void fill_unix_cache( ++static void fill_unix_cache( + struct unixsocket_list **unixsocket_head) { - FILE *fp; -@@ -1735,6 +1902,8 @@ void fill_unix_cache(struct unixsocket_list **unixsocket_head) - while (fgets(line, BUFSIZ, fp) != NULL) { - char *path; - char *scanned_path = NULL; -+ int mnt_id = -1; -+ mntinfo_t *mountinfo; - if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %llu %ms", - &scanned_inode, &scanned_path) != 2) { - if (scanned_path) -@@ -1750,6 +1919,8 @@ void fill_unix_cache(struct unixsocket_list **unixsocket_head) - free(path); - continue; - } -+ if (find_mountpoint(scanned_path, &mountinfo) == 0) -+ mnt_id = mountinfo->id; - if ((newsocket = (struct unixsocket_list *) - malloc(sizeof(struct unixsocket_list))) == NULL) { - free(path); -@@ -1758,6 +1929,7 @@ void fill_unix_cache(struct unixsocket_list **unixsocket_head) - newsocket->sun_name = strdup(scanned_path); - newsocket->inode = st.st_ino; - newsocket->dev = st.st_dev; -+ newsocket->mnt_id = mnt_id; - newsocket->net_inode = scanned_inode; - newsocket->next = *unixsocket_head; - *unixsocket_head = newsocket; -@@ -1770,6 +1942,7 @@ void fill_unix_cache(struct unixsocket_list **unixsocket_head) + FILE *fp; +@@ -1808,6 +1998,8 @@ void fill_unix_cache( + { + char *path; + char *scanned_path = NULL; ++ int mnt_id = -1; ++ mntinfo_t *mountinfo; + if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %llu %ms", + &scanned_inode, &scanned_path) != 2) + { +@@ -1820,11 +2012,13 @@ void fill_unix_cache( + path = scanned_path; + if (*scanned_path == '@') + scanned_path++; +- if (statn(scanned_path, STATX_INO, &st) < 0) ++ if (statn(scanned_path, STATX_INO, &st) < 0) + { + free(path); + continue; + } ++ if (find_mountpoint(scanned_path, &mountinfo) == 0) ++ mnt_id = mountinfo->id; + if ((newsocket = (struct unixsocket_list *) + malloc(sizeof(struct unixsocket_list))) == NULL) + { +@@ -1834,6 +2028,7 @@ void fill_unix_cache( + newsocket->sun_name = strdup(scanned_path); + newsocket->inode = st.st_ino; + newsocket->dev = st.st_dev; ++ newsocket->mnt_id = mnt_id; + newsocket->net_inode = scanned_inode; + newsocket->next = *unixsocket_head; + *unixsocket_head = newsocket; +@@ -1846,7 +2041,7 @@ void fill_unix_cache( /* * Free up the list of Unix sockets */ -+static - void clear_unix_cache(struct unixsocket_list **unixsocket_head) +-void clear_unix_cache( ++static void clear_unix_cache( + struct unixsocket_list **unixsocket_head) { - while(*unixsocket_head != NULL) { -@@ -1941,34 +2114,21 @@ scan_mounts(struct names *names_head, struct inode_list *ino_head, + while(*unixsocket_head != NULL) +@@ -2037,47 +2232,32 @@ static void scan_mounts( { - struct device_list *dev_tmp; - struct inode_list *ino_tmp; -- FILE *fp; -- char line[BUFSIZ]; -- char *find_mountp; -- char *find_space; - struct stat st; -+ list_t *ptr; + struct device_list *dev_tmp; + struct inode_list *ino_tmp; +- FILE *fp; +- char line[BUFSIZ]; +- char *find_mountp; +- char *find_space; + struct stat st; ++ list_t *ptr; + + if ( (ino_head == NULL) && (dev_head == NULL) ) + return; -- if ( (ino_head == NULL) && (dev_head == NULL) ) -- return; - -+ list_for_each(ptr, &mntinfo) { -+ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); -+ const char *find_mountp = mnt->mpoint; - -- if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) { -- fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS); -- return; -- } -- while (fgets(line, BUFSIZ, fp) != NULL) { -- if ((find_mountp = strchr(line, ' ')) == NULL) -- continue; -- find_mountp++; -- if ((find_space = strchr(find_mountp, ' ')) == NULL) -+ if (timeout(thestat, find_mountp, &st, 5) != 0) - continue; -- *find_space = '\0'; -- if (timeout(thestat, find_mountp, &st, 5) != 0) { -- continue; -- } +- if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) ++ list_for_each(ptr, &mntinfo) + { +- fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS); +- return; +- } +- while (fgets(line, BUFSIZ, fp) != NULL) +- { +- if ((find_mountp = strchr(line, ' ')) == NULL) +- continue; +- find_mountp++; +- if ((find_space = strchr(find_mountp, ' ')) == NULL) +- continue; +- *find_space = '\0'; +- if (statn(find_mountp, STATX_INO, &st) != 0) ++ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); ++ const char *find_mountp = mnt->mpoint; + - /* Scan the devices */ - for (dev_tmp = dev_head; dev_tmp != NULL; - dev_tmp = dev_tmp->next) { -- if (st.st_dev == dev_tmp->device) -+ if (st.st_dev == dev_tmp->device && -+ mnt->id == dev_tmp->mnt_id) - add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0, - find_mountp); - } -@@ -1980,7 +2140,6 @@ scan_mounts(struct names *names_head, struct inode_list *ino_head, - find_mountp); - } - } -- fclose(fp); ++ if (statn(find_mountp, STATX_INO, &st) != 0) + continue; ++ + /* Scan the devices */ +- for (dev_tmp = dev_head; dev_tmp != NULL; +- dev_tmp = dev_tmp->next) ++ for (dev_tmp = dev_head; dev_tmp != NULL; dev_tmp = dev_tmp->next) + { +- if (st.st_dev == dev_tmp->device) ++ if (st.st_dev == dev_tmp->device && mnt->id == dev_tmp->mnt_id) + add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0, find_mountp); + } +- for (ino_tmp = ino_head; ino_tmp != NULL; +- ino_tmp = ino_tmp->next) ++ for (ino_tmp = ino_head; ino_tmp != NULL; ino_tmp = ino_tmp->next) + { +- if (st.st_dev == ino_tmp->device +- && st.st_ino == ino_tmp->inode) ++ if (st.st_dev == ino_tmp->device && st.st_ino == ino_tmp->inode) + add_special_proc(ino_tmp->name, PTYPE_MOUNT, 0, find_mountp); + } + } +- fclose(fp); } - static void -@@ -2033,16 +2192,44 @@ scan_swaps(struct names *names_head, struct inode_list *ino_head, - fclose(fp); + static void scan_swaps( +@@ -2113,7 +2293,7 @@ static void scan_swaps( + if (*find_space == '\0') + continue; + } +- if (statn(line, STATX_INO, &st) != 0) ++ if (statn(line, STATX_INO, &st) != 0) + continue; + + /* Scan the devices */ +@@ -2134,6 +2314,385 @@ static void scan_swaps( + fclose(fp); } --#if defined(WITH_MOUNTINFO_LIST) - /* - * Use /proc/self/mountinfo of modern linux system to determine - * the device numbers of the mount points. Use this to avoid the -- * stat(2) system call wherever possible. ++/* ++ * Use /proc/self/mountinfo of modern linux system to determine ++ * the device numbers of the mount points. Use this to avoid the + * stat(2) system call for remote file system. - */ - --static list_t mntinfo = { &mntinfo, &mntinfo }; -+static mntinfo_t* -+add_mntinfo(const char *mpoint, const char *type, int mid, int parid, dev_t dev) ++ */ ++ ++static mntinfo_t* add_mntinfo( ++ const char *mpoint, ++ const char *type, ++ int mid, ++ int parid, ++ dev_t dev) +{ -+ const size_t nlen = strlen(mpoint); -+ mntinfo_t *restrict mnt; -+ if (posix_memalign -+ ((void *)&mnt, sizeof(void *), -+ alignof(mntinfo_t) + (nlen + 1)) != 0) { -+ fprintf(stderr, -+ _ -+ ("Cannot allocate memory for matched proc: %s\n"), -+ strerror(errno)); -+ exit(1); -+ } -+ append(mnt, mntinfo); -+ mnt->mpoint = ((char *)mnt) + alignof(mntinfo_t); -+ strcpy(mnt->mpoint, mpoint); -+ mnt->nlen = nlen; -+ mnt->parid = parid; -+ mnt->dev = dev; -+ mnt->id = mid; -+ if (strncmp("nfs", type, 3) == 0 || strncmp("afs", type, 3) == 0 || strncmp("autofs", type, 6)) -+ mnt->isremote = 1; -+ else mnt->isremote = 0; -+ /* E.g. sub volumes of BtrFS do not show main device number in -+ /proc/self/mountinfo, for now just map the device to this */ -+ mnt->vol = dev; -+ return mnt; ++ const size_t nlen = strlen(mpoint); ++ mntinfo_t *restrict mnt; ++ if (posix_memalign((void *)&mnt, sizeof(void *), ++ alignof(mntinfo_t) + (nlen + 1)) != 0) ++ { ++ fprintf(stderr, _("Cannot allocate memory for matched proc: %s\n"), ++ strerror(errno)); ++ exit(1); ++ } ++ append(mnt, mntinfo); ++ mnt->mpoint = ((char *)mnt) + alignof(mntinfo_t); ++ strcpy(mnt->mpoint, mpoint); ++ mnt->nlen = nlen; ++ mnt->parid = parid; ++ mnt->dev = dev; ++ mnt->id = mid; ++ if (strncmp("nfs", type, 3) == 0 || strncmp("afs", type, 3) == 0 || strncmp("autofs", type, 6)) ++ mnt->isremote = 1; ++ else mnt->isremote = 0; ++ /* E.g. sub volumes of BtrFS do not show main device number in ++ /proc/self/mountinfo, for now just map the device to this */ ++ mnt->vol = dev; ++ return mnt; +} - --static void clear_mntinfo(void) -+static void -+clear_mntinfo(void) - { - list_t *ptr, *tmp; - -@@ -2053,72 +2240,319 @@ static void clear_mntinfo(void) - } - } - --static void init_mntinfo(void) -+static void -+init_mntinfo(void) - { -+ char type[256]; - char mpoint[PATH_MAX *4 + 1]; // octal escaping takes 4 chars per 1 char -- int mid, parid, max = 0; -+ char devname[PATH_MAX]; -+ int mid, parid; -+ mntinfo_t *mntinf; ++ ++static void clear_mntinfo(void) ++{ ++ list_t *ptr, *tmp; ++ ++ list_for_each_safe(ptr, tmp, &mntinfo) ++ { ++ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); ++ delete(ptr); ++ free(mnt); ++ } ++} ++ ++static void init_mntinfo(void) ++{ ++ char type[256]; ++ char mpoint[PATH_MAX *4 + 1]; // octal escaping takes 4 chars per 1 char ++ char devname[PATH_MAX]; ++ int mid, parid; ++ mntinfo_t *mntinf; +#if defined(HAS_MOUNTINFO) - uint maj, min; -- list_t sort; ++ uint maj, min; +#endif - FILE *mnt; - - if (!list_empty(&mntinfo)) - return; -- if ((mnt = fopen("/proc/self/mountinfo", "r")) == (FILE *) 0) ++ FILE *mnt; ++ ++ if (!list_empty(&mntinfo)) ++ return; +#if defined(HAS_MOUNTINFO) -+ /* -+ * We could also loop over all mount namespaces, that is not only -+ * over /proc/self/ns/mnt. But this expands this list as well as -+ * we can use name_to_handle_at(2) in our get_mountid() function. -+ */ -+ if ((mnt = fopen(PROC_MOUNTINFO, "r")) == (FILE *) 0) - return; - while (fscanf -- (mnt, "%i %i %u:%u %*s %s %*[^\n]", &mid, &parid, &maj, &min, -- &mpoint[0]) == 5) { -- const size_t nlen = strlen(mpoint); -- mntinfo_t *restrict mnt; -- if (posix_memalign -- ((void *)&mnt, sizeof(void *), -- alignof(mntinfo_t) + (nlen + 1)) != 0) { -- fprintf(stderr, -- _ -- ("Cannot allocate memory for matched proc: %s\n"), -- strerror(errno)); -- exit(1); -+ (mnt, "%i %i %u:%u %*s %s %*[^-] - %s %s %*[^\n]", -+ &mid, &parid, &maj, &min, &mpoint[0], &type[0], &devname[0]) == 7) { -+ struct stat st; -+ mntinf = add_mntinfo(mpoint, type, mid, parid, makedev(maj, min)); -+ if (mntinf && strncmp(devname, "/dev/", 5) == 0 && stat(devname, &st) == 0) { -+ if (st.st_rdev != 0 && mntinf->dev != st.st_rdev) { -+ mntinf->vol = st.st_rdev; -+ stat(mpoint, &st); -+ mntinf->dev = st.st_dev; /* stat(2) on binary does not see subvol dev */ -+ } - } -- append(mnt, mntinfo); -- mnt->mpoint = ((char *)mnt) + alignof(mntinfo_t); -- strcpy(mnt->mpoint, mpoint); -- mnt->nlen = nlen; -- mnt->parid = parid; -- mnt->dev = makedev(maj, min); -- mnt->id = mid; -- if (mid > max) -- max = mid; - } ++ /* ++ * We could also loop over all mount namespaces, that is not only ++ * over /proc/self/ns/mnt. But this expands this list as well as ++ * we can use name_to_handle_at(2) in our get_mountid() function. ++ */ ++ if ((mnt = fopen(PROC_MOUNTINFO, "r")) == (FILE *) 0) ++ return; ++ while (fscanf (mnt, "%i %i %u:%u %*s %s %*[^-] - %s %s %*[^\n]", ++ &mid, &parid, &maj, &min, &mpoint[0], &type[0], &devname[0]) == 7) ++ { ++ struct stat st; ++ mntinf = add_mntinfo(mpoint, type, mid, parid, makedev(maj, min)); ++ if (mntinf && strncmp(devname, "/dev/", 5) == 0 && statn(devname, 0, &st) == 0) ++ { ++ if (st.st_rdev != 0 && mntinf->dev != st.st_rdev) ++ { ++ mntinf->vol = st.st_rdev; ++ statn(mpoint, 0, &st); ++ mntinf->dev = st.st_dev; /* stat(2) on binary does not see subvol dev */ ++ } ++ } ++ } +#else -+ if ((mnt = fopen(PROC_MOUNTS, "r")) == (FILE *) 0) -+ return; -+ mid = 1; -+ parid = -1; -+ while (fscanf (mnt, "%s %s %s %*[^\n]", &devname[0], &mpoint[0], &type[0]) == 3) { -+ struct stat st; -+ if (stat(mpoint, &st) != 0) { -+ if (errno != EACCES) { -+ fprintf(stderr, _("Cannot stat %s: %s\n"), -+ mpoint, strerror(errno)); -+ exit(1); -+ } -+ st.st_dev = (dev_t)-1; -+ } -+ mntinf = add_mntinfo(mpoint, type, mid++, parid, st.st_dev); -+ if (mntinf && strncmp(devname, "/dev/", 5) == 0 && stat(devname, &st) == 0) { -+ if (st.st_rdev != 0 && mntinf->dev != st.st_rdev) -+ mntinf->vol = st.st_rdev; -+ } -+ } ++ if ((mnt = fopen(PROC_MOUNTS, "r")) == (FILE *) 0) ++ return; ++ mid = 1; ++ parid = -1; ++ while (fscanf (mnt, "%s %s %s %*[^\n]", &devname[0], &mpoint[0], &type[0]) == 3) ++ { ++ struct stat st; ++ if (statn(mpoint, 0, &st) != 0) ++ { ++ if (errno != EACCES) ++ { ++ fprintf(stderr, _("Cannot stat %s: %s\n"), mpoint, strerror(errno)); ++ exit(1); ++ } ++ st.st_dev = (dev_t)-1; ++ } ++ mntinf = add_mntinfo(mpoint, type, mid++, parid, st.st_dev); ++ if (mntinf && strncmp(devname, "/dev/", 5) == 0 && statn(devname, 0, &st) == 0) ++ { ++ if (st.st_rdev != 0 && mntinf->dev != st.st_rdev) ++ mntinf->vol = st.st_rdev; ++ } ++ } +#endif - fclose(mnt); ++ fclose(mnt); +} + -+static int -+get_fdinfo(const pid_t pid, const char *fd, struct fdinfo *info, const ino_t ns) ++static int get_fdinfo( ++ const pid_t pid, ++ const char *fd, ++ struct fdinfo *info, ++ const ino_t ns) +{ -+ int ret = 0; -+ char pathname[512]; -+ int mnt_id = 0, flags = 0; -+#if defined(HAS_FDINFO) /* Here we get the private namespace as well */ -+ const static char delimiters[] = ": \t\n"; -+ char line[BUFSIZ]; -+ FILE *fp; ++ int ret = 0; ++ char pathname[512]; ++ int mnt_id = 0, flags = 0; ++#if defined(HAS_FDINFO) /* Here we get the private namespace as well */ ++ const static char delimiters[] = ": \t\n"; ++ char line[BUFSIZ]; ++ FILE *fp; +# if defined(HAS_NAME_TO_HANDLE_AT) -+ static ino_t mynamespace; -+ struct stat st; -+ -+ if (!mynamespace) { -+ if (stat("/proc/self/ns/mnt", &st) != 0) { -+ fprintf(stderr, _("Cannot stat %s: %s\n"), -+ "/proc/self/ns/mnt", strerror(errno)); -+ exit(1); -+ } -+ mynamespace = st.st_ino; -+ } ++ char *realname; +# endif -+ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fdinfo/%s", pid, fd); -+ if ((fp = fopen(pathname, "r")) == NULL) -+ goto out; /* forbidden namesspace, try our own namespace */ -+ while (fgets(line, BUFSIZ, fp) && ret < 2) { -+ char *xp, *vp, *ep; -+ unsigned long ul; -+ xp = strtok(&line[0], delimiters); -+ if (!xp || *xp == 0) -+ continue; -+ vp = strtok(NULL, delimiters); -+ if (!vp || *vp == 0) -+ continue; -+ if (strcmp(xp, "flags") == 0 && (ul = strtoul(vp, &ep, 0)) != ULONG_MAX && ep && *ep == 0) { -+ info->flags = (mode_t)ul; -+ flags++; -+ ret++; -+ } -+ if (strcmp(xp, "mnt_id") == 0 && (ul = strtoul(vp, &ep, 0)) != ULONG_MAX && ep && *ep == 0) { -+ info->mnt_id = (int)ul; -+ mnt_id++; -+ ret++; -+ } -+ } -+ fclose(fp); ++ ++ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fdinfo/%s", pid, fd); ++ if ((fp = fopen(pathname, "r")) == NULL) ++ goto out; ++ ++ while (fgets(line, BUFSIZ, fp) && ret < 1) ++ { ++ char *xp, *vp, *ep; ++ unsigned long ul; ++ xp = strtok(&line[0], delimiters); ++ if (!xp || *xp == 0) ++ continue; ++ vp = strtok(NULL, delimiters); ++ if (!vp || *vp == 0) ++ continue; ++ if (strcmp(xp, "flags") == 0 && (ul = strtoul(vp, &ep, 0)) != ULONG_MAX && ep && *ep == 0) ++ { ++ info->flags = (mode_t)ul; ++ flags++; ++ ret++; ++ break; ++ } ++ } ++ fclose(fp); +out: +# if defined(HAS_NAME_TO_HANDLE_AT) -+ if (mynamespace != ns) { -+ char *realname; -+ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); -+ realname = expandpath(pathname); -+ if (realname) { /* Use our namespace for mount ID */ -+ info->mnt_id = get_mountid(realname); -+ mnt_id++; -+ } -+ } ++ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); ++ realname = expandpath(pathname); ++ if (realname) ++ { ++ info->mnt_id = get_mountid(realname); ++ mnt_id++; ++ ret++; ++ } +# endif +#endif -+ if (!flags || !mnt_id) { -+ struct stat lst; ++ if (!flags || !mnt_id) ++ { ++ struct stat lst; + -+ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); -+ if (!flags && lstat(pathname, &lst) == 0) { -+ if (lst.st_mode & S_IWUSR) -+ info->flags |= O_WRONLY; -+ ret++; -+ } ++ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); ++ if (!flags && lstatn(pathname, STATX_MODE, &lst) == 0) ++ { ++ if (lst.st_mode & S_IWUSR) ++ info->flags |= O_WRONLY; ++ ret++; ++ } + -+ if (!mnt_id) { -+ char *realname = expandpath(pathname); -+ if (realname) { -+ mntinfo_t *mountinfo; -+ if (find_mountpoint(realname, &mountinfo) == 0) { -+ info->mnt_id = mountinfo->id; -+ ret++; -+ } -+ } -+ } -+ } -+ return ret == 2 ? 0 : -1; ++ if (!mnt_id) ++ { ++ realname = expandpath(pathname); ++ if (realname) ++ { ++ mntinfo_t *mountinfo; ++ if (find_mountpoint(realname, &mountinfo) == 0) ++ { ++ info->mnt_id = mountinfo->id; ++ ret++; ++ } ++ } ++ } ++ } ++ ++ return ret == 2 ? 0 : -1; +} - -- /* Sort mount points accordingly to the reverse mount order */ -- initial(&sort); -- for (mid = 1; mid <= max; mid++) { -- list_t *ptr, *tmp; -- list_for_each_safe(ptr, tmp, &mntinfo) { ++ +#if defined(HAS_NAME_TO_HANDLE_AT) -+static ino_t -+get_namespace(const pid_t pid) ++static ino_t get_namespace( ++ const pid_t pid) +{ -+ char pathname[512]; -+ struct stat st; -+ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/ns/mnt", pid); -+ if (stat(pathname, &st) == 0) -+ return st.st_ino; -+ return -1; ++ char pathname[512]; ++ struct stat st; ++ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/ns/mnt", pid); ++ if (statn(pathname, STATX_INO, &st) == 0) ++ return st.st_ino; ++ return -1; +} + -+static int -+get_mountid(const char *path) ++static int get_mountid( ++ const char *path) +{ -+ union fh_u { -+ struct file_handle handle; -+ char buffer[sizeof(struct file_handle) + MAX_HANDLE_SZ]; -+ } fh = { .handle.handle_bytes = MAX_HANDLE_SZ }; -+ int mnt_id = -1; ++ union fh_u { ++ struct file_handle handle; ++ char buffer[sizeof(struct file_handle) + MAX_HANDLE_SZ]; ++ } fh = { .handle.handle_bytes = MAX_HANDLE_SZ }; ++ int mnt_id = -1; + -+ errno = 0; -+ if (name_to_handle_at(0, path, &fh.handle, &mnt_id, 0) == -1) { -+ const static char delimiters[] = ": \t\n"; -+ char fdinfo[PATH_MAX+1]; -+ char line[BUFSIZ]; -+ FILE* fp; -+ int fd; ++ errno = 0; ++ if (name_to_handle_at(0, path, &fh.handle, &mnt_id, 0) == -1) ++ { ++ const static char delimiters[] = ": \t\n"; ++ char fdinfo[PATH_MAX+1]; ++ char line[BUFSIZ]; ++ FILE* fp; ++ int fd; + -+ if (errno != EOPNOTSUPP) -+ return -1; -+ fd = open(path, O_PATH); -+ if (fd < 0) -+ return -1; ++ if (errno != EOPNOTSUPP) ++ return -1; ++ fd = open(path, O_PATH); ++ if (fd < 0) ++ return -1; + -+ snprintf(fdinfo, PATH_MAX, "/proc/self/fdinfo/%d", fd); -+ if ((fp = fopen(fdinfo, "r")) == NULL) { -+ close(fd); -+ return -1; -+ } -+ while (fgets(line, BUFSIZ, fp)) { -+ char *xp, *vp, *ep; -+ unsigned long ul; -+ xp = strtok(&line[0], delimiters); -+ if (!xp || *xp == 0) -+ continue; -+ vp = strtok(NULL, delimiters); -+ if (!vp || *vp == 0) -+ continue; -+ if (strcmp(xp, "mnt_id") == 0 && (ul = strtoul(vp, &ep, 0)) != ULONG_MAX && ep && *ep == 0) { -+ mnt_id = (int)ul; -+ break; -+ } -+ } -+ fclose(fp); -+ close(fd); -+ } -+ return mnt_id; ++ snprintf(fdinfo, PATH_MAX, "/proc/self/fdinfo/%d", fd); ++ if ((fp = fopen(fdinfo, "r")) == NULL) ++ { ++ close(fd); ++ return -1; ++ } ++ while (fgets(line, BUFSIZ, fp)) ++ { ++ char *xp, *vp, *ep; ++ unsigned long ul; ++ xp = strtok(&line[0], delimiters); ++ if (!xp || *xp == 0) ++ continue; ++ vp = strtok(NULL, delimiters); ++ if (!vp || *vp == 0) ++ continue; ++ if (strcmp(xp, "mnt_id") == 0 && (ul = strtoul(vp, &ep, 0)) != ULONG_MAX && ep && *ep == 0) ++ { ++ mnt_id = (int)ul; ++ break; ++ } ++ } ++ fclose(fp); ++ close(fd); ++ } ++ return mnt_id; +} +#endif + -+static int -+find_mountpoint(const char *path, mntinfo_t **mountinfo) ++static int find_mountpoint( ++ const char *path, ++ mntinfo_t **mountinfo) +{ -+ char *use, *end; -+ ssize_t nlen; ++ char *use, *end; ++ ssize_t nlen; +#if defined(HAS_NAME_TO_HANDLE_AT) -+ int mnt_id = get_mountid(path); ++ int mnt_id = get_mountid(path); +#endif -+ int ret = -1; ++ int ret = -1; + -+ *mountinfo = NULL; ++ *mountinfo = NULL; + +#if defined(HAS_NAME_TO_HANDLE_AT) -+ if (mnt_id >= 0) { -+ list_t *ptr; ++ if (mnt_id >= 0) ++ { ++ list_t *ptr; + -+ errno = ENOENT; -+ list_for_each(ptr, &mntinfo) { - mntinfo_t *mnt = list_entry(ptr, mntinfo_t); -- if (mid != mnt->id) ++ errno = ENOENT; ++ list_for_each(ptr, &mntinfo) ++ { ++ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); + -+ if (mnt_id != mnt->id) - continue; -- move_head(ptr, &sort); ++ if (mnt_id != mnt->id) ++ continue; + -+ ret = 0; -+ errno = 0; -+ *mountinfo = mnt; - break; - } -- list_for_each_safe(ptr, tmp, &mntinfo) { -+ if (*mountinfo) -+ goto out; ++ ret = 0; ++ errno = 0; ++ *mountinfo = mnt; ++ break; ++ } ++ if (*mountinfo) ++ goto out; + -+ if (strlen(path) == 1 && path[0] == '/') { -+ struct stat st; ++ if (strlen(path) == 1 && path[0] == '/') ++ { ++ struct stat st; + -+ /* could be a chroot or a container */ ++ /* could be a chroot or a container */ + -+ if (stat(path, &st) != 0) { -+ if (errno != EACCES) { -+ fprintf(stderr, _("Cannot stat %s: %s\n"), -+ path, strerror(errno)); -+ exit(1); -+ } -+ st.st_dev = (dev_t)-1; -+ } -+ ret = 0; -+ errno = 0; -+ *mountinfo = add_mntinfo(path, "unkown", mnt_id, -1, st.st_dev); -+ goto out; -+ } -+ } ++ if (statn(path, 0, &st) != 0) ++ { ++ if (errno != EACCES) ++ { ++ fprintf(stderr, _("Cannot stat %s: %s\n"), ++ path, strerror(errno)); ++ exit(1); ++ } ++ st.st_dev = (dev_t)-1; ++ } ++ ret = 0; ++ errno = 0; ++ *mountinfo = add_mntinfo(path, "unkown", mnt_id, -1, st.st_dev); ++ goto out; ++ } ++ } +#endif -+ use = strdup(path); -+ if (!use) -+ goto out; ++ use = strdup(path); ++ if (!use) ++ goto out; + -+ nlen = strlen(use); -+ end = use+nlen; -+ errno = ENOENT; -+ do { -+ list_t *ptr; -+ if (*end == '/') { -+ if (end == use) { /* root file system */ -+ end++; -+ if (nlen == 1) { -+ struct stat st; ++ nlen = strlen(use); ++ end = use+nlen; ++ errno = ENOENT; ++ do { ++ list_t *ptr; ++ if (*end == '/') ++ { ++ if (end == use) { /* root file system */ ++ end++; ++ if (nlen == 1) ++ { ++ struct stat st; + -+ /* could be a chroot or a container */ ++ /* could be a chroot or a container */ + -+ if (stat(use, &st) != 0) { -+ if (errno != EACCES) { -+ fprintf(stderr, _("Cannot stat %s: %s\n"), -+ use, strerror(errno)); -+ exit(1); -+ } -+ st.st_dev = (dev_t)-1; -+ } -+ ret = 0; -+ errno = 0; -+ *mountinfo = add_mntinfo(use, "unkown", 0, -1, st.st_dev); -+ break; -+ } -+ } -+ } -+ *end = '\0'; -+ nlen = end-use; -+ list_for_each(ptr, &mntinfo) { - mntinfo_t *mnt = list_entry(ptr, mntinfo_t); -- if (mid != mnt->parid) ++ if (statn(use, 0, &st) != 0) ++ { ++ if (errno != EACCES) ++ { ++ fprintf(stderr, _("Cannot stat %s: %s\n"), ++ use, strerror(errno)); ++ exit(1); ++ } ++ st.st_dev = (dev_t)-1; ++ } ++ ret = 0; ++ errno = 0; ++ *mountinfo = add_mntinfo(use, "unkown", 0, -1, st.st_dev); ++ break; ++ } ++ } ++ } ++ *end = '\0'; ++ nlen = end-use; ++ list_for_each(ptr, &mntinfo) ++ { ++ mntinfo_t *mnt = list_entry(ptr, mntinfo_t); + -+ if (nlen != mnt->nlen) - continue; -- move_head(ptr, &sort); ++ if (nlen != mnt->nlen) ++ continue; + -+ if (strcmp(use, mnt->mpoint)) -+ continue; ++ if (strcmp(use, mnt->mpoint)) ++ continue; + -+ ret = 0; -+ errno = 0; -+ *mountinfo = mnt; -+ break; - } -- } -- if (!list_empty(&mntinfo)) { --#ifdef EBADE -- errno = EBADE; --#else -- errno = ENOENT; --#endif /* EBADE */ -- } -- join(&sort, &mntinfo); ++ ret = 0; ++ errno = 0; ++ *mountinfo = mnt; ++ break; ++ } + -+ } while (!*mountinfo && (end = strrchr(use, '/'))); -+ free(use); ++ } while (!*mountinfo && (end = strrchr(use, '/'))); ++ free(use); +out: -+ return ret; - } - -+#if defined(WITH_MOUNTINFO_LIST) ++ return ret; ++} ++ /* - * Determine device of links below /proc/ - */ -@@ -2126,8 +2560,7 @@ static int mntstat(const char *path, struct stat *buf) - { - char name[PATH_MAX + 1]; - const char *use; -- ssize_t nlen; -- list_t *ptr; -+ mntinfo_t *mnt; + * Somehow the realpath(3) glibc function call, nevertheless + * it avoids lstat(2) system calls. +@@ -2215,6 +2774,52 @@ char *expandpath( + } + lnkbuf[n] = '\0'; /* Don't be fooled by readlink(2) */ - if ((use = realpath(path, name)) == NULL || *use != '/') - { -@@ -2139,27 +2572,26 @@ static int mntstat(const char *path, struct stat *buf) - errno = 0; - return stat(path, buf); - } -+ if (strncmp("/dev/", use, 5) == 0) { -+ /* -+ * Could be a special file (socket, pipe, inotify) -+ */ -+ errno = 0; -+ return stat(path, buf); -+ } - -- nlen = strlen(use); -- list_for_each(ptr, &mntinfo) { -- mntinfo_t *mnt = list_entry(ptr, mntinfo_t); -- if (nlen < mnt->nlen) -- continue; -- if (mnt->nlen == 1) { /* root fs is the last entry */ -- buf->st_dev = mnt->dev; -- buf->st_ino = 0; -- return 0; -- } -- if (use[mnt->nlen] != '\0' && use[mnt->nlen] != '/') -- continue; -- if (strncmp(use, mnt->mpoint, mnt->nlen) == 0) { -- buf->st_dev = mnt->dev; -- buf->st_ino = 0; -- return 0; -- } -+ if (find_mountpoint(use, &mnt) < 0) { -+ errno = ENOENT; -+ return -1; - } -- errno = ENOENT; -- return -1; ++ /* ++ * Expand to real path of named socket if any ++ */ ++ if (lnkbuf[0] != '/' && strncmp("socket:[", lnkbuf, 8) == 0) ++ { ++ FILE *fp; ++ char *inode; ++ char line[BUFSIZ]; ++ if ((inode = strchr(&lnkbuf[8], ']'))) ++ { ++ *inode = '\0'; ++ inode = &lnkbuf[8]; ++ } + -+ if (mnt->isremote) { -+ buf->st_dev = mnt->dev; -+ buf->st_ino = mnt->id; /* inode substitute */ -+ return 0; /* found on NFS */ -+ } ++ if (!inode || (fp = fopen(PROC_SOCKETS, "r")) == NULL) ++ { ++ /*fprintf(stderr, "Cannot open %s\n", PROC_SOCKETS); */ ++ return (char *)0; ++ } ++ while (fgets(line, BUFSIZ, fp) != NULL) ++ { ++ char *named = NULL; ++ unsigned long snode; + -+ return stat(path, buf); - } - #endif /* WITH_MOUNTINFO_LIST */ - ++ if (*line == 'N') ++ continue; ++ ++ if (sscanf(line, "%*x: %*x %*x %*x %*x %*x %lu %ms", ++ &snode, &named) == 2) ++ { ++ char *ep; ++ unsigned long oul = strtoul(inode, &ep, 0); ++ if (oul == snode) { ++ ep = named; ++ if (*ep == '@') ++ ep++; ++ n = strlen(ep); ++ memcpy(lnkbuf, ep, n); ++ lnkbuf[n] = '\0'; ++ } ++ free (named); ++ } ++ } ++ fclose(fp); ++ } ++ + len = strlen(end); + if ((n + len) > PATH_MAX) + { diff --git src/fuser.h src/fuser.h -index 4500ec5..16abc55 100644 +index 4500ec5..f90dad9 100644 --- src/fuser.h +++ src/fuser.h @@ -37,10 +37,16 @@ struct procs { @@ -1243,36 +1249,14 @@ index 4500ec5..16abc55 100644 #define NAMESPACE_FILE 0 #define NAMESPACE_TCP 1 -@@ -109,5 +123,6 @@ typedef struct mntinfo_s { +@@ -109,5 +123,7 @@ typedef struct mntinfo_s { #endif /* PATH_MAX */ #define KNFSD_EXPORTS "/proc/fs/nfs/exports" +#define PROC_MOUNTINFO "/proc/self/mountinfo" ++#define PROC_SOCKETS "/proc/self/net/unix" #define PROC_MOUNTS "/proc/mounts" #define PROC_SWAPS "/proc/swaps" -diff --git src/timeout.c src/timeout.c -index ca4a7cd..a3c7055 100644 ---- src/timeout.c -+++ src/timeout.c -@@ -67,9 +67,6 @@ - # ifndef constructor - # define constructor __constructor__ - # endif --# ifndef packed --# define packed __packed__ --# endif - # ifndef inline - # define inline __inline__ - # endif -@@ -107,7 +104,7 @@ typedef struct _handle { - stat_t function; - size_t len; - char path[0]; --} attribute((packed)) handle_t; -+} handle_t; - - /* - * Using a forked process for doing e.g. stat(2) system call as this -- -2.26.2 +2.35.3 diff --git a/0002-Use-new-statx-2-system-call-to-avoid-hangs-on-NFS.patch b/0002-Use-new-statx-2-system-call-to-avoid-hangs-on-NFS.patch deleted file mode 100644 index 1e33755..0000000 --- a/0002-Use-new-statx-2-system-call-to-avoid-hangs-on-NFS.patch +++ /dev/null @@ -1,1021 +0,0 @@ -From ab950c00ff36acf1731330f3b55863b3102cfe6a Mon Sep 17 00:00:00 2001 -From: Werner Fink -Date: Tue, 1 Feb 2022 13:34:41 +0100 -Subject: [PATCH] Use new statx(2) system call to avoid hangs on NFS - -Signed-off-by: Werner Fink ---- - Makefile.am | 4 +- - configure.ac | 38 ++---- - src/fuser.c | 102 ++++---------- - src/statx.c | 149 ++++++++++++++++++++ - src/statx.h | 68 ++++++++++ - src/timeout.c | 369 -------------------------------------------------- - src/timeout.h | 45 ------ - 7 files changed, 260 insertions(+), 515 deletions(-) - create mode 100644 src/statx.c - create mode 100644 src/statx.h - delete mode 100644 src/timeout.c - delete mode 100644 src/timeout.h - -diff --git Makefile.am Makefile.am -index 8067689..ea44203 100644 ---- Makefile.am -+++ Makefile.am -@@ -65,8 +65,8 @@ src_fuser_SOURCES = \ - src/fuser.h \ - src/lists.h - --if WANT_TIMEOUT_STAT --src_fuser_SOURCES += src/timeout.c src/timeout.h -+if HAVE_SYSCALL_STATX -+src_fuser_SOURCES += src/statx.c src/statx.h - endif - src_fuser_LDADD = @LIBINTL@ - src_killall_SOURCES = src/killall.c src/comm.h src/signals.c src/signals.h src/i18n.h -diff --git configure.ac configure.ac -index d4dee51..eda0e62 100644 ---- configure.ac -+++ configure.ac -@@ -46,20 +46,6 @@ if test "$enable_selinux" = "yes"; then - fi - AC_SUBST([DL_LIB]) - --# Call fork before all stat calls to stop hanging on NFS mounts --AC_SUBST([WITH_TIMEOUT_STAT]) --AC_ARG_ENABLE([timeout_stat], -- [AS_HELP_STRING([--enable-timeout-stat], [Use a timeout on stat calls (optional with argument "static" for a static background process)])], -- [enable_timeout_stat=$enableval], -- [enable_timeout_stat="no"]) --if test "$enable_timeout_stat" = "yes"; then -- AC_DEFINE([WITH_TIMEOUT_STAT], [1], [Use timeout on stat calls]) --fi --if test "$enable_timeout_stat" = "static"; then -- AC_DEFINE([WITH_TIMEOUT_STAT], [2], [Use timeout on stat calls]) --fi --AM_CONDITIONAL([WANT_TIMEOUT_STAT], [test "$enable_timeout_stat" = "static"]) -- - # Use /proc/self/mountinfo if available - if test -e /proc/self/mountinfo ; then - AC_DEFINE([HAS_MOUNTINFO], [1], [System has /proc/self/mountinfo which can used instead /proc(/self)/mounts]) -@@ -73,16 +59,20 @@ fi - AC_CHECK_FUNC([name_to_handle_at],[ - AC_DEFINE([HAS_NAME_TO_HANDLE_AT], [1], [System has name_to_handle_at(2) system call])]) - --# Use string search for network based file systems but only if the system --# has /proc/self/mountinfo --AC_SUBST([WITH_MOUNTINFO_LIST]) --AC_ARG_ENABLE([mountinfo_list], -- [AS_HELP_STRING([--enable-mountinfo-list], [Use the list in /proc/self/mountinfo to replace stat(2) syscall on network file systems shares])], -- [enable_mountinfo_list="yes"], -- [enable_mountinfo_list="no"]) --if test "$enable_mountinfo_list" = "yes" -a -e /proc/self/mountinfo ; then -- AC_DEFINE([WITH_MOUNTINFO_LIST], [1], [Use list in /proc/self/mountinfo to replace stat calls]) --fi -+AC_CHECK_HEADERS([sys/syscall.h]) -+AC_CHECK_DECLS([SYS_statx], -+ [has_syscall_statx="yes"], -+ [has_syscall_statx="no"], -+ [[#include ]] -+) -+AC_CHECK_FUNCS([statx]) -+# Check for linux specific statx(2) system call -+AC_SUBST([HAS_SYSCALL_STATX]) -+AC_ARG_ENABLE([disable_statx], -+ [AS_HELP_STRING([--disable-statx], [Do not use linux specific statx(2) system call as replacement for stat(2), lstat(2), and fstat(2)])], -+ [enable_syscall_statx="no"], -+ [enable_syscall_statx=$has_syscall_statx]) -+AM_CONDITIONAL([HAVE_SYSCALL_STATX], [test "$enable_syscall_statx" = "yes"]) - - # Enable hardened compile and link flags - AC_ARG_ENABLE([harden_flags], -diff --git src/fuser.c src/fuser.c -index 79d44ef..21b4695 100644 ---- src/fuser.c -+++ src/fuser.c -@@ -65,7 +65,7 @@ - #include "fuser.h" - #include "signals.h" - #include "i18n.h" --#include "timeout.h" -+#include "statx.h" - #include "comm.h" - - //#define DEBUG 1 -@@ -128,10 +128,6 @@ static ino_t get_namespace(const pid_t pid); - static int get_mountid(const char *path); - #endif - static int find_mountpoint(const char *path, mntinfo_t **mountinfo); --#if defined(WITH_MOUNTINFO_LIST) --static int mntstat(const char *path, struct stat *buf); --#endif --static stat_t thestat = stat; - static char *expandpath(const char *path); - static struct unixsocket_list *unixsockets = NULL; - static struct names *names_head = NULL, *names_tail = NULL; -@@ -519,7 +515,7 @@ int parse_file(struct names *this_name, struct inode_list **ino_list, - free(this_name->filename); - this_name->filename = strdup(new); - } -- if (timeout(thestat, this_name->filename, &(this_name->st), 5) != 0 || -+ if (statn(this_name->filename, STATX_INO|STATX_TYPE, &(this_name->st)) != 0 || - find_mountpoint(this_name->filename, &mountinfo) != 0) { - if (errno == ENOENT) - fprintf(stderr, -@@ -1253,9 +1249,7 @@ int main(int argc, char *argv[]) - opts |= OPT_INTERACTIVE; - break; - case 'I': --#if defined(WITH_MOUNTINFO_LIST) - opts |= OPT_ALWAYSSTAT; --#endif - break; - case 'k': - opts |= OPT_KILL; -@@ -1321,10 +1315,11 @@ int main(int argc, char *argv[]) - continue; - } - --#if defined(WITH_MOUNTINFO_LIST) -- if ((opts & (OPT_MOUNTS|OPT_ALWAYSSTAT)) == OPT_MOUNTS) -- thestat = mntstat; -+#if defined(HAVE_DECL_SYS_STATX) && HAVE_DECL_SYS_STATX == 1 -+ if ((opts & OPT_ALWAYSSTAT)) -+ stat_flags = 0; /* Triggers sync with e.g. remote NFS server even on autofs */ - #endif -+ - /* an option */ - /* Not an option, must be a file specification */ - if ((this_name = malloc(sizeof(struct names))) == NULL) -@@ -1644,7 +1639,7 @@ static struct stat *get_pidstat(const pid_t pid, const char *filename, int *id) - if ((st = (struct stat *)malloc(sizeof(struct stat))) == NULL) - return NULL; - snprintf(pathname, PATH_MAX-1, "/proc/%d/%s", pid, filename); -- if (timeout(thestat, pathname, st, 5) != 0) { -+ if (statn(pathname, STATX_UID|STATX_INO|STATX_TYPE, st) != 0) { - free(st); - return NULL; - } -@@ -1698,7 +1693,7 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - snprintf(filepath, sizeof filepath - 1, "/proc/%d/%s/%s", - pid, dirname, direntry->d_name); - -- if (timeout(thestat, filepath, &st, 5) != 0) { -+ if (statn(filepath, STATX_INO, &st) != 0) { - if (errno != ENOENT && errno != ENOTDIR) { - fprintf(stderr, _("Cannot stat file %s: %s\n"), - filepath, strerror(errno)); -@@ -1775,7 +1770,7 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - if (thedev != ino_tmp->device) - continue; - if (!st.st_ino -- && timeout(thestat, filepath, &st, 5) != 0) { -+ && statn(filepath, STATX_INO, &st) != 0) { - fprintf(stderr, - _("Cannot stat file %s: %s\n"), - filepath, strerror(errno)); -@@ -1873,11 +1868,11 @@ static uid_t getpiduid(const pid_t pid) - - if (asprintf(&pathname, "/proc/%d", pid) < 0) - return 0; -- if (timeout(thestat, pathname, &st, 5) != 0) { -- free(pathname); -+ if (statn(pathname, STATX_UID, &st) != 0) { -+ free(pathname); - return 0; -- } -- free(pathname); -+ } -+ free(pathname); - return st.st_uid; - } - -@@ -1915,7 +1910,7 @@ void fill_unix_cache(struct unixsocket_list **unixsocket_head) - path = scanned_path; - if (*scanned_path == '@') - scanned_path++; -- if (timeout(thestat, scanned_path, &st, 5) < 0) { -+ if (statn(scanned_path, STATX_INO, &st) < 0) { - free(path); - continue; - } -@@ -2050,7 +2045,7 @@ static dev_t find_net_dev(void) - fprintf(stderr, _("Cannot open a network socket.\n")); - return -1; - } -- if (fstat(skt, &st) != 0) { -+ if (fstatn(skt, STATX_INO, &st) != 0) { - fprintf(stderr, _("Cannot find socket's device number.\n")); - close(skt); - return -1; -@@ -2087,7 +2082,7 @@ scan_knfsd(struct names *names_head, struct inode_list *ino_head, - if ((find_space = strpbrk(line, " \t")) == NULL) - continue; - *find_space = '\0'; -- if (timeout(thestat, line, &st, 5) != 0) { -+ if (statn(line, STATX_INO, &st) != 0) { - continue; - } - /* Scan the devices */ -@@ -2121,7 +2116,7 @@ scan_mounts(struct names *names_head, struct inode_list *ino_head, - mntinfo_t *mnt = list_entry(ptr, mntinfo_t); - const char *find_mountp = mnt->mpoint; - -- if (timeout(thestat, find_mountp, &st, 5) != 0) -+ if (statn(find_mountp, STATX_INO, &st) != 0) - continue; - - /* Scan the devices */ -@@ -2171,7 +2166,7 @@ scan_swaps(struct names *names_head, struct inode_list *ino_head, - if (*find_space == '\0') - continue; - } -- if (timeout(thestat, line, &st, 5) != 0) { -+ if (statn(line, STATX_INO, &st) != 0) { - continue; - } - /* Scan the devices */ -@@ -2268,10 +2263,10 @@ init_mntinfo(void) - &mid, &parid, &maj, &min, &mpoint[0], &type[0], &devname[0]) == 7) { - struct stat st; - mntinf = add_mntinfo(mpoint, type, mid, parid, makedev(maj, min)); -- if (mntinf && strncmp(devname, "/dev/", 5) == 0 && stat(devname, &st) == 0) { -+ if (mntinf && strncmp(devname, "/dev/", 5) == 0 && statn(devname, 0, &st) == 0) { - if (st.st_rdev != 0 && mntinf->dev != st.st_rdev) { - mntinf->vol = st.st_rdev; -- stat(mpoint, &st); -+ statn(mpoint, 0, &st); - mntinf->dev = st.st_dev; /* stat(2) on binary does not see subvol dev */ - } - } -@@ -2283,7 +2278,7 @@ init_mntinfo(void) - parid = -1; - while (fscanf (mnt, "%s %s %s %*[^\n]", &devname[0], &mpoint[0], &type[0]) == 3) { - struct stat st; -- if (stat(mpoint, &st) != 0) { -+ if (statn(mpoint, 0, &st) != 0) { - if (errno != EACCES) { - fprintf(stderr, _("Cannot stat %s: %s\n"), - mpoint, strerror(errno)); -@@ -2292,7 +2287,7 @@ init_mntinfo(void) - st.st_dev = (dev_t)-1; - } - mntinf = add_mntinfo(mpoint, type, mid++, parid, st.st_dev); -- if (mntinf && strncmp(devname, "/dev/", 5) == 0 && stat(devname, &st) == 0) { -+ if (mntinf && strncmp(devname, "/dev/", 5) == 0 && statn(devname, 0, &st) == 0) { - if (st.st_rdev != 0 && mntinf->dev != st.st_rdev) - mntinf->vol = st.st_rdev; - } -@@ -2316,7 +2311,7 @@ get_fdinfo(const pid_t pid, const char *fd, struct fdinfo *info, const ino_t ns) - struct stat st; - - if (!mynamespace) { -- if (stat("/proc/self/ns/mnt", &st) != 0) { -+ if (statn("/proc/self/ns/mnt", STATX_INO, &st) != 0) { - fprintf(stderr, _("Cannot stat %s: %s\n"), - "/proc/self/ns/mnt", strerror(errno)); - exit(1); -@@ -2365,7 +2360,7 @@ out: - struct stat lst; - - snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); -- if (!flags && lstat(pathname, &lst) == 0) { -+ if (!flags && lstatn(pathname, STATX_MODE, &lst) == 0) { - if (lst.st_mode & S_IWUSR) - info->flags |= O_WRONLY; - ret++; -@@ -2392,7 +2387,7 @@ get_namespace(const pid_t pid) - char pathname[512]; - struct stat st; - snprintf(pathname, sizeof(pathname)-1, "/proc/%d/ns/mnt", pid); -- if (stat(pathname, &st) == 0) -+ if (statn(pathname, STATX_INO, &st) == 0) - return st.st_ino; - return -1; - } -@@ -2449,7 +2444,7 @@ find_mountpoint(const char *path, mntinfo_t **mountinfo) - - /* could be a chroot or a container */ - -- if (stat(path, &st) != 0) { -+ if (statn(path, 0, &st) != 0) { - if (errno != EACCES) { - fprintf(stderr, _("Cannot stat %s: %s\n"), - path, strerror(errno)); -@@ -2481,7 +2476,7 @@ find_mountpoint(const char *path, mntinfo_t **mountinfo) - - /* could be a chroot or a container */ - -- if (stat(use, &st) != 0) { -+ if (statn(use, 0, &st) != 0) { - if (errno != EACCES) { - fprintf(stderr, _("Cannot stat %s: %s\n"), - use, strerror(errno)); -@@ -2519,49 +2514,6 @@ out: - return ret; - } - --#if defined(WITH_MOUNTINFO_LIST) --/* -- * Determine device of links below /proc/ -- */ --static int mntstat(const char *path, struct stat *buf) --{ -- char name[PATH_MAX + 1]; -- const char *use; -- mntinfo_t *mnt; -- -- if ((use = realpath(path, name)) == NULL || *use != '/') -- { -- if (errno == ENOENT) -- return -1; -- /* -- * Could be a special file (socket, pipe, inotify) -- */ -- errno = 0; -- return stat(path, buf); -- } -- if (strncmp("/dev/", use, 5) == 0) { -- /* -- * Could be a special file (socket, pipe, inotify) -- */ -- errno = 0; -- return stat(path, buf); -- } -- -- if (find_mountpoint(use, &mnt) < 0) { -- errno = ENOENT; -- return -1; -- } -- -- if (mnt->isremote) { -- buf->st_dev = mnt->dev; -- buf->st_ino = mnt->id; /* inode substitute */ -- return 0; /* found on NFS */ -- } -- -- return stat(path, buf); --} --#endif /* WITH_MOUNTINFO_LIST */ -- - /* - * Somehow the realpath(3) glibc function call, nevertheless - * it avoids lstat(2) system calls. -diff --git src/statx.c src/statx.c -new file mode 100644 -index 0000000..a598c89 ---- /dev/null -+++ src/statx.c -@@ -0,0 +1,149 @@ -+/* -+ * statx.c - Map modern statx(2) system call to older stat(2), lstat(2), -+ * and fstat(2) replacements named {,l,f}statn() -+ * -+ * Copyright (C) 2018 Werner Fink -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#ifndef HAVE_STATX -+# define _ASM_GENERIC_FCNTL_H /* Avoid collisions between asm/fcntl.h and bits/fcntl.h ! */ -+# include /* Definition of AT_* and AT_STATX_* constants ! */ -+#endif -+#include /* Definition of AT_* constants */ -+#include -+#ifndef HAVE_STATX -+# ifndef STATX_TYPE -+# include /* Provides 'struct statx' and STATX_* ! */ -+# endif -+#endif -+#include -+#include -+#include -+#include -+ -+int stat_flags = AT_NO_AUTOMOUNT|AT_STATX_DONT_SYNC; -+ -+int statn(const char *pathname, unsigned int mask, struct stat *st) -+{ -+ int flags = stat_flags; -+ int dirfd = pathname && *pathname == '/' ? 0 : AT_FDCWD; -+ int ret; -+ struct statx stx; -+ -+#ifndef HAVE_STATX -+ ret = syscall(SYS_statx, dirfd, pathname, flags, mask, &stx); -+#else -+ ret = statx(dirfd, pathname, flags, mask, &stx); -+#endif -+ if (ret >= 0) { -+ st->st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor); -+ st->st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor); -+ -+ st->st_ino = stx.stx_ino; -+ st->st_mode = stx.stx_mode; -+ st->st_nlink = stx.stx_nlink; -+ st->st_uid = stx.stx_uid; -+ st->st_gid = stx.stx_gid; -+ st->st_size = stx.stx_size; -+ st->st_blksize = stx.stx_blksize; -+ st->st_blocks = stx.stx_blocks; -+ -+ st->st_atim.tv_sec = stx.stx_atime.tv_sec; -+ st->st_atim.tv_nsec = stx.stx_atime.tv_nsec; -+ st->st_mtim.tv_sec = stx.stx_mtime.tv_sec; -+ st->st_mtim.tv_nsec = stx.stx_mtime.tv_nsec; -+ st->st_ctim.tv_sec = stx.stx_ctime.tv_sec; -+ st->st_ctim.tv_nsec = stx.stx_ctime.tv_nsec; -+ } -+ return ret; -+} -+ -+int fstatn(int fd, unsigned int mask, struct stat *st) -+{ -+ int flags = AT_EMPTY_PATH|stat_flags; -+ int ret; -+ struct statx stx; -+ -+#ifndef HAVE_STATX -+ ret = syscall(SYS_statx, fd, "", flags, mask, &stx); -+#else -+ ret = statx(fd, "", flags, mask, &stx); -+#endif -+ if (ret >= 0) { -+ st->st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor); -+ st->st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor); -+ -+ st->st_ino = stx.stx_ino; -+ st->st_mode = stx.stx_mode; -+ st->st_nlink = stx.stx_nlink; -+ st->st_uid = stx.stx_uid; -+ st->st_gid = stx.stx_gid; -+ st->st_size = stx.stx_size; -+ st->st_blksize = stx.stx_blksize; -+ st->st_blocks = stx.stx_blocks; -+ -+ st->st_atim.tv_sec = stx.stx_atime.tv_sec; -+ st->st_atim.tv_nsec = stx.stx_atime.tv_nsec; -+ st->st_mtim.tv_sec = stx.stx_mtime.tv_sec; -+ st->st_mtim.tv_nsec = stx.stx_mtime.tv_nsec; -+ st->st_ctim.tv_sec = stx.stx_ctime.tv_sec; -+ st->st_ctim.tv_nsec = stx.stx_ctime.tv_nsec; -+ } -+ return ret; -+} -+ -+int lstatn(const char *pathname, unsigned int mask, struct stat *st) -+{ -+ int flags = AT_SYMLINK_NOFOLLOW|stat_flags; -+ int dirfd = pathname && *pathname == '/' ? 0 : AT_FDCWD; -+ int ret; -+ struct statx stx; -+ -+#ifndef HAVE_STATX -+ ret = syscall(SYS_statx, dirfd, pathname, flags, mask, &stx); -+#else -+ ret = statx(dirfd, pathname, flags, mask, &stx); -+#endif -+ if (ret >= 0) { -+ st->st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor); -+ st->st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor); -+ -+ st->st_ino = stx.stx_ino; -+ st->st_mode = stx.stx_mode; -+ st->st_nlink = stx.stx_nlink; -+ st->st_uid = stx.stx_uid; -+ st->st_gid = stx.stx_gid; -+ st->st_size = stx.stx_size; -+ st->st_blksize = stx.stx_blksize; -+ st->st_blocks = stx.stx_blocks; -+ -+ st->st_atim.tv_sec = stx.stx_atime.tv_sec; -+ st->st_atim.tv_nsec = stx.stx_atime.tv_nsec; -+ st->st_mtim.tv_sec = stx.stx_mtime.tv_sec; -+ st->st_mtim.tv_nsec = stx.stx_mtime.tv_nsec; -+ st->st_ctim.tv_sec = stx.stx_ctime.tv_sec; -+ st->st_ctim.tv_nsec = stx.stx_ctime.tv_nsec; -+ } -+ return ret; -+} -diff --git src/statx.h src/statx.h -new file mode 100644 -index 0000000..fdd0137 ---- /dev/null -+++ src/statx.h -@@ -0,0 +1,68 @@ -+/* -+ * statx.h - Map modern statx(2) system call to older stat(2), lstat(2), -+ * and fstat(2) replacements named {,l,f}statn() -+ * -+ * Copyright (C) 2018 Werner Fink -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef _STATX_H -+#define _STATX_H -+ -+extern int stat_flags; -+#if defined(HAVE_DECL_SYS_STATX) && HAVE_DECL_SYS_STATX == 1 -+# ifndef HAVE_STATX -+# define _ASM_GENERIC_FCNTL_H /* Avoid collisions between asm/fcntl.h and bits/fcntl.h ! */ -+# include /* Definition of AT_* and AT_STATX_* constants ! */ -+# ifndef STATX_TYPE -+# include /* Provides 'struct statx' and STATX_* ! */ -+# endif -+# endif -+extern int statn(const char*, unsigned int, struct stat*); -+extern int fstatn(int, unsigned int, struct stat*); -+extern int lstatn(const char*, unsigned int, struct stat*); -+#else -+extern inline int -+statn(const char *path, unsigned int mask __attribute__((unused)), struct stat *st) -+{ -+ return stat(path, st); -+} -+extern inline int -+fstatn(int fd, unsigned int mask __attribute__((unused)), struct stat *st) -+{ -+ return fstat(fd, st); -+} -+extern inline int -+lstatn(const char *path, unsigned int mask __attribute__((unused)), struct stat *st) -+{ -+ return lstat(path, st); -+} -+#define STATX_TYPE 0 -+#define STATX_MODE 0 -+#define STATX_NLINK 0 -+#define STATX_UID 0 -+#define STATX_GID 0 -+#define STATX_ATIME 0 -+#define STATX_MTIME 0 -+#define STATX_CTIME 0 -+#define STATX_INO 0 -+#define STATX_SIZE 0 -+#define STATX_BLOCKS 0 -+#define STATX_BASIC_STATS 0 -+#define STATX_BTIME 0 -+#define STATX_ALL 0 -+#endif -+#endif -diff --git src/timeout.c src/timeout.c -deleted file mode 100644 -index a3c7055..0000000 ---- src/timeout.c -+++ /dev/null -@@ -1,369 +0,0 @@ --/* -- * timout.c Advanced timeout handling for file system calls -- * to avoid deadlocks on remote file shares. -- * -- * Version: 0.2 11-Dec-2012 Fink -- * -- * Copyright 2011,2012 Werner Fink, 2011,2012 SUSE LINUX Products GmbH, Germany. -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * Author: Werner Fink , 2011 -- */ -- --#ifndef _GNU_SOURCE --# define _GNU_SOURCE --#endif -- --#ifdef _FEATURES_H --# error Include local config.h before any system header file --#endif --#include "config.h" -- --#ifndef WITH_TIMEOUT_STAT --# define WITH_TIMEOUT_STAT 0 --#endif -- --#ifndef USE_SOCKETPAIR --# define USE_SOCKETPAIR 1 --#endif -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#if USE_SOCKETPAIR --# include --# include --# include --# ifndef SHUT_RD --# define SHUT_RD 0 --# endif --# ifndef SHUT_WR --# define SHUT_WR 1 --# endif --# undef pipe --# define pipe(v) (((socketpair(AF_UNIX,SOCK_STREAM,0,v) < 0) || \ -- (shutdown((v)[1],SHUT_RD) < 0) || (shutdown((v)[0],SHUT_WR) < 0)) ? -1 : 0) --#endif --#include -- --#include "timeout.h" -- --#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) --# ifndef destructor --# define destructor __destructor__ --# endif --# ifndef constructor --# define constructor __constructor__ --# endif --# ifndef inline --# define inline __inline__ --# endif --# ifndef unused --# define unused __unused__ --# endif --# ifndef volatile --# define volatile __volatile__ --# endif --#endif --#ifndef attribute --# define attribute(attr) __attribute__(attr) --#endif -- --#if defined __GNUC__ --# undef strcpy --# define strcpy(d,s) __builtin_strcpy((d),(s)) /* Without boundary check please */ --#endif -- --#if WITH_TIMEOUT_STAT --static sigjmp_buf jenv; --static void sigjump(int sig attribute((unused))) --{ -- siglongjmp(jenv, 1); --} --#endif -- --#if WITH_TIMEOUT_STAT == 2 --/* -- * The structure used for communication between the processes -- */ --typedef struct _handle { -- int errcode; -- struct stat argument; -- stat_t function; -- size_t len; -- char path[0]; --} handle_t; -- --/* -- * Using a forked process for doing e.g. stat(2) system call as this -- * allows us to send e.g. SIGKILL to this process if it hangs in `D' -- * state on a file share due a stalled NFS server. This does not work -- * with (p)threads as SIGKILL would kill all threads including main. -- */ -- --static volatile pid_t active; --static int pipes[4] = {-1, -1, -1, -1}; --static handle_t *restrict handle; --static const size_t buflen = PATH_MAX+sizeof(handle_t)+1; -- --static void sigchild(int sig attribute((unused))) --{ -- pid_t pid = waitpid(active, NULL, WNOHANG|WUNTRACED); -- if (pid <= 0) -- return; -- if (errno == ECHILD) -- return; -- active = 0; --} -- --static void attribute((constructor)) start(void) --{ -- sigset_t sigset, oldset; -- struct sigaction act; -- char sync[1]; -- ssize_t in; -- -- if (pipes[1] >= 0) close(pipes[1]); -- if (pipes[2] >= 0) close(pipes[2]); -- -- if (pipe(&pipes[0])) -- goto error; -- if (pipe(&pipes[2])) -- goto error; -- -- memset(&act, 0, sizeof(act)); -- sigemptyset(&act.sa_mask); -- act.sa_flags = SA_RESTART; -- act.sa_handler = sigchild; -- sigaction(SIGCHLD, &act, 0); -- -- if (!handle) -- handle = mmap(NULL, buflen, PROT_READ|PROT_WRITE, -- MAP_ANONYMOUS|MAP_SHARED, -1, 0); -- if (handle == MAP_FAILED) -- goto error; -- -- if ((active = fork()) < 0) -- goto error; -- -- if (active) { -- close(pipes[0]); -- close(pipes[3]); -- pipes[0] = pipes[3] = -1; -- return; -- } -- -- sigemptyset(&sigset); -- sigaddset(&sigset, SIGALRM); -- sigprocmask(SIG_BLOCK, &sigset, &oldset); -- -- act.sa_handler = SIG_DFL; -- sigaction(SIGCHLD, &act, 0); -- -- close(pipes[1]); -- close(pipes[2]); -- dup2(pipes[0], STDIN_FILENO); -- dup2(pipes[3], STDOUT_FILENO); -- close(pipes[0]); -- close(pipes[3]); -- pipes[1] = pipes[2] = -1; -- pipes[0] = pipes[3] = -1; -- -- while ((in = read(STDIN_FILENO, &sync, sizeof(sync))) != 0) { -- ssize_t out; -- if (in < 0) { -- if (errno == EINTR) -- continue; -- break; -- } -- if (!handle) -- break; -- if (handle->function(handle->path, &handle->argument) < 0) -- handle->errcode = errno; -- do -- out = write(STDOUT_FILENO, &sync, sizeof(sync)); -- while (out < 0 && errno == EINTR); -- } -- -- sigprocmask(SIG_SETMASK, &oldset, NULL); -- exit(0); --error: -- if (pipes[0] >= 0) close(pipes[0]); -- if (pipes[1] >= 0) close(pipes[1]); -- if (pipes[2] >= 0) close(pipes[2]); -- if (pipes[3] >= 0) close(pipes[3]); -- if (handle && handle != MAP_FAILED) -- munmap(handle, buflen); -- handle = NULL; --} -- --static void /* attribute((destructor)) */ stop(void) --{ -- if (active && waitpid(active, NULL, WNOHANG|WUNTRACED) == 0) -- kill(active, SIGKILL); --} -- --/* -- * External routine -- * -- * Execute stat(2) system call with timeout to avoid deadlock -- * on network based file systems. -- * -- */ --int --timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds) --{ -- struct sigaction alrm_act, pipe_act, new_act; -- sigset_t sigset, oldset; -- char sync[1] = "x"; -- -- if (active <= 0) /* Oops, last one failed therefore clear status and restart */ -- start(); -- if (!handle) /* No shared memory area */ -- return function(path, argument); -- memset(handle, 0, sizeof(handle_t)); -- handle->len = strlen(path) + 1; -- if (handle->len >= PATH_MAX) { -- errno = ENAMETOOLONG; -- goto error; -- } -- handle->errcode = 0; -- handle->argument = *argument; -- handle->function = function; -- strcpy(handle->path, path); -- -- sigemptyset(&sigset); -- sigaddset(&sigset, SIGALRM); -- sigaddset(&sigset, SIGPIPE); -- sigprocmask(SIG_UNBLOCK, &sigset, &oldset); -- -- memset(&new_act, 0, sizeof(new_act)); -- sigemptyset(&new_act.sa_mask); -- new_act.sa_flags = SA_RESETHAND; -- -- if (sigsetjmp(jenv, 1)) -- goto timed; -- -- new_act.sa_handler = sigjump; -- sigaction(SIGALRM, &new_act, &alrm_act); -- sigaction(SIGPIPE, &new_act, &pipe_act); -- alarm(seconds); -- -- write(pipes[1], &sync, sizeof(sync)); -- read(pipes[2], &sync, sizeof(sync)); -- -- alarm(0); -- sigaction(SIGPIPE, &pipe_act, NULL); -- sigaction(SIGALRM, &alrm_act, NULL); -- -- if (handle->errcode) { -- errno = handle->errcode; -- goto error; -- } -- -- *argument = handle->argument; -- sigprocmask(SIG_SETMASK, &oldset, NULL); -- -- return 0; --timed: -- (void) alarm(0); -- sigaction(SIGPIPE, &pipe_act, NULL); -- sigaction(SIGALRM, &alrm_act, NULL); -- sigprocmask(SIG_SETMASK, &oldset, NULL); -- stop(); -- errno = ETIMEDOUT; --error: -- return -1; --} --#elif WITH_TIMEOUT_STAT == 1 --/* -- * External routine -- * -- * Execute stat(2) system call with timeout to avoid deadlock -- * on network based file systems. -- * -- */ --int --timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds) --{ -- struct sigaction alrm_act, pipe_act, new_act; -- sigset_t sigset, oldset; -- int ret = 0, pipes[4]; -- pid_t pid = 0; -- ssize_t len; -- -- if (pipe(&pipes[0]) < 0) -- goto error; -- switch ((pid = fork())) { -- case -1: -- close(pipes[0]); -- close(pipes[1]); -- goto error; -- case 0: -- new_act.sa_handler = SIG_DFL; -- sigaction(SIGALRM, &new_act, NULL); -- close(pipes[0]); -- if ((ret = function(path, argument)) == 0) -- do -- len = write(pipes[1], argument, sizeof(struct stat)); -- while (len < 0 && errno == EINTR); -- close(pipes[1]); -- exit(ret); -- default: -- close(pipes[1]); -- -- sigemptyset(&sigset); -- sigaddset(&sigset, SIGALRM); -- sigaddset(&sigset, SIGPIPE); -- sigprocmask(SIG_UNBLOCK, &sigset, &oldset); -- -- memset(&new_act, 0, sizeof(new_act)); -- sigemptyset(&new_act.sa_mask); -- -- if (sigsetjmp(jenv, 1)) -- goto timed; -- -- new_act.sa_handler = sigjump; -- sigaction(SIGALRM, &new_act, &alrm_act); -- sigaction(SIGPIPE, &new_act, &pipe_act); -- alarm(seconds); -- if (read(pipes[0], argument, sizeof(struct stat)) == 0) { -- errno = EFAULT; -- ret = -1; -- } -- (void)alarm(0); -- sigaction(SIGPIPE, &pipe_act, NULL); -- sigaction(SIGALRM, &alrm_act, NULL); -- -- close(pipes[0]); -- waitpid(pid, NULL, 0); -- break; -- } -- return ret; --timed: -- (void)alarm(0); -- sigaction(SIGPIPE, &pipe_act, NULL); -- sigaction(SIGALRM, &alrm_act, NULL); -- if (waitpid(0, NULL, WNOHANG) == 0) -- kill(pid, SIGKILL); -- errno = ETIMEDOUT; --error: -- return -1; --} --#endif -- --/* -- * End of timeout.c -- */ -diff --git src/timeout.h src/timeout.h -deleted file mode 100644 -index f372297..0000000 ---- src/timeout.h -+++ /dev/null -@@ -1,45 +0,0 @@ --/* -- * timout.h Advanced timeout handling for file system calls -- * to avoid deadlocks on remote file shares. -- * -- * Version: 0.1 07-Sep-2011 Fink -- * -- * Copyright 2011 Werner Fink, 2011 SUSE LINUX Products GmbH, Germany. -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * Author: Werner Fink , 2011 -- */ -- --#ifndef _TIMEOUT_H --#define _TIMEOUT_H -- --#include "config.h" -- --#ifndef WITH_TIMEOUT_STAT --# define WITH_TIMEOUT_STAT 0 --#endif -- --#include --#include --#include --#include -- --#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) --# ifndef restrict --# define restrict __restrict__ --# endif --#endif -- --typedef int (*stat_t)(const char *, struct stat *); -- --#if WITH_TIMEOUT_STAT > 0 --extern int timeout(stat_t, const char *, struct stat *restrict, time_t); --#else --# define timeout(func,path,buf,dummy) (func)((path),(buf)) --#endif -- --#endif --- -2.26.2 - diff --git a/psmisc-22.21-pstree.patch b/psmisc-22.21-pstree.patch index 903c8c9..f293f18 100644 --- a/psmisc-22.21-pstree.patch +++ b/psmisc-22.21-pstree.patch @@ -1,10 +1,10 @@ --- - src/pstree.c | 37 ++++++++++++++++++++++++++++++------- - 1 file changed, 30 insertions(+), 7 deletions(-) + src/pstree.c | 38 +++++++++++++++++++++++++++++++------- + 1 file changed, 31 insertions(+), 7 deletions(-) --- src/pstree.c -+++ src/pstree.c 2022-01-20 13:27:44.175949055 +0000 -@@ -72,6 +72,7 @@ extern const char *__progname; ++++ src/pstree.c 2022-12-13 07:46:58.243076344 +0000 +@@ -79,6 +79,7 @@ extern const char *__progname; #define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */ #define VT_BEG "\033(0\017" /* use graphic chars */ @@ -12,8 +12,8 @@ #define VT_END "\033(B" /* back to normal char set */ #define VT_V "x" /* see UTF definitions above */ #define VT_VR "t" -@@ -522,6 +523,27 @@ static void out_scontext(const PROC *cur - } +@@ -578,6 +579,28 @@ static void out_scontext(const PROC *cur + out_string("'"); } +/* @@ -23,24 +23,25 @@ +static void +out_sym (const char *str) +{ -+ int seq = 0; -+ if (sym == &sym_vt100 && *str == '\033') { -+ seq = 1; -+ if (cur_x <= output_width || !trunc) -+ cur_x -= VT_LEN; -+ } -+ out_string(str); -+ if (seq) { -+ str = VT_END; -+ while (*str) -+ putchar (*str++); -+ } ++ int seq = 0; ++ if (sym == &sym_vt100 && *str == '\033') { ++ seq = 1; ++ if (cur_x <= output_width || !trunc) ++ cur_x -= VT_LEN; ++ } ++ out_string(str); ++ if (seq) { ++ str = VT_END; ++ while (*str) ++ putchar (*str++); ++ } +} ++ + static void out_newline(void) { if (last_char && cur_x == output_width) -@@ -761,11 +783,12 @@ dump_tree(PROC * current, int level, int +@@ -817,11 +840,12 @@ dump_tree(PROC * current, int level, int for (lvl = 0; lvl < level; lvl++) { for (i = width[lvl] + 1; i; i--) out_char(' '); @@ -58,7 +59,7 @@ } if (rep < 2) -@@ -875,7 +898,7 @@ dump_tree(PROC * current, int level, int +@@ -931,7 +955,7 @@ dump_tree(PROC * current, int level, int } width[level] = comm_len + cur_x - offset + add; if (cur_x >= output_width && trunc) { @@ -67,7 +68,7 @@ out_string("+"); out_newline(); return; -@@ -899,7 +922,7 @@ dump_tree(PROC * current, int level, int +@@ -955,7 +979,7 @@ dump_tree(PROC * current, int level, int } } if (first) { diff --git a/psmisc-v23.4.dif b/psmisc-v23.4.dif deleted file mode 100644 index 695b153..0000000 --- a/psmisc-v23.4.dif +++ /dev/null @@ -1,51 +0,0 @@ ---- - configure.ac | 2 +- - src/fuser.c | 5 ++++- - 2 files changed, 5 insertions(+), 2 deletions(-) - ---- configure.ac -+++ configure.ac 2021-01-14 11:31:31.640709812 +0000 -@@ -145,7 +145,7 @@ AC_CHECK_MEMBERS([struct user_regs_struc - struct user_regs_struct.rdi, - struct user_regs_struct.rsi, - struct user_regs_struct.rdx], [],[], -- [#include -+ [#include - #include ]) - AC_CHECK_MEMBERS([struct pt_regs.orig_gpr3, - struct pt_regs.gpr], [],[], [#include ]) ---- src/fuser.c -+++ src/fuser.c 2021-01-14 11:31:31.640709812 +0000 -@@ -1153,6 +1153,7 @@ int main(int argc, char *argv[]) - struct option *optr; - char *nsptr; - int skip_argv; -+ int seen_file; - - struct option options[] = { - {"all", 0, NULL, 'a'}, -@@ -1196,6 +1197,7 @@ int main(int argc, char *argv[]) - #endif - atexit(atexit_free_lists); - -+ seen_file = 0; - for (argc_cnt = 1; argc_cnt < argc; argc_cnt++) { - current_argv = argv[argc_cnt]; - if (current_argv[0] == '-') { /* its an option */ -@@ -1340,6 +1342,7 @@ int main(int argc, char *argv[]) - } - } - this_name->matched_procs = NULL; -+ seen_file = 1; - if (opts & (OPT_MOUNTS | OPT_ISMOUNTPOINT) - && this_name->name_space != NAMESPACE_FILE) { - free(this_name); -@@ -1393,7 +1396,7 @@ int main(int argc, char *argv[]) - names_tail->next = this_name; - names_tail = this_name; - } /* for across the argvs */ -- if (names_head == NULL) -+ if (names_head == NULL && !seen_file) - usage(_("No process specification given")); - - /* Check if -M flag was used and if so check mounts */ diff --git a/psmisc-v23.6.dif b/psmisc-v23.6.dif new file mode 100644 index 0000000..afedfb7 --- /dev/null +++ b/psmisc-v23.6.dif @@ -0,0 +1,51 @@ +--- + configure.ac | 2 +- + src/fuser.c | 5 ++++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- configure.ac ++++ configure.ac 2022-12-13 07:57:11.751636898 +0000 +@@ -162,7 +162,7 @@ AC_CHECK_MEMBERS([struct user_regs_struc + struct user_regs_struct.rdi, + struct user_regs_struct.rsi, + struct user_regs_struct.rdx], [],[], +- [#include ++ [#include + #include ]) + AC_CHECK_MEMBERS([struct pt_regs.orig_gpr3, + struct pt_regs.gpr], [],[], [#include ]) +--- src/fuser.c ++++ src/fuser.c 2022-12-13 07:59:50.896670010 +0000 +@@ -1223,6 +1223,7 @@ int main(int argc, char *argv[]) + struct option *optr; + char *nsptr; + int skip_argv; ++ int seen_file; + + struct option options[] = { + {"all", 0, NULL, 'a'}, +@@ -1266,6 +1267,7 @@ int main(int argc, char *argv[]) + #endif + atexit(atexit_free_lists); + ++ seen_file = 0; + for (argc_cnt = 1; argc_cnt < argc; argc_cnt++) + { + current_argv = argv[argc_cnt]; +@@ -1416,6 +1418,7 @@ int main(int argc, char *argv[]) + } + } + this_name->matched_procs = NULL; ++ seen_file = 1; + if (opts & (OPT_MOUNTS | OPT_ISMOUNTPOINT) + && this_name->name_space != NAMESPACE_FILE) + { +@@ -1467,7 +1470,7 @@ int main(int argc, char *argv[]) + names_tail->next = this_name; + names_tail = this_name; + } /* for across the argvs */ +- if (names_head == NULL) ++ if (names_head == NULL && !seen_file) + usage(_("No process specification given")); + + /* Check if -M flag was used and if so check mounts */ diff --git a/psmisc-v23.6.tar.bz2 b/psmisc-v23.6.tar.bz2 new file mode 100644 index 0000000..b2a48a2 --- /dev/null +++ b/psmisc-v23.6.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91573ca0a1a50bd491b7c3cbe400126b0dadef9a2e328030d6469bb2448e0794 +size 263463 diff --git a/psmisc.changes b/psmisc.changes index 61a8337..79d00ae 100644 --- a/psmisc.changes +++ b/psmisc.changes @@ -1,3 +1,26 @@ +------------------------------------------------------------------- +Tue Dec 13 08:01:33 UTC 2022 - Dr. Werner Fink + +- Update to 23.6: + * buildsys: Fix DEJAGNU work-around Debian #1015089 + * killall: Use kill if pidfd_send_signal fails Debian #1015228 + * fuser: Do not mention nonexistent - reset option #42 + * fuser: Use modern statn where possible + * pstree: Better AppArmor support !30 + * killall: Check truncated names !28 + * killall: Use openat and pidfd_send_signal #37 + * killall: Don't check paths of sockets #35 + * pstree: Check for process with show_parents #38 + * pstree: Don't disable compaction with show pgids #34 + * pstree: Fix storage leak !29 +- Enable new apparmor support +- Remove patch now upstream + 0002-Use-new-statx-2-system-call-to-avoid-hangs-on-NFS.patch +- Port patch psmisc-22.21-pstree.patch +- Port patch psmisc-v23.4.dif which now becomes psmisc-v23.6.dif +- Merge patch socket-fix.patch with ported patch + 0001-Use-mountinfo-to-be-able-to-use-the-mount-identity.patch + ------------------------------------------------------------------- Fri Nov 25 11:48:39 UTC 2022 - Dr. Werner Fink diff --git a/psmisc.spec b/psmisc.spec index 96e00d5..90fbf44 100644 --- a/psmisc.spec +++ b/psmisc.spec @@ -27,8 +27,9 @@ BuildRequires: libselinux-devel BuildRequires: linux-glibc-devel >= 4.12 BuildRequires: ncurses-devel BuildRequires: netcat-openbsd +BuildRequires: pkgconfig(libapparmor) URL: https://gitlab.com/psmisc/psmisc/ -Version: 23.4 +Version: 23.6 Release: 0 Provides: ps:/usr/bin/killall Summary: Utilities for managing processes on your system @@ -40,8 +41,6 @@ Patch2: %{name}-22.21-pstree.patch # PATCH-ADD-SUSE boo#908068, boo#1046237, boo#1046237 # https://gitlab.com/bitstreamout/psmisc/tree/mountinfo Patch3: 0001-Use-mountinfo-to-be-able-to-use-the-mount-identity.patch -Patch4: 0002-Use-new-statx-2-system-call-to-avoid-hangs-on-NFS.patch -Patch5: socket-fix.patch %define have_peekfd %ix86 x86_64 ppc ppc64 ppc64le %arm mipsel m68k aarch64 @@ -59,8 +58,6 @@ processes that are using specified files or filesystems. %setup -q -n %{name}-v%{version} %patch2 -p0 -b .pstree %patch3 -p0 -b .mntinf -%patch4 -p0 -b .statx -%patch5 -p0 -b .sk %patch0 -p0 -b .p0 %build diff --git a/socket-fix.patch b/socket-fix.patch deleted file mode 100644 index 1dafc7b..0000000 --- a/socket-fix.patch +++ /dev/null @@ -1,183 +0,0 @@ ---- - src/fuser.c | 93 +++++++++++++++++++++++++++++++--------------- - src/fuser.h | 1 - testsuite/config/unix.exp | 19 +++++++++ - 3 files changed, 83 insertions(+), 30 deletions(-) - ---- src/fuser.c -+++ src/fuser.c 2022-11-25 11:42:29.019144216 +0000 -@@ -1741,8 +1741,9 @@ check_dir(const pid_t pid, const char *d - continue; - } - -- /* check the paths match if it is not a block device */ -- if (! S_ISBLK(dev_tmp->name->st.st_mode)) { -+ /* check the paths match if it is not a block device or socket */ -+ if (! S_ISBLK(dev_tmp->name->st.st_mode) -+ & !S_ISSOCK(st.st_mode)) { - if (readlink(filepath, real_filepath, PATH_MAX-1) < 0) { - if (strncmp(dev_tmp->name->filename, filepath, strlen(dev_tmp->name->filename)) != 0) - continue; -@@ -1750,13 +1751,14 @@ check_dir(const pid_t pid, const char *d - if (strncmp(dev_tmp->name->filename, real_filepath, strlen(dev_tmp->name->filename)) != 0) - continue; - } -- } - -- if (fdret != 0) -+ if (fdret != 0) - continue; -- if (fd.mnt_id != dev_tmp->mnt_id) -+ if (fd.mnt_id != dev_tmp->mnt_id) - continue; - -+ } -+ - if (access == ACCESS_FILE - && (fd.flags & (O_WRONLY|O_RDWR))) { - add_matched_proc(dev_tmp->name, -@@ -2310,22 +2312,12 @@ get_fdinfo(const pid_t pid, const char * - char line[BUFSIZ]; - FILE *fp; - # if defined(HAS_NAME_TO_HANDLE_AT) -- static ino_t mynamespace; -- struct stat st; -- -- if (!mynamespace) { -- if (statn("/proc/self/ns/mnt", STATX_INO, &st) != 0) { -- fprintf(stderr, _("Cannot stat %s: %s\n"), -- "/proc/self/ns/mnt", strerror(errno)); -- exit(1); -- } -- mynamespace = st.st_ino; -- } -+ char *realname; - # endif - snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fdinfo/%s", pid, fd); - if ((fp = fopen(pathname, "r")) == NULL) - goto out; /* forbidden namesspace, try our own namespace */ -- while (fgets(line, BUFSIZ, fp) && ret < 2) { -+ while (fgets(line, BUFSIZ, fp) && ret < 1) { - char *xp, *vp, *ep; - unsigned long ul; - xp = strtok(&line[0], delimiters); -@@ -2338,24 +2330,18 @@ get_fdinfo(const pid_t pid, const char * - info->flags = (mode_t)ul; - flags++; - ret++; -- } -- if (strcmp(xp, "mnt_id") == 0 && (ul = strtoul(vp, &ep, 0)) != ULONG_MAX && ep && *ep == 0) { -- info->mnt_id = (int)ul; -- mnt_id++; -- ret++; -+ break; - } - } - fclose(fp); - out: - # if defined(HAS_NAME_TO_HANDLE_AT) -- if (mynamespace != ns) { -- char *realname; -- snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); -- realname = expandpath(pathname); -- if (realname) { /* Use our namespace for mount ID */ -- info->mnt_id = get_mountid(realname); -- mnt_id++; -- } -+ snprintf(pathname, sizeof(pathname)-1, "/proc/%d/fd/%s", pid, fd); -+ realname = expandpath(pathname); -+ if (realname) { /* Use our namespace for mount ID */ -+ info->mnt_id = get_mountid(realname); -+ mnt_id++; -+ ret++; - } - # endif - #endif -@@ -2625,6 +2611,53 @@ char *expandpath(const char *path) - } - lnkbuf[n] = '\0'; /* Don't be fooled by readlink(2) */ - -+ /* -+ * Expand to real path of named socket if any -+ */ -+ if (lnkbuf[0] != '/' && strncmp("socket:[", lnkbuf, 8) == 0) -+ { -+ FILE *fp; -+ char *inode; -+ char line[BUFSIZ]; -+ if ((inode = strchr(&lnkbuf[8], ']'))) -+ { -+ *inode = '\0'; -+ inode = &lnkbuf[8]; -+ } -+ -+ if (!inode || (fp = fopen(PROC_SOCKETS, "r")) == NULL) -+ { -+ /*fprintf(stderr, "Cannot open %s\n", PROC_SOCKETS); */ -+ return (char *)0; -+ } -+ while (fgets(line, BUFSIZ, fp) != NULL) -+ { -+ char *named = NULL; -+ unsigned long snode; -+ -+ if (*line == 'N') -+ continue; -+ -+ if (sscanf(line, "%*x: %*x %*x %*x %*x %*x %lu %ms", -+ &snode, &named) == 2) -+ { -+ char *ep; -+ unsigned long oul = strtoul(inode, &ep, 0); -+ if (oul == snode) { -+ ep = named; -+ if (*ep == '@') -+ ep++; -+ n = strlen(ep); -+ memcpy(lnkbuf, ep, n); -+ lnkbuf[n] = '\0'; -+ } -+ free (named); -+ } -+ } -+ fclose(fp); -+ } -+ -+ - len = strlen(end); - if ((n + len) > PATH_MAX) { - errno = ENAMETOOLONG; ---- src/fuser.h -+++ src/fuser.h 2022-11-25 11:26:23.523783208 +0000 -@@ -124,5 +124,6 @@ typedef struct mntinfo_s { - - #define KNFSD_EXPORTS "/proc/fs/nfs/exports" - #define PROC_MOUNTINFO "/proc/self/mountinfo" -+#define PROC_SOCKETS "/proc/self/net/unix" - #define PROC_MOUNTS "/proc/mounts" - #define PROC_SWAPS "/proc/swaps" ---- testsuite/config/unix.exp -+++ testsuite/config/unix.exp 2022-11-25 10:07:30.595008557 +0000 -@@ -29,3 +29,22 @@ proc expect_nothing { test } { - eof { pass "$test" } - } - } -+ -+proc kill_process pid { -+ set cmdline "kill $pid" -+ if { [catch { exec /bin/sh -c $cmdline } msg]} { -+ warning "Could not kill process: $msg\n" -+ } -+} -+ -+proc make_socketproc { sktpath } { -+ global topdir socketproc_pid socketproc_spawnid testsocket_path -+ -+ set testproc_realpath "nc" -+ set socketproc_pid [ spawn $testproc_realpath -lU $sktpath ] -+} -+ -+proc kill_socketproc { } { -+ global socketproc_pid -+ kill_process $socketproc_pid -+}