xref: /haiku/src/bin/fdinfo.cpp (revision d52bb3081c38f29a6d962260a7f3200923ad58a2)
1 /*
2  * Copyright 2006-2015, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Author:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include <OS.h>
11 #include <fs_info.h>
12 
13 #include <syscalls.h>
14 #include <vfs_defs.h>
15 
16 #include <ctype.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 
23 enum info_mode {
24 	kList,
25 	kFilterDevice,
26 	kFilterFile,
27 };
28 
29 extern const char *__progname;
30 
31 
32 const char *
open_mode_to_string(int openMode)33 open_mode_to_string(int openMode)
34 {
35 	switch (openMode & O_RWMASK) {
36 		case O_RDONLY:
37 			return "R  ";
38 		case O_WRONLY:
39 			return "  W";
40 		default:
41 			return "R/W";
42 	}
43 }
44 
45 
46 void
print_fds(team_info & teamInfo)47 print_fds(team_info &teamInfo)
48 {
49 	printf("Team: (%" B_PRId32 ") %s\n", teamInfo.team, teamInfo.args);
50 
51 	uint32 cookie = 0;
52 	fd_info info;
53 
54 	while (_kern_get_next_fd_info(teamInfo.team, &cookie, &info, sizeof(fd_info)) == B_OK) {
55 		printf("%5d  %s %" B_PRIdDEV ":%" B_PRIdINO "\n", info.number,
56 			open_mode_to_string(info.open_mode), info.device, info.node);
57 	}
58 }
59 
60 
61 void
filter_device(team_info & teamInfo,dev_t device,bool brief)62 filter_device(team_info &teamInfo, dev_t device, bool brief)
63 {
64 	uint32 cookie = 0;
65 	fd_info info;
66 
67 	while (_kern_get_next_fd_info(teamInfo.team, &cookie, &info, sizeof(fd_info)) == B_OK) {
68 		if (info.device != device)
69 			continue;
70 
71 		if (brief) {
72 			printf("%5" B_PRId32 " %s\n", teamInfo.team, teamInfo.args);
73 			break;
74 		}
75 
76 		printf("%5" B_PRId32 " %3d  %3s  %" B_PRIdDEV ":%" B_PRIdINO " %s\n",
77 			teamInfo.team, info.number, open_mode_to_string(info.open_mode),
78 				info.device, info.node, teamInfo.args);
79 	}
80 }
81 
82 
83 void
filter_file(team_info & teamInfo,dev_t device,ino_t node,bool brief)84 filter_file(team_info &teamInfo, dev_t device, ino_t node, bool brief)
85 {
86 	uint32 cookie = 0;
87 	fd_info info;
88 
89 	while (_kern_get_next_fd_info(teamInfo.team, &cookie, &info, sizeof(fd_info)) == B_OK) {
90 		if (info.device != device || info.node != node)
91 			continue;
92 
93 		if (brief) {
94 			printf("%5" B_PRId32 " %s\n", teamInfo.team, teamInfo.args);
95 			break;
96 		}
97 
98 		printf("%5" B_PRId32 " %3d  %3s  %s\n", teamInfo.team, info.number,
99 			open_mode_to_string(info.open_mode), teamInfo.args);
100 	}
101 }
102 
103 
104 void
usage(bool failure)105 usage(bool failure)
106 {
107 	printf("Usage: %s <id/pattern> or -[dD] <path-to-device> or -[fF] <file>\n"
108 		"  Shows info about the used file descriptors in the system.\n\n"
109 		"  -d\tOnly shows accesses to the given device\n"
110 		"  -D\tLikewise, but only shows the teams that access it\n"
111 		"  -f\tOnly shows accesses to the given file\n"
112 		"  -F\tLikewise, but only shows the teams that access it\n",
113 		__progname);
114 
115 	exit(failure ? 1 : 0);
116 }
117 
118 
119 int
main(int argc,char ** argv)120 main(int argc, char **argv)
121 {
122 	const char *pattern = NULL;
123 	dev_t device = -1;
124 	ino_t node = -1;
125 	int32 id = -1;
126 	info_mode mode = kList;
127 	bool brief = false;
128 
129 	// parse arguments
130 
131 	if (argc == 2) {
132 		// filter output
133 		if (isdigit(argv[1][0]))
134 			id = atol(argv[1]);
135 		else if (argv[1][0] == '-')
136 			usage(!strcmp(argv[1], "--help"));
137 		else
138 			pattern = argv[1];
139 	} else if (argc > 2) {
140 		if (!strcmp(argv[1], "-d") || !strcmp(argv[1], "-D")) {
141 			// filter by device usage
142 			device = dev_for_path(argv[2]);
143 			if (device < 0) {
144 				fprintf(stderr, "%s: could not find device: %s\n", __progname,
145 					strerror(errno));
146 				return 1;
147 			}
148 			mode = kFilterDevice;
149 			if (argv[1][1] == 'D')
150 				brief = true;
151 		} else if (!strcmp(argv[1], "-f") || !strcmp(argv[1], "-F")) {
152 			// filter by file usage
153 			struct stat stat;
154 			if (::stat(argv[2], &stat) < 0) {
155 				fprintf(stderr, "%s: could not open file: %s\n", __progname,
156 					strerror(errno));
157 				return 1;
158 			}
159 			device = stat.st_dev;
160 			node = stat.st_ino;
161 			mode = kFilterFile;
162 			if (argv[1][1] == 'F')
163 				brief = true;
164 		} else
165 			usage(true);
166 	}
167 
168 	// do the job!
169 
170 	team_info info;
171 	int32 cookie = 0;
172 
173 	while (get_next_team_info(&cookie, &info) == B_OK) {
174 		switch (mode) {
175 			case kList:
176 				if ((id != -1 && id != info.team)
177 					|| (pattern != NULL && !strstr(info.args, pattern)))
178 					continue;
179 				print_fds(info);
180 				break;
181 
182 			case kFilterDevice:
183 				filter_device(info, device, brief);
184 				break;
185 			case kFilterFile:
186 				filter_file(info, device, node, brief);
187 				break;
188 		}
189 	}
190 
191 	return 0;
192 }
193 
194