2 * fuser.c - identify processes using files
4 * Based on fuser.c Copyright (C) 1993-2005 Werner Almesberger and Craig Small
6 * Completely re-written
7 * Copyright (C) 2005-2020 Craig Small <csmall@dropbear.xyz>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include <sys/param.h>
36 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/sysmacros.h>
41 #include <arpa/inet.h>
42 #include <netinet/in.h>
53 /* MAXSYMLINKS is a BSDism. If it doesn't exist, fall back to SYMLINK_MAX,
54 which is the POSIX name. */
56 #define MAXSYMLINKS SYMLINK_MAX
67 #define NAME_FIELD 20 /* space reserved for file name */
68 /* Function defines */
69 static void add_matched_proc(struct names *name_list, const pid_t pid,
70 const uid_t uid, const char access);
71 static void add_special_proc(struct names *name_list, const char ptype,
72 const uid_t uid, const char *command);
73 static void check_dir(const pid_t pid, const char *dirname,
74 struct device_list *dev_head,
75 struct inode_list *ino_head, const uid_t uid,
76 const char access, struct unixsocket_list *sockets,
78 static void check_map(const pid_t pid, const char *filename,
79 struct device_list *dev_head,
80 struct inode_list *ino_head, const uid_t uid,
82 static struct stat *get_pidstat(const pid_t pid, const char *filename);
83 static uid_t getpiduid(const pid_t pid);
84 static int print_matches(struct names *names_head, const opt_type opts,
85 const int sig_number);
86 static int kill_matched_proc(struct procs *pptr, const opt_type opts,
87 const int sig_number);
89 /*int parse_mount(struct names *this_name, struct device_list **dev_list);*/
90 static void add_device(struct device_list **dev_list,
91 struct names *this_name, dev_t device);
92 void fill_unix_cache(struct unixsocket_list **unixsocket_head);
93 void clear_unix_cache(struct unixsocket_list **unixsocket_head);
94 static void atexit_clear_unix_cache();
95 static dev_t find_net_dev(void);
96 static void scan_procs(struct names *names_head, struct inode_list *ino_head,
97 struct device_list *dev_head,
98 struct unixsocket_list *sockets, dev_t netdev);
99 static void scan_knfsd(struct names *names_head, struct inode_list *ino_head,
100 struct device_list *dev_head);
101 static void scan_mounts(struct names *names_head,
102 struct inode_list *ino_head,
103 struct device_list *dev_head);
104 static void scan_swaps(struct names *names_head, struct inode_list *ino_head,
105 struct device_list *dev_head);
107 static void debug_match_lists(struct names *names_head,
108 struct inode_list *ino_head,
109 struct device_list *dev_head);
112 #if defined(WITH_MOUNTINFO_LIST)
113 static void clear_mntinfo(void) __attribute__ ((__destructor__));
114 static void init_mntinfo(void) __attribute__ ((__constructor__));
115 static int mntstat(const char *path, struct stat *buf);
117 static stat_t thestat = stat;
118 static char *expandpath(const char *path);
119 static struct unixsocket_list *unixsockets = NULL;
120 static struct names *names_head = NULL, *names_tail = NULL;
121 static struct ip_connections *tcp_connection_list = NULL;
122 static struct ip_connections *udp_connection_list = NULL;
124 static struct ip6_connections *tcp6_connection_list = NULL;
125 static struct ip6_connections *udp6_connection_list = NULL;
127 static struct device_list *match_devices = NULL;
128 static struct inode_list *match_inodes = NULL;
130 static void usage(const char *errormsg)
132 if (errormsg != NULL)
133 fprintf(stderr, "%s\n", errormsg);
137 ("Usage: fuser [-fIMuvw] [-a|-s] [-4|-6] [-c|-m|-n SPACE]\n"
138 " [-k [-i] [-SIGNAL]] NAME...\n"
141 "Show which processes use the named files, sockets, or filesystems.\n\n"
142 " -a,--all display unused files too\n"
143 " -i,--interactive ask before killing (ignored without -k)\n"
144 " -I,--inode use always inodes to compare files\n"
145 " -k,--kill kill processes accessing the named file\n"
146 " -l,--list-signals list available signal names\n"
147 " -m,--mount show all processes using the named filesystems or\n"
149 " -M,--ismountpoint fulfill request only if NAME is a mount point\n"
150 " -n,--namespace SPACE search in this name space (file, udp, or tcp)\n"
151 " -s,--silent silent operation\n"
152 " -SIGNAL send this signal instead of SIGKILL\n"
153 " -u,--user display user IDs\n"
154 " -v,--verbose verbose output\n"
155 " -w,--writeonly kill only processes with write access\n"
156 " -V,--version display version information\n"));
158 fprintf(stderr, _(" -4,--ipv4 search IPv4 sockets only\n"
159 " -6,--ipv6 search IPv6 sockets only\n"));
161 fprintf(stderr, _(" - reset options\n\n"
162 " udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
168 fprintf(stderr, _("fuser (PSmisc) %s\n"), VERSION);
171 ("Copyright (C) 1993-2020 Werner Almesberger and Craig Small\n\n"));
173 _("PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
174 "This is free software, and you are welcome to redistribute it under\n"
175 "the terms of the GNU General Public License.\n"
176 "For more information about these matters, see the files named COPYING.\n"));
180 scan_procs(struct names *names_head, struct inode_list *ino_head,
181 struct device_list *dev_head, struct unixsocket_list *sockets,
185 struct dirent *topproc_dent;
186 struct inode_list *ino_tmp;
187 struct device_list *dev_tmp;
191 if ( (ino_head == NULL) && (dev_head == NULL) )
194 if ((topproc_dir = opendir("/proc")) == NULL) {
195 fprintf(stderr, _("Cannot open /proc directory: %s\n"),
200 while ((topproc_dent = readdir(topproc_dir)) != NULL) {
201 dev_t cwd_dev, exe_dev, root_dev;
202 struct stat *cwd_stat = NULL;
203 struct stat *exe_stat = NULL;
204 struct stat *root_stat = NULL;
206 if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */
208 pid = atoi(topproc_dent->d_name);
209 /* Dont print myself */
212 uid = getpiduid(pid);
214 cwd_stat = get_pidstat(pid, "cwd");
215 exe_stat = get_pidstat(pid, "exe");
216 root_stat = get_pidstat(pid, "root");
217 cwd_dev = cwd_stat ? cwd_stat->st_dev : 0;
218 exe_dev = exe_stat ? exe_stat->st_dev : 0;
219 root_dev = root_stat ? root_stat->st_dev : 0;
221 /* Scan the devices */
222 for (dev_tmp = dev_head; dev_tmp != NULL;
223 dev_tmp = dev_tmp->next) {
224 if (exe_dev == dev_tmp->device)
225 add_matched_proc(dev_tmp->name, pid, uid,
227 if (root_dev == dev_tmp->device)
228 add_matched_proc(dev_tmp->name, pid, uid,
230 if (cwd_dev == dev_tmp->device)
231 add_matched_proc(dev_tmp->name, pid, uid,
234 for (ino_tmp = ino_head; ino_tmp != NULL;
235 ino_tmp = ino_tmp->next) {
236 if (exe_dev == ino_tmp->device) {
238 exe_stat = get_pidstat(pid, "exe");
240 && exe_stat->st_dev == ino_tmp->device
241 && exe_stat->st_ino == ino_tmp->inode)
242 add_matched_proc(ino_tmp->name, pid,
245 if (root_dev == ino_tmp->device) {
247 root_stat = get_pidstat(pid, "root");
249 && root_stat->st_dev == ino_tmp->device
250 && root_stat->st_ino == ino_tmp->inode)
251 add_matched_proc(ino_tmp->name, pid,
254 if (cwd_dev == ino_tmp->device) {
256 cwd_stat = get_pidstat(pid, "cwd");
258 && cwd_stat->st_dev == ino_tmp->device
259 && cwd_stat->st_ino == ino_tmp->inode)
260 add_matched_proc(ino_tmp->name, pid,
270 #if !defined (__linux__) && !defined (__CYGWIN__)
271 check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP,
273 check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP,
276 check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE,
278 check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
280 } /* while topproc_dent */
281 closedir(topproc_dir);
285 add_inode(struct inode_list **ino_list, struct names *this_name,
286 dev_t device, ino_t inode)
288 struct inode_list *ino_tmp, *ino_head;
291 (struct inode_list *)malloc(sizeof(struct inode_list))) == NULL)
293 ino_head = *ino_list;
294 ino_tmp->name = this_name;
295 ino_tmp->device = device;
296 ino_tmp->inode = inode;
297 ino_tmp->next = ino_head;
302 add_device(struct device_list **dev_list, struct names *this_name, dev_t device)
304 struct device_list *dev_tmp, *dev_head;
306 fprintf(stderr, "add_device(%s %u\n", this_name->filename,
307 (unsigned int)device);
311 (struct device_list *)malloc(sizeof(struct device_list))) == NULL)
313 dev_head = *dev_list;
314 dev_tmp->name = this_name;
315 dev_tmp->device = device;
316 dev_tmp->next = dev_head;
321 add_ip_conn(struct ip_connections **ip_list, const char *protocol,
322 struct names *this_name, const int lcl_port, const int rmt_port,
323 unsigned long rmt_address)
325 struct ip_connections *ip_tmp, *ip_head;
328 (struct ip_connections *)malloc(sizeof(struct ip_connections))) ==
332 ip_tmp->name = this_name;
333 ip_tmp->lcl_port = lcl_port;
334 ip_tmp->rmt_port = rmt_port;
335 ip_tmp->rmt_address.s_addr = rmt_address;
336 ip_tmp->next = ip_head;
343 add_ip6_conn(struct ip6_connections **ip_list, const char *protocol,
344 struct names *this_name, const int lcl_port, const int rmt_port,
345 struct in6_addr rmt_address)
347 struct ip6_connections *ip_tmp, *ip_head;
350 (struct ip6_connections *)malloc(sizeof(struct ip6_connections)))
354 ip_tmp->name = this_name;
355 ip_tmp->lcl_port = lcl_port;
356 ip_tmp->rmt_port = rmt_port;
357 memcpy(&(ip_tmp->rmt_address), &(rmt_address), sizeof(struct in6_addr));
358 ip_tmp->next = ip_head;
364 /* Adds a normal process only */
366 add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid,
369 struct procs *pptr, *last_proc;
371 char cmdname[101], *cptr;
376 for (pptr = name_list->matched_procs; pptr != NULL; pptr = pptr->next) {
378 if (pptr->pid == pid) {
379 pptr->access |= access;
384 if ((pptr = (struct procs *)malloc(sizeof(struct procs))) == NULL) {
386 _("Cannot allocate memory for matched proc: %s\n"),
392 pptr->access = access;
393 pptr->proc_type = PTYPE_NORMAL;
395 /* set command name */
396 pptr->command = NULL;
400 if ((asprintf(&pathname, "/proc/%d/stat", pid) > 0) &&
401 ((fp = fopen(pathname, "r")) != NULL) &&
402 (fscanf(fp, "%*d (%100[^)]", cmdname) == 1))
403 if ((pptr->command = (char *)malloc(COMM_LEN + 1)) != NULL) {
405 for (cptr = cmdname; cmdlen < COMM_LEN && *cptr;
408 pptr->command[cmdlen++] = *cptr;
409 else if (cmdlen < (COMM_LEN - 4))
411 sprintf(&(pptr->command[cmdlen]),
414 pptr->command[cmdlen] = '\0';
416 if (last_proc == NULL)
417 name_list->matched_procs = pptr;
419 last_proc->next = pptr;
426 /* Adds a knfsd etc process */
428 add_special_proc(struct names *name_list, const char ptype, const uid_t uid,
433 for (pptr = name_list->matched_procs; pptr != NULL; pptr = pptr->next) {
434 if (pptr->proc_type == ptype)
437 if ((pptr = malloc(sizeof(struct procs))) == NULL) {
439 _("Cannot allocate memory for matched proc: %s\n"),
446 pptr->proc_type = ptype;
447 /* Append the special processes */
448 pptr->next = name_list->matched_procs;
449 name_list->matched_procs = pptr;
450 /* set command name */
451 pptr->command = strdup(command);
454 int parse_file(struct names *this_name, struct inode_list **ino_list,
457 char *new = expandpath(this_name->filename);
459 if (this_name->filename)
460 free(this_name->filename);
461 this_name->filename = strdup(new);
463 if (timeout(thestat, this_name->filename, &(this_name->st), 5) != 0) {
466 _("Specified filename %s does not exist.\n"),
467 this_name->filename);
469 fprintf(stderr, _("Cannot stat %s: %s\n"),
470 this_name->filename, strerror(errno));
474 printf("adding file %s %lX %lX\n", this_name->filename,
475 (unsigned long)this_name->st.st_dev,
476 (unsigned long)this_name->st.st_ino);
478 add_inode(ino_list, this_name, this_name->st.st_dev,
479 this_name->st.st_ino);
484 parse_unixsockets(struct names *this_name, struct inode_list **ino_list,
485 struct unixsocket_list *sun_head)
487 struct unixsocket_list *sun_tmp;
490 net_dev = find_net_dev();
492 for (sun_tmp = sun_head; sun_tmp != NULL; sun_tmp = sun_tmp->next) {
493 if (sun_tmp->dev == this_name->st.st_dev
494 && sun_tmp->inode == this_name->st.st_ino) {
495 add_inode(ino_list, this_name, net_dev,
504 parse_mounts(struct names *this_name, struct device_list **dev_list,
509 if (S_ISBLK(this_name->st.st_mode))
510 match_device = this_name->st.st_rdev;
512 match_device = this_name->st.st_dev;
513 add_device(dev_list, this_name, match_device);
519 parse_inet(struct names *this_name, const int ipv4_only, const int ipv6_only,
520 struct ip_connections **ip_list, struct ip6_connections **ip6_list)
522 int parse_inet(struct names *this_name, struct ip_connections **ip_list)
525 struct addrinfo *res, *resptr;
526 struct addrinfo hints;
528 char *lcl_port_str, *rmt_addr_str, *rmt_port_str, *tmpstr, *tmpstr2;
530 struct sockaddr_in *sin;
532 struct sockaddr_in6 *sin6;
538 if ((protocol = strchr(this_name->filename, '/')) == NULL)
541 if (protocol[0] == '\0')
544 i < 99 && this_name->filename[i] != '\0'
545 && this_name->filename[i] != '/'; i++)
546 hostspec[i] = this_name->filename[i];
549 lcl_port_str = rmt_addr_str = rmt_port_str = NULL;
550 /* Split out the names */
551 if ((tmpstr = strchr(hostspec, ',')) == NULL) {
553 lcl_port_str = strdup(hostspec);
555 if (tmpstr == hostspec)
559 lcl_port_str = strdup(hostspec);
562 if (*tmpstr != '\0') {
563 if ((tmpstr2 = strchr(tmpstr, ',')) == NULL) {
565 rmt_addr_str = tmpstr;
567 if (tmpstr2 == tmpstr)
570 rmt_addr_str = tmpstr;
574 if (*tmpstr2 != '\0')
575 rmt_port_str = tmpstr2;
580 printf("parsed to lp %s rh %s rp %s\n", lcl_port_str, rmt_addr_str,
584 memset(&hints, 0, sizeof(hints));
587 hints.ai_family = PF_INET6;
588 } else if (ipv4_only) {
589 hints.ai_family = PF_INET;
591 hints.ai_family = PF_UNSPEC;
593 hints.ai_family = PF_INET;
595 if (strcmp(protocol, "tcp") == 0)
596 hints.ai_socktype = SOCK_STREAM;
598 hints.ai_socktype = SOCK_DGRAM;
600 if (lcl_port_str == NULL) {
603 /* Resolve local port first */
605 getaddrinfo(NULL, lcl_port_str, &hints, &res)) != 0) {
606 fprintf(stderr, _("Cannot resolve local port %s: %s\n"),
607 lcl_port_str, gai_strerror(errcode));
612 switch (res->ai_family) {
615 ((struct sockaddr_in *)(res->ai_addr))->sin_port;
620 ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port;
624 fprintf(stderr, _("Unknown local port AF %d\n"),
634 if (rmt_addr_str == NULL && rmt_port_str == NULL) {
635 add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), 0,
638 add_ip6_conn(ip6_list, protocol, this_name, ntohs(lcl_port), 0,
643 /* Resolve remote address and port */
644 if (getaddrinfo(rmt_addr_str, rmt_port_str, &hints, &res) == 0) {
645 for (resptr = res; resptr != NULL;
646 resptr = resptr->ai_next) {
647 switch (resptr->ai_family) {
649 sin = (struct sockaddr_in *)
651 if (rmt_addr_str == NULL) {
652 add_ip_conn(ip_list, protocol,
659 add_ip_conn(ip_list, protocol,
670 sin6 = (struct sockaddr_in6 *)
672 if (rmt_addr_str == NULL) {
673 add_ip6_conn(ip6_list, protocol,
680 add_ip6_conn(ip6_list, protocol,
699 find_net_sockets(struct inode_list **ino_list,
700 struct ip_connections *conn_list, const char *protocol,
704 char pathname[200], line[BUFSIZ];
705 unsigned long loc_port, rmt_port;
706 unsigned long rmt_addr;
707 unsigned long long scanned_inode;
709 struct ip_connections *conn_tmp;
711 if (snprintf(pathname, 200, "/proc/net/%s", protocol) < 0)
714 if ((fp = fopen(pathname, "r")) == NULL) {
715 fprintf(stderr, _("Cannot open protocol file \"%s\": %s\n"),
716 pathname, strerror(errno));
719 while (fgets(line, BUFSIZ, fp) != NULL) {
722 "%*u: %*x:%lx %08lx:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %llu",
723 &loc_port, &rmt_addr, &rmt_port, &scanned_inode) != 4)
726 printf("Found IPv4 *:%lu with %s:%lu\n", loc_port,
727 inet_ntoa(*((struct in_addr *)&rmt_addr)), rmt_port);
729 inode = scanned_inode;
730 for (conn_tmp = conn_list; conn_tmp != NULL;
731 conn_tmp = conn_tmp->next) {
733 printf(" Comparing with *.%lu %s:%lu\n",
735 inet_ntoa(conn_tmp->rmt_address),
738 if ((conn_tmp->lcl_port == 0
739 || conn_tmp->lcl_port == loc_port)
740 && (conn_tmp->rmt_port == 0
741 || conn_tmp->rmt_port == rmt_port)
742 && (conn_tmp->rmt_address.s_addr == INADDR_ANY
745 (&(conn_tmp->rmt_address), &(rmt_addr),
747 /* add inode to list */
749 printf("Added inode!\n");
751 add_inode(ino_list, conn_tmp->name, netdev,
762 find_net6_sockets(struct inode_list **ino_list,
763 struct ip6_connections *conn_list, const char *protocol,
767 char pathname[200], line[BUFSIZ];
768 unsigned long loc_port, rmt_port;
769 struct in6_addr rmt_addr;
770 unsigned int tmp_addr[4];
771 char rmt_addr6str[INET6_ADDRSTRLEN];
772 struct ip6_connections *conn_tmp;
773 unsigned long long scanned_inode;
776 if (snprintf(pathname, 200, "/proc/net/%s6", protocol) < 0)
779 if ((fp = fopen(pathname, "r")) == NULL) {
781 printf("Cannot open protocol file \"%s\": %s\n", pathname,
786 while (fgets(line, BUFSIZ, fp) != NULL) {
789 "%*u: %*x:%lx %08x%08x%08x%08x:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %llu",
790 &loc_port, &(tmp_addr[0]), &(tmp_addr[1]), &(tmp_addr[2]),
791 &(tmp_addr[3]), &rmt_port, &scanned_inode) != 7)
793 inode = scanned_inode;
794 rmt_addr.s6_addr32[0] = tmp_addr[0];
795 rmt_addr.s6_addr32[1] = tmp_addr[1];
796 rmt_addr.s6_addr32[2] = tmp_addr[2];
797 rmt_addr.s6_addr32[3] = tmp_addr[3];
798 inet_ntop(AF_INET6, &rmt_addr, rmt_addr6str, INET6_ADDRSTRLEN);
800 printf("Found IPv6 %ld with %s:%ld\n", loc_port, rmt_addr6str,
803 for (conn_tmp = conn_list; conn_tmp != NULL;
804 conn_tmp = conn_tmp->next) {
805 inet_ntop(AF_INET6, &conn_tmp->rmt_address,
806 rmt_addr6str, INET6_ADDRSTRLEN);
808 printf(" Comparing with *.%lu %s:%lu ...\n",
809 conn_tmp->lcl_port, rmt_addr6str,
812 if ((conn_tmp->lcl_port == 0
813 || conn_tmp->lcl_port == loc_port)
814 && (conn_tmp->rmt_port == 0
815 || conn_tmp->rmt_port == rmt_port)
817 (memcmp(&(conn_tmp->rmt_address), &in6addr_any, 16)
820 (memcmp(&(conn_tmp->rmt_address), &(rmt_addr), 16)
822 add_inode(ino_list, conn_tmp->name, netdev,
831 static void read_proc_mounts(struct mount_list **mnt_list)
837 struct mount_list *mnt_tmp;
839 if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
840 fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
843 while (fgets(line, BUFSIZ, fp) != NULL) {
844 if ((find_mountp = strchr(line, ' ')) == NULL)
847 if ((find_space = strchr(find_mountp, ' ')) == NULL)
850 if ((mnt_tmp = malloc(sizeof(struct mount_list))) == NULL)
852 if ((mnt_tmp->mountpoint = strdup(find_mountp)) == NULL) {
856 mnt_tmp->next = *mnt_list;
863 free_proc_mounts(struct mount_list *mnt_list)
865 struct mount_list *mnt_tmp, *mnt_next;
868 while(mnt_tmp != NULL) {
869 mnt_next = mnt_tmp->next;
870 free(mnt_tmp->mountpoint);
877 * Free up structures allocated in add_matched_proc and add_special_proc
880 free_matched_procs(struct procs *matched_procs)
882 struct procs *procs_tmp, *procs_next;
884 procs_tmp = matched_procs;
885 while(procs_tmp != NULL) {
886 procs_next = procs_tmp->next;
887 if (procs_tmp->command)
888 free(procs_tmp->command);
890 procs_tmp = procs_next;
897 while(names_head != NULL) {
898 struct names *this_name = names_head;
899 names_head = this_name->next;
900 free_matched_procs(this_name->matched_procs);
901 free(this_name->filename);
908 * Free up structures allocated in add_ip_conn and add_ip6_conn
911 free_connection(struct ip_connections **conn)
913 struct ip_connections *conn_tmp, *conn_next;
916 while(conn_tmp != NULL) {
917 conn_next = conn_tmp->next;
919 conn_tmp = conn_next;
926 free_connection6(struct ip6_connections **conn)
928 struct ip6_connections *conn_tmp, *conn_next;
931 while(conn_tmp != NULL) {
932 conn_next = conn_tmp->next;
934 conn_tmp = conn_next;
941 * Free up structures allocated in add_inode
944 free_inodes(struct inode_list **match_inodes)
946 struct inode_list *inode_tmp, *inode_next;
948 inode_tmp = *match_inodes;
949 while(inode_tmp != NULL) {
950 inode_next = inode_tmp->next;
952 inode_tmp = inode_next;
954 *match_inodes = NULL;
958 * Free up structures allocated in add_device
961 free_devices(struct device_list **match_devices)
963 struct device_list *device_tmp, *device_next;
965 device_tmp = *match_devices;
966 while(device_tmp != NULL) {
967 device_next = device_tmp->next;
969 device_tmp = device_next;
971 *match_devices = NULL;
977 free_connection(&tcp_connection_list);
978 free_connection(&udp_connection_list);
980 free_connection6(&tcp6_connection_list);
981 free_connection6(&udp6_connection_list);
984 free_inodes(&match_inodes);
985 free_devices(&match_devices);
991 static int is_mountpoint(struct mount_list **mnt_list, char *arg)
994 struct mount_list *mnt_tmp;
998 /* Remove trailing slashes. */
999 for (p = arg; *p != '\0'; p++) ;
1000 while (*(--p) == '/' && p > arg)
1003 for (mnt_tmp = *mnt_list; mnt_tmp != NULL; mnt_tmp = mnt_tmp->next)
1004 if (!strcmp(mnt_tmp->mountpoint, arg))
1009 static void check_mountpoints(struct mount_list **mnt_list, struct names **head, struct names **tail)
1011 struct names *this, *last;
1014 for(this = *head; this != NULL; this = this->next) {
1015 if (this->name_space == NAMESPACE_FILE &&
1016 !is_mountpoint(mnt_list, this->filename)) {
1018 _("Specified filename %s is not a mountpoint.\n"),
1020 /* Remove from list */
1022 last->next = this->next;
1032 int main(int argc, char *argv[])
1037 int ipv4_only, ipv6_only;
1039 unsigned char default_namespace = NAMESPACE_FILE;
1042 struct names *this_name;
1044 char *current_argv, *option;
1046 struct option *optr;
1050 struct option options[] = {
1051 {"all", 0, NULL, 'a'},
1052 {"kill", 0, NULL, 'k'},
1053 {"interactive", 0, NULL, 'i'},
1054 {"inode", 0, NULL, 'I'},
1055 {"list-signals", 0, NULL, 'l'},
1056 {"mount", 0, NULL, 'm'},
1057 {"ismountpoint", 0, NULL, 'M'},
1058 {"namespace", 1, NULL, 'n'},
1059 {"silent", 0, NULL, 's'},
1060 {"user", 0, NULL, 'u'},
1061 {"verbose", 0, NULL, 'v'},
1062 {"writeonly", 0, NULL, 'w'},
1063 {"version", 0, NULL, 'V'},
1065 {"ipv4", 0, NULL, '4'},
1066 {"ipv6", 0, NULL, '6'},
1072 ipv4_only = ipv6_only = 0;
1076 sig_number = SIGKILL;
1079 /* Set up the i18n */
1080 setlocale(LC_ALL, "");
1081 bindtextdomain(PACKAGE, LOCALEDIR);
1082 textdomain(PACKAGE);
1085 netdev = find_net_dev();
1086 #ifndef __CYGWIN__ /* Cygwin doesn't support /proc/net/unix */
1087 fill_unix_cache(&unixsockets);
1088 atexit(atexit_clear_unix_cache);
1090 atexit(atexit_free_lists);
1092 for (argc_cnt = 1; argc_cnt < argc; argc_cnt++) {
1093 current_argv = argv[argc_cnt];
1094 if (current_argv[0] == '-') { /* its an option */
1095 if (current_argv[1] == '-') { /* its a long option */
1096 if (current_argv[2] == '\0') /* -- */
1098 /* Parse the long options */
1099 option = option_buf;
1100 for (optr = options; optr->name != NULL; optr++) {
1101 if (strcmp(current_argv + 2, optr->name)
1103 sprintf(option_buf, "-%c",
1108 if (optr->name == NULL) {
1110 _("%s: Invalid option %s\n"),
1111 argv[0], current_argv);
1115 option = current_argv;
1118 while (*(++option) != '\0' && !skip_argv) { /* skips over the - */
1127 #endif /* WITH_IPV6 */
1129 opts |= OPT_ALLFILES;
1141 opts |= OPT_INTERACTIVE;
1144 #if defined(WITH_MOUNTINFO_LIST)
1145 opts |= OPT_ALWAYSSTAT;
1158 opts |= OPT_ISMOUNTPOINT;
1162 if (argc_cnt >= argc) {
1164 ("Namespace option requires an argument."));
1167 //while(option != '\0') option++;
1168 if (strcmp(argv[argc_cnt], "tcp") == 0)
1171 else if (strcmp(argv[argc_cnt], "udp")
1175 else if (strcmp(argv[argc_cnt], "file")
1181 ("Invalid namespace name"));
1190 opts |= OPT_VERBOSE;
1199 if (isupper(*option)
1200 || isdigit(*option)) {
1202 get_signal(current_argv + 1,
1208 "%s: Invalid option %c\n",
1213 } /* while option */
1217 #if defined(WITH_MOUNTINFO_LIST)
1218 if ((opts & OPT_ALWAYSSTAT) == 0)
1222 /* Not an option, must be a file specification */
1223 if ((this_name = malloc(sizeof(struct names))) == NULL)
1225 this_name->next = NULL;
1226 /* try to find namespace spec */
1227 this_name->name_space = default_namespace;
1228 if (((nsptr = strchr(current_argv, '/')) != NULL)
1229 && (nsptr != current_argv)) {
1230 if (strcmp(nsptr + 1, "tcp") == 0) {
1231 this_name->name_space = NAMESPACE_TCP;
1233 } else if (strcmp(nsptr + 1, "udp") == 0) {
1234 this_name->name_space = NAMESPACE_UDP;
1236 } else if (strcmp(nsptr + 1, "file") == 0) {
1237 this_name->name_space = NAMESPACE_FILE;
1241 this_name->matched_procs = NULL;
1242 if (opts & (OPT_MOUNTS | OPT_ISMOUNTPOINT)
1243 && this_name->name_space != NAMESPACE_FILE) {
1246 ("You can only use files with mountpoint options"));
1248 switch (this_name->name_space) {
1251 (&(this_name->filename), "%s/tcp",
1252 current_argv) > 0) {
1254 parse_inet(this_name, ipv4_only, ipv6_only,
1255 &tcp_connection_list,
1256 &tcp6_connection_list);
1258 parse_inet(this_name, &tcp_connection_list);
1264 (&(this_name->filename), "%s/udp",
1265 current_argv) > 0) {
1267 parse_inet(this_name, ipv4_only, ipv6_only,
1268 &udp_connection_list,
1269 &udp6_connection_list);
1271 parse_inet(this_name, &udp_connection_list);
1276 this_name->filename = strdup(current_argv);
1277 if (parse_file(this_name, &match_inodes, opts) == 0) {
1278 if (opts & OPT_MOUNTS)
1279 parse_mounts(this_name, &match_devices,
1282 parse_unixsockets(this_name,
1289 if (names_head == NULL)
1290 names_head = this_name;
1291 if (names_tail != NULL)
1292 names_tail->next = this_name;
1293 names_tail = this_name;
1294 } /* for across the argvs */
1295 if (names_head == NULL)
1296 usage(_("No process specification given"));
1298 /* Check if -M flag was used and if so check mounts */
1299 if (opts & OPT_ISMOUNTPOINT) {
1300 struct mount_list *mounts = NULL;
1301 read_proc_mounts(&mounts);
1302 check_mountpoints(&mounts, &names_head, &names_tail);
1303 free_proc_mounts(mounts);
1306 if (opts & OPT_SILENT) {
1307 opts &= ~OPT_VERBOSE;
1309 if (opts & OPT_ALLFILES)
1311 ("all option cannot be used with silent option."));
1314 if (ipv4_only && ipv6_only)
1316 ("You cannot search for only IPv4 and only IPv6 sockets at the same time"));
1319 if (tcp_connection_list != NULL)
1320 find_net_sockets(&match_inodes, tcp_connection_list,
1322 if (udp_connection_list != NULL)
1323 find_net_sockets(&match_inodes, udp_connection_list,
1328 if (tcp6_connection_list != NULL)
1329 find_net6_sockets(&match_inodes, tcp6_connection_list,
1331 if (udp6_connection_list != NULL)
1332 find_net6_sockets(&match_inodes, udp6_connection_list,
1336 free_connection(&tcp_connection_list);
1337 free_connection(&udp_connection_list);
1339 free_connection6(&tcp6_connection_list);
1340 free_connection6(&udp6_connection_list);
1343 debug_match_lists(names_head, match_inodes, match_devices);
1345 scan_procs(names_head, match_inodes, match_devices, unixsockets,
1347 #ifndef __CYGWIN__ /* Cygwin doesn't support /proc/net/unix */
1348 clear_unix_cache(&unixsockets);
1350 scan_knfsd(names_head, match_inodes, match_devices);
1351 scan_mounts(names_head, match_inodes, match_devices);
1352 scan_swaps(names_head, match_inodes, match_devices);
1353 free_inodes(&match_inodes);
1354 free_devices(&match_devices);
1355 return print_matches(names_head, opts, sig_number);
1359 * returns 0 if match, 1 if no match
1362 print_matches(struct names *names_head, const opt_type opts,
1363 const int sig_number)
1370 struct passwd *pwent = NULL;
1373 int name_has_procs = 0;
1375 for (nptr = names_head; nptr != NULL; nptr = nptr->next) {
1376 if (opts & OPT_SILENT) {
1377 for (pptr = nptr->matched_procs; pptr != NULL;
1378 pptr = pptr->next) {
1379 if (pptr->proc_type != PTYPE_NORMAL)
1384 } else { /* We're not silent */
1385 if ((opts & OPT_ALLFILES) == 0) {
1387 if (opts & OPT_VERBOSE) {
1388 if (nptr->matched_procs)
1391 for (pptr = nptr->matched_procs;
1392 pptr != NULL; pptr = pptr->next) {
1393 if (pptr->proc_type ==
1401 if (name_has_procs == 1 || opts & OPT_ALLFILES) {
1402 if (head == 0 && opts & OPT_VERBOSE) {
1405 ("%*s USER PID ACCESS COMMAND\n"),
1410 fprintf(stderr, "%s:", nptr->filename);
1411 len = strlen(nptr->filename) + 1;
1415 for (pptr = nptr->matched_procs; pptr != NULL;
1416 pptr = pptr->next) {
1417 /* Suppress any special "processes" */
1418 if (!(opts & OPT_VERBOSE)
1419 && (pptr->proc_type != PTYPE_NORMAL))
1423 if (opts & (OPT_VERBOSE | OPT_USER)) {
1425 || pwent->pw_uid != pptr->uid)
1426 pwent = getpwuid(pptr->uid);
1428 if (len > NAME_FIELD && (opts & OPT_VERBOSE)) {
1432 if ((opts & OPT_VERBOSE) || first)
1433 while (len++ < NAME_FIELD)
1435 if (opts & OPT_VERBOSE) {
1437 fprintf(stderr, " %-8s ",
1440 fprintf(stderr, " %-8s ",
1443 if (pptr->proc_type == PTYPE_NORMAL)
1444 printf(" %5d", pptr->pid);
1448 if (opts & OPT_VERBOSE) {
1449 switch (pptr->proc_type) {
1451 fprintf(stderr, " knfsd ");
1454 fprintf(stderr, " mount ");
1457 fprintf(stderr, " swap ");
1460 fprintf(stderr, " %c%c%c%c%c ",
1464 ACCESS_FILEWR ? 'F' :
1467 access & ACCESS_ROOT ?
1470 access & ACCESS_CWD ?
1473 access & ACCESS_EXE ?
1476 access & ACCESS_MMAP)
1483 if (pptr->access & ACCESS_ROOT)
1485 if (pptr->access & ACCESS_CWD)
1487 if (pptr->access & ACCESS_EXE)
1489 else if (pptr->access & ACCESS_MMAP)
1492 if (opts & OPT_USER) {
1494 fprintf(stderr, " %-8s ",
1497 fprintf(stderr, "(%s)",
1500 if (opts & OPT_VERBOSE) {
1501 if (pptr->command == NULL)
1502 fprintf(stderr, "???\n");
1504 fprintf(stderr, "%s\n",
1510 if (opts & OPT_VERBOSE) {
1511 /* put a newline if showing all files and no procs */
1512 if (nptr->matched_procs == NULL
1513 && (opts & OPT_ALLFILES))
1516 if (name_has_procs || (opts & OPT_ALLFILES))
1520 if (opts & OPT_KILL)
1521 have_kill |= kill_matched_proc(nptr->matched_procs,
1525 if (opts & OPT_KILL)
1526 return (have_kill == 1 ? 0 : 1);
1528 return (have_match == 1 ? 0 : 1);
1532 static struct stat *get_pidstat(const pid_t pid, const char *filename)
1537 if ((st = (struct stat *)malloc(sizeof(struct stat))) == NULL)
1539 snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
1540 if (timeout(thestat, pathname, st, 5) != 0) {
1548 check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head,
1549 struct inode_list *ino_head, const uid_t uid, const char access,
1550 struct unixsocket_list *sockets, dev_t netdev)
1554 struct dirent *direntry;
1555 struct inode_list *ino_tmp;
1556 struct device_list *dev_tmp;
1557 struct unixsocket_list *sock_tmp;
1558 struct stat st, lst;
1560 char filepath[PATH_MAX];
1562 if (asprintf(&dirpath, "/proc/%d/%s", pid, dirname) < 0)
1564 if ((dirp = opendir(dirpath)) == NULL) {
1570 while ((direntry = readdir(dirp)) != NULL) {
1571 if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
1574 snprintf(filepath, sizeof filepath - 1, "/proc/%d/%s/%s",
1575 pid, dirname, direntry->d_name);
1577 if (timeout(thestat, filepath, &st, 5) != 0) {
1578 if (errno != ENOENT && errno != ENOTDIR) {
1579 fprintf(stderr, _("Cannot stat file %s: %s\n"),
1580 filepath, strerror(errno));
1584 if (thedev == netdev) {
1585 for (sock_tmp = sockets; sock_tmp != NULL;
1586 sock_tmp = sock_tmp->next) {
1587 if (sock_tmp->net_inode == st.st_ino) {
1588 st.st_ino = sock_tmp->inode;
1589 st.st_dev = sock_tmp->dev;
1590 thedev = sock_tmp->dev;
1595 for (dev_tmp = dev_head; dev_tmp != NULL;
1596 dev_tmp = dev_tmp->next) {
1597 if (thedev != dev_tmp->device)
1599 if (access == ACCESS_FILE
1600 && (lstat(filepath, &lst) == 0)
1601 && (lst.st_mode & S_IWUSR)) {
1602 add_matched_proc(dev_tmp->name,
1607 add_matched_proc(dev_tmp->name,
1611 for (ino_tmp = ino_head; ino_tmp != NULL;
1612 ino_tmp = ino_tmp->next) {
1613 if (thedev != ino_tmp->device)
1616 && timeout(thestat, filepath, &st, 5) != 0) {
1618 _("Cannot stat file %s: %s\n"),
1619 filepath, strerror(errno));
1622 if (st.st_ino == ino_tmp->inode) {
1623 if (access == ACCESS_FILE
1624 && (lstat(filepath, &lst) == 0)
1625 && (lst.st_mode & S_IWUSR)) {
1626 add_matched_proc(ino_tmp->name,
1631 add_matched_proc(ino_tmp->name,
1638 } /* while fd_dent */
1643 check_map(const pid_t pid, const char *filename,
1644 struct device_list *dev_head, struct inode_list *ino_head,
1645 const uid_t uid, const char access)
1649 struct inode_list *ino_tmp;
1650 struct device_list *dev_tmp;
1652 unsigned long long tmp_inode;
1653 unsigned int tmp_maj, tmp_min;
1656 if (asprintf(&pathname, "/proc/%d/%s", pid, filename) < 0)
1658 if ((fp = fopen(pathname, "r")) == NULL) {
1663 while (fgets(line, BUFSIZ, fp)) {
1664 if (sscanf(line, "%*s %*s %*s %x:%x %lld",
1665 &tmp_maj, &tmp_min, &tmp_inode) == 3) {
1666 tmp_device = tmp_maj * 256 + tmp_min;
1667 for (dev_tmp = dev_head; dev_tmp != NULL;
1668 dev_tmp = dev_tmp->next)
1669 if (dev_tmp->device == tmp_device)
1670 add_matched_proc(dev_tmp->name, pid,
1672 for (ino_tmp = ino_head; ino_tmp != NULL;
1673 ino_tmp = ino_tmp->next)
1674 if (ino_tmp->device == tmp_device
1675 && ino_tmp->inode == tmp_inode)
1676 add_matched_proc(ino_tmp->name, pid,
1683 static uid_t getpiduid(const pid_t pid)
1688 if (asprintf(&pathname, "/proc/%d", pid) < 0)
1690 if (timeout(thestat, pathname, &st, 5) != 0) {
1699 * fill_unix_cache : Create a list of Unix sockets
1700 * This list is used later for matching purposes
1702 void fill_unix_cache(struct unixsocket_list **unixsocket_head)
1706 unsigned long long scanned_inode;
1708 struct unixsocket_list *newsocket;
1710 if ((fp = fopen("/proc/net/unix", "r")) == NULL) {
1711 fprintf(stderr, _("Cannot open /proc/net/unix: %s\n"),
1715 while (fgets(line, BUFSIZ, fp) != NULL) {
1717 char *scanned_path = NULL;
1718 if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %llu %ms",
1719 &scanned_inode, &scanned_path) != 2) {
1724 if (scanned_path == NULL)
1726 path = scanned_path;
1727 if (*scanned_path == '@')
1729 if (timeout(thestat, scanned_path, &st, 5) < 0) {
1733 if ((newsocket = (struct unixsocket_list *)
1734 malloc(sizeof(struct unixsocket_list))) == NULL) {
1738 newsocket->sun_name = strdup(scanned_path);
1739 newsocket->inode = st.st_ino;
1740 newsocket->dev = st.st_dev;
1741 newsocket->net_inode = scanned_inode;
1742 newsocket->next = *unixsocket_head;
1743 *unixsocket_head = newsocket;
1751 * Free up the list of Unix sockets
1753 void clear_unix_cache(struct unixsocket_list **unixsocket_head)
1755 while(*unixsocket_head != NULL) {
1756 struct unixsocket_list *oldsocket = *unixsocket_head;
1757 *unixsocket_head = oldsocket->next;
1758 free(oldsocket->sun_name);
1764 atexit_clear_unix_cache()
1766 clear_unix_cache(&unixsockets);
1770 /* often not used, doesn't need translation */
1772 debug_match_lists(struct names *names_head, struct inode_list *ino_head,
1773 struct device_list *dev_head)
1776 struct inode_list *iptr;
1777 struct device_list *dptr;
1779 fprintf(stderr, "Specified Names:\n");
1780 for (nptr = names_head; nptr != NULL; nptr = nptr->next) {
1781 fprintf(stderr, "\t%s %c\n", nptr->filename, nptr->name_space);
1783 fprintf(stderr, "\nInodes:\n");
1784 for (iptr = ino_head; iptr != NULL; iptr = iptr->next) {
1785 fprintf(stderr, " Dev:%0lx Inode:(%0ld) 0x%0lx => %s\n",
1786 (unsigned long)iptr->device, (unsigned long)iptr->inode,
1787 (unsigned long)iptr->inode, iptr->name->filename);
1789 fprintf(stderr, "\nDevices:\n");
1790 for (dptr = dev_head; dptr != NULL; dptr = dptr->next) {
1791 fprintf(stderr, "\tDev:%0lx\n", (unsigned long)dptr->device);
1798 static int ask(const pid_t pid)
1806 fprintf(stderr, _("Kill process %d ? (y/N) "), pid);
1808 if (getline(&line, &len, stdin) < 0)
1810 if (line[0] == '\n') {
1814 res = rpmatch(line);
1823 kill_matched_proc(struct procs *proc_head, const opt_type opts,
1824 const int sig_number)
1832 for (pptr = proc_head; pptr != NULL; pptr = pptr->next) {
1833 if (pptr->pid == mypid)
1834 continue; /* dont kill myself */
1835 if (pptr->proc_type != PTYPE_NORMAL)
1837 if ((opts & OPT_WRITE) && ((pptr->access & ACCESS_FILEWR) == 0))
1839 if ((opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
1841 if (kill(pptr->pid, sig_number) < 0) {
1842 fprintf(stderr, _("Could not kill process %d: %s\n"),
1843 pptr->pid, strerror(errno));
1851 static dev_t find_net_dev(void)
1856 if ((skt = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1857 fprintf(stderr, _("Cannot open a network socket.\n"));
1860 if (fstat(skt, &st) != 0) {
1861 fprintf(stderr, _("Cannot find socket's device number.\n"));
1870 scan_knfsd(struct names *names_head, struct inode_list *ino_head,
1871 struct device_list *dev_head)
1873 struct device_list *dev_tmp;
1874 struct inode_list *ino_tmp;
1880 if ( (ino_head == NULL) && (dev_head == NULL) )
1884 if ((fp = fopen(KNFSD_EXPORTS, "r")) == NULL) {
1886 printf("Cannot open %s\n", KNFSD_EXPORTS);
1890 while (fgets(line, BUFSIZ, fp) != NULL) {
1891 if (line[0] == '#') {
1894 if ((find_space = strpbrk(line, " \t")) == NULL)
1897 if (timeout(thestat, line, &st, 5) != 0) {
1900 /* Scan the devices */
1901 for (dev_tmp = dev_head; dev_tmp != NULL;
1902 dev_tmp = dev_tmp->next) {
1903 if (st.st_dev == dev_tmp->device)
1904 add_special_proc(dev_tmp->name, PTYPE_KNFSD, 0,
1907 for (ino_tmp = ino_head; ino_tmp != NULL;
1908 ino_tmp = ino_tmp->next) {
1909 if (st.st_dev == ino_tmp->device
1910 && st.st_ino == ino_tmp->inode)
1911 add_special_proc(ino_tmp->name, PTYPE_KNFSD, 0,
1919 scan_mounts(struct names *names_head, struct inode_list *ino_head,
1920 struct device_list *dev_head)
1922 struct device_list *dev_tmp;
1923 struct inode_list *ino_tmp;
1930 if ( (ino_head == NULL) && (dev_head == NULL) )
1934 if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
1935 fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
1938 while (fgets(line, BUFSIZ, fp) != NULL) {
1939 if ((find_mountp = strchr(line, ' ')) == NULL)
1942 if ((find_space = strchr(find_mountp, ' ')) == NULL)
1945 if (timeout(thestat, find_mountp, &st, 5) != 0) {
1948 /* Scan the devices */
1949 for (dev_tmp = dev_head; dev_tmp != NULL;
1950 dev_tmp = dev_tmp->next) {
1951 if (st.st_dev == dev_tmp->device)
1952 add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0,
1955 for (ino_tmp = ino_head; ino_tmp != NULL;
1956 ino_tmp = ino_tmp->next) {
1957 if (st.st_dev == ino_tmp->device
1958 && st.st_ino == ino_tmp->inode)
1959 add_special_proc(ino_tmp->name, PTYPE_MOUNT, 0,
1967 scan_swaps(struct names *names_head, struct inode_list *ino_head,
1968 struct device_list *dev_head)
1970 struct device_list *dev_tmp;
1971 struct inode_list *ino_tmp;
1977 if ( (ino_head == NULL) && (dev_head == NULL) )
1980 if ((fp = fopen(PROC_SWAPS, "r")) == NULL) {
1981 /*fprintf(stderr, "Cannot open %s\n", PROC_SWAPS); */
1984 /* lines are filename type */
1985 while (fgets(line, BUFSIZ, fp) != NULL) {
1986 if ((find_space = strchr(line, ' ')) == NULL)
1990 while (*find_space == ' ') {
1992 if (*find_space == '\0')
1995 if (timeout(thestat, line, &st, 5) != 0) {
1998 /* Scan the devices */
1999 for (dev_tmp = dev_head; dev_tmp != NULL;
2000 dev_tmp = dev_tmp->next) {
2001 if (st.st_dev == dev_tmp->device)
2002 add_special_proc(dev_tmp->name, PTYPE_SWAP, 0,
2005 for (ino_tmp = ino_head; ino_tmp != NULL;
2006 ino_tmp = ino_tmp->next) {
2007 if (st.st_dev == ino_tmp->device
2008 && st.st_ino == ino_tmp->inode)
2009 add_special_proc(ino_tmp->name, PTYPE_SWAP, 0,
2016 #if defined(WITH_MOUNTINFO_LIST)
2018 * Use /proc/self/mountinfo of modern linux system to determine
2019 * the device numbers of the mount points. Use this to avoid the
2020 * stat(2) system call wherever possible.
2023 static list_t mntinfo = { &mntinfo, &mntinfo };
2025 static void clear_mntinfo(void)
2029 list_for_each_safe(ptr, tmp, &mntinfo) {
2030 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2036 static void init_mntinfo(void)
2038 char mpoint[PATH_MAX *4 + 1]; // octal escaping takes 4 chars per 1 char
2039 int mid, parid, max = 0;
2044 if (!list_empty(&mntinfo))
2046 if ((mnt = fopen("/proc/self/mountinfo", "r")) == (FILE *) 0)
2049 (mnt, "%i %i %u:%u %*s %s %*[^\n]", &mid, &parid, &maj, &min,
2051 const size_t nlen = strlen(mpoint);
2052 mntinfo_t *restrict mnt;
2054 ((void *)&mnt, sizeof(void *),
2055 alignof(mntinfo_t) + (nlen + 1)) != 0) {
2058 ("Cannot allocate memory for matched proc: %s\n"),
2062 append(mnt, mntinfo);
2063 mnt->mpoint = ((char *)mnt) + alignof(mntinfo_t);
2064 strcpy(mnt->mpoint, mpoint);
2067 mnt->dev = makedev(maj, min);
2074 /* Sort mount points accordingly to the reverse mount order */
2076 for (mid = 1; mid <= max; mid++) {
2078 list_for_each_safe(ptr, tmp, &mntinfo) {
2079 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2082 move_head(ptr, &sort);
2085 list_for_each_safe(ptr, tmp, &mntinfo) {
2086 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2087 if (mid != mnt->parid)
2089 move_head(ptr, &sort);
2092 if (!list_empty(&mntinfo)) {
2099 join(&sort, &mntinfo);
2103 * Determine device of links below /proc/
2105 static int mntstat(const char *path, struct stat *buf)
2107 char name[PATH_MAX + 1];
2112 if ((use = realpath(path, name)) == NULL || *use != '/')
2114 if (errno == ENOENT)
2117 * Could be a special file (socket, pipe, inotify)
2120 return stat(path, buf);
2124 list_for_each(ptr, &mntinfo) {
2125 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2126 if (nlen < mnt->nlen)
2128 if (mnt->nlen == 1) { /* root fs is the last entry */
2129 buf->st_dev = mnt->dev;
2133 if (use[mnt->nlen] != '\0' && use[mnt->nlen] != '/')
2135 if (strncmp(use, mnt->mpoint, mnt->nlen) == 0) {
2136 buf->st_dev = mnt->dev;
2144 #endif /* WITH_MOUNTINFO_LIST */
2147 * Somehow the realpath(3) glibc function call, nevertheless
2148 * it avoids lstat(2) system calls.
2150 static char real[PATH_MAX + 1];
2151 char *expandpath(const char *path)
2153 char tmpbuf[PATH_MAX + 1];
2154 const char *start, *end;
2156 int deep = MAXSYMLINKS;
2158 if (!path || *path == '\0')
2164 if (!getcwd(curr, PATH_MAX))
2166 #ifdef HAVE_RAWMEMCHR
2167 dest = rawmemchr(curr, '\0');
2169 dest = strchr(curr, '\0');
2176 for (start = end = path; *start; start = end) {
2178 while (*start == '/')
2181 for (end = start; *end && *end != '/'; ++end) ;
2183 if (end - start == 0)
2185 else if (end - start == 1 && start[0] == '.') {
2187 } else if (end - start == 2 && start[0] == '.'
2188 && start[1] == '.') {
2189 if (dest > curr + 1)
2190 while ((--dest)[-1] != '/') ;
2192 char lnkbuf[PATH_MAX + 1];
2196 if (dest[-1] != '/')
2199 if (dest + (end - start) > curr + PATH_MAX) {
2200 errno = ENAMETOOLONG;
2204 dest = mempcpy(dest, start, end - start);
2213 if ((n = readlink(curr, lnkbuf, PATH_MAX)) < 0) {
2215 if (errno == EINVAL)
2216 continue; /* Not a symlink */
2219 lnkbuf[n] = '\0'; /* Don't be fooled by readlink(2) */
2222 if ((n + len) > PATH_MAX) {
2223 errno = ENAMETOOLONG;
2227 memmove(&tmpbuf[n], end, len + 1);
2228 path = end = memcpy(tmpbuf, lnkbuf, n);
2230 if (lnkbuf[0] == '/')
2232 else if (dest > curr + 1)
2233 while ((--dest)[-1] != '/') ;
2238 if (dest > curr + 1 && dest[-1] == '/')