]> granicus.if.org Git - psmisc/blob - src/fuser.c
misc: update date to 2020
[psmisc] / src / fuser.c
1 /*
2  * fuser.c - identify processes using files
3  *
4  * Based on fuser.c Copyright (C) 1993-2005 Werner Almesberger and Craig Small
5  *
6  * Completely re-written
7  * Copyright (C) 2005-2020 Craig Small <csmall@dropbear.xyz>
8  *
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.
13  *
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.
18  *
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
22  */
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #include <sys/sysmacros.h>
40 #include <sys/wait.h>
41 #include <arpa/inet.h>
42 #include <netinet/in.h>
43 #include <pwd.h>
44 #include <netdb.h>
45 #include <dirent.h>
46 #include <unistd.h>
47 #include <ctype.h>
48 #include <mntent.h>
49 #include <signal.h>
50 #include <getopt.h>
51 #include <setjmp.h>
52 #include <limits.h>
53 /* MAXSYMLINKS is a BSDism.  If it doesn't exist, fall back to SYMLINK_MAX,
54    which is the POSIX name. */
55 #ifndef MAXSYMLINKS
56 #define MAXSYMLINKS SYMLINK_MAX
57 #endif
58
59 #include "fuser.h"
60 #include "signals.h"
61 #include "i18n.h"
62 #include "timeout.h"
63 #include "comm.h"
64
65 //#define DEBUG 1
66
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,
77                       dev_t netdev);
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,
81                       const char access);
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);
88
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);
106 #ifdef DEBUG
107 static void debug_match_lists(struct names *names_head,
108                               struct inode_list *ino_head,
109                               struct device_list *dev_head);
110 #endif
111
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);
116 #endif
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;
123 #ifdef WITH_IPV6
124 static struct ip6_connections *tcp6_connection_list = NULL;
125 static struct ip6_connections *udp6_connection_list = NULL;
126 #endif
127 static struct device_list *match_devices = NULL;
128 static struct inode_list *match_inodes = NULL;
129
130 static void usage(const char *errormsg)
131 {
132         if (errormsg != NULL)
133                 fprintf(stderr, "%s\n", errormsg);
134
135         fprintf(stderr,
136                 _
137                 ("Usage: fuser [-fIMuvw] [-a|-s] [-4|-6] [-c|-m|-n SPACE]\n"
138                  "             [-k [-i] [-SIGNAL]] NAME...\n"
139                  "       fuser -l\n"
140                  "       fuser -V\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"
148                  "                        block device\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"));
157 #ifdef WITH_IPV6
158         fprintf(stderr, _("  -4,--ipv4             search IPv4 sockets only\n"
159                           "  -6,--ipv6             search IPv6 sockets only\n"));
160 #endif
161         fprintf(stderr, _("  -                     reset options\n\n"
162                           "  udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
163         exit(1);
164 }
165
166 void print_version()
167 {
168         fprintf(stderr, _("fuser (PSmisc) %s\n"), VERSION);
169         fprintf(stderr,
170                 _
171                 ("Copyright (C) 1993-2020 Werner Almesberger and Craig Small\n\n"));
172         fprintf(stderr,
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"));
177 }
178
179 static void
180 scan_procs(struct names *names_head, struct inode_list *ino_head,
181            struct device_list *dev_head, struct unixsocket_list *sockets,
182            dev_t netdev)
183 {
184         DIR *topproc_dir;
185         struct dirent *topproc_dent;
186         struct inode_list *ino_tmp;
187         struct device_list *dev_tmp;
188         pid_t pid, my_pid;
189         uid_t uid;
190
191         if ( (ino_head == NULL) && (dev_head == NULL) )
192                 return;
193
194         if ((topproc_dir = opendir("/proc")) == NULL) {
195                 fprintf(stderr, _("Cannot open /proc directory: %s\n"),
196                         strerror(errno));
197                 exit(1);
198         }
199         my_pid = getpid();
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;
205
206                 if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9')     /* Not a process */
207                         continue;
208                 pid = atoi(topproc_dent->d_name);
209                 /* Dont print myself */
210                 if (pid == my_pid)
211                         continue;
212                 uid = getpiduid(pid);
213
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;
220
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,
226                                                  ACCESS_EXE);
227                         if (root_dev == dev_tmp->device)
228                                 add_matched_proc(dev_tmp->name, pid, uid,
229                                                  ACCESS_ROOT);
230                         if (cwd_dev == dev_tmp->device)
231                                 add_matched_proc(dev_tmp->name, pid, uid,
232                                                  ACCESS_CWD);
233                 }
234                 for (ino_tmp = ino_head; ino_tmp != NULL;
235                      ino_tmp = ino_tmp->next) {
236                         if (exe_dev == ino_tmp->device) {
237                                 if (!exe_stat)
238                                         exe_stat = get_pidstat(pid, "exe");
239                                 if (exe_stat
240                                     && exe_stat->st_dev == ino_tmp->device
241                                     && exe_stat->st_ino == ino_tmp->inode)
242                                         add_matched_proc(ino_tmp->name, pid,
243                                                          uid, ACCESS_EXE);
244                         }
245                         if (root_dev == ino_tmp->device) {
246                                 if (!root_stat)
247                                         root_stat = get_pidstat(pid, "root");
248                                 if (root_stat
249                                     && root_stat->st_dev == ino_tmp->device
250                                     && root_stat->st_ino == ino_tmp->inode)
251                                         add_matched_proc(ino_tmp->name, pid,
252                                                          uid, ACCESS_ROOT);
253                         }
254                         if (cwd_dev == ino_tmp->device) {
255                                 if (!cwd_stat)
256                                         cwd_stat = get_pidstat(pid, "cwd");
257                                 if (cwd_stat
258                                     && cwd_stat->st_dev == ino_tmp->device
259                                     && cwd_stat->st_ino == ino_tmp->inode)
260                                         add_matched_proc(ino_tmp->name, pid,
261                                                          uid, ACCESS_CWD);
262                         }
263                 }
264                 if (root_stat)
265                         free(root_stat);
266                 if (cwd_stat)
267                         free(cwd_stat);
268                 if (exe_stat)
269                         free(exe_stat);
270 #if !defined (__linux__) && !defined (__CYGWIN__)
271                 check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP,
272                           sockets, netdev);
273                 check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP,
274                           sockets, netdev);
275 #endif
276                 check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE,
277                           sockets, netdev);
278                 check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
279
280         }                       /* while topproc_dent */
281         closedir(topproc_dir);
282 }
283
284 static void
285 add_inode(struct inode_list **ino_list, struct names *this_name,
286           dev_t device, ino_t inode)
287 {
288         struct inode_list *ino_tmp, *ino_head;
289
290         if ((ino_tmp =
291              (struct inode_list *)malloc(sizeof(struct inode_list))) == NULL)
292                 return;
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;
298         *ino_list = ino_tmp;
299 }
300
301 static void
302 add_device(struct device_list **dev_list, struct names *this_name, dev_t device)
303 {
304         struct device_list *dev_tmp, *dev_head;
305 #ifdef DEBUG
306         fprintf(stderr, "add_device(%s %u\n", this_name->filename,
307                 (unsigned int)device);
308 #endif                          /* DEBUG */
309
310         if ((dev_tmp =
311              (struct device_list *)malloc(sizeof(struct device_list))) == NULL)
312                 return;
313         dev_head = *dev_list;
314         dev_tmp->name = this_name;
315         dev_tmp->device = device;
316         dev_tmp->next = dev_head;
317         *dev_list = dev_tmp;
318 }
319
320 static void
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)
324 {
325         struct ip_connections *ip_tmp, *ip_head;
326
327         if ((ip_tmp =
328              (struct ip_connections *)malloc(sizeof(struct ip_connections))) ==
329             NULL)
330                 return;
331         ip_head = *ip_list;
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;
337
338         *ip_list = ip_tmp;
339 }
340
341 #ifdef WITH_IPV6
342 static void
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)
346 {
347         struct ip6_connections *ip_tmp, *ip_head;
348
349         if ((ip_tmp =
350              (struct ip6_connections *)malloc(sizeof(struct ip6_connections)))
351             == NULL)
352                 return;
353         ip_head = *ip_list;
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;
359
360         *ip_list = ip_tmp;
361 }
362 #endif
363
364 /* Adds a normal process only */
365 static void
366 add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid,
367                  const char access)
368 {
369         struct procs *pptr, *last_proc;
370         char *pathname;
371         char cmdname[101], *cptr;
372         int cmdlen;
373         FILE *fp;
374
375         last_proc = NULL;
376         for (pptr = name_list->matched_procs; pptr != NULL; pptr = pptr->next) {
377                 last_proc = pptr;
378                 if (pptr->pid == pid) {
379                         pptr->access |= access;
380                         return;
381                 }
382         }
383         /* Not found */
384         if ((pptr = (struct procs *)malloc(sizeof(struct procs))) == NULL) {
385                 fprintf(stderr,
386                         _("Cannot allocate memory for matched proc: %s\n"),
387                         strerror(errno));
388                 return;
389         }
390         pptr->pid = pid;
391         pptr->uid = uid;
392         pptr->access = access;
393         pptr->proc_type = PTYPE_NORMAL;
394         pptr->next = NULL;
395         /* set command name */
396         pptr->command = NULL;
397
398         fp = NULL;
399         pathname = 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) {
404                         cmdlen = 0;
405                         for (cptr = cmdname; cmdlen < COMM_LEN && *cptr;
406                              cptr++) {
407                                 if (isprint(*cptr))
408                                         pptr->command[cmdlen++] = *cptr;
409                                 else if (cmdlen < (COMM_LEN - 4))
410                                         cmdlen +=
411                                             sprintf(&(pptr->command[cmdlen]),
412                                                     "\\%03o", *cptr);
413                         }
414                         pptr->command[cmdlen] = '\0';
415                 }
416         if (last_proc == NULL)
417                 name_list->matched_procs = pptr;
418         else
419                 last_proc->next = pptr;
420         if (pathname)
421                 free(pathname);
422         if (fp)
423                 fclose(fp);
424 }
425
426 /* Adds a knfsd etc process */
427 static void
428 add_special_proc(struct names *name_list, const char ptype, const uid_t uid,
429                  const char *command)
430 {
431         struct procs *pptr;
432
433         for (pptr = name_list->matched_procs; pptr != NULL; pptr = pptr->next) {
434                 if (pptr->proc_type == ptype)
435                         return;
436         }
437         if ((pptr = malloc(sizeof(struct procs))) == NULL) {
438                 fprintf(stderr,
439                         _("Cannot allocate memory for matched proc: %s\n"),
440                         strerror(errno));
441                 return;
442         }
443         pptr->pid = 0;
444         pptr->uid = uid;
445         pptr->access = 0;
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);
452 }
453
454 int parse_file(struct names *this_name, struct inode_list **ino_list,
455                const opt_type opts)
456 {
457         char *new = expandpath(this_name->filename);
458         if (new) {
459                 if (this_name->filename)
460                         free(this_name->filename);
461                 this_name->filename = strdup(new);
462         }
463         if (timeout(thestat, this_name->filename, &(this_name->st), 5) != 0) {
464                 if (errno == ENOENT)
465                         fprintf(stderr,
466                                 _("Specified filename %s does not exist.\n"),
467                                 this_name->filename);
468                 else
469                         fprintf(stderr, _("Cannot stat %s: %s\n"),
470                                 this_name->filename, strerror(errno));
471                 return -1;
472         }
473 #ifdef DEBUG
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);
477 #endif                          /* DEBUG */
478         add_inode(ino_list, this_name, this_name->st.st_dev,
479                   this_name->st.st_ino);
480         return 0;
481 }
482
483 int
484 parse_unixsockets(struct names *this_name, struct inode_list **ino_list,
485                   struct unixsocket_list *sun_head)
486 {
487         struct unixsocket_list *sun_tmp;
488         dev_t net_dev;
489
490         net_dev = find_net_dev();
491
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,
496                                   sun_tmp->net_inode);
497                         return 0;
498                 }
499         }
500         return 0;
501 }
502
503 int
504 parse_mounts(struct names *this_name, struct device_list **dev_list,
505              const opt_type opts)
506 {
507         dev_t match_device;
508
509         if (S_ISBLK(this_name->st.st_mode))
510                 match_device = this_name->st.st_rdev;
511         else
512                 match_device = this_name->st.st_dev;
513         add_device(dev_list, this_name, match_device);
514         return 0;
515 }
516
517 #ifdef WITH_IPV6
518 int
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)
521 #else
522 int parse_inet(struct names *this_name, struct ip_connections **ip_list)
523 #endif
524 {
525         struct addrinfo *res, *resptr;
526         struct addrinfo hints;
527         int errcode;
528         char *lcl_port_str, *rmt_addr_str, *rmt_port_str, *tmpstr, *tmpstr2;
529         in_port_t lcl_port;
530         struct sockaddr_in *sin;
531 #ifdef WITH_IPV6
532         struct sockaddr_in6 *sin6;
533 #endif
534         char hostspec[100];
535         char *protocol;
536         int i;
537
538         if ((protocol = strchr(this_name->filename, '/')) == NULL)
539                 return -1;
540         protocol++;
541         if (protocol[0] == '\0')
542                 return -1;
543         for (i = 0;
544              i < 99 && this_name->filename[i] != '\0'
545              && this_name->filename[i] != '/'; i++)
546                 hostspec[i] = this_name->filename[i];
547         hostspec[i] = '\0';
548
549         lcl_port_str = rmt_addr_str = rmt_port_str = NULL;
550         /* Split out the names */
551         if ((tmpstr = strchr(hostspec, ',')) == NULL) {
552                 /* Single option */
553                 lcl_port_str = strdup(hostspec);
554         } else {
555                 if (tmpstr == hostspec)
556                         lcl_port_str = NULL;
557                 else {
558                         *tmpstr = '\0';
559                         lcl_port_str = strdup(hostspec);
560                 }
561                 tmpstr++;
562                 if (*tmpstr != '\0') {
563                         if ((tmpstr2 = strchr(tmpstr, ',')) == NULL) {
564                                 /* Only 2 options */
565                                 rmt_addr_str = tmpstr;
566                         } else {
567                                 if (tmpstr2 == tmpstr)
568                                         rmt_addr_str = NULL;
569                                 else {
570                                         rmt_addr_str = tmpstr;
571                                         *tmpstr2 = '\0';
572                                 }
573                                 tmpstr2++;
574                                 if (*tmpstr2 != '\0')
575                                         rmt_port_str = tmpstr2;
576                         }
577                 }
578         }
579 #ifdef DEBUG
580         printf("parsed to lp %s rh %s rp %s\n", lcl_port_str, rmt_addr_str,
581                rmt_port_str);
582 #endif
583
584         memset(&hints, 0, sizeof(hints));
585 #ifdef WITH_IPV6
586         if (ipv6_only) {
587                 hints.ai_family = PF_INET6;
588         } else if (ipv4_only) {
589                 hints.ai_family = PF_INET;
590         } else
591                 hints.ai_family = PF_UNSPEC;
592 #else
593         hints.ai_family = PF_INET;
594 #endif
595         if (strcmp(protocol, "tcp") == 0)
596                 hints.ai_socktype = SOCK_STREAM;
597         else
598                 hints.ai_socktype = SOCK_DGRAM;
599
600         if (lcl_port_str == NULL) {
601                 lcl_port = 0;
602         } else {
603                 /* Resolve local port first */
604                 if ((errcode =
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));
608                         return -1;
609                 }
610                 if (res == NULL)
611                         return -1;
612                 switch (res->ai_family) {
613                 case AF_INET:
614                         lcl_port =
615                             ((struct sockaddr_in *)(res->ai_addr))->sin_port;
616                         break;
617 #ifdef WITH_IPV6
618                 case AF_INET6:
619                         lcl_port =
620                             ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port;
621                         break;
622 #endif
623                 default:
624                         fprintf(stderr, _("Unknown local port AF %d\n"),
625                                 res->ai_family);
626                         freeaddrinfo(res);
627             free(lcl_port_str);
628                         return -1;
629                 }
630                 freeaddrinfo(res);
631         }
632         free(lcl_port_str);
633         res = NULL;
634         if (rmt_addr_str == NULL && rmt_port_str == NULL) {
635                 add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), 0,
636                             INADDR_ANY);
637 #ifdef WITH_IPV6
638                 add_ip6_conn(ip6_list, protocol, this_name, ntohs(lcl_port), 0,
639                              in6addr_any);
640 #endif
641                 return 0;
642         } else {
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) {
648                                 case AF_INET:
649                                         sin = (struct sockaddr_in *)
650                                             resptr->ai_addr;
651                                         if (rmt_addr_str == NULL) {
652                                                 add_ip_conn(ip_list, protocol,
653                                                             this_name,
654                                                             ntohs(lcl_port),
655                                                             ntohs
656                                                             (sin->sin_port),
657                                                             INADDR_ANY);
658                                         } else {
659                                                 add_ip_conn(ip_list, protocol,
660                                                             this_name,
661                                                             ntohs(lcl_port),
662                                                             ntohs
663                                                             (sin->sin_port),
664                                                             sin->sin_addr.
665                                                             s_addr);
666                                         }
667                                         break;
668 #ifdef WITH_IPV6
669                                 case AF_INET6:
670                                         sin6 = (struct sockaddr_in6 *)
671                                             resptr->ai_addr;
672                                         if (rmt_addr_str == NULL) {
673                                                 add_ip6_conn(ip6_list, protocol,
674                                                              this_name,
675                                                              ntohs(lcl_port),
676                                                              ntohs
677                                                              (sin6->sin6_port),
678                                                              in6addr_any);
679                                         } else {
680                                                 add_ip6_conn(ip6_list, protocol,
681                                                              this_name,
682                                                              ntohs(lcl_port),
683                                                              ntohs
684                                                              (sin6->sin6_port),
685                                                              sin6->sin6_addr);
686                                         }
687                                         break;
688 #endif
689                                 }
690                         }       /*while */
691                     freeaddrinfo(res);
692                         return 0;
693                 }
694         }
695         return 1;
696 }
697
698 void
699 find_net_sockets(struct inode_list **ino_list,
700                  struct ip_connections *conn_list, const char *protocol,
701                  dev_t netdev)
702 {
703         FILE *fp;
704         char pathname[200], line[BUFSIZ];
705         unsigned long loc_port, rmt_port;
706         unsigned long rmt_addr;
707     unsigned long long scanned_inode;
708         ino_t inode;
709         struct ip_connections *conn_tmp;
710
711         if (snprintf(pathname, 200, "/proc/net/%s", protocol) < 0)
712                 return;
713
714         if ((fp = fopen(pathname, "r")) == NULL) {
715                 fprintf(stderr, _("Cannot open protocol file \"%s\": %s\n"),
716                         pathname, strerror(errno));
717                 return;
718         }
719         while (fgets(line, BUFSIZ, fp) != NULL) {
720                 if (sscanf
721                     (line,
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)
724                         continue;
725 #ifdef DEBUG
726                 printf("Found IPv4 *:%lu with %s:%lu\n", loc_port,
727                        inet_ntoa(*((struct in_addr *)&rmt_addr)), rmt_port);
728 #endif                          /* DEBUG */
729                 inode = scanned_inode;
730                 for (conn_tmp = conn_list; conn_tmp != NULL;
731                      conn_tmp = conn_tmp->next) {
732 #ifdef DEBUG
733                         printf("  Comparing with *.%lu %s:%lu\n",
734                                conn_tmp->lcl_port,
735                                inet_ntoa(conn_tmp->rmt_address),
736                                conn_tmp->rmt_port);
737 #endif
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
743                                 ||
744                                 (memcmp
745                                  (&(conn_tmp->rmt_address), &(rmt_addr),
746                                   4) == 0))) {
747                                 /* add inode to list */
748 #ifdef DEBUG
749                                 printf("Added inode!\n");
750 #endif                          /* DEBUG */
751                                 add_inode(ino_list, conn_tmp->name, netdev,
752                                           inode);
753                         }
754                 }
755
756         }
757         fclose(fp);
758 }
759
760 #ifdef WITH_IPV6
761 void
762 find_net6_sockets(struct inode_list **ino_list,
763                   struct ip6_connections *conn_list, const char *protocol,
764                   const dev_t netdev)
765 {
766         FILE *fp;
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;
774         ino_t inode;
775
776         if (snprintf(pathname, 200, "/proc/net/%s6", protocol) < 0)
777                 return;
778
779         if ((fp = fopen(pathname, "r")) == NULL) {
780 #ifdef DEBUG
781                 printf("Cannot open protocol file \"%s\": %s\n", pathname,
782                        strerror(errno));
783 #endif                          /* DEBUG */
784                 return;
785         }
786         while (fgets(line, BUFSIZ, fp) != NULL) {
787                 if (sscanf
788                     (line,
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)
792                         continue;
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);
799 #ifdef DEBUG
800                 printf("Found IPv6 %ld with %s:%ld\n", loc_port, rmt_addr6str,
801                        rmt_port);
802 #endif                          /* DEBUG */
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);
807 #ifdef DEBUG
808                         printf("  Comparing with *.%lu %s:%lu ...\n",
809                                conn_tmp->lcl_port, rmt_addr6str,
810                                conn_tmp->rmt_port);
811 #endif                          /* DEBUG */
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)
816                             &&
817                             (memcmp(&(conn_tmp->rmt_address), &in6addr_any, 16)
818                              == 0
819                              ||
820                              (memcmp(&(conn_tmp->rmt_address), &(rmt_addr), 16)
821                               == 0))) {
822                                 add_inode(ino_list, conn_tmp->name, netdev,
823                                           inode);
824                         }
825                 }
826         }
827         fclose(fp);
828 }
829 #endif
830
831 static void read_proc_mounts(struct mount_list **mnt_list)
832 {
833         FILE *fp;
834         char line[BUFSIZ];
835         char *find_mountp;
836         char *find_space;
837         struct mount_list *mnt_tmp;
838
839         if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
840                 fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
841                 return;
842         }
843         while (fgets(line, BUFSIZ, fp) != NULL) {
844                 if ((find_mountp = strchr(line, ' ')) == NULL)
845                         continue;
846                 find_mountp++;
847                 if ((find_space = strchr(find_mountp, ' ')) == NULL)
848                         continue;
849                 *find_space = '\0';
850                 if ((mnt_tmp = malloc(sizeof(struct mount_list))) == NULL)
851                         continue;
852                 if ((mnt_tmp->mountpoint = strdup(find_mountp)) == NULL) {
853                         free(mnt_tmp);
854                         continue;
855                 }
856                 mnt_tmp->next = *mnt_list;
857                 *mnt_list = mnt_tmp;
858         }
859         fclose(fp);
860 }
861
862 static void
863 free_proc_mounts(struct mount_list *mnt_list)
864 {
865     struct mount_list *mnt_tmp, *mnt_next;
866
867     mnt_tmp = mnt_list;
868     while(mnt_tmp != NULL) {
869         mnt_next = mnt_tmp->next;
870         free(mnt_tmp->mountpoint);
871         free(mnt_tmp);
872         mnt_tmp = mnt_next;
873     }
874 }
875
876 /*
877  * Free up structures allocated in add_matched_proc and add_special_proc
878  */
879 static void
880 free_matched_procs(struct procs *matched_procs)
881 {
882         struct procs *procs_tmp, *procs_next;
883
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);
889                 free(procs_tmp);
890                 procs_tmp = procs_next;
891         }
892 }
893
894 static void
895 free_names()
896 {
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);
902                 free(this_name);
903         }
904         names_tail = NULL;
905 }
906
907 /*
908  * Free up structures allocated in add_ip_conn and add_ip6_conn
909  */
910 static void
911 free_connection(struct ip_connections **conn)
912 {
913         struct ip_connections *conn_tmp, *conn_next;
914
915         conn_tmp = *conn;
916         while(conn_tmp != NULL) {
917                 conn_next = conn_tmp->next;
918                 free(conn_tmp);
919                 conn_tmp = conn_next;
920         }
921         *conn = NULL;
922 }
923
924 #ifdef WITH_IPV6
925 static void
926 free_connection6(struct ip6_connections **conn)
927 {
928         struct ip6_connections *conn_tmp, *conn_next;
929
930         conn_tmp = *conn;
931         while(conn_tmp != NULL) {
932                 conn_next = conn_tmp->next;
933                 free(conn_tmp);
934                 conn_tmp = conn_next;
935         }
936         *conn = NULL;
937 }
938 #endif
939
940 /*
941  * Free up structures allocated in add_inode
942  */
943 static void
944 free_inodes(struct inode_list **match_inodes)
945 {
946         struct inode_list *inode_tmp, *inode_next;
947
948         inode_tmp = *match_inodes;
949         while(inode_tmp != NULL) {
950                 inode_next = inode_tmp->next;
951                 free(inode_tmp);
952                 inode_tmp = inode_next;
953         }
954         *match_inodes = NULL;
955 }
956
957 /*
958  * Free up structures allocated in add_device
959  */
960 static void
961 free_devices(struct device_list **match_devices)
962 {
963         struct device_list *device_tmp, *device_next;
964
965         device_tmp = *match_devices;
966         while(device_tmp != NULL) {
967                 device_next = device_tmp->next;
968                 free(device_tmp);
969                 device_tmp = device_next;
970         }
971         *match_devices = NULL;
972 }
973
974 static void
975 atexit_free_lists()
976 {
977         free_connection(&tcp_connection_list);
978         free_connection(&udp_connection_list);
979 #ifdef WITH_IPV6
980         free_connection6(&tcp6_connection_list);
981         free_connection6(&udp6_connection_list);
982 #endif
983
984         free_inodes(&match_inodes);
985         free_devices(&match_devices);
986
987         free_names();
988 }
989
990
991 static int is_mountpoint(struct mount_list **mnt_list, char *arg)
992 {
993         char *p;
994         struct mount_list *mnt_tmp;
995
996         if (*arg == '\0')
997                 return 0;
998         /* Remove trailing slashes. */
999         for (p = arg; *p != '\0'; p++) ;
1000         while (*(--p) == '/' && p > arg)
1001                 *p = '\0';
1002
1003         for (mnt_tmp = *mnt_list; mnt_tmp != NULL; mnt_tmp = mnt_tmp->next)
1004                 if (!strcmp(mnt_tmp->mountpoint, arg))
1005                         return 1;
1006         return 0;
1007 }
1008
1009 static void check_mountpoints(struct mount_list **mnt_list, struct names **head, struct names **tail)
1010 {
1011     struct names *this, *last;
1012
1013     last = NULL;
1014     for(this = *head; this != NULL; this = this->next) {
1015         if (this->name_space == NAMESPACE_FILE &&
1016                 !is_mountpoint(mnt_list, this->filename)) {
1017             fprintf(stderr,
1018                     _("Specified filename %s is not a mountpoint.\n"),
1019                     this->filename);
1020             /* Remove from list */
1021             if (last)
1022                 last->next = this->next;
1023             if (*head == this)
1024                 *head = this->next;
1025             if (*tail == this)
1026                 *tail = last;
1027         } else {
1028             last = this;
1029         }
1030     }
1031 }
1032 int main(int argc, char *argv[])
1033 {
1034         opt_type opts;
1035         int sig_number;
1036 #ifdef WITH_IPV6
1037         int ipv4_only, ipv6_only;
1038 #endif
1039         unsigned char default_namespace = NAMESPACE_FILE;
1040
1041         dev_t netdev;
1042         struct names *this_name;
1043         int argc_cnt;
1044         char *current_argv, *option;
1045         char option_buf[3];
1046         struct option *optr;
1047         char *nsptr;
1048         int skip_argv;
1049
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'},
1064 #ifdef WITH_IPV6
1065                 {"ipv4", 0, NULL, '4'},
1066                 {"ipv6", 0, NULL, '6'},
1067 #endif
1068                 {0, 0, 0, 0}
1069         };
1070
1071 #ifdef WITH_IPV6
1072         ipv4_only = ipv6_only = 0;
1073 #endif
1074         this_name = NULL;
1075         opts = 0;
1076         sig_number = SIGKILL;
1077
1078 #ifdef ENABLE_NLS
1079         /* Set up the i18n */
1080         setlocale(LC_ALL, "");
1081         bindtextdomain(PACKAGE, LOCALEDIR);
1082         textdomain(PACKAGE);
1083 #endif
1084
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);
1089 #endif
1090         atexit(atexit_free_lists);
1091
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')    /* -- */
1097                                         break;
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)
1102                                             == 0) {
1103                                                 sprintf(option_buf, "-%c",
1104                                                         (char)optr->val);
1105                                                 break;
1106                                         }
1107                                 }
1108                                 if (optr->name == NULL) {
1109                                         fprintf(stderr,
1110                                                 _("%s: Invalid option %s\n"),
1111                                                 argv[0], current_argv);
1112                                         usage(NULL);
1113                                 }
1114                         } else {
1115                                 option = current_argv;
1116                         }
1117                         skip_argv = 0;
1118                         while (*(++option) != '\0' && !skip_argv) {     /* skips over the - */
1119                                 switch (*option) {
1120 #ifdef WITH_IPV6
1121                                 case '4':
1122                                         ipv4_only = 1;
1123                                         break;
1124                                 case '6':
1125                                         ipv6_only = 1;
1126                                         break;
1127 #endif                          /* WITH_IPV6 */
1128                                 case 'a':
1129                                         opts |= OPT_ALLFILES;
1130                                         break;
1131                                 case 'c':
1132                                         opts |= OPT_MOUNTS;
1133                                         break;
1134                                 case 'f':
1135                                         /* ignored */
1136                                         break;
1137                                 case 'h':
1138                                         usage(NULL);
1139                                         break;
1140                                 case 'i':
1141                                         opts |= OPT_INTERACTIVE;
1142                                         break;
1143                                 case 'I':
1144 #if defined(WITH_MOUNTINFO_LIST)
1145                                         opts |= OPT_ALWAYSSTAT;
1146 #endif
1147                                         break;
1148                                 case 'k':
1149                                         opts |= OPT_KILL;
1150                                         break;
1151                                 case 'l':
1152                                         list_signals();
1153                                         return 0;
1154                                 case 'm':
1155                                         opts |= OPT_MOUNTS;
1156                                         break;
1157                                 case 'M':
1158                                         opts |= OPT_ISMOUNTPOINT;
1159                                         break;
1160                                 case 'n':
1161                                         argc_cnt++;
1162                                         if (argc_cnt >= argc) {
1163                                                 usage(_
1164                                                       ("Namespace option requires an argument."));
1165                                         }
1166                                         skip_argv = 1;
1167                                         //while(option != '\0') option++;
1168                                         if (strcmp(argv[argc_cnt], "tcp") == 0)
1169                                                 default_namespace =
1170                                                     NAMESPACE_TCP;
1171                                         else if (strcmp(argv[argc_cnt], "udp")
1172                                                  == 0)
1173                                                 default_namespace =
1174                                                     NAMESPACE_UDP;
1175                                         else if (strcmp(argv[argc_cnt], "file")
1176                                                  == 0)
1177                                                 default_namespace =
1178                                                     NAMESPACE_FILE;
1179                                         else
1180                                                 usage(_
1181                                                       ("Invalid namespace name"));
1182                                         break;
1183                                 case 's':
1184                                         opts |= OPT_SILENT;
1185                                         break;
1186                                 case 'u':
1187                                         opts |= OPT_USER;
1188                                         break;
1189                                 case 'v':
1190                                         opts |= OPT_VERBOSE;
1191                                         break;
1192                                 case 'w':
1193                                         opts |= OPT_WRITE;
1194                                         break;
1195                                 case 'V':
1196                                         print_version();
1197                                         return 0;
1198                                 default:
1199                                         if (isupper(*option)
1200                                             || isdigit(*option)) {
1201                                                 sig_number =
1202                                                     get_signal(current_argv + 1,
1203                                                                argv[0]);
1204                                                 skip_argv = 1;
1205                                                 break;
1206                                         }
1207                                         fprintf(stderr,
1208                                                 "%s: Invalid option %c\n",
1209                                                 argv[0], *option);
1210                                         usage(NULL);
1211                                         break;
1212                                 }       /* switch */
1213                         }       /* while option */
1214                         continue;
1215                 }
1216
1217 #if defined(WITH_MOUNTINFO_LIST)
1218                 if ((opts & OPT_ALWAYSSTAT) == 0)
1219                         thestat = mntstat;
1220 #endif
1221                 /* an option */
1222                 /* Not an option, must be a file specification */
1223                 if ((this_name = malloc(sizeof(struct names))) == NULL)
1224                         continue;
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;
1232                                 *nsptr = '\0';
1233                         } else if (strcmp(nsptr + 1, "udp") == 0) {
1234                                 this_name->name_space = NAMESPACE_UDP;
1235                                 *nsptr = '\0';
1236                         } else if (strcmp(nsptr + 1, "file") == 0) {
1237                                 this_name->name_space = NAMESPACE_FILE;
1238                                 *nsptr = '\0';
1239                         }
1240                 }
1241                 this_name->matched_procs = NULL;
1242                 if (opts & (OPT_MOUNTS | OPT_ISMOUNTPOINT)
1243                     && this_name->name_space != NAMESPACE_FILE) {
1244                         free(this_name);
1245                         usage(_
1246                               ("You can only use files with mountpoint options"));
1247                 }
1248                 switch (this_name->name_space) {
1249                 case NAMESPACE_TCP:
1250                         if (asprintf
1251                             (&(this_name->filename), "%s/tcp",
1252                              current_argv) > 0) {
1253 #ifdef WITH_IPV6
1254                                 parse_inet(this_name, ipv4_only, ipv6_only,
1255                                            &tcp_connection_list,
1256                                            &tcp6_connection_list);
1257 #else
1258                                 parse_inet(this_name, &tcp_connection_list);
1259 #endif
1260                         }
1261                         break;
1262                 case NAMESPACE_UDP:
1263                         if (asprintf
1264                             (&(this_name->filename), "%s/udp",
1265                              current_argv) > 0) {
1266 #ifdef WITH_IPV6
1267                                 parse_inet(this_name, ipv4_only, ipv6_only,
1268                                            &udp_connection_list,
1269                                            &udp6_connection_list);
1270 #else
1271                                 parse_inet(this_name, &udp_connection_list);
1272 #endif
1273                         }
1274                         break;
1275                 default:        /* FILE */
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,
1280                                                      opts);
1281                                 else
1282                                         parse_unixsockets(this_name,
1283                                                           &match_inodes,
1284                                                           unixsockets);
1285                         }
1286                         break;
1287                 }
1288
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"));
1297
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);
1304         }
1305
1306         if (opts & OPT_SILENT) {
1307                 opts &= ~OPT_VERBOSE;
1308                 opts &= ~OPT_USER;
1309                 if (opts & OPT_ALLFILES)
1310                         usage(_
1311                               ("all option cannot be used with silent option."));
1312         }
1313 #ifdef WITH_IPV6
1314         if (ipv4_only && ipv6_only)
1315                 usage(_
1316                       ("You cannot search for only IPv4 and only IPv6 sockets at the same time"));
1317         if (!ipv6_only) {
1318 #endif
1319                 if (tcp_connection_list != NULL)
1320                         find_net_sockets(&match_inodes, tcp_connection_list,
1321                                          "tcp", netdev);
1322                 if (udp_connection_list != NULL)
1323                         find_net_sockets(&match_inodes, udp_connection_list,
1324                                          "udp", netdev);
1325 #ifdef WITH_IPV6
1326         }
1327         if (!ipv4_only) {
1328                 if (tcp6_connection_list != NULL)
1329                         find_net6_sockets(&match_inodes, tcp6_connection_list,
1330                                           "tcp", netdev);
1331                 if (udp6_connection_list != NULL)
1332                         find_net6_sockets(&match_inodes, udp6_connection_list,
1333                                           "udp", netdev);
1334         }
1335 #endif
1336         free_connection(&tcp_connection_list);
1337         free_connection(&udp_connection_list);
1338 #ifdef WITH_IPV6
1339         free_connection6(&tcp6_connection_list);
1340         free_connection6(&udp6_connection_list);
1341 #endif
1342 #ifdef DEBUG
1343         debug_match_lists(names_head, match_inodes, match_devices);
1344 #endif
1345         scan_procs(names_head, match_inodes, match_devices, unixsockets,
1346                    netdev);
1347 #ifndef __CYGWIN__              /* Cygwin doesn't support /proc/net/unix */
1348         clear_unix_cache(&unixsockets);
1349 #endif
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);
1356 }
1357
1358 /* 
1359  * returns 0 if match, 1 if no match
1360  */
1361 static int
1362 print_matches(struct names *names_head, const opt_type opts,
1363               const int sig_number)
1364 {
1365         struct names *nptr;
1366         struct procs *pptr;
1367         char head = 0;
1368         char first = 1;
1369         int len = 0;
1370         struct passwd *pwent = NULL;
1371         int have_match = 0;
1372         int have_kill = 0;
1373         int name_has_procs = 0;
1374
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)
1380                                         continue;
1381
1382                                 have_match = 1;
1383                         }
1384                 } else {        /* We're not silent */
1385                         if ((opts & OPT_ALLFILES) == 0) {
1386                                 name_has_procs = 0;
1387                                 if (opts & OPT_VERBOSE) {
1388                                         if (nptr->matched_procs)
1389                                                 name_has_procs = 1;
1390                                 } else {
1391                                         for (pptr = nptr->matched_procs;
1392                                              pptr != NULL; pptr = pptr->next) {
1393                                                 if (pptr->proc_type ==
1394                                                     PTYPE_NORMAL) {
1395                                                         name_has_procs = 1;
1396                                                         break;
1397                                                 }
1398                                         }
1399                                 }
1400                         }
1401                         if (name_has_procs == 1 || opts & OPT_ALLFILES) {
1402                                 if (head == 0 && opts & OPT_VERBOSE) {
1403                                         fprintf(stderr,
1404                                                 _
1405                                                 ("%*s USER        PID ACCESS COMMAND\n"),
1406                                                 NAME_FIELD, "");
1407                                         head = 1;
1408                                 }
1409
1410                                 fprintf(stderr, "%s:", nptr->filename);
1411                                 len = strlen(nptr->filename) + 1;
1412                         }
1413
1414                         first = 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))
1420                                         continue;
1421
1422                                 have_match = 1;
1423                                 if (opts & (OPT_VERBOSE | OPT_USER)) {
1424                                         if (pwent == NULL
1425                                             || pwent->pw_uid != pptr->uid)
1426                                                 pwent = getpwuid(pptr->uid);
1427                                 }
1428                                 if (len > NAME_FIELD && (opts & OPT_VERBOSE)) {
1429                                         putc('\n', stderr);
1430                                         len = 0;
1431                                 }
1432                                 if ((opts & OPT_VERBOSE) || first)
1433                                         while (len++ < NAME_FIELD)
1434                                                 putc(' ', stderr);
1435                                 if (opts & OPT_VERBOSE) {
1436                                         if (pwent == NULL)
1437                                                 fprintf(stderr, " %-8s ",
1438                                                         _("(unknown)"));
1439                                         else
1440                                                 fprintf(stderr, " %-8s ",
1441                                                         pwent->pw_name);
1442                                 }
1443                                 if (pptr->proc_type == PTYPE_NORMAL)
1444                                         printf(" %5d", pptr->pid);
1445                                 else
1446                                         printf("kernel");
1447                                 fflush(stdout);
1448                                 if (opts & OPT_VERBOSE) {
1449                                         switch (pptr->proc_type) {
1450                                         case PTYPE_KNFSD:
1451                                                 fprintf(stderr, " knfsd ");
1452                                                 break;
1453                                         case PTYPE_MOUNT:
1454                                                 fprintf(stderr, " mount ");
1455                                                 break;
1456                                         case PTYPE_SWAP:
1457                                                 fprintf(stderr, " swap  ");
1458                                                 break;
1459                                         default:
1460                                                 fprintf(stderr, " %c%c%c%c%c ",
1461                                                         pptr->access &
1462                                                         ACCESS_FILE
1463                                                         ? (pptr->access &
1464                                                            ACCESS_FILEWR ? 'F' :
1465                                                            'f') : '.',
1466                                                         pptr->
1467                                                         access & ACCESS_ROOT ?
1468                                                         'r' : '.',
1469                                                         pptr->
1470                                                         access & ACCESS_CWD ?
1471                                                         'c' : '.',
1472                                                         pptr->
1473                                                         access & ACCESS_EXE ?
1474                                                         'e' : '.',
1475                                                         (pptr->
1476                                                          access & ACCESS_MMAP)
1477                                                         && !(pptr->
1478                                                              access &
1479                                                              ACCESS_EXE) ? 'm' :
1480                                                         '.');
1481                                         }       /* switch */
1482                                 } else {
1483                                         if (pptr->access & ACCESS_ROOT)
1484                                                 putc('r', stderr);
1485                                         if (pptr->access & ACCESS_CWD)
1486                                                 putc('c', stderr);
1487                                         if (pptr->access & ACCESS_EXE)
1488                                                 putc('e', stderr);
1489                                         else if (pptr->access & ACCESS_MMAP)
1490                                                 putc('m', stderr);
1491                                 }
1492                                 if (opts & OPT_USER) {
1493                                         if (pwent == NULL)
1494                                                 fprintf(stderr, " %-8s ",
1495                                                         _("(unknown)"));
1496                                         else
1497                                                 fprintf(stderr, "(%s)",
1498                                                         pwent->pw_name);
1499                                 }
1500                                 if (opts & OPT_VERBOSE) {
1501                                         if (pptr->command == NULL)
1502                                                 fprintf(stderr, "???\n");
1503                                         else
1504                                                 fprintf(stderr, "%s\n",
1505                                                         pptr->command);
1506                                 }
1507                                 len = 0;
1508                                 first = 0;
1509                         }
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))
1514                                         putc('\n', stderr);
1515                         } else {
1516                                 if (name_has_procs || (opts & OPT_ALLFILES))
1517                                         putc('\n', stderr);
1518                         }
1519                 }               /* be silent */
1520                 if (opts & OPT_KILL)
1521                         have_kill |= kill_matched_proc(nptr->matched_procs,
1522                                                       opts, sig_number);
1523
1524         }                       /* next name */
1525         if (opts & OPT_KILL)
1526                 return (have_kill == 1 ? 0 : 1);
1527         else
1528                 return (have_match == 1 ? 0 : 1);
1529
1530 }
1531
1532 static struct stat *get_pidstat(const pid_t pid, const char *filename)
1533 {
1534         char pathname[256];
1535         struct stat *st;
1536
1537         if ((st = (struct stat *)malloc(sizeof(struct stat))) == NULL)
1538                 return NULL;
1539         snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
1540         if (timeout(thestat, pathname, st, 5) != 0) {
1541                 free(st);
1542                 return NULL;
1543         }
1544         return st;
1545 }
1546
1547 static void
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)
1551 {
1552         DIR *dirp;
1553         dev_t thedev;
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;
1559         char *dirpath;
1560         char filepath[PATH_MAX];
1561
1562         if (asprintf(&dirpath, "/proc/%d/%s", pid, dirname) < 0)
1563         return;
1564         if ((dirp = opendir(dirpath)) == NULL) {
1565         free(dirpath);
1566                 return;
1567     }
1568     free(dirpath);
1569
1570         while ((direntry = readdir(dirp)) != NULL) {
1571                 if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
1572                         continue;
1573
1574                 snprintf(filepath, sizeof filepath - 1, "/proc/%d/%s/%s",
1575                          pid, dirname, direntry->d_name);
1576
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));
1581                         }
1582                 } else {
1583                         thedev = st.st_dev;
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;
1591                                                 break;
1592                                         }
1593                                 }
1594                         }
1595                         for (dev_tmp = dev_head; dev_tmp != NULL;
1596                              dev_tmp = dev_tmp->next) {
1597                                 if (thedev != dev_tmp->device)
1598                                         continue;
1599                                 if (access == ACCESS_FILE
1600                                     && (lstat(filepath, &lst) == 0)
1601                                     && (lst.st_mode & S_IWUSR)) {
1602                                         add_matched_proc(dev_tmp->name,
1603                                                          pid, uid,
1604                                                          ACCESS_FILEWR |
1605                                                          access);
1606                                 } else {
1607                                         add_matched_proc(dev_tmp->name,
1608                                                          pid, uid, access);
1609                                 }
1610                         }
1611                         for (ino_tmp = ino_head; ino_tmp != NULL;
1612                              ino_tmp = ino_tmp->next) {
1613                                 if (thedev != ino_tmp->device)
1614                                         continue;
1615                                 if (!st.st_ino
1616                                     && timeout(thestat, filepath, &st, 5) != 0) {
1617                                         fprintf(stderr,
1618                                                 _("Cannot stat file %s: %s\n"),
1619                                                 filepath, strerror(errno));
1620                                         continue;
1621                                 }
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,
1627                                                                  pid, uid,
1628                                                                  ACCESS_FILEWR |
1629                                                                  access);
1630                                         } else {
1631                                                 add_matched_proc(ino_tmp->name,
1632                                                                  pid, uid,
1633                                                                  access);
1634                                         }
1635                                 }
1636                         }
1637                 }
1638         }                       /* while fd_dent */
1639         closedir(dirp);
1640 }
1641
1642 static void
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)
1646 {
1647         char *pathname;
1648         char line[BUFSIZ];
1649         struct inode_list *ino_tmp;
1650         struct device_list *dev_tmp;
1651         FILE *fp;
1652         unsigned long long tmp_inode;
1653         unsigned int tmp_maj, tmp_min;
1654         dev_t tmp_device;
1655
1656         if (asprintf(&pathname, "/proc/%d/%s", pid, filename) < 0)
1657         return;
1658         if ((fp = fopen(pathname, "r")) == NULL) {
1659         free(pathname);
1660                 return;
1661     }
1662     free(pathname);
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,
1671                                                          uid, access);
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,
1677                                                          uid, access);
1678                 }
1679         }
1680         fclose(fp);
1681 }
1682
1683 static uid_t getpiduid(const pid_t pid)
1684 {
1685         char *pathname;
1686         struct stat st;
1687
1688         if (asprintf(&pathname, "/proc/%d", pid) < 0)
1689                 return 0;
1690         if (timeout(thestat, pathname, &st, 5) != 0) {
1691         free(pathname);
1692                 return 0;
1693     }
1694     free(pathname);
1695         return st.st_uid;
1696 }
1697
1698 /*
1699  * fill_unix_cache : Create a list of Unix sockets
1700  *   This list is used later for matching purposes
1701  */
1702 void fill_unix_cache(struct unixsocket_list **unixsocket_head)
1703 {
1704         FILE *fp;
1705         char line[BUFSIZ];
1706         unsigned long long scanned_inode;
1707         struct stat st;
1708         struct unixsocket_list *newsocket;
1709
1710         if ((fp = fopen("/proc/net/unix", "r")) == NULL) {
1711                 fprintf(stderr, _("Cannot open /proc/net/unix: %s\n"),
1712                         strerror(errno));
1713                 return;
1714         }
1715         while (fgets(line, BUFSIZ, fp) != NULL) {
1716                 char *path;
1717                 char *scanned_path = NULL;
1718                 if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %llu %ms",
1719                            &scanned_inode, &scanned_path) != 2) {
1720                         if (scanned_path)
1721                                 free(scanned_path);
1722                         continue;
1723                 }
1724                 if (scanned_path == NULL)
1725                         continue;
1726                 path = scanned_path;
1727                 if (*scanned_path == '@')
1728                         scanned_path++;
1729                 if (timeout(thestat, scanned_path, &st, 5) < 0) {
1730                         free(path);
1731                         continue;
1732                 }
1733                 if ((newsocket = (struct unixsocket_list *)
1734                      malloc(sizeof(struct unixsocket_list))) == NULL) {
1735                         free(path);
1736                         continue;
1737                 }
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;
1744                 free(path);
1745         }                       /* while */
1746
1747         fclose(fp);
1748 }
1749
1750 /*
1751  * Free up the list of Unix sockets
1752  */
1753 void clear_unix_cache(struct unixsocket_list **unixsocket_head)
1754 {
1755         while(*unixsocket_head != NULL) {
1756                 struct unixsocket_list *oldsocket = *unixsocket_head;
1757                 *unixsocket_head = oldsocket->next;
1758                 free(oldsocket->sun_name);
1759                 free(oldsocket);
1760         }
1761 }
1762
1763 static void
1764 atexit_clear_unix_cache()
1765 {
1766         clear_unix_cache(&unixsockets);
1767 }
1768
1769 #ifdef DEBUG
1770 /* often not used, doesn't need translation */
1771 static void
1772 debug_match_lists(struct names *names_head, struct inode_list *ino_head,
1773                   struct device_list *dev_head)
1774 {
1775         struct names *nptr;
1776         struct inode_list *iptr;
1777         struct device_list *dptr;
1778
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);
1782         }
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);
1788         }
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);
1792         }
1793 }
1794
1795 #endif
1796
1797 /* 0 = no, 1=yes */
1798 static int ask(const pid_t pid)
1799 {
1800         int res;
1801         size_t len = 0;
1802         char *line = NULL;
1803
1804         fflush(stdout);
1805         while (1) {
1806                 fprintf(stderr, _("Kill process %d ? (y/N) "), pid);
1807                 fflush(stderr);
1808                 if (getline(&line, &len, stdin) < 0)
1809                         return 0;
1810                 if (line[0] == '\n') {
1811                         free(line);
1812                         return 0;
1813                 }
1814                 res = rpmatch(line);
1815                 if (res >= 0) {
1816                         free(line);
1817                         return res;
1818                 }
1819         }                       /* while */
1820 }
1821
1822 static int
1823 kill_matched_proc(struct procs *proc_head, const opt_type opts,
1824                   const int sig_number)
1825 {
1826         struct procs *pptr;
1827         pid_t mypid;
1828         int ret = 0;
1829
1830         mypid = getpid();
1831
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)
1836                         continue;
1837                 if ((opts & OPT_WRITE) && ((pptr->access & ACCESS_FILEWR) == 0))
1838                         continue;
1839                 if ((opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
1840                         continue;
1841                 if (kill(pptr->pid, sig_number) < 0) {
1842                         fprintf(stderr, _("Could not kill process %d: %s\n"),
1843                                 pptr->pid, strerror(errno));
1844                         continue;
1845                 }
1846                 ret = 1;
1847         }
1848         return ret;
1849 }
1850
1851 static dev_t find_net_dev(void)
1852 {
1853         int skt;
1854         struct stat st;
1855
1856         if ((skt = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1857                 fprintf(stderr, _("Cannot open a network socket.\n"));
1858                 return -1;
1859         }
1860         if (fstat(skt, &st) != 0) {
1861                 fprintf(stderr, _("Cannot find socket's device number.\n"));
1862                 close(skt);
1863                 return -1;
1864         }
1865         close(skt);
1866         return st.st_dev;
1867 }
1868
1869 static void
1870 scan_knfsd(struct names *names_head, struct inode_list *ino_head,
1871            struct device_list *dev_head)
1872 {
1873         struct device_list *dev_tmp;
1874         struct inode_list *ino_tmp;
1875         FILE *fp;
1876         char line[BUFSIZ];
1877         char *find_space;
1878         struct stat st;
1879
1880         if ( (ino_head == NULL) && (dev_head == NULL) )
1881                 return;
1882
1883
1884         if ((fp = fopen(KNFSD_EXPORTS, "r")) == NULL) {
1885 #ifdef DEBUG
1886                 printf("Cannot open %s\n", KNFSD_EXPORTS);
1887 #endif
1888                 return;
1889         }
1890         while (fgets(line, BUFSIZ, fp) != NULL) {
1891                 if (line[0] == '#') {
1892                         continue;
1893                 }
1894                 if ((find_space = strpbrk(line, " \t")) == NULL)
1895                         continue;
1896                 *find_space = '\0';
1897                 if (timeout(thestat, line, &st, 5) != 0) {
1898                         continue;
1899                 }
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,
1905                                                  line);
1906                 }
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,
1912                                                  line);
1913                 }
1914         }
1915         fclose(fp);
1916 }
1917
1918 static void
1919 scan_mounts(struct names *names_head, struct inode_list *ino_head,
1920             struct device_list *dev_head)
1921 {
1922         struct device_list *dev_tmp;
1923         struct inode_list *ino_tmp;
1924         FILE *fp;
1925         char line[BUFSIZ];
1926         char *find_mountp;
1927         char *find_space;
1928         struct stat st;
1929
1930         if ( (ino_head == NULL) && (dev_head == NULL) )
1931                 return;
1932
1933
1934         if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
1935                 fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
1936                 return;
1937         }
1938         while (fgets(line, BUFSIZ, fp) != NULL) {
1939                 if ((find_mountp = strchr(line, ' ')) == NULL)
1940                         continue;
1941                 find_mountp++;
1942                 if ((find_space = strchr(find_mountp, ' ')) == NULL)
1943                         continue;
1944                 *find_space = '\0';
1945                 if (timeout(thestat, find_mountp, &st, 5) != 0) {
1946                         continue;
1947                 }
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,
1953                                                  find_mountp);
1954                 }
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,
1960                                                  find_mountp);
1961                 }
1962         }
1963         fclose(fp);
1964 }
1965
1966 static void
1967 scan_swaps(struct names *names_head, struct inode_list *ino_head,
1968            struct device_list *dev_head)
1969 {
1970         struct device_list *dev_tmp;
1971         struct inode_list *ino_tmp;
1972         FILE *fp;
1973         char line[BUFSIZ];
1974         char *find_space;
1975         struct stat st;
1976
1977         if ( (ino_head == NULL) && (dev_head == NULL) )
1978                 return;
1979
1980         if ((fp = fopen(PROC_SWAPS, "r")) == NULL) {
1981                 /*fprintf(stderr, "Cannot open %s\n", PROC_SWAPS); */
1982                 return;
1983         }
1984         /* lines are filename   type */
1985         while (fgets(line, BUFSIZ, fp) != NULL) {
1986                 if ((find_space = strchr(line, ' ')) == NULL)
1987                         continue;
1988                 *find_space = '\0';
1989                 find_space++;
1990                 while (*find_space == ' ') {
1991                         find_space++;
1992                         if (*find_space == '\0')
1993                                 continue;
1994                 }
1995                 if (timeout(thestat, line, &st, 5) != 0) {
1996                         continue;
1997                 }
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,
2003                                                  line);
2004                 }
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,
2010                                                  line);
2011                 }
2012         }
2013         fclose(fp);
2014 }
2015
2016 #if defined(WITH_MOUNTINFO_LIST)
2017 /*
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.
2021  */
2022
2023 static list_t mntinfo = { &mntinfo, &mntinfo };
2024
2025 static void clear_mntinfo(void)
2026 {
2027         list_t *ptr, *tmp;
2028
2029         list_for_each_safe(ptr, tmp, &mntinfo) {
2030                 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2031                 delete(ptr);
2032                 free(mnt);
2033         }
2034 }
2035
2036 static void init_mntinfo(void)
2037 {
2038         char mpoint[PATH_MAX *4 + 1]; // octal escaping takes 4 chars per 1 char
2039         int mid, parid, max = 0;
2040         uint maj, min;
2041         list_t sort;
2042         FILE *mnt;
2043
2044         if (!list_empty(&mntinfo))
2045                 return;
2046         if ((mnt = fopen("/proc/self/mountinfo", "r")) == (FILE *) 0)
2047                 return;
2048         while (fscanf
2049                (mnt, "%i %i %u:%u %*s %s %*[^\n]", &mid, &parid, &maj, &min,
2050                 &mpoint[0]) == 5) {
2051                 const size_t nlen = strlen(mpoint);
2052                 mntinfo_t *restrict mnt;
2053                 if (posix_memalign
2054                     ((void *)&mnt, sizeof(void *),
2055                      alignof(mntinfo_t) + (nlen + 1)) != 0) {
2056                         fprintf(stderr,
2057                                 _
2058                                 ("Cannot allocate memory for matched proc: %s\n"),
2059                                 strerror(errno));
2060                         exit(1);
2061                 }
2062                 append(mnt, mntinfo);
2063                 mnt->mpoint = ((char *)mnt) + alignof(mntinfo_t);
2064                 strcpy(mnt->mpoint, mpoint);
2065                 mnt->nlen = nlen;
2066                 mnt->parid = parid;
2067                 mnt->dev = makedev(maj, min);
2068                 mnt->id = mid;
2069                 if (mid > max)
2070                         max = mid;
2071         }
2072         fclose(mnt);
2073
2074         /* Sort mount points accordingly to the reverse mount order */
2075         initial(&sort);
2076         for (mid = 1; mid <= max; mid++) {
2077                 list_t *ptr, *tmp;
2078                 list_for_each_safe(ptr, tmp, &mntinfo) {
2079                         mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2080                         if (mid != mnt->id)
2081                                 continue;
2082                         move_head(ptr, &sort);
2083                         break;
2084                 }
2085                 list_for_each_safe(ptr, tmp, &mntinfo) {
2086                         mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2087                         if (mid != mnt->parid)
2088                                 continue;
2089                         move_head(ptr, &sort);
2090                 }
2091         }
2092         if (!list_empty(&mntinfo)) {
2093 #ifdef EBADE
2094                 errno = EBADE;
2095 #else
2096                 errno = ENOENT;
2097 #endif                          /* EBADE */
2098         }
2099         join(&sort, &mntinfo);
2100 }
2101
2102 /*
2103  * Determine device of links below /proc/
2104  */
2105 static int mntstat(const char *path, struct stat *buf)
2106 {
2107         char name[PATH_MAX + 1];
2108         const char *use;
2109         ssize_t nlen;
2110         list_t *ptr;
2111
2112         if ((use = realpath(path, name)) == NULL || *use != '/')
2113         {
2114                 if (errno == ENOENT)
2115                         return -1;
2116                 /*
2117                  * Could be a special file (socket, pipe, inotify)
2118                  */
2119                 errno = 0;
2120                 return stat(path, buf);
2121         }
2122
2123         nlen = strlen(use);
2124         list_for_each(ptr, &mntinfo) {
2125                 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
2126                 if (nlen < mnt->nlen)
2127                         continue;
2128                 if (mnt->nlen == 1) {   /* root fs is the last entry */
2129                         buf->st_dev = mnt->dev;
2130                         buf->st_ino = 0;
2131                         return 0;
2132                 }
2133                 if (use[mnt->nlen] != '\0' && use[mnt->nlen] != '/')
2134                         continue;
2135                 if (strncmp(use, mnt->mpoint, mnt->nlen) == 0) {
2136                         buf->st_dev = mnt->dev;
2137                         buf->st_ino = 0;
2138                         return 0;
2139                 }
2140         }
2141         errno = ENOENT;
2142         return -1;
2143 }
2144 #endif                          /* WITH_MOUNTINFO_LIST */
2145
2146 /*
2147  * Somehow the realpath(3) glibc function call, nevertheless
2148  * it avoids lstat(2) system calls.
2149  */
2150 static char real[PATH_MAX + 1];
2151 char *expandpath(const char *path)
2152 {
2153         char tmpbuf[PATH_MAX + 1];
2154         const char *start, *end;
2155         char *curr, *dest;
2156         int deep = MAXSYMLINKS;
2157
2158         if (!path || *path == '\0')
2159                 return (char *)0;
2160
2161         curr = &real[0];
2162
2163         if (*path != '/') {
2164                 if (!getcwd(curr, PATH_MAX))
2165                         return (char *)0;
2166 #ifdef HAVE_RAWMEMCHR
2167                 dest = rawmemchr(curr, '\0');
2168 #else
2169                 dest = strchr(curr, '\0');
2170 #endif
2171         } else {
2172                 *curr = '/';
2173                 dest = curr + 1;
2174         }
2175
2176         for (start = end = path; *start; start = end) {
2177
2178                 while (*start == '/')
2179                         ++start;
2180
2181                 for (end = start; *end && *end != '/'; ++end) ;
2182
2183                 if (end - start == 0)
2184                         break;
2185                 else if (end - start == 1 && start[0] == '.') {
2186                         ;
2187                 } else if (end - start == 2 && start[0] == '.'
2188                            && start[1] == '.') {
2189                         if (dest > curr + 1)
2190                                 while ((--dest)[-1] != '/') ;
2191                 } else {
2192                         char lnkbuf[PATH_MAX + 1];
2193                         size_t len;
2194                         ssize_t n;
2195
2196                         if (dest[-1] != '/')
2197                                 *dest++ = '/';
2198
2199                         if (dest + (end - start) > curr + PATH_MAX) {
2200                                 errno = ENAMETOOLONG;
2201                                 return (char *)0;
2202                         }
2203
2204                         dest = mempcpy(dest, start, end - start);
2205                         *dest = '\0';
2206
2207                         if (deep-- < 0) {
2208                                 errno = ELOOP;
2209                                 return (char *)0;
2210                         }
2211
2212                         errno = 0;
2213                         if ((n = readlink(curr, lnkbuf, PATH_MAX)) < 0) {
2214                                 deep = MAXSYMLINKS;
2215                                 if (errno == EINVAL)
2216                                         continue;       /* Not a symlink */
2217                                 return (char *)0;
2218                         }
2219                         lnkbuf[n] = '\0';       /* Don't be fooled by readlink(2) */
2220
2221                         len = strlen(end);
2222                         if ((n + len) > PATH_MAX) {
2223                                 errno = ENAMETOOLONG;
2224                                 return (char *)0;
2225                         }
2226
2227                         memmove(&tmpbuf[n], end, len + 1);
2228                         path = end = memcpy(tmpbuf, lnkbuf, n);
2229
2230                         if (lnkbuf[0] == '/')
2231                                 dest = curr + 1;
2232                         else if (dest > curr + 1)
2233                                 while ((--dest)[-1] != '/') ;
2234
2235                 }
2236         }
2237
2238         if (dest > curr + 1 && dest[-1] == '/')
2239                 --dest;
2240         *dest = '\0';
2241
2242         return curr;
2243 }