139230Sgibbs/*
239230Sgibbs * Copyright (c) 1998 Kenneth D. Merry.
339230Sgibbs * All rights reserved.
439230Sgibbs *
539230Sgibbs * Redistribution and use in source and binary forms, with or without
639230Sgibbs * modification, are permitted provided that the following conditions
739230Sgibbs * are met:
839230Sgibbs * 1. Redistributions of source code must retain the above copyright
939230Sgibbs *    notice, this list of conditions and the following disclaimer.
1039230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1139230Sgibbs *    notice, this list of conditions and the following disclaimer in the
1239230Sgibbs *    documentation and/or other materials provided with the distribution.
1339230Sgibbs * 3. The name of the author may not be used to endorse or promote products
1439230Sgibbs *    derived from this software without specific prior written permission.
1539230Sgibbs *
1639230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939230Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2039230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639230Sgibbs * SUCH DAMAGE.
2739230Sgibbs */
2839230Sgibbs/*-
2939230Sgibbs * Copyright (c) 1980, 1992, 1993
3039230Sgibbs *	The Regents of the University of California.  All rights reserved.
3139230Sgibbs *
3239230Sgibbs * Redistribution and use in source and binary forms, with or without
3339230Sgibbs * modification, are permitted provided that the following conditions
3439230Sgibbs * are met:
3539230Sgibbs * 1. Redistributions of source code must retain the above copyright
3639230Sgibbs *    notice, this list of conditions and the following disclaimer.
3739230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
3839230Sgibbs *    notice, this list of conditions and the following disclaimer in the
3939230Sgibbs *    documentation and/or other materials provided with the distribution.
4039230Sgibbs * 4. Neither the name of the University nor the names of its contributors
4139230Sgibbs *    may be used to endorse or promote products derived from this software
4239230Sgibbs *    without specific prior written permission.
4339230Sgibbs *
4439230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4539230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4639230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4739230Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
4839230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4939230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5039230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5139230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5239230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5339230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5439230Sgibbs * SUCH DAMAGE.
5539230Sgibbs */
5639230Sgibbs
5787715Smarkm#include <sys/cdefs.h>
5887715Smarkm
5987715Smarkm__FBSDID("$FreeBSD$");
6087715Smarkm
6187715Smarkm#ifdef lint
6287715Smarkmstatic const char sccsid[] = "@(#)disks.c	8.1 (Berkeley) 6/6/93";
6387715Smarkm#endif
6487715Smarkm
6539230Sgibbs#include <sys/types.h>
6639230Sgibbs#include <sys/devicestat.h>
67111007Sphk#include <sys/resource.h>
6839230Sgibbs
6987715Smarkm#include <ctype.h>
7039230Sgibbs#include <devstat.h>
7187715Smarkm#include <err.h>
7240060Sobrien#include <stdlib.h>
7387715Smarkm#include <string.h>
7487715Smarkm
7539230Sgibbs#include "systat.h"
7639230Sgibbs#include "extern.h"
7740060Sobrien#include "devs.h"
7839230Sgibbs
7939230Sgibbstypedef enum {
8039230Sgibbs	DS_MATCHTYPE_NONE,
8139230Sgibbs	DS_MATCHTYPE_SPEC,
8239230Sgibbs	DS_MATCHTYPE_PATTERN
8339230Sgibbs} last_match_type;
8439230Sgibbs
8539230Sgibbslast_match_type last_type;
8639230Sgibbsstruct device_selection *dev_select;
8739498Skenlong generation;
8839498Skenint num_devices, num_selected;
8939498Skenint num_selections;
9039498Skenlong select_generation;
9139230Sgibbsstruct devstat_match *matches = NULL;
9239230Sgibbsint num_matches = 0;
9339230Sgibbschar **specified_devices;
9439230Sgibbsint num_devices_specified = 0;
9539230Sgibbs
9687715Smarkmstatic int dsmatchselect(const char *args, devstat_select_mode select_mode,
9739230Sgibbs			 int maxshowdevs, struct statinfo *s1);
9887715Smarkmstatic int dsselect(const char *args, devstat_select_mode select_mode,
9939230Sgibbs		    int maxshowdevs, struct statinfo *s1);
10039230Sgibbs
10139230Sgibbsint
10287715Smarkmdsinit(int maxshowdevs, struct statinfo *s1, struct statinfo *s2 __unused,
10387715Smarkm       struct statinfo *s3 __unused)
10439230Sgibbs{
10539230Sgibbs
10639230Sgibbs	/*
10739230Sgibbs	 * Make sure that the userland devstat version matches the kernel
108226396Sed	 * devstat version.  If not, exit and print a message informing
10939230Sgibbs	 * the user of his mistake.
11039230Sgibbs	 */
11183131Sken	if (devstat_checkversion(NULL) < 0)
11239230Sgibbs		errx(1, "%s", devstat_errbuf);
11339230Sgibbs
11439230Sgibbs	generation = 0;
11539230Sgibbs	num_devices = 0;
11639230Sgibbs	num_selected = 0;
11739230Sgibbs	num_selections = 0;
11839230Sgibbs	select_generation = 0;
11939230Sgibbs	last_type = DS_MATCHTYPE_NONE;
12039230Sgibbs
12183131Sken	if (devstat_getdevs(NULL, s1) == -1)
12239230Sgibbs		errx(1, "%s", devstat_errbuf);
12339230Sgibbs
12439230Sgibbs	num_devices = s1->dinfo->numdevs;
12539230Sgibbs	generation = s1->dinfo->generation;
12639230Sgibbs
12739230Sgibbs	dev_select = NULL;
12839230Sgibbs
12939230Sgibbs	/*
13039230Sgibbs	 * At this point, selectdevs will almost surely indicate that the
13139230Sgibbs	 * device list has changed, so we don't look for return values of 0
13239230Sgibbs	 * or 1.  If we get back -1, though, there is an error.
13339230Sgibbs	 */
13483131Sken	if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
13583131Sken	    &select_generation, generation, s1->dinfo->devices, num_devices,
13683131Sken	    NULL, 0, NULL, 0, DS_SELECT_ADD, maxshowdevs, 0) == -1)
137121291Sphk		errx(1, "%d %s", __LINE__, devstat_errbuf);
13839230Sgibbs
13939230Sgibbs	return(1);
14039230Sgibbs}
14139230Sgibbs
14239230Sgibbsint
14387715Smarkmdscmd(const char *cmd, const char *args, int maxshowdevs, struct statinfo *s1)
14439230Sgibbs{
14539230Sgibbs	int retval;
14639230Sgibbs
14739230Sgibbs	if (prefix(cmd, "display") || prefix(cmd, "add"))
14839230Sgibbs		return(dsselect(args, DS_SELECT_ADDONLY, maxshowdevs, s1));
14939230Sgibbs	if (prefix(cmd, "ignore") || prefix(cmd, "delete"))
15039230Sgibbs		return(dsselect(args, DS_SELECT_REMOVE, maxshowdevs, s1));
15139230Sgibbs	if (prefix(cmd, "show") || prefix(cmd, "only"))
15239230Sgibbs		return(dsselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
15339230Sgibbs	if (prefix(cmd, "type") || prefix(cmd, "match"))
15439230Sgibbs		return(dsmatchselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
15539230Sgibbs	if (prefix(cmd, "refresh")) {
15683131Sken		retval = devstat_selectdevs(&dev_select, &num_selected,
15783131Sken		    &num_selections, &select_generation, generation,
158226396Sed		    s1->dinfo->devices, num_devices,
15983131Sken		    (last_type ==DS_MATCHTYPE_PATTERN) ?  matches : NULL,
16083131Sken		    (last_type ==DS_MATCHTYPE_PATTERN) ?  num_matches : 0,
161226396Sed		    (last_type == DS_MATCHTYPE_SPEC) ?specified_devices : NULL,
16283131Sken		    (last_type == DS_MATCHTYPE_SPEC) ?num_devices_specified : 0,
16383131Sken		    (last_type == DS_MATCHTYPE_NONE) ?  DS_SELECT_ADD :
16483131Sken		    DS_SELECT_ADDONLY, maxshowdevs, 0);
16539230Sgibbs		if (retval == -1) {
16639230Sgibbs			warnx("%s", devstat_errbuf);
16739230Sgibbs			return(0);
16839230Sgibbs		} else if (retval == 1)
16939230Sgibbs			return(2);
17039230Sgibbs	}
17139230Sgibbs	if (prefix(cmd, "drives")) {
172175387Sdelphij		int i;
17339230Sgibbs		move(CMDLINE, 0);
17439230Sgibbs		clrtoeol();
17539230Sgibbs		for (i = 0; i < num_devices; i++) {
17639230Sgibbs			printw("%s%d ", s1->dinfo->devices[i].device_name,
17739230Sgibbs			       s1->dinfo->devices[i].unit_number);
17839230Sgibbs		}
17939230Sgibbs		return(1);
18039230Sgibbs	}
18139230Sgibbs	return(0);
18239230Sgibbs}
18339230Sgibbs
18439230Sgibbsstatic int
18587715Smarkmdsmatchselect(const char *args, devstat_select_mode select_mode, int maxshowdevs,
18639230Sgibbs	      struct statinfo *s1)
18739230Sgibbs{
18887715Smarkm	char **tempstr, *tmpstr, *tmpstr1;
18939230Sgibbs	char *tstr[100];
19039230Sgibbs	int num_args = 0;
19187715Smarkm	int i;
19239230Sgibbs	int retval = 0;
19339230Sgibbs
19439230Sgibbs	/*
19539230Sgibbs	 * Break the (pipe delimited) input string out into separate
19639230Sgibbs	 * strings.
19739230Sgibbs	 */
19887715Smarkm	tmpstr = tmpstr1 = strdup(args);
19939230Sgibbs	for (tempstr = tstr, num_args  = 0;
20087715Smarkm	     (*tempstr = strsep(&tmpstr1, "|")) != NULL && (num_args < 100);
20139230Sgibbs	     num_args++)
20239230Sgibbs		if (**tempstr != '\0')
20339230Sgibbs			if (++tempstr >= &tstr[100])
20439230Sgibbs				break;
20587715Smarkm	free(tmpstr);
20639230Sgibbs
20739230Sgibbs	if (num_args > 99) {
20839230Sgibbs		warnx("dsmatchselect: too many match arguments");
20939230Sgibbs		return(0);
21039230Sgibbs	}
21139230Sgibbs
21239230Sgibbs	/*
21339230Sgibbs	 * If we've gone through the matching code before, clean out
21439230Sgibbs	 * previously used memory.
21539230Sgibbs	 */
21639230Sgibbs	if (num_matches > 0) {
21739230Sgibbs		free(matches);
21839230Sgibbs		matches = NULL;
21939230Sgibbs		num_matches = 0;
22039230Sgibbs	}
22139230Sgibbs
22239230Sgibbs	for (i = 0; i < num_args; i++) {
223226396Sed		if (devstat_buildmatch(tstr[i], &matches, &num_matches) != 0) {
22439230Sgibbs			warnx("%s", devstat_errbuf);
22539230Sgibbs			return(0);
22639230Sgibbs		}
22739230Sgibbs	}
22839230Sgibbs	if (num_args > 0) {
22939230Sgibbs
23039230Sgibbs		last_type = DS_MATCHTYPE_PATTERN;
23139230Sgibbs
23283131Sken		retval = devstat_selectdevs(&dev_select, &num_selected,
23383131Sken		    &num_selections, &select_generation, generation,
23483131Sken		    s1->dinfo->devices, num_devices, matches, num_matches,
23583131Sken		    NULL, 0, select_mode, maxshowdevs, 0);
23639230Sgibbs		if (retval == -1)
23739230Sgibbs			err(1, "device selection error");
23839230Sgibbs		else if (retval == 1)
23939230Sgibbs			return(2);
24039230Sgibbs	}
24139230Sgibbs	return(1);
24239230Sgibbs}
24339230Sgibbs
24439230Sgibbsstatic int
24587715Smarkmdsselect(const char *args, devstat_select_mode select_mode, int maxshowdevs,
24639230Sgibbs	 struct statinfo *s1)
24739230Sgibbs{
24887715Smarkm	char *cp, *tmpstr, *tmpstr1, *buffer;
24987715Smarkm	int i;
25039230Sgibbs	int retval = 0;
25139230Sgibbs
25239230Sgibbs	/*
25339230Sgibbs	 * If we've gone through this code before, free previously
25439230Sgibbs	 * allocated resources.
25539230Sgibbs	 */
25639230Sgibbs	if (num_devices_specified > 0) {
25739230Sgibbs		for (i = 0; i < num_devices_specified; i++)
25839230Sgibbs			free(specified_devices[i]);
25939230Sgibbs		free(specified_devices);
26039230Sgibbs		specified_devices = NULL;
26139230Sgibbs		num_devices_specified = 0;
26239230Sgibbs	}
26339230Sgibbs
26439230Sgibbs	/* do an initial malloc */
26539230Sgibbs	specified_devices = (char **)malloc(sizeof(char *));
26639230Sgibbs
26787715Smarkm	tmpstr = tmpstr1 = strdup(args);
268229403Sed	cp = strchr(tmpstr1, '\n');
26939230Sgibbs	if (cp)
27039230Sgibbs		*cp = '\0';
27139230Sgibbs	for (;;) {
27287715Smarkm		for (cp = tmpstr1; *cp && isspace(*cp); cp++)
27339230Sgibbs			;
27487715Smarkm		tmpstr1 = cp;
27539230Sgibbs		for (; *cp && !isspace(*cp); cp++)
27639230Sgibbs			;
27739230Sgibbs		if (*cp)
27839230Sgibbs			*cp++ = '\0';
27939230Sgibbs		if (cp - args == 0)
28039230Sgibbs			break;
28139230Sgibbs		for (i = 0; i < num_devices; i++) {
28287715Smarkm			asprintf(&buffer, "%s%d", dev_select[i].device_name,
28339230Sgibbs				dev_select[i].unit_number);
28487715Smarkm			if (strcmp(buffer, tmpstr1) == 0) {
285226396Sed
28639230Sgibbs				num_devices_specified++;
28739230Sgibbs
28839230Sgibbs				specified_devices =(char **)realloc(
28939230Sgibbs						specified_devices,
29039230Sgibbs						sizeof(char *) *
29139230Sgibbs						num_devices_specified);
29239230Sgibbs				specified_devices[num_devices_specified -1]=
29387715Smarkm					strdup(tmpstr1);
29487715Smarkm				free(buffer);
29539230Sgibbs
29639230Sgibbs				break;
29739230Sgibbs			}
29887715Smarkm			else
29987715Smarkm				free(buffer);
30039230Sgibbs		}
30139230Sgibbs		if (i >= num_devices)
30239230Sgibbs			error("%s: unknown drive", args);
30339230Sgibbs		args = cp;
30439230Sgibbs	}
30587715Smarkm	free(tmpstr);
30639230Sgibbs
30739230Sgibbs	if (num_devices_specified > 0) {
30839230Sgibbs		last_type = DS_MATCHTYPE_SPEC;
30939230Sgibbs
31083131Sken		retval = devstat_selectdevs(&dev_select, &num_selected,
31183131Sken		    &num_selections, &select_generation, generation,
31283131Sken		    s1->dinfo->devices, num_devices, NULL, 0,
31383131Sken		    specified_devices, num_devices_specified,
31483131Sken		    select_mode, maxshowdevs, 0);
31539230Sgibbs		if (retval == -1)
31639230Sgibbs			err(1, "%s", devstat_errbuf);
31739230Sgibbs		else if (retval == 1)
31839230Sgibbs			return(2);
31939230Sgibbs	}
32039230Sgibbs	return(1);
32139230Sgibbs}
322