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