xref: /freebsd/usr.bin/systat/devs.c (revision 7bd6fde3)
1 /*
2  * Copyright (c) 1998 Kenneth D. Merry.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*-
29  * Copyright (c) 1980, 1992, 1993
30  *	The Regents of the University of California.  All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  * 1. Redistributions of source code must retain the above copyright
36  *    notice, this list of conditions and the following disclaimer.
37  * 2. Redistributions in binary form must reproduce the above copyright
38  *    notice, this list of conditions and the following disclaimer in the
39  *    documentation and/or other materials provided with the distribution.
40  * 3. All advertising materials mentioning features or use of this software
41  *    must display the following acknowledgement:
42  *	This product includes software developed by the University of
43  *	California, Berkeley and its contributors.
44  * 4. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  */
60 
61 #include <sys/cdefs.h>
62 
63 __FBSDID("$FreeBSD$");
64 
65 #ifdef lint
66 static const char sccsid[] = "@(#)disks.c	8.1 (Berkeley) 6/6/93";
67 #endif
68 
69 #include <sys/types.h>
70 #include <sys/devicestat.h>
71 #include <sys/resource.h>
72 
73 #include <ctype.h>
74 #include <devstat.h>
75 #include <err.h>
76 #include <stdlib.h>
77 #include <string.h>
78 
79 #include "systat.h"
80 #include "extern.h"
81 #include "devs.h"
82 
83 typedef enum {
84 	DS_MATCHTYPE_NONE,
85 	DS_MATCHTYPE_SPEC,
86 	DS_MATCHTYPE_PATTERN
87 } last_match_type;
88 
89 last_match_type last_type;
90 struct device_selection *dev_select;
91 long generation;
92 int num_devices, num_selected;
93 int num_selections;
94 long select_generation;
95 struct devstat_match *matches = NULL;
96 int num_matches = 0;
97 char **specified_devices;
98 int num_devices_specified = 0;
99 
100 static int dsmatchselect(const char *args, devstat_select_mode select_mode,
101 			 int maxshowdevs, struct statinfo *s1);
102 static int dsselect(const char *args, devstat_select_mode select_mode,
103 		    int maxshowdevs, struct statinfo *s1);
104 
105 int
106 dsinit(int maxshowdevs, struct statinfo *s1, struct statinfo *s2 __unused,
107        struct statinfo *s3 __unused)
108 {
109 
110 	/*
111 	 * Make sure that the userland devstat version matches the kernel
112 	 * devstat version.  If not, exit and print a message informing
113 	 * the user of his mistake.
114 	 */
115 	if (devstat_checkversion(NULL) < 0)
116 		errx(1, "%s", devstat_errbuf);
117 
118 	generation = 0;
119 	num_devices = 0;
120 	num_selected = 0;
121 	num_selections = 0;
122 	select_generation = 0;
123 	last_type = DS_MATCHTYPE_NONE;
124 
125 	if (devstat_getdevs(NULL, s1) == -1)
126 		errx(1, "%s", devstat_errbuf);
127 
128 	num_devices = s1->dinfo->numdevs;
129 	generation = s1->dinfo->generation;
130 
131 	dev_select = NULL;
132 
133 	/*
134 	 * At this point, selectdevs will almost surely indicate that the
135 	 * device list has changed, so we don't look for return values of 0
136 	 * or 1.  If we get back -1, though, there is an error.
137 	 */
138 	if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
139 	    &select_generation, generation, s1->dinfo->devices, num_devices,
140 	    NULL, 0, NULL, 0, DS_SELECT_ADD, maxshowdevs, 0) == -1)
141 		errx(1, "%d %s", __LINE__, devstat_errbuf);
142 
143 	return(1);
144 }
145 
146 int
147 dscmd(const char *cmd, const char *args, int maxshowdevs, struct statinfo *s1)
148 {
149 	int retval;
150 
151 	if (prefix(cmd, "display") || prefix(cmd, "add"))
152 		return(dsselect(args, DS_SELECT_ADDONLY, maxshowdevs, s1));
153 	if (prefix(cmd, "ignore") || prefix(cmd, "delete"))
154 		return(dsselect(args, DS_SELECT_REMOVE, maxshowdevs, s1));
155 	if (prefix(cmd, "show") || prefix(cmd, "only"))
156 		return(dsselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
157 	if (prefix(cmd, "type") || prefix(cmd, "match"))
158 		return(dsmatchselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
159 	if (prefix(cmd, "refresh")) {
160 		retval = devstat_selectdevs(&dev_select, &num_selected,
161 		    &num_selections, &select_generation, generation,
162 		    s1->dinfo->devices, num_devices,
163 		    (last_type ==DS_MATCHTYPE_PATTERN) ?  matches : NULL,
164 		    (last_type ==DS_MATCHTYPE_PATTERN) ?  num_matches : 0,
165 		    (last_type == DS_MATCHTYPE_SPEC) ?specified_devices : NULL,
166 		    (last_type == DS_MATCHTYPE_SPEC) ?num_devices_specified : 0,
167 		    (last_type == DS_MATCHTYPE_NONE) ?  DS_SELECT_ADD :
168 		    DS_SELECT_ADDONLY, maxshowdevs, 0);
169 		if (retval == -1) {
170 			warnx("%s", devstat_errbuf);
171 			return(0);
172 		} else if (retval == 1)
173 			return(2);
174 	}
175 	if (prefix(cmd, "drives")) {
176 		register int i;
177 		move(CMDLINE, 0);
178 		clrtoeol();
179 		for (i = 0; i < num_devices; i++) {
180 			printw("%s%d ", s1->dinfo->devices[i].device_name,
181 			       s1->dinfo->devices[i].unit_number);
182 		}
183 		return(1);
184 	}
185 	return(0);
186 }
187 
188 static int
189 dsmatchselect(const char *args, devstat_select_mode select_mode, int maxshowdevs,
190 	      struct statinfo *s1)
191 {
192 	char **tempstr, *tmpstr, *tmpstr1;
193 	char *tstr[100];
194 	int num_args = 0;
195 	int i;
196 	int retval = 0;
197 
198 	/*
199 	 * Break the (pipe delimited) input string out into separate
200 	 * strings.
201 	 */
202 	tmpstr = tmpstr1 = strdup(args);
203 	for (tempstr = tstr, num_args  = 0;
204 	     (*tempstr = strsep(&tmpstr1, "|")) != NULL && (num_args < 100);
205 	     num_args++)
206 		if (**tempstr != '\0')
207 			if (++tempstr >= &tstr[100])
208 				break;
209 	free(tmpstr);
210 
211 	if (num_args > 99) {
212 		warnx("dsmatchselect: too many match arguments");
213 		return(0);
214 	}
215 
216 	/*
217 	 * If we've gone through the matching code before, clean out
218 	 * previously used memory.
219 	 */
220 	if (num_matches > 0) {
221 		free(matches);
222 		matches = NULL;
223 		num_matches = 0;
224 	}
225 
226 	for (i = 0; i < num_args; i++) {
227 		if (devstat_buildmatch(tstr[i], &matches, &num_matches) != 0) {
228 			warnx("%s", devstat_errbuf);
229 			return(0);
230 		}
231 	}
232 	if (num_args > 0) {
233 
234 		last_type = DS_MATCHTYPE_PATTERN;
235 
236 		retval = devstat_selectdevs(&dev_select, &num_selected,
237 		    &num_selections, &select_generation, generation,
238 		    s1->dinfo->devices, num_devices, matches, num_matches,
239 		    NULL, 0, select_mode, maxshowdevs, 0);
240 		if (retval == -1)
241 			err(1, "device selection error");
242 		else if (retval == 1)
243 			return(2);
244 	}
245 	return(1);
246 }
247 
248 static int
249 dsselect(const char *args, devstat_select_mode select_mode, int maxshowdevs,
250 	 struct statinfo *s1)
251 {
252 	char *cp, *tmpstr, *tmpstr1, *buffer;
253 	int i;
254 	int retval = 0;
255 
256 	/*
257 	 * If we've gone through this code before, free previously
258 	 * allocated resources.
259 	 */
260 	if (num_devices_specified > 0) {
261 		for (i = 0; i < num_devices_specified; i++)
262 			free(specified_devices[i]);
263 		free(specified_devices);
264 		specified_devices = NULL;
265 		num_devices_specified = 0;
266 	}
267 
268 	/* do an initial malloc */
269 	specified_devices = (char **)malloc(sizeof(char *));
270 
271 	tmpstr = tmpstr1 = strdup(args);
272 	cp = index(tmpstr1, '\n');
273 	if (cp)
274 		*cp = '\0';
275 	for (;;) {
276 		for (cp = tmpstr1; *cp && isspace(*cp); cp++)
277 			;
278 		tmpstr1 = cp;
279 		for (; *cp && !isspace(*cp); cp++)
280 			;
281 		if (*cp)
282 			*cp++ = '\0';
283 		if (cp - args == 0)
284 			break;
285 		for (i = 0; i < num_devices; i++) {
286 			asprintf(&buffer, "%s%d", dev_select[i].device_name,
287 				dev_select[i].unit_number);
288 			if (strcmp(buffer, tmpstr1) == 0) {
289 
290 				num_devices_specified++;
291 
292 				specified_devices =(char **)realloc(
293 						specified_devices,
294 						sizeof(char *) *
295 						num_devices_specified);
296 				specified_devices[num_devices_specified -1]=
297 					strdup(tmpstr1);
298 				free(buffer);
299 
300 				break;
301 			}
302 			else
303 				free(buffer);
304 		}
305 		if (i >= num_devices)
306 			error("%s: unknown drive", args);
307 		args = cp;
308 	}
309 	free(tmpstr);
310 
311 	if (num_devices_specified > 0) {
312 		last_type = DS_MATCHTYPE_SPEC;
313 
314 		retval = devstat_selectdevs(&dev_select, &num_selected,
315 		    &num_selections, &select_generation, generation,
316 		    s1->dinfo->devices, num_devices, NULL, 0,
317 		    specified_devices, num_devices_specified,
318 		    select_mode, maxshowdevs, 0);
319 		if (retval == -1)
320 			err(1, "%s", devstat_errbuf);
321 		else if (retval == 1)
322 			return(2);
323 	}
324 	return(1);
325 }
326