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-2011 Craig Small
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/wait.h>
40 #include <arpa/inet.h>
41 #include <netinet/in.h>
42 #include <pwd.h>
43 #include <netdb.h>
44 #include <dirent.h>
45 #include <unistd.h>
46 #include <ctype.h>
47 #include <mntent.h>
48 #include <signal.h>
49 #include <getopt.h>
50 #include <setjmp.h>
51 #include <limits.h>
52 /* MAXSYMLINKS is a BSDism. If it doesn't exist, fall back to SYMLINK_MAX,
53 which is the POSIX name. */
54 #ifndef MAXSYMLINKS
55 #define MAXSYMLINKS SYMLINK_MAX
56 #endif
57
58 #include "fuser.h"
59 #include "signals.h"
60 #include "i18n.h"
61
62 //#define DEBUG 1
63
64 #define NAME_FIELD 20 /* space reserved for file name */
65 /* Function defines */
66 static void add_matched_proc(struct names *name_list, const pid_t pid,
67 const uid_t uid, const char access);
68 static void add_special_proc(struct names *name_list, const char ptype,
69 const uid_t uid, const char *command);
70 static void check_dir(const pid_t pid, const char *dirname,
71 struct device_list *dev_head,
72 struct inode_list *ino_head, const uid_t uid,
73 const char access, struct unixsocket_list *sockets,
74 dev_t netdev);
75 static void check_map(const pid_t pid, const char *filename,
76 struct device_list *dev_head,
77 struct inode_list *ino_head, const uid_t uid,
78 const char access);
79 static struct stat *get_pidstat(const pid_t pid, const char *filename);
80 static uid_t getpiduid(const pid_t pid);
81 static int print_matches(struct names *names_head, const opt_type opts,
82 const int sig_number);
83 static int kill_matched_proc(struct procs *pptr, const opt_type opts,
84 const int sig_number);
85
86 /*int parse_mount(struct names *this_name, struct device_list **dev_list);*/
87 static void add_device(struct device_list **dev_list,
88 struct names *this_name, dev_t device);
89 void fill_unix_cache(struct unixsocket_list **unixsocket_head);
90 static dev_t find_net_dev(void);
91 static void scan_procs(struct names *names_head, struct inode_list *ino_head,
92 struct device_list *dev_head,
93 struct unixsocket_list *sockets, dev_t netdev);
94 static void scan_knfsd(struct names *names_head, struct inode_list *ino_head,
95 struct device_list *dev_head);
96 static void scan_mounts(struct names *names_head,
97 struct inode_list *ino_head,
98 struct device_list *dev_head);
99 static void scan_swaps(struct names *names_head, struct inode_list *ino_head,
100 struct device_list *dev_head);
101 #ifdef DEBUG
102 static void debug_match_lists(struct names *names_head,
103 struct inode_list *ino_head,
104 struct device_list *dev_head);
105 #endif
106
107 #ifdef _LISTS_H
108 static void clear_mntinfo(void) __attribute__((__destructor__));
109 static void init_mntinfo(void) __attribute__((__constructor__));
110 static dev_t device(const char *path);
111 #endif
112 static char *expandpath(const char *path);
113
114 typedef int (*stat_t)(const char*, struct stat*);
115 #ifdef WITH_TIMEOUT_STAT
116 static int timeout(stat_t func, const char *path, struct stat *buf, unsigned int seconds);
117 #else
118 #define timeout(func,path,buf,dummy) (func)((path),(buf))
119 #endif /* WITH_TIMEOUT_STAT */
120
usage(const char * errormsg)121 static void usage(const char *errormsg)
122 {
123 if (errormsg != NULL)
124 fprintf(stderr, "%s\n", errormsg);
125
126 fprintf(stderr,
127 _
128 ("Usage: fuser [-fMuv] [-a|-s] [-4|-6] [-c|-m|-n SPACE] [-k [-i] [-SIGNAL]] NAME...\n"
129 " fuser -l\n" " fuser -V\n"
130 "Show which processes use the named files, sockets, or filesystems.\n\n"
131 " -a,--all display unused files too\n"
132 " -i,--interactive ask before killing (ignored without -k)\n"
133 " -k,--kill kill processes accessing the named file\n"
134 " -l,--list-signals list available signal names\n"
135 " -m,--mount show all processes using the named filesystems or block device\n"
136 " -M,--ismountpoint fulfill request only if NAME is a mount point\n"
137 " -n,--namespace SPACE search in this name space (file, udp, or tcp)\n"
138 " -s,--silent silent operation\n"
139 " -SIGNAL send this signal instead of SIGKILL\n"
140 " -u,--user display user IDs\n"
141 " -v,--verbose verbose output\n"
142 " -w,--writeonly kill only processes with write access\n"
143 " -V,--version display version information\n"));
144 #ifdef WITH_IPV6
145 fprintf(stderr, _(
146 " -4,--ipv4 search IPv4 sockets only\n"
147 " -6,--ipv6 search IPv6 sockets only\n"));
148 #endif
149 fprintf(stderr, _(
150 " - reset options\n\n"
151 " udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
152 exit(1);
153 }
154
print_version()155 void print_version()
156 {
157 fprintf(stderr, _("fuser (PSmisc) %s\n"), VERSION);
158 fprintf(stderr,
159 _
160 ("Copyright (C) 1993-2010 Werner Almesberger and Craig Small\n\n"));
161 fprintf(stderr,
162 _("PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
163 "This is free software, and you are welcome to redistribute it under\n"
164 "the terms of the GNU General Public License.\n"
165 "For more information about these matters, see the files named COPYING.\n"));
166 }
167
168 static void
scan_procs(struct names * names_head,struct inode_list * ino_head,struct device_list * dev_head,struct unixsocket_list * sockets,dev_t netdev)169 scan_procs(struct names *names_head, struct inode_list *ino_head,
170 struct device_list *dev_head, struct unixsocket_list *sockets,
171 dev_t netdev)
172 {
173 DIR *topproc_dir;
174 struct dirent *topproc_dent;
175 struct inode_list *ino_tmp;
176 struct device_list *dev_tmp;
177 pid_t pid, my_pid;
178 uid_t uid;
179
180 if ((topproc_dir = opendir("/proc")) == NULL) {
181 fprintf(stderr, _("Cannot open /proc directory: %s\n"),
182 strerror(errno));
183 exit(1);
184 }
185 my_pid = getpid();
186 while ((topproc_dent = readdir(topproc_dir)) != NULL) {
187 dev_t cwd_dev, exe_dev, root_dev;
188 struct stat *cwd_stat = NULL;
189 struct stat *exe_stat = NULL;
190 struct stat *root_stat = NULL;
191 #ifdef _LISTS_H
192 char path[256] = "/proc/", *slash;
193 ssize_t len;
194 #endif
195
196 if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */
197 continue;
198 pid = atoi(topproc_dent->d_name);
199 /* Dont print myself */
200 if (pid == my_pid)
201 continue;
202 uid = getpiduid(pid);
203
204 #ifdef _LISTS_H
205 strcpy(&path[6], topproc_dent->d_name);
206 len = strlen(path);
207 slash = &path[len];
208
209 *slash = '\0';
210 strcat(slash, "/cwd");
211 cwd_dev = device(path);
212
213 *slash = '\0';
214 strcat(slash, "/exe");
215 exe_dev = device(path);
216
217 *slash = '\0';
218 strcat(slash, "/root");
219 root_dev = device(path);
220 #else
221 cwd_stat = get_pidstat(pid, "cwd");
222 exe_stat = get_pidstat(pid, "exe");
223 root_stat = get_pidstat(pid, "root");
224 cwd_dev = cwd_stat ? cwd_stat->st_dev : 0;
225 exe_dev = exe_stat ? exe_stat->st_dev : 0;
226 root_dev = root_stat ? root_stat->st_dev : 0;
227 #endif
228
229 /* Scan the devices */
230 for (dev_tmp = dev_head; dev_tmp != NULL; dev_tmp = dev_tmp->next) {
231 if (exe_dev == dev_tmp->device)
232 add_matched_proc(dev_tmp->name, pid, uid, ACCESS_EXE);
233 if (root_dev == dev_tmp->device)
234 add_matched_proc(dev_tmp->name, pid, uid, ACCESS_ROOT);
235 if (cwd_dev == dev_tmp->device)
236 add_matched_proc(dev_tmp->name, pid, uid, ACCESS_CWD);
237 }
238 for (ino_tmp = ino_head; ino_tmp != NULL; ino_tmp = ino_tmp->next) {
239 if (exe_dev == ino_tmp->device) {
240 if (!exe_stat)
241 exe_stat = get_pidstat(pid, "exe");
242 if (exe_stat && exe_stat->st_dev == ino_tmp->device
243 && exe_stat->st_ino == ino_tmp->inode)
244 add_matched_proc(ino_tmp->name, pid, uid, ACCESS_EXE);
245 }
246 if (root_dev == ino_tmp->device) {
247 if (!root_stat)
248 root_stat = get_pidstat(pid, "root");
249 if (root_stat && root_stat->st_dev == ino_tmp->device
250 && root_stat->st_ino == ino_tmp->inode)
251 add_matched_proc(ino_tmp->name, pid, uid, ACCESS_ROOT);
252 }
253 if (cwd_dev == ino_tmp->device) {
254 if (!cwd_stat)
255 cwd_stat = get_pidstat(pid, "cwd");
256 if (cwd_stat && cwd_stat->st_dev == ino_tmp->device
257 && cwd_stat->st_ino == ino_tmp->inode)
258 add_matched_proc(ino_tmp->name, pid, uid, ACCESS_CWD);
259 }
260 }
261 if (root_stat) free(root_stat);
262 if (cwd_stat) free(cwd_stat);
263 if (exe_stat) free(exe_stat);
264 #ifndef __linux__
265 check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP,
266 sockets, netdev);
267 check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP,
268 sockets, netdev);
269 #endif
270 check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE,
271 sockets, netdev);
272 check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
273
274 } /* while topproc_dent */
275 closedir(topproc_dir);
276 }
277
278 static void
add_inode(struct inode_list ** ino_list,struct names * this_name,dev_t device,ino_t inode)279 add_inode(struct inode_list **ino_list, struct names *this_name,
280 dev_t device, ino_t inode)
281 {
282 struct inode_list *ino_tmp, *ino_head;
283
284 if ((ino_tmp = (struct inode_list*)malloc(sizeof(struct inode_list))) == NULL)
285 return;
286 ino_head = *ino_list;
287 ino_tmp->name = this_name;
288 ino_tmp->device = device;
289 ino_tmp->inode = inode;
290 ino_tmp->next = ino_head;
291 *ino_list = ino_tmp;
292 }
293
294 static void
add_device(struct device_list ** dev_list,struct names * this_name,dev_t device)295 add_device(struct device_list **dev_list, struct names *this_name, dev_t device)
296 {
297 struct device_list *dev_tmp, *dev_head;
298
299 /*printf("Adding device %s %d\n", this_name->filename, device); */
300
301 if ((dev_tmp = (struct device_list*)malloc(sizeof(struct device_list))) == NULL)
302 return;
303 dev_head = *dev_list;
304 dev_tmp->name = this_name;
305 dev_tmp->device = device;
306 dev_tmp->next = dev_head;
307 *dev_list = dev_tmp;
308 }
309
310 static void
add_ip_conn(struct ip_connections ** ip_list,const char * protocol,struct names * this_name,const int lcl_port,const int rmt_port,unsigned long rmt_address)311 add_ip_conn(struct ip_connections **ip_list, const char *protocol,
312 struct names *this_name, const int lcl_port, const int rmt_port,
313 unsigned long rmt_address)
314 {
315 struct ip_connections *ip_tmp, *ip_head;
316
317 if ((ip_tmp = (struct ip_connections*)malloc(sizeof(struct ip_connections))) == NULL)
318 return;
319 ip_head = *ip_list;
320 ip_tmp->name = this_name;
321 ip_tmp->lcl_port = lcl_port;
322 ip_tmp->rmt_port = rmt_port;
323 ip_tmp->rmt_address.s_addr = rmt_address;
324 ip_tmp->next = ip_head;
325
326 *ip_list = ip_tmp;
327 }
328
329 #ifdef WITH_IPV6
330 static void
add_ip6_conn(struct ip6_connections ** ip_list,const char * protocol,struct names * this_name,const int lcl_port,const int rmt_port,struct in6_addr rmt_address)331 add_ip6_conn(struct ip6_connections **ip_list, const char *protocol,
332 struct names *this_name, const int lcl_port, const int rmt_port,
333 struct in6_addr rmt_address)
334 {
335 struct ip6_connections *ip_tmp, *ip_head;
336
337 if ((ip_tmp = (struct ip6_connections*)malloc(sizeof(struct ip6_connections))) == NULL)
338 return;
339 ip_head = *ip_list;
340 ip_tmp->name = this_name;
341 ip_tmp->lcl_port = lcl_port;
342 ip_tmp->rmt_port = rmt_port;
343 memcpy(&(ip_tmp->rmt_address), &(rmt_address), sizeof(struct in6_addr));
344 ip_tmp->next = ip_head;
345
346 *ip_list = ip_tmp;
347 }
348 #endif
349
350 /* Adds a normal process only */
351 static void
add_matched_proc(struct names * name_list,const pid_t pid,const uid_t uid,const char access)352 add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid,
353 const char access)
354 {
355 struct procs *pptr, *last_proc;
356 char *pathname;
357 char cmdname[101], *cptr;
358 int cmdlen;
359 FILE *fp;
360
361 last_proc = NULL;
362 for (pptr = name_list->matched_procs; pptr != NULL; pptr = pptr->next) {
363 last_proc = pptr;
364 if (pptr->pid == pid) {
365 pptr->access |= access;
366 return;
367 }
368 }
369 /* Not found */
370 if ((pptr = (struct procs*)malloc(sizeof(struct procs))) == NULL) {
371 fprintf(stderr,
372 _("Cannot allocate memory for matched proc: %s\n"),
373 strerror(errno));
374 return;
375 }
376 pptr->pid = pid;
377 pptr->uid = uid;
378 pptr->access = access;
379 pptr->proc_type = PTYPE_NORMAL;
380 pptr->next = NULL;
381 /* set command name */
382 pptr->command = NULL;
383
384 fp = NULL;
385 pathname = NULL;
386 if ((asprintf(&pathname, "/proc/%d/stat", pid) > 0) &&
387 ((fp = fopen(pathname, "r")) != NULL) &&
388 (fscanf(fp, "%*d (%100[^)]", cmdname) == 1))
389 if ((pptr->command = (char*)malloc(MAX_CMDNAME + 1)) != NULL) {
390 cmdlen = 0;
391 for (cptr = cmdname; cmdlen < MAX_CMDNAME && *cptr;
392 cptr++) {
393 if (isprint(*cptr))
394 pptr->command[cmdlen++] = *cptr;
395 else if (cmdlen < (MAX_CMDNAME - 4))
396 cmdlen +=
397 sprintf(&(pptr->command[cmdlen]),
398 "\\%03o", *cptr);
399 }
400 pptr->command[cmdlen] = '\0';
401 }
402 if (last_proc == NULL)
403 name_list->matched_procs = pptr;
404 else
405 last_proc->next = pptr;
406 if (pathname)
407 free(pathname);
408 if (fp)
409 fclose(fp);
410 }
411
412 /* Adds a knfsd etc process */
413 static void
add_special_proc(struct names * name_list,const char ptype,const uid_t uid,const char * command)414 add_special_proc(struct names *name_list, const char ptype, const uid_t uid,
415 const char *command)
416 {
417 struct procs *pptr;
418
419 for (pptr = name_list->matched_procs; pptr != NULL; pptr = pptr->next) {
420 if (pptr->proc_type == ptype)
421 return;
422 }
423 if ((pptr = malloc(sizeof(struct procs))) == NULL) {
424 fprintf(stderr,
425 _("Cannot allocate memory for matched proc: %s\n"),
426 strerror(errno));
427 return;
428 }
429 pptr->pid = 0;
430 pptr->uid = uid;
431 pptr->access = 0;
432 pptr->proc_type = ptype;
433 /* Append the special processes */
434 pptr->next = name_list->matched_procs;
435 name_list->matched_procs = pptr;
436 /* set command name */
437 pptr->command = strdup(command);
438 }
439
parse_file(struct names * this_name,struct inode_list ** ino_list,const char opts)440 int parse_file(struct names *this_name, struct inode_list **ino_list, const char opts)
441 {
442 char * new = expandpath(this_name->filename);
443 if (new) {
444 if (this_name->filename)
445 free(this_name->filename);
446 this_name->filename = strdup(new);
447 }
448 #ifdef _LISTS_H
449 if (opts & OPT_MOUNTS) {
450 this_name->st.st_dev = device(this_name->filename);
451 this_name->st.st_ino = 0;
452 add_inode(ino_list, this_name, this_name->st.st_dev, this_name->st.st_ino);
453 return 0;
454 }
455 #endif
456
457 if (timeout(stat, this_name->filename, &(this_name->st), 5) != 0) {
458 if (errno == ENOENT)
459 fprintf(stderr, _("Specified filename %s does not exist.\n"), this_name->filename);
460 else
461 fprintf(stderr, _("Cannot stat %s: %s\n"), this_name->filename, strerror(errno));
462 return -1;
463 }
464 #ifdef DEBUG
465 printf("adding file %s %lX %lX\n", this_name->filename,
466 (unsigned long)this_name->st.st_dev, (unsigned long)this_name->st.st_ino);
467 #endif /* DEBUG */
468 add_inode(ino_list, this_name, this_name->st.st_dev, this_name->st.st_ino);
469 return 0;
470 }
471
472 int
parse_unixsockets(struct names * this_name,struct inode_list ** ino_list,struct unixsocket_list * sun_head)473 parse_unixsockets(struct names *this_name, struct inode_list **ino_list,
474 struct unixsocket_list *sun_head)
475 {
476 struct unixsocket_list *sun_tmp;
477 dev_t net_dev;
478
479 net_dev = find_net_dev();
480
481 for (sun_tmp = sun_head; sun_tmp != NULL; sun_tmp = sun_tmp->next) {
482 if (sun_tmp->dev == this_name->st.st_dev && sun_tmp->inode == this_name->st.st_ino) {
483 add_inode(ino_list, this_name, net_dev,
484 sun_tmp->net_inode);
485 return 0;
486 }
487 }
488 return 0;
489 }
490
491 int
parse_mounts(struct names * this_name,struct device_list ** dev_list,const char opts)492 parse_mounts(struct names *this_name, struct device_list **dev_list,
493 const char opts)
494 {
495 dev_t match_device;
496
497 if (S_ISBLK(this_name->st.st_mode))
498 match_device = this_name->st.st_rdev;
499 else
500 match_device = this_name->st.st_dev;
501 add_device(dev_list, this_name, match_device);
502 return 0;
503 }
504
505 #ifdef WITH_IPV6
506 int
parse_inet(struct names * this_name,const int ipv6_only,const int ipv4_only,struct ip_connections ** ip_list,struct ip6_connections ** ip6_list)507 parse_inet(struct names *this_name, const int ipv6_only, const int ipv4_only,
508 struct ip_connections **ip_list, struct ip6_connections **ip6_list)
509 #else
510 int parse_inet(struct names *this_name, struct ip_connections **ip_list)
511 #endif
512 {
513 struct addrinfo *res, *resptr;
514 struct addrinfo hints;
515 int errcode;
516 char *lcl_port_str, *rmt_addr_str, *rmt_port_str, *tmpstr, *tmpstr2;
517 in_port_t lcl_port;
518 struct sockaddr_in *sin;
519 #ifdef WITH_IPV6
520 struct sockaddr_in6 *sin6;
521 #endif
522 char hostspec[100];
523 char *protocol;
524 int i;
525
526 if ((protocol = strchr(this_name->filename, '/')) == NULL)
527 return -1;
528 protocol++;
529 if (protocol[0] == '\0')
530 return -1;
531 for (i = 0;
532 i < 99 && this_name->filename[i] != '\0'
533 && this_name->filename[i] != '/'; i++)
534 hostspec[i] = this_name->filename[i];
535 hostspec[i] = '\0';
536
537 lcl_port_str = rmt_addr_str = rmt_port_str = NULL;
538 /* Split out the names */
539 if ((tmpstr = strchr(hostspec, ',')) == NULL) {
540 /* Single option */
541 lcl_port_str = strdup(hostspec);
542 } else {
543 if (tmpstr == hostspec)
544 lcl_port_str = NULL;
545 else {
546 *tmpstr = '\0';
547 lcl_port_str = strdup(hostspec);
548 }
549 tmpstr++;
550 if (*tmpstr != '\0') {
551 if ((tmpstr2 = strchr(tmpstr, ',')) == NULL) {
552 /* Only 2 options */
553 rmt_addr_str = tmpstr;
554 } else {
555 if (tmpstr2 == tmpstr)
556 rmt_addr_str = NULL;
557 else {
558 rmt_addr_str = tmpstr;
559 *tmpstr2 = '\0';
560 }
561 tmpstr2++;
562 if (*tmpstr2 != '\0')
563 rmt_port_str = tmpstr2;
564 }
565 }
566 }
567 #ifdef DEBUG
568 printf("parsed to lp %s rh %s rp %s\n", lcl_port_str, rmt_addr_str,
569 rmt_port_str);
570 #endif
571
572 memset(&hints, 0, sizeof(hints));
573 #ifdef WITH_IPV6
574 if (ipv6_only) {
575 hints.ai_family = PF_INET6;
576 } else if (ipv4_only) {
577 hints.ai_family = PF_INET;
578 } else
579 hints.ai_family = PF_UNSPEC;
580 #else
581 hints.ai_family = PF_INET;
582 #endif
583 if (strcmp(protocol, "tcp") == 0)
584 hints.ai_socktype = SOCK_STREAM;
585 else
586 hints.ai_socktype = SOCK_DGRAM;
587
588 if (lcl_port_str == NULL) {
589 lcl_port = 0;
590 } else {
591 /* Resolve local port first */
592 if ((errcode =
593 getaddrinfo(NULL, lcl_port_str, &hints, &res)) != 0) {
594 fprintf(stderr, _("Cannot resolve local port %s: %s\n"),
595 lcl_port_str, gai_strerror(errcode));
596 return -1;
597 }
598 if (res == NULL)
599 return -1;
600 switch (res->ai_family) {
601 case AF_INET:
602 lcl_port =
603 ((struct sockaddr_in *)(res->ai_addr))->sin_port;
604 break;
605 #ifdef WITH_IPV6
606 case AF_INET6:
607 lcl_port =
608 ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port;
609 break;
610 #endif
611 default:
612 fprintf(stderr, _("Unknown local port AF %d\n"),
613 res->ai_family);
614 freeaddrinfo(res);
615 return -1;
616 }
617 freeaddrinfo(res);
618 }
619 free(lcl_port_str);
620 res = NULL;
621 if (rmt_addr_str == NULL && rmt_port_str == NULL) {
622 add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), 0,
623 INADDR_ANY);
624 #ifdef WITH_IPV6
625 add_ip6_conn(ip6_list, protocol, this_name, ntohs(lcl_port), 0,
626 in6addr_any);
627 #endif
628 return 0;
629 } else {
630 /* Resolve remote address and port */
631 if (getaddrinfo(rmt_addr_str, rmt_port_str, &hints, &res) == 0) {
632 for (resptr = res; resptr != NULL;
633 resptr = resptr->ai_next) {
634 switch (resptr->ai_family) {
635 case AF_INET:
636 sin =
637 (struct sockaddr_in *)
638 resptr->ai_addr;
639 if (rmt_addr_str == NULL) {
640 add_ip_conn(ip_list, protocol,
641 this_name,
642 ntohs(lcl_port),
643 ntohs
644 (sin->sin_port),
645 INADDR_ANY);
646 } else {
647 add_ip_conn(ip_list, protocol,
648 this_name,
649 ntohs(lcl_port),
650 ntohs
651 (sin->sin_port),
652 sin->
653 sin_addr.s_addr);
654 }
655 break;
656 #ifdef WITH_IPV6
657 case AF_INET6:
658 sin6 =
659 (struct sockaddr_in6 *)
660 resptr->ai_addr;
661 if (rmt_addr_str == NULL) {
662 add_ip6_conn(ip6_list, protocol,
663 this_name,
664 ntohs(lcl_port),
665 ntohs
666 (sin6->sin6_port),
667 in6addr_any);
668 } else {
669 add_ip6_conn(ip6_list, protocol,
670 this_name,
671 ntohs(lcl_port),
672 ntohs
673 (sin6->sin6_port),
674 sin6->sin6_addr);
675 }
676 break;
677 #endif
678 }
679 } /*while */
680 return 0;
681 }
682 }
683 return 1;
684 }
685
686 void
find_net_sockets(struct inode_list ** ino_list,struct ip_connections * conn_list,const char * protocol,dev_t netdev)687 find_net_sockets(struct inode_list **ino_list,
688 struct ip_connections *conn_list, const char *protocol,
689 dev_t netdev)
690 {
691 FILE *fp;
692 char pathname[200], line[BUFSIZ];
693 unsigned long loc_port, rmt_port;
694 unsigned long rmt_addr, scanned_inode;
695 ino_t inode;
696 struct ip_connections *conn_tmp;
697
698 if (snprintf(pathname, 200, "/proc/net/%s", protocol) < 0)
699 return;
700
701 if ((fp = fopen(pathname, "r")) == NULL) {
702 fprintf(stderr, _("Cannot open protocol file \"%s\": %s\n"),
703 pathname, strerror(errno));
704 return;
705 }
706 while (fgets(line, BUFSIZ, fp) != NULL) {
707 if (sscanf
708 (line,
709 "%*u: %*x:%lx %08lx:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
710 &loc_port, &rmt_addr, &rmt_port, &scanned_inode) != 4)
711 continue;
712 #ifdef DEBUG
713 printf("Found IPv4 *:%lu with %s:%lu\n", loc_port,
714 inet_ntoa(*((struct in_addr *)&rmt_addr)), rmt_port);
715 #endif /* DEBUG */
716 inode = scanned_inode;
717 for (conn_tmp = conn_list; conn_tmp != NULL;
718 conn_tmp = conn_tmp->next) {
719 #ifdef DEBUG
720 printf(" Comparing with *.%lu %s:%lu\n",
721 conn_tmp->lcl_port,
722 inet_ntoa(conn_tmp->rmt_address),
723 conn_tmp->rmt_port);
724 #endif
725 if ((conn_tmp->lcl_port == 0
726 || conn_tmp->lcl_port == loc_port)
727 && (conn_tmp->rmt_port == 0
728 || conn_tmp->rmt_port == rmt_port)
729 && (conn_tmp->rmt_address.s_addr == INADDR_ANY
730 ||
731 (memcmp
732 (&(conn_tmp->rmt_address), &(rmt_addr),
733 4) == 0))) {
734 /* add inode to list */
735 #ifdef DEBUG
736 printf("Added inode!\n");
737 #endif /* DEBUG */
738 add_inode(ino_list, conn_tmp->name, netdev,
739 inode);
740 }
741 }
742
743 }
744 fclose(fp);
745 }
746
747 #ifdef WITH_IPV6
748 void
find_net6_sockets(struct inode_list ** ino_list,struct ip6_connections * conn_list,const char * protocol,const dev_t netdev)749 find_net6_sockets(struct inode_list **ino_list,
750 struct ip6_connections *conn_list, const char *protocol,
751 const dev_t netdev)
752 {
753 FILE *fp;
754 char pathname[200], line[BUFSIZ];
755 unsigned long loc_port, rmt_port;
756 struct in6_addr rmt_addr;
757 unsigned int tmp_addr[4];
758 char rmt_addr6str[INET6_ADDRSTRLEN];
759 struct ip6_connections *conn_tmp;
760 unsigned long scanned_inode;
761 ino_t inode;
762
763 if (snprintf(pathname, 200, "/proc/net/%s6", protocol) < 0)
764 return;
765
766 if ((fp = fopen(pathname, "r")) == NULL) {
767 #ifdef DEBUG
768 printf("Cannot open protocol file \"%s\": %s\n", pathname,
769 strerror(errno));
770 #endif /* DEBUG */
771 return;
772 }
773 while (fgets(line, BUFSIZ, fp) != NULL) {
774 if (sscanf
775 (line,
776 "%*u: %*x:%lx %08x%08x%08x%08x:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
777 &loc_port, &(tmp_addr[0]), &(tmp_addr[1]), &(tmp_addr[2]),
778 &(tmp_addr[3]), &rmt_port, &scanned_inode) != 7)
779 continue;
780 inode = scanned_inode;
781 rmt_addr.s6_addr32[0] = tmp_addr[0];
782 rmt_addr.s6_addr32[1] = tmp_addr[1];
783 rmt_addr.s6_addr32[2] = tmp_addr[2];
784 rmt_addr.s6_addr32[3] = tmp_addr[3];
785 inet_ntop(AF_INET6, &rmt_addr, rmt_addr6str, INET6_ADDRSTRLEN);
786 #ifdef DEBUG
787 printf("Found IPv6 %ld with %s:%ld\n", loc_port, rmt_addr6str,
788 rmt_port);
789 #endif /* DEBUG */
790 for (conn_tmp = conn_list; conn_tmp != NULL;
791 conn_tmp = conn_tmp->next) {
792 inet_ntop(AF_INET6, &conn_tmp->rmt_address,
793 rmt_addr6str, INET6_ADDRSTRLEN);
794 #ifdef DEBUG
795 printf(" Comparing with *.%lu %s:%lu ...\n",
796 conn_tmp->lcl_port, rmt_addr6str,
797 conn_tmp->rmt_port);
798 #endif /* DEBUG */
799 if ((conn_tmp->lcl_port == 0
800 || conn_tmp->lcl_port == loc_port)
801 && (conn_tmp->rmt_port == 0
802 || conn_tmp->rmt_port == rmt_port)
803 &&
804 (memcmp(&(conn_tmp->rmt_address), &in6addr_any, 16)
805 == 0
806 ||
807 (memcmp(&(conn_tmp->rmt_address), &(rmt_addr), 16)
808 == 0))) {
809 add_inode(ino_list, conn_tmp->name, netdev,
810 inode);
811 }
812 }
813 }
814 fclose(fp);
815 }
816 #endif
817
818 static void
read_proc_mounts(struct mount_list ** mnt_list)819 read_proc_mounts(struct mount_list **mnt_list)
820 {
821 FILE *fp;
822 char line[BUFSIZ];
823 char *find_mountp;
824 char *find_space;
825 struct mount_list *mnt_tmp;
826
827 if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
828 fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
829 return;
830 }
831 while (fgets(line, BUFSIZ, fp) != NULL) {
832 if ((find_mountp = strchr(line, ' ')) == NULL)
833 continue;
834 find_mountp++;
835 if ((find_space = strchr(find_mountp, ' ')) == NULL)
836 continue;
837 *find_space = '\0';
838 if ((mnt_tmp = malloc(sizeof(struct mount_list))) == NULL)
839 continue;
840 if ((mnt_tmp->mountpoint = strdup(find_mountp)) == NULL)
841 continue;
842 mnt_tmp->next = *mnt_list;
843 *mnt_list = mnt_tmp;
844 }
845 fclose(fp);
846 }
847
848 static int
is_mountpoint(struct mount_list ** mnt_list,char * arg)849 is_mountpoint(struct mount_list **mnt_list, char *arg)
850 {
851 char *p;
852 struct mount_list *mnt_tmp;
853
854 if (*arg == '\0')
855 return 0;
856 /* Remove trailing slashes. */
857 for (p = arg; *p != '\0'; p++)
858 ;
859 while (*(--p) == '/' && p > arg)
860 *p = '\0';
861
862 for (mnt_tmp = *mnt_list; mnt_tmp != NULL; mnt_tmp = mnt_tmp->next)
863 if (!strcmp(mnt_tmp->mountpoint, arg))
864 return 1;
865 return 0;
866 }
867
main(int argc,char * argv[])868 int main(int argc, char *argv[])
869 {
870 opt_type opts;
871 int sig_number;
872 #ifdef WITH_IPV6
873 int ipv4_only, ipv6_only;
874 #endif
875 unsigned char default_namespace = NAMESPACE_FILE;
876 struct device_list *match_devices = NULL;
877 struct unixsocket_list *unixsockets = NULL;
878 struct mount_list *mounts = NULL;
879
880 dev_t netdev;
881 struct ip_connections *tcp_connection_list = NULL;
882 struct ip_connections *udp_connection_list = NULL;
883 #ifdef WITH_IPV6
884 struct ip6_connections *tcp6_connection_list = NULL;
885 struct ip6_connections *udp6_connection_list = NULL;
886 #endif
887 struct inode_list *match_inodes = NULL;
888 struct names *names_head, *this_name, *names_tail;
889 int argc_cnt;
890 char *current_argv, *option;
891 char option_buf[3];
892 struct option *optr;
893 char *nsptr;
894 int skip_argv;
895
896 struct option options[] = {
897 {"all", 0, NULL, 'a'},
898 {"kill", 0, NULL, 'k'},
899 {"interactive", 0, NULL, 'i'},
900 {"list-signals", 0, NULL, 'l'},
901 {"mount", 0, NULL, 'm'},
902 {"ismountpoint", 0, NULL, 'M'},
903 {"namespace", 1, NULL, 'n'},
904 {"silent", 0, NULL, 's'},
905 {"user", 0, NULL, 'u'},
906 {"verbose", 0, NULL, 'v'},
907 {"writeonly", 0, NULL, 'w'},
908 {"version", 0, NULL, 'V'},
909 #ifdef WITH_IPV6
910 {"ipv4", 0, NULL, '4'},
911 {"ipv6", 0, NULL, '6'},
912 #endif
913 { 0, 0, 0, 0 }
914 };
915
916 #ifdef WITH_IPV6
917 ipv4_only = ipv6_only = 0;
918 #endif
919 names_head = this_name = names_tail = NULL;
920 opts = 0;
921 sig_number = SIGKILL;
922
923 #ifdef ENABLE_NLS
924 /* Set up the i18n */
925 setlocale(LC_ALL, "");
926 bindtextdomain(PACKAGE, LOCALEDIR);
927 textdomain(PACKAGE);
928 #endif
929
930 netdev = find_net_dev();
931 fill_unix_cache(&unixsockets);
932
933 for (argc_cnt = 1; argc_cnt < argc; argc_cnt++) {
934 current_argv = argv[argc_cnt];
935 if (current_argv[0] == '-') { /* its an option */
936 if (current_argv[1] == '-') { /* its a long option */
937 if (current_argv[2] == '\0') /* -- */
938 break;
939 /* Parse the long options */
940 option = option_buf;
941 for (optr = options; optr->name != NULL; optr++) {
942 if (strcmp(current_argv+2,optr->name) == 0) {
943 sprintf(option_buf, "-%c", (char)optr->val);
944 break;
945 }
946 }
947 if (optr->name == NULL) {
948 fprintf(stderr, _("%s: Invalid option %s\n"), argv[0],
949 current_argv);
950 usage(NULL);
951 }
952 } else {
953 option = current_argv;
954 }
955 skip_argv=0;
956 while (*(++option) != '\0' && !skip_argv) { /* skips over the - */
957 switch (*option) {
958 #ifdef WITH_IPV6
959 case '4':
960 ipv4_only = 1;
961 break;
962 case '6':
963 ipv6_only = 1;
964 break;
965 #endif /* WITH_IPV6 */
966 case 'a':
967 opts |= OPT_ALLFILES;
968 break;
969 case 'c':
970 opts |= OPT_MOUNTS;
971 break;
972 case 'f':
973 /* ignored */
974 break;
975 case 'h':
976 usage(NULL);
977 break;
978 case 'i':
979 opts |= OPT_INTERACTIVE;
980 break;
981 case 'k':
982 opts |= OPT_KILL;
983 break;
984 case 'l':
985 list_signals();
986 return 0;
987 case 'm':
988 opts |= OPT_MOUNTS;
989 read_proc_mounts(&mounts);
990 break;
991 case 'M':
992 opts |= OPT_ISMOUNTPOINT;
993 read_proc_mounts(&mounts);
994 break;
995 case 'n':
996 argc_cnt++;
997 if (argc_cnt >= argc) {
998 usage(_ ("Namespace option requires an argument."));
999 exit(1);;
1000 }
1001 skip_argv=1;
1002 //while(option != '\0') option++;
1003 if (strcmp(argv[argc_cnt], "tcp") == 0)
1004 default_namespace = NAMESPACE_TCP;
1005 else if (strcmp(argv[argc_cnt], "udp") == 0)
1006 default_namespace = NAMESPACE_UDP;
1007 else if (strcmp(argv[argc_cnt], "file") == 0)
1008 default_namespace = NAMESPACE_FILE;
1009 else
1010 usage(_("Invalid namespace name"));
1011 break;
1012 case 's':
1013 opts |= OPT_SILENT;
1014 break;
1015 case 'u':
1016 opts |= OPT_USER;
1017 break;
1018 case 'v':
1019 opts |= OPT_VERBOSE;
1020 break;
1021 case 'w':
1022 opts |= OPT_WRITE;
1023 break;
1024 case 'V':
1025 print_version();
1026 return 0;
1027 default:
1028 if (isupper(*option) || isdigit(*option)) {
1029 sig_number = get_signal(current_argv+1, argv[0]);
1030 skip_argv=1;
1031 break;
1032 }
1033 fprintf(stderr, "%s: Invalid option %c\n", argv[0],
1034 *option);
1035 usage(NULL);
1036 exit(1);
1037 break;
1038 } /* switch */
1039 } /* while option */
1040 continue;
1041 } /* an option */
1042 /* Not an option, must be a file specification */
1043
1044 if ((this_name = malloc(sizeof(struct names))) == NULL)
1045 continue;
1046 this_name->next = NULL;
1047 /* try to find namespace spec */
1048 this_name->name_space = default_namespace;
1049 if (((nsptr = strchr(current_argv, '/')) != NULL)
1050 && (nsptr != current_argv)) {
1051 if (strcmp(nsptr + 1, "tcp") == 0) {
1052 this_name->name_space = NAMESPACE_TCP;
1053 *nsptr = '\0';
1054 } else if (strcmp(nsptr + 1, "udp") == 0) {
1055 this_name->name_space = NAMESPACE_UDP;
1056 *nsptr = '\0';
1057 } else if (strcmp(nsptr + 1, "file") == 0) {
1058 this_name->name_space = NAMESPACE_FILE;
1059 *nsptr = '\0';
1060 }
1061 }
1062 this_name->matched_procs = NULL;
1063 if (opts & (OPT_MOUNTS|OPT_ISMOUNTPOINT)
1064 && this_name->name_space != NAMESPACE_FILE)
1065 usage(_
1066 ("You can only use files with mountpoint options"));
1067 if (opts & OPT_ISMOUNTPOINT &&
1068 !is_mountpoint(&mounts, current_argv)) {
1069 free(this_name);
1070 continue;
1071 }
1072 switch (this_name->name_space) {
1073 case NAMESPACE_TCP:
1074 if (asprintf(&(this_name->filename), "%s/tcp", current_argv) > 0) {
1075 #ifdef WITH_IPV6
1076 parse_inet(this_name, ipv4_only, ipv6_only,
1077 &tcp_connection_list, &tcp6_connection_list);
1078 #else
1079 parse_inet(this_name, &tcp_connection_list);
1080 #endif
1081 }
1082 break;
1083 case NAMESPACE_UDP:
1084 if (asprintf(&(this_name->filename), "%s/udp", current_argv) > 0) {
1085 #ifdef WITH_IPV6
1086 parse_inet(this_name, ipv4_only, ipv6_only,
1087 &udp_connection_list, &udp6_connection_list);
1088 #else
1089 parse_inet(this_name, &udp_connection_list);
1090 #endif
1091 }
1092 break;
1093 default: /* FILE */
1094 this_name->filename = strdup(current_argv);
1095 if (parse_file(this_name, &match_inodes, opts) == 0) {
1096 if (opts & OPT_MOUNTS)
1097 parse_mounts(this_name, &match_devices, opts);
1098 else
1099 parse_unixsockets(this_name, &match_inodes, unixsockets);
1100 }
1101 break;
1102 }
1103
1104 if (names_head == NULL)
1105 names_head = this_name;
1106 if (names_tail != NULL)
1107 names_tail->next = this_name;
1108 names_tail = this_name;
1109 } /* for across the argvs */
1110 if (names_head == NULL)
1111 usage(_("No process specification given"));
1112
1113 if (opts & OPT_SILENT) {
1114 opts &= ~OPT_VERBOSE;
1115 opts &= ~OPT_USER;
1116 if (opts & OPT_ALLFILES)
1117 usage(_
1118 ("all option cannot be used with silent option."));
1119 }
1120 #ifdef WITH_IPV6
1121 if (ipv4_only && ipv6_only)
1122 usage(_
1123 ("You cannot search for only IPv4 and only IPv6 sockets at the same time"));
1124 if (!ipv6_only) {
1125 #endif
1126 if (tcp_connection_list != NULL)
1127 find_net_sockets(&match_inodes, tcp_connection_list,
1128 "tcp", netdev);
1129 if (udp_connection_list != NULL)
1130 find_net_sockets(&match_inodes, udp_connection_list,
1131 "udp", netdev);
1132 #ifdef WITH_IPV6
1133 }
1134 if (!ipv4_only) {
1135 if (tcp6_connection_list != NULL)
1136 find_net6_sockets(&match_inodes, tcp6_connection_list,
1137 "tcp", netdev);
1138 if (udp6_connection_list != NULL)
1139 find_net6_sockets(&match_inodes, udp6_connection_list,
1140 "udp", netdev);
1141 }
1142 #endif
1143 #ifdef DEBUG
1144 debug_match_lists(names_head, match_inodes, match_devices);
1145 #endif
1146 scan_procs(names_head, match_inodes, match_devices, unixsockets,
1147 netdev);
1148 scan_knfsd(names_head, match_inodes, match_devices);
1149 scan_mounts(names_head, match_inodes, match_devices);
1150 scan_swaps(names_head, match_inodes, match_devices);
1151 return print_matches(names_head, opts, sig_number);
1152 }
1153
1154 /*
1155 * returns 0 if match, 1 if no match
1156 */
1157 static int
print_matches(struct names * names_head,const opt_type opts,const int sig_number)1158 print_matches(struct names *names_head, const opt_type opts,
1159 const int sig_number)
1160 {
1161 struct names *nptr;
1162 struct procs *pptr;
1163 char head = 0;
1164 char first = 1;
1165 int len = 0;
1166 struct passwd *pwent = NULL;
1167 int have_match = 0;
1168 int have_kill = 0;
1169 int name_has_procs = 0;
1170
1171 for (nptr = names_head; nptr != NULL; nptr = nptr->next) {
1172 if (opts & OPT_SILENT) {
1173 for (pptr = nptr->matched_procs; pptr != NULL;
1174 pptr = pptr->next) {
1175 if(pptr->proc_type != PTYPE_NORMAL)
1176 continue;
1177
1178 have_match = 1;
1179 }
1180 } else { /* We're not silent */
1181 if ((opts & OPT_ALLFILES) == 0) {
1182 name_has_procs = 0;
1183 if (opts & OPT_VERBOSE) {
1184 if (nptr->matched_procs)
1185 name_has_procs = 1;
1186 } else {
1187 for (pptr = nptr->matched_procs;
1188 pptr != NULL; pptr = pptr->next) {
1189 if (pptr->proc_type ==
1190 PTYPE_NORMAL) {
1191 name_has_procs = 1;
1192 break;
1193 }
1194 }
1195 }
1196 }
1197 if (name_has_procs == 1 || opts & OPT_ALLFILES) {
1198 if (head == 0 && opts & OPT_VERBOSE) {
1199 fprintf(stderr,
1200 _
1201 ("%*s USER PID ACCESS COMMAND\n"),
1202 NAME_FIELD, "");
1203 head = 1;
1204 }
1205
1206 fprintf(stderr, "%s:", nptr->filename);
1207 len = strlen(nptr->filename) + 1;
1208 }
1209
1210 first = 1;
1211 for (pptr = nptr->matched_procs; pptr != NULL;
1212 pptr = pptr->next) {
1213 /* Suppress any special "processes" */
1214 if (!(opts & OPT_VERBOSE)
1215 && (pptr->proc_type != PTYPE_NORMAL))
1216 continue;
1217
1218 have_match = 1;
1219 if (opts & (OPT_VERBOSE | OPT_USER)) {
1220 if (pwent == NULL
1221 || pwent->pw_uid != pptr->uid)
1222 pwent = getpwuid(pptr->uid);
1223 }
1224 if (len > NAME_FIELD && (opts & OPT_VERBOSE)) {
1225 putc('\n', stderr);
1226 len = 0;
1227 }
1228 if ((opts & OPT_VERBOSE) || first)
1229 while (len++ < NAME_FIELD)
1230 putc(' ', stderr);
1231 if (opts & OPT_VERBOSE) {
1232 if (pwent == NULL)
1233 fprintf(stderr, " %-8s ",
1234 _("(unknown)"));
1235 else
1236 fprintf(stderr, " %-8s ",
1237 pwent->pw_name);
1238 }
1239 if (pptr->proc_type == PTYPE_NORMAL)
1240 printf(" %5d", pptr->pid);
1241 else
1242 printf("kernel");
1243 fflush(stdout);
1244 if (opts & OPT_VERBOSE) {
1245 switch (pptr->proc_type) {
1246 case PTYPE_KNFSD:
1247 fprintf(stderr, " knfsd ");
1248 break;
1249 case PTYPE_MOUNT:
1250 fprintf(stderr, " mount ");
1251 break;
1252 case PTYPE_SWAP:
1253 fprintf(stderr, " swap ");
1254 break;
1255 default:
1256 fprintf(stderr, " %c%c%c%c%c ",
1257 pptr->access &
1258 ACCESS_FILE ? (pptr->
1259 access &
1260 ACCESS_FILEWR
1261 ? 'F' :
1262 'f') :
1263 '.',
1264 pptr->access &
1265 ACCESS_ROOT ? 'r' : '.',
1266 pptr->access &
1267 ACCESS_CWD ? 'c' : '.',
1268 pptr->access &
1269 ACCESS_EXE ? 'e' : '.',
1270 (pptr->access &
1271 ACCESS_MMAP)
1272 && !(pptr->access &
1273 ACCESS_EXE) ? 'm' :
1274 '.');
1275 } /* switch */
1276 } else {
1277 if (pptr->access & ACCESS_ROOT)
1278 putc('r', stderr);
1279 if (pptr->access & ACCESS_CWD)
1280 putc('c', stderr);
1281 if (pptr->access & ACCESS_EXE)
1282 putc('e', stderr);
1283 else if (pptr->access & ACCESS_MMAP)
1284 putc('m', stderr);
1285 }
1286 if (opts & OPT_USER) {
1287 if (pwent == NULL)
1288 fprintf(stderr, " %-8s ",
1289 _("(unknown)"));
1290 else
1291 fprintf(stderr, "(%s)",
1292 pwent->pw_name);
1293 }
1294 if (opts & OPT_VERBOSE) {
1295 if (pptr->command == NULL)
1296 fprintf(stderr, "???\n");
1297 else
1298 fprintf(stderr, "%s\n",
1299 pptr->command);
1300 }
1301 len = 0;
1302 first = 0;
1303 }
1304 if (opts & OPT_VERBOSE) {
1305 /* put a newline if showing all files and no procs */
1306 if (nptr->matched_procs == NULL
1307 && (opts & OPT_ALLFILES))
1308 putc('\n', stderr);
1309 } else {
1310 if (name_has_procs || (opts & OPT_ALLFILES))
1311 putc('\n', stderr);
1312 }
1313 } /* be silent */
1314 if (opts & OPT_KILL)
1315 have_kill = kill_matched_proc(nptr->matched_procs,
1316 opts, sig_number);
1317
1318 } /* next name */
1319 if (opts & OPT_KILL)
1320 return (have_kill == 1 ? 0 : 1);
1321 else
1322 return (have_match == 1 ? 0 : 1);
1323
1324 }
1325
get_pidstat(const pid_t pid,const char * filename)1326 static struct stat *get_pidstat(const pid_t pid, const char *filename)
1327 {
1328 char pathname[256];
1329 struct stat *st;
1330
1331 if ((st = (struct stat*)malloc(sizeof(struct stat))) == NULL)
1332 return NULL;
1333 snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
1334 if (timeout(stat, pathname, st, 5) != 0) {
1335 free(st);
1336 return NULL;
1337 }
1338 return st;
1339 }
1340
1341 static void
check_dir(const pid_t pid,const char * dirname,struct device_list * dev_head,struct inode_list * ino_head,const uid_t uid,const char access,struct unixsocket_list * sockets,dev_t netdev)1342 check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head,
1343 struct inode_list *ino_head, const uid_t uid, const char access,
1344 struct unixsocket_list *sockets, dev_t netdev)
1345 {
1346 char *dirpath = NULL, *filepath = NULL;
1347 DIR *dirp;
1348 struct dirent *direntry;
1349 struct inode_list *ino_tmp;
1350 struct device_list *dev_tmp;
1351 struct unixsocket_list *sock_tmp;
1352 struct stat st, lst;
1353 dev_t thedev;
1354
1355 if ((dirpath = (char*)malloc(MAX_PATHNAME)) == NULL)
1356 goto out;
1357 if ((filepath = (char*)malloc(MAX_PATHNAME)) == NULL)
1358 goto out;
1359
1360 snprintf(dirpath, MAX_PATHNAME, "/proc/%d/%s", pid, dirname);
1361 if ((dirp = opendir(dirpath)) == NULL)
1362 goto out;
1363 while ((direntry = readdir(dirp)) != NULL) {
1364 if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
1365 continue;
1366
1367 snprintf(filepath, MAX_PATHNAME, "/proc/%d/%s/%s",
1368 pid, dirname, direntry->d_name);
1369
1370 #ifdef _LISTS_H
1371 st.st_ino = 0;
1372 if ((thedev = device(filepath)) < 0)
1373 #else
1374 if (!st.st_ino && timeout(stat, filepath, &st, 5) != 0)
1375 #endif
1376 {
1377 if (errno != ENOENT) {
1378 fprintf(stderr, _("Cannot stat file %s: %s\n"),
1379 filepath, strerror(errno));
1380 }
1381 } else {
1382 if (thedev == netdev) {
1383 for (sock_tmp = sockets; sock_tmp != NULL;
1384 sock_tmp = sock_tmp->next) {
1385 if (sock_tmp->net_inode == st.st_ino) {
1386 st.st_ino = sock_tmp->inode;
1387 st.st_dev = sock_tmp->dev;
1388 thedev = sock_tmp->dev;
1389 break;
1390 }
1391 }
1392 }
1393 for (dev_tmp = dev_head; dev_tmp != NULL;
1394 dev_tmp = dev_tmp->next) {
1395 if (thedev != dev_tmp->device)
1396 continue;
1397 if (access == ACCESS_FILE
1398 && (lstat(filepath, &lst) == 0)
1399 && (lst.st_mode & S_IWUSR)) {
1400 add_matched_proc(dev_tmp->name,
1401 pid, uid,
1402 ACCESS_FILEWR |
1403 access);
1404 } else {
1405 add_matched_proc(dev_tmp->name,
1406 pid, uid,
1407 access);
1408 }
1409 }
1410 for (ino_tmp = ino_head; ino_tmp != NULL;
1411 ino_tmp = ino_tmp->next) {
1412 if (thedev != ino_tmp->device)
1413 continue;
1414 if (!st.st_ino && timeout(stat, filepath, &st, 5) != 0) {
1415 fprintf(stderr,
1416 _("Cannot stat file %s: %s\n"),
1417 filepath, strerror(errno));
1418 continue;
1419 }
1420 if (st.st_ino == ino_tmp->inode) {
1421 if (access == ACCESS_FILE
1422 && (lstat(filepath, &lst) == 0)
1423 && (lst.st_mode & S_IWUSR)) {
1424 add_matched_proc(ino_tmp->name,
1425 pid, uid,
1426 ACCESS_FILEWR |
1427 access);
1428 } else {
1429 add_matched_proc(ino_tmp->name,
1430 pid, uid,
1431 access);
1432 }
1433 }
1434 }
1435 }
1436 } /* while fd_dent */
1437 closedir(dirp);
1438 out:
1439 if (dirpath)
1440 free(dirpath);
1441 if (filepath)
1442 free(filepath);
1443 }
1444
1445 static void
check_map(const pid_t pid,const char * filename,struct device_list * dev_head,struct inode_list * ino_head,const uid_t uid,const char access)1446 check_map(const pid_t pid, const char *filename,
1447 struct device_list *dev_head, struct inode_list *ino_head,
1448 const uid_t uid, const char access)
1449 {
1450 char pathname[MAX_PATHNAME];
1451 char line[BUFSIZ];
1452 struct inode_list *ino_tmp;
1453 struct device_list *dev_tmp;
1454 FILE *fp;
1455 unsigned long long tmp_inode;
1456 unsigned int tmp_maj, tmp_min;
1457 dev_t tmp_device;
1458
1459 snprintf(pathname, MAX_PATHNAME, "/proc/%d/%s", pid, filename);
1460 if ((fp = fopen(pathname, "r")) == NULL)
1461 return;
1462 while (fgets(line, BUFSIZ, fp)) {
1463 if (sscanf(line, "%*s %*s %*s %x:%x %lld",
1464 &tmp_maj, &tmp_min, &tmp_inode) == 3) {
1465 tmp_device = tmp_maj * 256 + tmp_min;
1466 for (dev_tmp = dev_head; dev_tmp != NULL;
1467 dev_tmp = dev_tmp->next)
1468 if (dev_tmp->device == tmp_device)
1469 add_matched_proc(dev_tmp->name, pid,
1470 uid, access);
1471 for (ino_tmp = ino_head; ino_tmp != NULL;
1472 ino_tmp = ino_tmp->next)
1473 if (ino_tmp->device == tmp_device
1474 && ino_tmp->inode == tmp_inode)
1475 add_matched_proc(ino_tmp->name, pid,
1476 uid, access);
1477 }
1478 }
1479 fclose(fp);
1480 }
1481
getpiduid(const pid_t pid)1482 static uid_t getpiduid(const pid_t pid)
1483 {
1484 char pathname[MAX_PATHNAME];
1485 struct stat st;
1486
1487 if (snprintf(pathname, MAX_PATHNAME, "/proc/%d", pid) < 0)
1488 return 0;
1489 if (timeout(stat, pathname, &st, 5) != 0)
1490 return 0;
1491 return st.st_uid;
1492 }
1493
1494 /*
1495 * fill_unix_cache : Create a list of Unix sockets
1496 * This list is used later for matching purposes
1497 */
fill_unix_cache(struct unixsocket_list ** unixsocket_head)1498 void fill_unix_cache(struct unixsocket_list **unixsocket_head)
1499 {
1500 FILE *fp;
1501 char line[BUFSIZ];
1502 int scanned_inode;
1503 struct stat st;
1504 struct unixsocket_list *newsocket;
1505
1506 if ((fp = fopen("/proc/net/unix", "r")) == NULL) {
1507 fprintf(stderr, _("Cannot open /proc/net/unix: %s\n"),
1508 strerror(errno));
1509 return;
1510 }
1511 while (fgets(line, BUFSIZ, fp) != NULL) {
1512 char * path;
1513 char * scanned_path = NULL;
1514 if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %d %as",
1515 &scanned_inode, &scanned_path) != 2) {
1516 if (scanned_path)
1517 free(scanned_path);
1518 continue;
1519 }
1520 if (scanned_path == NULL)
1521 continue;
1522 path = scanned_path;
1523 if (*scanned_path == '@')
1524 scanned_path++;
1525 if (timeout(stat, scanned_path, &st, 5) < 0) {
1526 free(path);
1527 continue;
1528 }
1529 if ((newsocket = (struct unixsocket_list*)
1530 malloc(sizeof(struct unixsocket_list))) == NULL) {
1531 free(path);
1532 continue;
1533 }
1534 newsocket->sun_name = strdup(scanned_path);
1535 newsocket->inode = st.st_ino;
1536 newsocket->dev = st.st_dev;
1537 newsocket->net_inode = scanned_inode;
1538 newsocket->next = *unixsocket_head;
1539 *unixsocket_head = newsocket;
1540 free(path);
1541 } /* while */
1542
1543 fclose(fp);
1544 }
1545
1546 #ifdef DEBUG
1547 /* often not used, doesnt need translation */
1548 static void
debug_match_lists(struct names * names_head,struct inode_list * ino_head,struct device_list * dev_head)1549 debug_match_lists(struct names *names_head, struct inode_list *ino_head,
1550 struct device_list *dev_head)
1551 {
1552 struct names *nptr;
1553 struct inode_list *iptr;
1554 struct device_list *dptr;
1555
1556 fprintf(stderr, "Specified Names:\n");
1557 for (nptr = names_head; nptr != NULL; nptr = nptr->next) {
1558 fprintf(stderr, "\t%s %c\n", nptr->filename, nptr->name_space);
1559 }
1560 fprintf(stderr, "\nInodes:\n");
1561 for (iptr = ino_head; iptr != NULL; iptr = iptr->next) {
1562 fprintf(stderr, " Dev:%0lx Inode:(%0ld) 0x%0lx => %s\n",
1563 (unsigned long)iptr->device, (unsigned long)iptr->inode,
1564 (unsigned long)iptr->inode, iptr->name->filename);
1565 }
1566 fprintf(stderr, "\nDevices:\n");
1567 for (dptr = dev_head; dptr != NULL; dptr = dptr->next) {
1568 fprintf(stderr, "\tDev:%0lx\n", (unsigned long)dptr->device);
1569 }
1570 }
1571
1572 #endif
1573
1574 /* 0 = no, 1=yes */
ask(const pid_t pid)1575 static int ask(const pid_t pid)
1576 {
1577 int res;
1578 size_t len = 0;
1579 char *line = NULL;
1580
1581 fflush(stdout);
1582 while (1) {
1583 fprintf(stderr, _("Kill process %d ? (y/N) "), pid);
1584 fflush(stderr);
1585 if (getline(&line, &len, stdin) < 0)
1586 return 0;
1587 if (line[0] == '\n') {
1588 free(line);
1589 return 0;
1590 }
1591 res = rpmatch(line);
1592 if (res >= 0) {
1593 free(line);
1594 return res;
1595 }
1596 } /* while */
1597 }
1598
1599 static int
kill_matched_proc(struct procs * proc_head,const opt_type opts,const int sig_number)1600 kill_matched_proc(struct procs *proc_head, const opt_type opts,
1601 const int sig_number)
1602 {
1603 struct procs *pptr;
1604 pid_t mypid;
1605 int ret = 0;
1606
1607 mypid = getpid();
1608
1609 for (pptr = proc_head; pptr != NULL; pptr = pptr->next) {
1610 if ( pptr->pid == mypid)
1611 continue; /* dont kill myself */
1612 if ( pptr->proc_type != PTYPE_NORMAL )
1613 continue;
1614 if ((opts & OPT_WRITE) && ((pptr->access & ACCESS_FILEWR) == 0))
1615 continue;
1616 if ((opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
1617 continue;
1618 if ( kill(pptr->pid, sig_number) < 0) {
1619 fprintf(stderr, _("Could not kill process %d: %s\n"),
1620 pptr->pid, strerror(errno));
1621 continue;
1622 }
1623 ret = 1;
1624 }
1625 return ret;
1626 }
1627
find_net_dev(void)1628 static dev_t find_net_dev(void)
1629 {
1630 int skt;
1631 struct stat st;
1632
1633 if ((skt = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1634 fprintf(stderr, _("Cannot open a network socket.\n"));
1635 return -1;
1636 }
1637 if (fstat(skt, &st) != 0) {
1638 fprintf(stderr, _("Cannot find socket's device number.\n"));
1639 close(skt);
1640 return -1;
1641 }
1642 close(skt);
1643 return st.st_dev;
1644 }
1645
1646 static void
scan_knfsd(struct names * names_head,struct inode_list * ino_head,struct device_list * dev_head)1647 scan_knfsd(struct names *names_head, struct inode_list *ino_head,
1648 struct device_list *dev_head)
1649 {
1650 struct device_list *dev_tmp;
1651 struct inode_list *ino_tmp;
1652 FILE *fp;
1653 char line[BUFSIZ];
1654 char *find_space;
1655 struct stat st;
1656
1657 if ((fp = fopen(KNFSD_EXPORTS, "r")) == NULL) {
1658 #ifdef DEBUG
1659 printf("Cannot open %s\n", KNFSD_EXPORTS);
1660 #endif
1661 return;
1662 }
1663 while (fgets(line, BUFSIZ, fp) != NULL) {
1664 if (line[0] == '#') {
1665 continue;
1666 }
1667 if ((find_space = strpbrk(line, " \t")) == NULL)
1668 continue;
1669 *find_space = '\0';
1670 if (timeout(stat, line, &st, 5) != 0) {
1671 continue;
1672 }
1673 /* Scan the devices */
1674 for (dev_tmp = dev_head; dev_tmp != NULL;
1675 dev_tmp = dev_tmp->next) {
1676 if (st.st_dev == dev_tmp->device)
1677 add_special_proc(dev_tmp->name, PTYPE_KNFSD, 0,
1678 line);
1679 }
1680 for (ino_tmp = ino_head; ino_tmp != NULL;
1681 ino_tmp = ino_tmp->next) {
1682 if (st.st_dev == ino_tmp->device
1683 && st.st_ino == ino_tmp->inode)
1684 add_special_proc(ino_tmp->name, PTYPE_KNFSD, 0,
1685 line);
1686 }
1687 }
1688 fclose(fp);
1689 }
1690
1691 static void
scan_mounts(struct names * names_head,struct inode_list * ino_head,struct device_list * dev_head)1692 scan_mounts(struct names *names_head, struct inode_list *ino_head,
1693 struct device_list *dev_head)
1694 {
1695 struct device_list *dev_tmp;
1696 struct inode_list *ino_tmp;
1697 FILE *fp;
1698 char line[BUFSIZ];
1699 char *find_mountp;
1700 char *find_space;
1701 struct stat st;
1702
1703 if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
1704 fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
1705 return;
1706 }
1707 while (fgets(line, BUFSIZ, fp) != NULL) {
1708 if ((find_mountp = strchr(line, ' ')) == NULL)
1709 continue;
1710 find_mountp++;
1711 if ((find_space = strchr(find_mountp, ' ')) == NULL)
1712 continue;
1713 *find_space = '\0';
1714 if (timeout(stat, find_mountp, &st, 5) != 0) {
1715 continue;
1716 }
1717 /* Scan the devices */
1718 for (dev_tmp = dev_head; dev_tmp != NULL;
1719 dev_tmp = dev_tmp->next) {
1720 if (st.st_dev == dev_tmp->device)
1721 add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0,
1722 find_mountp);
1723 }
1724 for (ino_tmp = ino_head; ino_tmp != NULL;
1725 ino_tmp = ino_tmp->next) {
1726 if (st.st_dev == ino_tmp->device
1727 && st.st_ino == ino_tmp->inode)
1728 add_special_proc(ino_tmp->name, PTYPE_MOUNT, 0,
1729 find_mountp);
1730 }
1731 }
1732 fclose(fp);
1733 }
1734
1735 static void
scan_swaps(struct names * names_head,struct inode_list * ino_head,struct device_list * dev_head)1736 scan_swaps(struct names *names_head, struct inode_list *ino_head,
1737 struct device_list *dev_head)
1738 {
1739 struct device_list *dev_tmp;
1740 struct inode_list *ino_tmp;
1741 FILE *fp;
1742 char line[BUFSIZ];
1743 char *find_space;
1744 struct stat st;
1745
1746 if ((fp = fopen(PROC_SWAPS, "r")) == NULL) {
1747 /*fprintf(stderr, "Cannot open %s\n", PROC_SWAPS);*/
1748 return;
1749 }
1750 /* lines are filename type */
1751 while (fgets(line, BUFSIZ, fp) != NULL) {
1752 if ((find_space = strchr(line, ' ')) == NULL)
1753 continue;
1754 *find_space = '\0';
1755 find_space++;
1756 while (*find_space == ' ') {
1757 find_space++;
1758 if (*find_space == '\0')
1759 continue;
1760 }
1761 if (timeout(stat, line, &st, 5) != 0) {
1762 continue;
1763 }
1764 /* Scan the devices */
1765 for (dev_tmp = dev_head; dev_tmp != NULL;
1766 dev_tmp = dev_tmp->next) {
1767 if (st.st_dev == dev_tmp->device)
1768 add_special_proc(dev_tmp->name, PTYPE_SWAP, 0,
1769 line);
1770 }
1771 for (ino_tmp = ino_head; ino_tmp != NULL;
1772 ino_tmp = ino_tmp->next) {
1773 if (st.st_dev == ino_tmp->device
1774 && st.st_ino == ino_tmp->inode)
1775 add_special_proc(ino_tmp->name, PTYPE_SWAP, 0,
1776 line);
1777 }
1778 }
1779 fclose(fp);
1780 }
1781
1782 /*
1783 * Execute stat(2) system call with timeout to avoid deadlock
1784 * on network based file systems.
1785 */
1786 #ifdef HAVE_TIMEOUT_STAT
1787
1788 static sigjmp_buf jenv;
1789
1790 static void
sigalarm(int sig)1791 sigalarm(int sig)
1792 {
1793 if (sig == SIGALRM)
1794 siglongjmp(jenv, 1);
1795 }
1796
1797 static int
timeout(stat_t func,const char * path,struct stat * buf,unsigned int seconds)1798 timeout(stat_t func, const char *path, struct stat *buf, unsigned int seconds)
1799 {
1800 pid_t pid = 0;
1801 int ret = 0, pipes[4];
1802 ssize_t len;
1803
1804 if (pipe(&pipes[0]) < 0)
1805 goto err;
1806 switch ((pid = fork ())) {
1807 case -1:
1808 close(pipes[0]);
1809 close(pipes[1]);
1810 goto err;
1811 case 0:
1812 (void) signal(SIGALRM, SIG_DFL);
1813 close(pipes[0]);
1814 if ((ret = func(path, buf)) == 0)
1815 do len = write(pipes[1], buf, sizeof(struct stat));
1816 while (len < 0 && errno == EINTR);
1817 close(pipes[1]);
1818 exit(ret);
1819 default:
1820 close(pipes[1]);
1821 if (sigsetjmp(jenv, 1)) {
1822 (void) alarm(0);
1823 (void) signal(SIGALRM, SIG_DFL);
1824 if (waitpid(0, (int*)0, WNOHANG) == 0)
1825 kill(pid, SIGKILL);
1826 errno = ETIMEDOUT;
1827 seconds = 1;
1828 goto err;
1829 }
1830 (void) signal(SIGALRM, sigalarm);
1831 (void) alarm(seconds);
1832 if (read(pipes[0], buf, sizeof(struct stat)) == 0) {
1833 errno = EFAULT;
1834 ret = -1;
1835 }
1836 (void) alarm(0);
1837 (void) signal(SIGALRM, SIG_DFL);
1838 close(pipes[0]);
1839 waitpid(pid, NULL, 0);
1840 break;
1841 }
1842 return ret;
1843 err:
1844 return -1;
1845 }
1846 #endif /* HAVE_TIMEOUT_STAT */
1847
1848 #ifdef _LISTS_H
1849 /*
1850 * Use /proc/self/mountinfo of modern linux system to determine
1851 * the device numbers of the mount points. Use this to avoid the
1852 * stat(2) system call wherever possible.
1853 */
1854
1855 static list_t mntinfo = {&mntinfo, &mntinfo};
1856
1857 static void
clear_mntinfo(void)1858 clear_mntinfo(void)
1859 {
1860 list_t *ptr, *tmp;
1861
1862 list_for_each_safe(ptr, tmp, &mntinfo) {
1863 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
1864 delete(ptr);
1865 free(mnt);
1866 }
1867 }
1868
1869
1870 static void
init_mntinfo(void)1871 init_mntinfo(void)
1872 {
1873 char mpoint[PATH_MAX+1];
1874 int mid, parid, max = 0;
1875 uint maj, min;
1876 list_t sort;
1877 FILE * mnt;
1878
1879 if (!list_empty(&mntinfo))
1880 return;
1881 if ((mnt = fopen("/proc/self/mountinfo", "r")) == (FILE*)0)
1882 return;
1883 while (fscanf(mnt, "%i %i %u:%u %*s %s %*[^\n]", &mid, &parid, &maj, &min, &mpoint[0]) == 5) {
1884 const size_t nlen = strlen(mpoint);
1885 mntinfo_t *restrict mnt;
1886 if (posix_memalign((void*)&mnt, sizeof(void*), alignof(mntinfo_t)+(nlen+1)) != 0) {
1887 fprintf(stderr, _("Cannot allocate memory for matched proc: %s\n"),
1888 strerror(errno));
1889 exit(1);
1890 }
1891 append(mnt, mntinfo);
1892 mnt->mpoint = ((char*)mnt)+alignof(mntinfo_t);
1893 strcpy(mnt->mpoint, mpoint);
1894 mnt->nlen = nlen;
1895 mnt->parid = parid;
1896 mnt->dev = makedev(maj, min);
1897 mnt->id = mid;
1898 if (mid > max)
1899 max = mid;
1900 }
1901 fclose(mnt);
1902
1903 /* Sort mount points accordingly to the reverse mount order */
1904 initial(&sort);
1905 for (mid = 1; mid <= max; mid++) {
1906 list_t *ptr, *tmp;
1907 list_for_each_safe(ptr, tmp, &mntinfo) {
1908 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
1909 if (mid != mnt->id)
1910 continue;
1911 move_head(ptr, &sort);
1912 break;
1913 }
1914 list_for_each_safe(ptr, tmp, &mntinfo) {
1915 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
1916 if (mid != mnt->parid)
1917 continue;
1918 move_head(ptr, &sort);
1919 }
1920 }
1921 if (!list_empty(&mntinfo)) {
1922 #ifdef EBADE
1923 errno = EBADE;
1924 #else
1925 errno = ENOENT;
1926 #endif /* EBADE */
1927 }
1928 join(&sort, &mntinfo);
1929 }
1930
1931 /*
1932 * Determine device of links below /proc/
1933 */
1934 static dev_t
device(const char * path)1935 device(const char * path)
1936 {
1937 char name[PATH_MAX+1];
1938 const char *use;
1939 ssize_t nlen;
1940 list_t *ptr;
1941
1942 if ((nlen = readlink(path, name, PATH_MAX)) < 0) {
1943 nlen = strlen(path);
1944 use = &path[0];
1945 } else {
1946 name[nlen] = '\0';
1947 use = &name[0];
1948 }
1949
1950 if (*use != '/') { /* special file (socket, pipe, inotify) */
1951 struct stat st;
1952 if (timeout(stat, path, &st, 5) != 0)
1953 return (dev_t)-1;
1954 return st.st_dev;
1955 }
1956
1957 list_for_each(ptr, &mntinfo) {
1958 mntinfo_t *mnt = list_entry(ptr, mntinfo_t);
1959 if (nlen < mnt->nlen)
1960 continue;
1961 if (mnt->nlen == 1) /* root fs is the last entry */
1962 return mnt->dev;
1963 if (use[mnt->nlen] != '\0' && use[mnt->nlen] != '/')
1964 continue;
1965 if (strncmp(use, mnt->mpoint, mnt->nlen) == 0)
1966 return mnt->dev;
1967 }
1968 return (dev_t)-1;
1969 }
1970 #endif /* _LISTS_H */
1971
1972 /*
1973 * Somehow the realpath(3) glibc function call, nevertheless
1974 * it avoids lstat(2) system calls.
1975 */
1976 static char real[PATH_MAX+1];
expandpath(const char * path)1977 char* expandpath(const char * path)
1978 {
1979 char tmpbuf[PATH_MAX+1];
1980 const char *start, *end;
1981 char *curr, *dest;
1982 int deep = MAXSYMLINKS;
1983
1984 if (!path || *path == '\0')
1985 return (char*)0;
1986
1987 curr = &real[0];
1988
1989 if (*path != '/') {
1990 if (!getcwd(curr, PATH_MAX))
1991 return (char*)0;
1992 #ifdef HAVE_RAWMEMCHR
1993 dest = rawmemchr(curr, '\0');
1994 #else
1995 dest = strchr(curr, '\0');
1996 #endif
1997 } else {
1998 *curr = '/';
1999 dest = curr + 1;
2000 }
2001
2002 for (start = end = path; *start; start = end) {
2003
2004 while (*start == '/')
2005 ++start;
2006
2007 for (end = start; *end && *end != '/'; ++end)
2008 ;
2009
2010 if (end - start == 0)
2011 break;
2012 else if (end - start == 1 && start[0] == '.') {
2013 ;
2014 } else if (end - start == 2 && start[0] == '.' && start[1] == '.') {
2015 if (dest > curr + 1)
2016 while ((--dest)[-1] != '/')
2017 ;
2018 } else {
2019 char lnkbuf[PATH_MAX+1];
2020 size_t len;
2021 ssize_t n;
2022
2023 if (dest[-1] != '/')
2024 *dest++ = '/';
2025
2026 if (dest + (end - start) > curr + PATH_MAX) {
2027 errno = ENAMETOOLONG;
2028 return (char*)0;
2029 }
2030
2031 dest = mempcpy(dest, start, end - start);
2032 *dest = '\0';
2033
2034 if (deep-- < 0) {
2035 errno = ELOOP;
2036 return (char*)0;
2037 }
2038
2039 errno = 0;
2040 if ((n = readlink(curr, lnkbuf, PATH_MAX)) < 0) {
2041 deep = MAXSYMLINKS;
2042 if (errno == EINVAL)
2043 continue; /* Not a symlink */
2044 return (char*)0;
2045 }
2046 lnkbuf[n] = '\0'; /* Don't be fooled by readlink(2) */
2047
2048 len = strlen(end);
2049 if ((n + len) > PATH_MAX) {
2050 errno = ENAMETOOLONG;
2051 return (char*)0;
2052 }
2053
2054 memmove(&tmpbuf[n], end, len + 1);
2055 path = end = memcpy(tmpbuf, lnkbuf, n);
2056
2057 if (lnkbuf[0] == '/')
2058 dest = curr + 1;
2059 else if (dest > curr + 1)
2060 while ((--dest)[-1] != '/');
2061
2062 }
2063 }
2064
2065 if (dest > curr + 1 && dest[-1] == '/')
2066 --dest;
2067 *dest = '\0';
2068
2069 return curr;
2070 }
2071