gcc47 build fixes: Unused-but-set-variable + more warnings
[dragonfly.git] / lib / libdevstat / devstat.c
1 /*
2  * Copyright (c) 1997, 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  * $FreeBSD: src/lib/libdevstat/devstat.c,v 1.6 1999/08/28 00:04:26 peter Exp $
29  * $DragonFly: src/lib/libdevstat/devstat.c,v 1.5 2005/01/08 19:19:26 joerg Exp $
30  */
31
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
34 #include <sys/errno.h>
35
36 #include <ctype.h>
37 #include <err.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "devstat.h"
43
44 char devstat_errbuf[DEVSTAT_ERRBUF_SIZE];
45
46 /*
47  * Table to match descriptive strings with device types.  These are in
48  * order from most common to least common to speed search time.
49  */
50 struct devstat_match_table match_table[] = {
51         {"da",          DEVSTAT_TYPE_DIRECT,    DEVSTAT_MATCH_TYPE},
52         {"cd",          DEVSTAT_TYPE_CDROM,     DEVSTAT_MATCH_TYPE},
53         {"scsi",        DEVSTAT_TYPE_IF_SCSI,   DEVSTAT_MATCH_IF},
54         {"ide",         DEVSTAT_TYPE_IF_IDE,    DEVSTAT_MATCH_IF},
55         {"other",       DEVSTAT_TYPE_IF_OTHER,  DEVSTAT_MATCH_IF},
56         {"worm",        DEVSTAT_TYPE_WORM,      DEVSTAT_MATCH_TYPE},
57         {"sa",          DEVSTAT_TYPE_SEQUENTIAL,DEVSTAT_MATCH_TYPE},
58         {"pass",        DEVSTAT_TYPE_PASS,      DEVSTAT_MATCH_PASS},
59         {"optical",     DEVSTAT_TYPE_OPTICAL,   DEVSTAT_MATCH_TYPE},
60         {"array",       DEVSTAT_TYPE_STORARRAY, DEVSTAT_MATCH_TYPE},
61         {"changer",     DEVSTAT_TYPE_CHANGER,   DEVSTAT_MATCH_TYPE},
62         {"scanner",     DEVSTAT_TYPE_SCANNER,   DEVSTAT_MATCH_TYPE},
63         {"printer",     DEVSTAT_TYPE_PRINTER,   DEVSTAT_MATCH_TYPE},
64         {"floppy",      DEVSTAT_TYPE_FLOPPY,    DEVSTAT_MATCH_TYPE},
65         {"proc",        DEVSTAT_TYPE_PROCESSOR, DEVSTAT_MATCH_TYPE},
66         {"comm",        DEVSTAT_TYPE_COMM,      DEVSTAT_MATCH_TYPE},
67         {"enclosure",   DEVSTAT_TYPE_ENCLOSURE, DEVSTAT_MATCH_TYPE},
68         {NULL,          0,                      0}
69 };
70
71 /*
72  * Local function declarations.
73  */
74 static int compare_select(const void *arg1, const void *arg2);
75
76 int
77 getnumdevs(void)
78 {
79         size_t numdevsize;
80         int numdevs;
81         const char *func_name = "getnumdevs";
82
83         numdevsize = sizeof(int);
84
85         /*
86          * Find out how many devices we have in the system.
87          */
88         if (sysctlbyname("kern.devstat.numdevs", &numdevs,
89                          &numdevsize, NULL, 0) == -1) {
90                 sprintf(devstat_errbuf, "%s: error getting number of devices\n"
91                         "%s: %s", func_name, func_name, strerror(errno));
92                 return(-1);
93         } else
94                 return(numdevs);
95 }
96
97 /*
98  * This is an easy way to get the generation number, but the generation is
99  * supplied in a more atmoic manner by the kern.devstat.all sysctl.
100  * Because this generation sysctl is separate from the statistics sysctl,
101  * the device list and the generation could change between the time that
102  * this function is called and the device list is retreived.
103  */
104 long
105 getgeneration(void)
106 {
107         size_t gensize;
108         long generation;
109         const char *func_name = "getgeneration";
110
111         gensize = sizeof(long);
112
113         /*
114          * Get the current generation number.
115          */
116         if (sysctlbyname("kern.devstat.generation", &generation, 
117                          &gensize, NULL, 0) == -1) {
118                 sprintf(devstat_errbuf,"%s: error getting devstat generation\n"
119                         "%s: %s", func_name, func_name, strerror(errno));
120                 return(-1);
121         } else
122                 return(generation);
123 }
124
125 /*
126  * Get the current devstat version.  The return value of this function
127  * should be compared with DEVSTAT_VERSION, which is defined in
128  * sys/devicestat.h.  This will enable userland programs to determine
129  * whether they are out of sync with the kernel.
130  */
131 int
132 getversion(void)
133 {
134         size_t versize;
135         int version;
136         const char *func_name = "getversion";
137
138         versize = sizeof(int);
139
140         /*
141          * Get the current devstat version.
142          */
143         if (sysctlbyname("kern.devstat.version", &version, &versize,
144                          NULL, 0) == -1) {
145                 sprintf(devstat_errbuf, "%s: error getting devstat version\n"
146                         "%s: %s", func_name, func_name, strerror(errno));
147                 return(-1);
148         } else
149                 return(version);
150 }
151
152 /*
153  * Check the devstat version we know about against the devstat version the
154  * kernel knows about.  If they don't match, print an error into the
155  * devstat error buffer, and return -1.  If they match, return 0.
156  */
157 int
158 checkversion(void)
159 {
160         int retval = 0;
161         int errlen = 0;
162         const char *func_name = "checkversion";
163         int version;
164
165         version = getversion();
166
167         if (version != DEVSTAT_VERSION) {
168                 int buflen = 0;
169                 char tmpstr[256];
170
171                 /*
172                  * This is really pretty silly, but basically the idea is
173                  * that if getversion() returns an error (i.e. -1), then it
174                  * has printed an error message in the buffer.  Therefore,
175                  * we need to add a \n to the end of that message before we
176                  * print our own message in the buffer.
177                  */
178                 if (version == -1) {
179                         buflen = strlen(devstat_errbuf);
180                         errlen = snprintf(tmpstr, sizeof(tmpstr), "\n");
181                         strncat(devstat_errbuf, tmpstr,
182                                 DEVSTAT_ERRBUF_SIZE - buflen - 1);
183                         buflen += errlen;
184                 }
185
186                 errlen = snprintf(tmpstr, sizeof(tmpstr),
187                                   "%s: userland devstat version %d is not "
188                                   "the same as the kernel\n%s: devstat "
189                                   "version %d\n", func_name, DEVSTAT_VERSION,
190                                   func_name, version);
191
192                 if (version == -1) {
193                         strncat(devstat_errbuf, tmpstr,
194                                 DEVSTAT_ERRBUF_SIZE - buflen - 1);
195                         buflen += errlen;
196                 } else {
197                         strncpy(devstat_errbuf, tmpstr, DEVSTAT_ERRBUF_SIZE);
198                         devstat_errbuf[DEVSTAT_ERRBUF_SIZE - 1] = '\0';
199                 }
200
201                 if (version < DEVSTAT_VERSION)
202                         snprintf(tmpstr, sizeof(tmpstr),
203                                  "%s: libdevstat newer than kernel\n",
204                                  func_name);
205                 else
206                         snprintf(tmpstr, sizeof(tmpstr),
207                                  "%s: kernel newer than libdevstat\n",
208                                  func_name);
209
210                 strncat(devstat_errbuf, tmpstr,
211                         DEVSTAT_ERRBUF_SIZE - buflen - 1);
212
213                 retval = -1;
214         }
215
216         return(retval);
217 }
218
219 /*
220  * Get the current list of devices and statistics, and the current
221  * generation number.
222  * 
223  * Return values:
224  * -1  -- error
225  *  0  -- device list is unchanged
226  *  1  -- device list has changed
227  */
228 int
229 getdevs(struct statinfo *stats)
230 {
231         int error;
232         size_t dssize;
233         long oldgeneration;
234         int retval = 0;
235         struct devinfo *dinfo;
236         const char *func_name = "getdevs";
237
238         dinfo = stats->dinfo;
239
240         if (dinfo == NULL) {
241                 sprintf(devstat_errbuf, "%s: stats->dinfo was NULL", func_name);
242                 return(-1);
243         }
244
245         oldgeneration = dinfo->generation;
246
247         /*
248          * If this is our first time through, mem_ptr will be null.  
249          */
250         if (dinfo->mem_ptr == NULL) {
251                 /*
252                  * Get the number of devices.  If it's negative, it's an
253                  * error.  Don't bother setting the error string, since
254                  * getnumdevs() has already done that for us.
255                  */
256                 if ((dinfo->numdevs = getnumdevs()) < 0)
257                         return(-1);
258
259                 /*
260                  * The kern.devstat.all sysctl returns the current generation
261                  * number, as well as all the devices.  So we need four
262                  * bytes more.
263                  */
264                 dssize =(dinfo->numdevs * sizeof(struct devstat)) +sizeof(long);
265                 dinfo->mem_ptr = (u_int8_t *)malloc(dssize);
266         } else
267                 dssize =(dinfo->numdevs * sizeof(struct devstat)) +sizeof(long);
268
269         /* Get the current time when we get the stats */
270         gettimeofday(&stats->busy_time, NULL);
271
272         /*
273          * Request all of the devices.  We only really allow for one
274          * ENOMEM failure.  It would, of course, be possible to just go in
275          * a loop and keep reallocing the device structure until we don't
276          * get ENOMEM back.  I'm not sure it's worth it, though.  If
277          * devices are being added to the system that quickly, maybe the
278          * user can just wait until all devices are added.
279          */
280         if ((error = sysctlbyname("kern.devstat.all", dinfo->mem_ptr, 
281              &dssize, NULL, 0)) == -1) {
282                 /*
283                  * If we get ENOMEM back, that means that there are 
284                  * more devices now, so we need to allocate more 
285                  * space for the device array.
286                  */
287                 if (errno == ENOMEM) {
288                         /*
289                          * No need to set the error string here, getnumdevs()
290                          * will do that if it fails.
291                          */
292                         if ((dinfo->numdevs = getnumdevs()) < 0)
293                                 return(-1);
294
295                         dssize = (dinfo->numdevs * sizeof(struct devstat)) +
296                                 sizeof(long);
297                         dinfo->mem_ptr = (u_int8_t *)realloc(dinfo->mem_ptr,
298                                                              dssize);
299                         if ((error = sysctlbyname("kern.devstat.all", 
300                             dinfo->mem_ptr, &dssize, NULL, 0)) == -1) {
301                                 sprintf(devstat_errbuf,
302                                         "%s: error getting device stats\n"
303                                         "%s: %s", func_name, func_name,
304                                         strerror(errno));
305                                 return(-1);
306                         }
307                 } else {
308                         sprintf(devstat_errbuf,
309                                 "%s: error getting device stats\n"
310                                 "%s: %s", func_name, func_name,
311                                 strerror(errno));
312                         return(-1);
313                 }
314         } 
315
316         /*
317          * The sysctl spits out the generation as the first four bytes,
318          * then all of the device statistics structures.
319          */
320         dinfo->generation = *(long *)dinfo->mem_ptr;
321
322         /*
323          * If the generation has changed, and if the current number of
324          * devices is not the same as the number of devices recorded in the
325          * devinfo structure, it is likely that the device list has shrunk.
326          * The reason that it is likely that the device list has shrunk in
327          * this case is that if the device list has grown, the sysctl above
328          * will return an ENOMEM error, and we will reset the number of
329          * devices and reallocate the device array.  If the second sysctl
330          * fails, we will return an error and therefore never get to this
331          * point.  If the device list has shrunk, the sysctl will not
332          * return an error since we have more space allocated than is
333          * necessary.  So, in the shrinkage case, we catch it here and
334          * reallocate the array so that we don't use any more space than is
335          * necessary.
336          */
337         if (oldgeneration != dinfo->generation) {
338                 if (getnumdevs() != dinfo->numdevs) {
339                         if ((dinfo->numdevs = getnumdevs()) < 0)
340                                 return(-1);
341                         dssize = (dinfo->numdevs * sizeof(struct devstat)) +
342                                 sizeof(long);
343                         dinfo->mem_ptr = (u_int8_t *)realloc(dinfo->mem_ptr,
344                                                              dssize);
345                 }
346                 retval = 1;
347         }
348
349         dinfo->devices = (struct devstat *)(dinfo->mem_ptr + sizeof(long));
350
351         return(retval);
352 }
353
354 /*
355  * selectdevs():
356  *
357  * Devices are selected/deselected based upon the following criteria:
358  * - devices specified by the user on the command line
359  * - devices matching any device type expressions given on the command line
360  * - devices with the highest I/O, if 'top' mode is enabled
361  * - the first n unselected devices in the device list, if maxshowdevs
362  *   devices haven't already been selected and if the user has not
363  *   specified any devices on the command line and if we're in "add" mode.
364  *
365  * Input parameters:
366  * - device selection list (dev_select)
367  * - current number of devices selected (num_selected)
368  * - total number of devices in the selection list (num_selections)
369  * - devstat generation as of the last time selectdevs() was called
370  *   (select_generation)
371  * - current devstat generation (current_generation)
372  * - current list of devices and statistics (devices)
373  * - number of devices in the current device list (numdevs)
374  * - compiled version of the command line device type arguments (matches)
375  *   - This is optional.  If the number of devices is 0, this will be ignored.
376  *   - The matching code pays attention to the current selection mode.  So
377  *     if you pass in a matching expression, it will be evaluated based
378  *     upon the selection mode that is passed in.  See below for details.
379  * - number of device type matching expressions (num_matches)
380  *   - Set to 0 to disable the matching code.
381  * - list of devices specified on the command line by the user (dev_selections)
382  * - number of devices selected on the command line by the user
383  *   (num_dev_selections)
384  * - Our selection mode.  There are four different selection modes:
385  *      - add mode.  (DS_SELECT_ADD) Any devices matching devices explicitly
386  *        selected by the user or devices matching a pattern given by the
387  *        user will be selected in addition to devices that are already
388  *        selected.  Additional devices will be selected, up to maxshowdevs
389  *        number of devices. 
390  *      - only mode. (DS_SELECT_ONLY)  Only devices matching devices
391  *        explicitly given by the user or devices matching a pattern
392  *        given by the user will be selected.  No other devices will be
393  *        selected.
394  *      - addonly mode.  (DS_SELECT_ADDONLY)  This is similar to add and
395  *        only.  Basically, this will not de-select any devices that are
396  *        current selected, as only mode would, but it will also not
397  *        gratuitously select up to maxshowdevs devices as add mode would.
398  *      - remove mode.  (DS_SELECT_REMOVE)  Any devices matching devices
399  *        explicitly selected by the user or devices matching a pattern
400  *        given by the user will be de-selected.
401  * - maximum number of devices we can select (maxshowdevs)
402  * - flag indicating whether or not we're in 'top' mode (perf_select)
403  *
404  * Output data:
405  * - the device selection list may be modified and passed back out
406  * - the number of devices selected and the total number of items in the
407  *   device selection list may be changed
408  * - the selection generation may be changed to match the current generation
409  * 
410  * Return values:
411  * -1  -- error
412  *  0  -- selected devices are unchanged
413  *  1  -- selected devices changed
414  */
415 int
416 selectdevs(struct device_selection **dev_select, int *num_selected,
417            int *num_selections, long *select_generation, 
418            long current_generation, struct devstat *devices, int numdevs,
419            struct devstat_match *matches, int num_matches,
420            char **dev_selections, int num_dev_selections,
421            devstat_select_mode select_mode, int maxshowdevs, int perf_select)
422 {
423         int i, j, k;
424         int init_selections = 0, init_selected_var = 0;
425         struct device_selection *old_dev_select = NULL;
426         int old_num_selections = 0, old_num_selected;
427         int selection_number = 0;
428         int changed = 0, found = 0;
429
430         if ((dev_select == NULL) || (devices == NULL) || (numdevs <= 0))
431                 return(-1);
432
433         /*
434          * We always want to make sure that we have as many dev_select
435          * entries as there are devices. 
436          */
437         /*
438          * In this case, we haven't selected devices before.
439          */
440         if (*dev_select == NULL) {
441                 *dev_select = (struct device_selection *)malloc(numdevs *
442                         sizeof(struct device_selection));
443                 *select_generation = current_generation;
444                 init_selections = 1;
445                 changed = 1;
446         /*
447          * In this case, we have selected devices before, but the device
448          * list has changed since we last selected devices, so we need to
449          * either enlarge or reduce the size of the device selection list.
450          */
451         } else if (*num_selections != numdevs) {
452                 *dev_select = (struct device_selection *)realloc(*dev_select,
453                         numdevs * sizeof(struct device_selection));
454                 *select_generation = current_generation;
455                 init_selections = 1;
456         /*
457          * In this case, we've selected devices before, and the selection
458          * list is the same size as it was the last time, but the device
459          * list has changed.
460          */
461         } else if (*select_generation < current_generation) {
462                 *select_generation = current_generation;
463                 init_selections = 1;
464         }
465
466         /*
467          * If we're in "only" mode, we want to clear out the selected
468          * variable since we're going to select exactly what the user wants
469          * this time through.
470          */
471         if (select_mode == DS_SELECT_ONLY)
472                 init_selected_var = 1;
473
474         /*
475          * In all cases, we want to back up the number of selected devices.
476          * It is a quick and accurate way to determine whether the selected
477          * devices have changed.
478          */
479         old_num_selected = *num_selected;
480
481         /*
482          * We want to make a backup of the current selection list if 
483          * the list of devices has changed, or if we're in performance 
484          * selection mode.  In both cases, we don't want to make a backup
485          * if we already know for sure that the list will be different.
486          * This is certainly the case if this is our first time through the
487          * selection code.
488          */
489         if (((init_selected_var != 0) || (init_selections != 0)
490          || (perf_select != 0)) && (changed == 0)){
491                 old_dev_select = (struct device_selection *)malloc(
492                     *num_selections * sizeof(struct device_selection));
493                 old_num_selections = *num_selections;
494                 bcopy(*dev_select, old_dev_select, 
495                     sizeof(struct device_selection) * *num_selections);
496         }
497
498         if (init_selections != 0) {
499                 bzero(*dev_select, sizeof(struct device_selection) * numdevs);
500
501                 for (i = 0; i < numdevs; i++) {
502                         (*dev_select)[i].device_number = 
503                                 devices[i].device_number;
504                         strncpy((*dev_select)[i].device_name,
505                                 devices[i].device_name,
506                                 DEVSTAT_NAME_LEN);
507                         (*dev_select)[i].device_name[DEVSTAT_NAME_LEN - 1]='\0';
508                         (*dev_select)[i].unit_number = devices[i].unit_number;
509                         (*dev_select)[i].position = i;
510                 }
511                 *num_selections = numdevs;
512         } else if (init_selected_var != 0) {
513                 for (i = 0; i < numdevs; i++) 
514                         (*dev_select)[i].selected = 0;
515         }
516
517         /* we haven't gotten around to selecting anything yet.. */
518         if ((select_mode == DS_SELECT_ONLY) || (init_selections != 0)
519          || (init_selected_var != 0))
520                 *num_selected = 0;
521
522         /*
523          * Look through any devices the user specified on the command line
524          * and see if they match known devices.  If so, select them.
525          */
526         for (i = 0; (i < *num_selections) && (num_dev_selections > 0); i++) {
527                 char tmpstr[80];
528
529                 snprintf(tmpstr, sizeof(tmpstr), "%s%d",
530                         (*dev_select)[i].device_name,
531                         (*dev_select)[i].unit_number);
532                 for (j = 0; j < num_dev_selections; j++) {
533                         if (strcmp(tmpstr, dev_selections[j]) == 0) {
534                                 /*
535                                  * Here we do different things based on the
536                                  * mode we're in.  If we're in add or
537                                  * addonly mode, we only select this device
538                                  * if it hasn't already been selected.
539                                  * Otherwise, we would be unnecessarily
540                                  * changing the selection order and
541                                  * incrementing the selection count.  If
542                                  * we're in only mode, we unconditionally
543                                  * select this device, since in only mode
544                                  * any previous selections are erased and
545                                  * manually specified devices are the first
546                                  * ones to be selected.  If we're in remove
547                                  * mode, we de-select the specified device and
548                                  * decrement the selection count.
549                                  */
550                                 switch(select_mode) {
551                                 case DS_SELECT_ADD:
552                                 case DS_SELECT_ADDONLY:
553                                         if ((*dev_select)[i].selected)
554                                                 break;
555                                         /* FALLTHROUGH */
556                                 case DS_SELECT_ONLY:
557                                         (*dev_select)[i].selected =
558                                                 ++selection_number;
559                                         (*num_selected)++;
560                                         break;
561                                 case DS_SELECT_REMOVE:
562                                         (*dev_select)[i].selected = 0;
563                                         (*num_selected)--;
564                                         /*
565                                          * This isn't passed back out, we
566                                          * just use it to keep track of
567                                          * how many devices we've removed.
568                                          */
569                                         num_dev_selections--;
570                                         break;
571                                 }
572                                 break;
573                         }
574                 }
575         }
576
577         /*
578          * Go through the user's device type expressions and select devices
579          * accordingly.  We only do this if the number of devices already
580          * selected is less than the maximum number we can show.
581          */
582         for (i = 0; (i < num_matches) && (*num_selected < maxshowdevs); i++) {
583                 /* We should probably indicate some error here */
584                 if ((matches[i].match_fields == DEVSTAT_MATCH_NONE)
585                  || (matches[i].num_match_categories <= 0))
586                         continue;
587
588                 for (j = 0; j < numdevs; j++) {
589                         int num_match_categories;
590
591                         num_match_categories = matches[i].num_match_categories;
592
593                         /*
594                          * Determine whether or not the current device
595                          * matches the given matching expression.  This if
596                          * statement consists of three components:
597                          *   - the device type check
598                          *   - the device interface check
599                          *   - the passthrough check
600                          * If a the matching test is successful, it 
601                          * decrements the number of matching categories,
602                          * and if we've reached the last element that
603                          * needed to be matched, the if statement succeeds.
604                          * 
605                          */
606                         if ((((matches[i].match_fields & DEVSTAT_MATCH_TYPE)!=0)
607                           && ((devices[j].device_type & DEVSTAT_TYPE_MASK) ==
608                                 (matches[i].device_type & DEVSTAT_TYPE_MASK))
609                           &&(((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0)
610                            || (((matches[i].match_fields & 
611                                 DEVSTAT_MATCH_PASS) == 0)
612                             && ((devices[j].device_type &
613                                 DEVSTAT_TYPE_PASS) == 0)))
614                           && (--num_match_categories == 0)) 
615                          || (((matches[i].match_fields & DEVSTAT_MATCH_IF) != 0)
616                           && ((devices[j].device_type & DEVSTAT_TYPE_IF_MASK) ==
617                                 (matches[i].device_type & DEVSTAT_TYPE_IF_MASK))
618                           &&(((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0)
619                            || (((matches[i].match_fields &
620                                 DEVSTAT_MATCH_PASS) == 0)
621                             && ((devices[j].device_type & 
622                                 DEVSTAT_TYPE_PASS) == 0)))
623                           && (--num_match_categories == 0))
624                          || (((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0)
625                           && ((devices[j].device_type & DEVSTAT_TYPE_PASS) != 0)
626                           && (--num_match_categories == 0))) {
627
628                                 /*
629                                  * This is probably a non-optimal solution
630                                  * to the problem that the devices in the
631                                  * device list will not be in the same
632                                  * order as the devices in the selection
633                                  * array.
634                                  */
635                                 for (k = 0; k < numdevs; k++) {
636                                         if ((*dev_select)[k].position == j) {
637                                                 found = 1;
638                                                 break;
639                                         }
640                                 }
641
642                                 /*
643                                  * There shouldn't be a case where a device
644                                  * in the device list is not in the
645                                  * selection list...but it could happen.
646                                  */
647                                 if (found != 1) {
648                                         fprintf(stderr, "selectdevs: couldn't"
649                                                 " find %s%d in selection "
650                                                 "list\n",
651                                                 devices[j].device_name,
652                                                 devices[j].unit_number);
653                                         break;
654                                 }
655
656                                 /*
657                                  * We do different things based upon the
658                                  * mode we're in.  If we're in add or only
659                                  * mode, we go ahead and select this device
660                                  * if it hasn't already been selected.  If
661                                  * it has already been selected, we leave
662                                  * it alone so we don't mess up the
663                                  * selection ordering.  Manually specified
664                                  * devices have already been selected, and
665                                  * they have higher priority than pattern
666                                  * matched devices.  If we're in remove
667                                  * mode, we de-select the given device and
668                                  * decrement the selected count.
669                                  */
670                                 switch(select_mode) {
671                                 case DS_SELECT_ADD:
672                                 case DS_SELECT_ADDONLY:
673                                 case DS_SELECT_ONLY:
674                                         if ((*dev_select)[k].selected != 0)
675                                                 break;
676                                         (*dev_select)[k].selected =
677                                                 ++selection_number;
678                                         (*num_selected)++;
679                                         break;
680                                 case DS_SELECT_REMOVE:
681                                         (*dev_select)[k].selected = 0;
682                                         (*num_selected)--;
683                                         break;
684                                 }
685                         }
686                 }
687         }
688
689         /*
690          * Here we implement "top" mode.  Devices are sorted in the
691          * selection array based on two criteria:  whether or not they are
692          * selected (not selection number, just the fact that they are
693          * selected!) and the number of bytes in the "bytes" field of the
694          * selection structure.  The bytes field generally must be kept up
695          * by the user.  In the future, it may be maintained by library
696          * functions, but for now the user has to do the work.
697          *
698          * At first glance, it may seem wrong that we don't go through and
699          * select every device in the case where the user hasn't specified
700          * any devices or patterns.  In fact, though, it won't make any
701          * difference in the device sorting.  In that particular case (i.e.
702          * when we're in "add" or "only" mode, and the user hasn't
703          * specified anything) the first time through no devices will be
704          * selected, so the only criterion used to sort them will be their
705          * performance.  The second time through, and every time thereafter,
706          * all devices will be selected, so again selection won't matter.
707          */
708         if (perf_select != 0) {
709
710                 /* Sort the device array by throughput  */
711                 qsort(*dev_select, *num_selections,
712                       sizeof(struct device_selection),
713                       compare_select);
714
715                 if (*num_selected == 0) {
716                         /*
717                          * Here we select every device in the array, if it
718                          * isn't already selected.  Because the 'selected'
719                          * variable in the selection array entries contains
720                          * the selection order, the devstats routine can show
721                          * the devices that were selected first.
722                          */
723                         for (i = 0; i < *num_selections; i++) {
724                                 if ((*dev_select)[i].selected == 0) {
725                                         (*dev_select)[i].selected =
726                                                 ++selection_number;
727                                         (*num_selected)++;
728                                 }
729                         }
730                 } else {
731                         selection_number = 0;
732                         for (i = 0; i < *num_selections; i++) {
733                                 if ((*dev_select)[i].selected != 0) {
734                                         (*dev_select)[i].selected =
735                                                 ++selection_number;
736                                 }
737                         }
738                 }
739         }
740
741         /*
742          * If we're in the "add" selection mode and if we haven't already
743          * selected maxshowdevs number of devices, go through the array and
744          * select any unselected devices.  If we're in "only" mode, we
745          * obviously don't want to select anything other than what the user
746          * specifies.  If we're in "remove" mode, it probably isn't a good
747          * idea to go through and select any more devices, since we might
748          * end up selecting something that the user wants removed.  Through
749          * more complicated logic, we could actually figure this out, but
750          * that would probably require combining this loop with the various
751          * selections loops above.
752          */
753         if ((select_mode == DS_SELECT_ADD) && (*num_selected < maxshowdevs)) {
754                 for (i = 0; i < *num_selections; i++)
755                         if ((*dev_select)[i].selected == 0) {
756                                 (*dev_select)[i].selected = ++selection_number;
757                                 (*num_selected)++;
758                         }
759         }
760
761         /*
762          * Look at the number of devices that have been selected.  If it
763          * has changed, set the changed variable.  Otherwise, if we've
764          * made a backup of the selection list, compare it to the current
765          * selection list to see if the selected devices have changed.
766          */
767         if ((changed == 0) && (old_num_selected != *num_selected))
768                 changed = 1;
769         else if ((changed == 0) && (old_dev_select != NULL)) {
770                 /*
771                  * Now we go through the selection list and we look at
772                  * it three different ways.
773                  */
774                 for (i = 0; (i < *num_selections) && (changed == 0) && 
775                      (i < old_num_selections); i++) {
776                         /*
777                          * If the device at index i in both the new and old
778                          * selection arrays has the same device number and
779                          * selection status, it hasn't changed.  We
780                          * continue on to the next index.
781                          */
782                         if (((*dev_select)[i].device_number ==
783                              old_dev_select[i].device_number)
784                          && ((*dev_select)[i].selected == 
785                              old_dev_select[i].selected))
786                                 continue;
787
788                         /*
789                          * Now, if we're still going through the if
790                          * statement, the above test wasn't true.  So we
791                          * check here to see if the device at index i in
792                          * the current array is the same as the device at
793                          * index i in the old array.  If it is, that means
794                          * that its selection number has changed.  Set
795                          * changed to 1 and exit the loop.
796                          */
797                         else if ((*dev_select)[i].device_number ==
798                                   old_dev_select[i].device_number) {
799                                 changed = 1;
800                                 break;
801                         }
802                         /*
803                          * If we get here, then the device at index i in
804                          * the current array isn't the same device as the
805                          * device at index i in the old array.
806                          */
807                         else {
808                                 found = 0;
809
810                                 /*
811                                  * Search through the old selection array
812                                  * looking for a device with the same
813                                  * device number as the device at index i
814                                  * in the current array.  If the selection
815                                  * status is the same, then we mark it as
816                                  * found.  If the selection status isn't
817                                  * the same, we break out of the loop.
818                                  * Since found isn't set, changed will be
819                                  * set to 1 below.
820                                  */
821                                 for (j = 0; j < old_num_selections; j++) {
822                                         if (((*dev_select)[i].device_number ==
823                                               old_dev_select[j].device_number)
824                                          && ((*dev_select)[i].selected ==
825                                               old_dev_select[j].selected)){
826                                                 found = 1;
827                                                 break;
828                                         }
829                                         else if ((*dev_select)[i].device_number
830                                             == old_dev_select[j].device_number)
831                                                 break;
832                                 }
833                                 if (found == 0)
834                                         changed = 1;
835                         }
836                 }
837         }
838         if (old_dev_select != NULL)
839                 free(old_dev_select);
840
841         return(changed);
842 }
843
844 /*
845  * Comparison routine for qsort() above.  Note that the comparison here is
846  * backwards -- generally, it should return a value to indicate whether
847  * arg1 is <, =, or > arg2.  Instead, it returns the opposite.  The reason
848  * it returns the opposite is so that the selection array will be sorted in
849  * order of decreasing performance.  We sort on two parameters.  The first
850  * sort key is whether or not one or the other of the devices in question
851  * has been selected.  If one of them has, and the other one has not, the
852  * selected device is automatically more important than the unselected
853  * device.  If neither device is selected, we judge the devices based upon
854  * performance.
855  */
856 static int
857 compare_select(const void *arg1, const void *arg2)
858 {
859         if ((((const struct device_selection *)arg1)->selected)
860          && (((const struct device_selection *)arg2)->selected == 0))
861                 return(-1);
862         else if ((((const struct device_selection *)arg1)->selected == 0)
863               && (((const struct device_selection *)arg2)->selected))
864                 return(1);
865         else if (((const struct device_selection *)arg2)->bytes <
866                  ((const struct device_selection *)arg1)->bytes)
867                 return(-1);
868         else if (((const struct device_selection *)arg2)->bytes >
869                  ((const struct device_selection *)arg1)->bytes)
870                 return(1);
871         else
872                 return(0);
873 }
874
875 /*
876  * Take a string with the general format "arg1,arg2,arg3", and build a
877  * device matching expression from it.
878  */
879 int
880 buildmatch(const char *match_str, struct devstat_match **matches,
881            int *num_matches)
882 {
883         char *tstr[5];
884         char **tempstr;
885         char *matchbuf_orig;    /* strdup of match_str */
886         char *matchbuf;         /* allow strsep to clobber */
887         int num_args;
888         int i, j;
889         int retval = -1;
890
891         /* We can't do much without a string to parse */
892         if (match_str == NULL) {
893                 sprintf(devstat_errbuf, "%s: no match expression", __func__);
894                 return(-1);
895         }
896
897         /*
898          * Break the (comma delimited) input string out into separate strings.
899          * strsep is destructive, so copy the string first.
900          */
901         matchbuf = matchbuf_orig = strdup(match_str);
902         if (matchbuf == NULL) {
903                 sprintf(devstat_errbuf, "%s: out of memory", __func__);
904                 return(-1);
905         }
906         for (tempstr = tstr, num_args  = 0; 
907              (*tempstr = strsep(&matchbuf, ",")) != NULL && (num_args < 5); 
908              num_args++)
909                 if (**tempstr != '\0')
910                         if (++tempstr >= &tstr[5])
911                                 break;
912
913         /* The user gave us too many type arguments */
914         if (num_args > 3) {
915                 sprintf(devstat_errbuf, "%s: too many type arguments",
916                         __func__);
917                 goto cleanup;
918         }
919
920         /*
921          * Since you can't realloc a pointer that hasn't been malloced
922          * first, we malloc first and then realloc.
923          */
924         if (*num_matches == 0)
925                 *matches = (struct devstat_match *)malloc(
926                            sizeof(struct devstat_match));
927         else
928                 *matches = (struct devstat_match *)realloc(*matches,
929                           sizeof(struct devstat_match) * (*num_matches + 1));
930                           
931         /* Make sure the current entry is clear */
932         bzero(&matches[0][*num_matches], sizeof(struct devstat_match));
933
934         /*
935          * Step through the arguments the user gave us and build a device
936          * matching expression from them.
937          */
938         for (i = 0; i < num_args; i++) {
939                 char *tempstr2, *tempstr3;
940
941                 /*
942                  * Get rid of leading white space.
943                  */
944                 tempstr2 = tstr[i];
945                 while (isspace(*tempstr2) && (*tempstr2 != '\0'))
946                         tempstr2++;
947
948                 /*
949                  * Get rid of trailing white space.
950                  */
951                 tempstr3 = &tempstr2[strlen(tempstr2) - 1];
952
953                 while ((*tempstr3 != '\0') && (tempstr3 > tempstr2)
954                     && (isspace(*tempstr3))) {
955                         *tempstr3 = '\0';
956                         tempstr3--;
957                 }
958
959                 /*
960                  * Go through the match table comparing the user's
961                  * arguments to known device types, interfaces, etc.  
962                  */
963                 for (j = 0; match_table[j].match_str != NULL; j++) {
964                         /*
965                          * We do case-insensitive matching, in case someone
966                          * wants to enter "SCSI" instead of "scsi" or
967                          * something like that.  Only compare as many 
968                          * characters as are in the string in the match 
969                          * table.  This should help if someone tries to use 
970                          * a super-long match expression.  
971                          */
972                         if (strncasecmp(tempstr2, match_table[j].match_str,
973                             strlen(match_table[j].match_str)) == 0) {
974                                 /*
975                                  * Make sure the user hasn't specified two
976                                  * items of the same type, like "da" and
977                                  * "cd".  One device cannot be both.
978                                  */
979                                 if (((*matches)[*num_matches].match_fields &
980                                     match_table[j].match_field) != 0) {
981                                         sprintf(devstat_errbuf,
982                                                 "%s: cannot have more than "
983                                                 "one match item in a single "
984                                                 "category", __func__);
985                                         goto cleanup;
986                                 }
987                                 /*
988                                  * If we've gotten this far, we have a
989                                  * winner.  Set the appropriate fields in
990                                  * the match entry.
991                                  */
992                                 (*matches)[*num_matches].match_fields |=
993                                         match_table[j].match_field;
994                                 (*matches)[*num_matches].device_type |=
995                                         match_table[j].type;
996                                 (*matches)[*num_matches].num_match_categories++;
997                                 break;
998                         }
999                 }
1000                 /*
1001                  * We should have found a match in the above for loop.  If
1002                  * not, that means the user entered an invalid device type
1003                  * or interface.
1004                  */
1005                 if ((*matches)[*num_matches].num_match_categories != (i + 1)) {
1006                         snprintf(devstat_errbuf, sizeof(devstat_errbuf),
1007                                 "%s: unknown match item \"%s\"", __func__,
1008                                 tstr[i]);
1009                         goto cleanup;
1010                 }
1011         }
1012
1013         (*num_matches)++;
1014         retval = 0;
1015 cleanup:
1016         free(matchbuf_orig);
1017         return(retval);
1018 }
1019
1020 /*
1021  * Compute a number of device statistics.  Only one field is mandatory, and
1022  * that is "current".  Everything else is optional.  The caller passes in
1023  * pointers to variables to hold the various statistics he desires.  If he
1024  * doesn't want a particular staistic, he should pass in a NULL pointer.
1025  * Return values:
1026  * 0   -- success
1027  * -1  -- failure
1028  */
1029 int
1030 compute_stats(struct devstat *current, struct devstat *previous,
1031               long double etime, u_int64_t *total_bytes,
1032               u_int64_t *total_transfers, u_int64_t *total_blocks,
1033               long double *kb_per_transfer, long double *transfers_per_second,
1034               long double *mb_per_second, long double *blocks_per_second,
1035               long double *ms_per_transaction)
1036 {
1037         u_int64_t totalbytes, totaltransfers, totalblocks;
1038
1039         /*
1040          * current is the only mandatory field.
1041          */
1042         if (current == NULL) {
1043                 sprintf(devstat_errbuf, "%s: current stats structure was NULL",
1044                         __func__);
1045                 return(-1);
1046         }
1047
1048         totalbytes = (current->bytes_written + current->bytes_read) -
1049                      ((previous) ? (previous->bytes_written +
1050                                     previous->bytes_read) : 0);
1051
1052         if (total_bytes)
1053                 *total_bytes = totalbytes;
1054
1055         totaltransfers = (current->num_reads +
1056                           current->num_writes +
1057                           current->num_other) -
1058                          ((previous) ?
1059                           (previous->num_reads +
1060                            previous->num_writes +
1061                            previous->num_other) : 0);
1062         if (total_transfers)
1063                 *total_transfers = totaltransfers;
1064
1065         if (transfers_per_second) {
1066                 if (etime > 0.0) {
1067                         *transfers_per_second = totaltransfers;
1068                         *transfers_per_second /= etime;
1069                 } else
1070                         *transfers_per_second = 0.0;
1071         }
1072
1073         if (kb_per_transfer) {
1074                 *kb_per_transfer = totalbytes;
1075                 *kb_per_transfer /= 1024;
1076                 if (totaltransfers > 0)
1077                         *kb_per_transfer /= totaltransfers;
1078                 else
1079                         *kb_per_transfer = 0.0;
1080         }
1081
1082         if (mb_per_second) {
1083                 *mb_per_second = totalbytes;
1084                 *mb_per_second /= 1024 * 1024;
1085                 if (etime > 0.0)
1086                         *mb_per_second /= etime;
1087                 else
1088                         *mb_per_second = 0.0;
1089         }
1090
1091         totalblocks = totalbytes;
1092         if (current->block_size > 0)
1093                 totalblocks /= current->block_size;
1094         else
1095                 totalblocks /= 512;
1096
1097         if (total_blocks)
1098                 *total_blocks = totalblocks;
1099
1100         if (blocks_per_second) {
1101                 *blocks_per_second = totalblocks;
1102                 if (etime > 0.0)
1103                         *blocks_per_second /= etime;
1104                 else
1105                         *blocks_per_second = 0.0;
1106         }
1107
1108         if (ms_per_transaction) {
1109                 if (totaltransfers > 0) {
1110                         *ms_per_transaction = etime;
1111                         *ms_per_transaction /= totaltransfers;
1112                         *ms_per_transaction *= 1000;
1113                 } else
1114                         *ms_per_transaction = 0.0;
1115         }
1116
1117         return(0);
1118 }
1119
1120 int
1121 compute_stats_read(struct devstat *current, struct devstat *previous,
1122               long double etime, u_int64_t *total_bytes,
1123               u_int64_t *total_transfers, u_int64_t *total_blocks,
1124               long double *kb_per_transfer, long double *transfers_per_second,
1125               long double *mb_per_second, long double *blocks_per_second,
1126               long double *ms_per_transaction)
1127 {
1128         u_int64_t totalbytes, totaltransfers, totalblocks;
1129
1130         /*
1131          * current is the only mandatory field.
1132          */
1133         if (current == NULL) {
1134                 sprintf(devstat_errbuf, "%s: current stats structure was NULL",
1135                         __func__);
1136                 return(-1);
1137         }
1138
1139         totalbytes = current->bytes_read -
1140                      (previous ? previous->bytes_read : 0);
1141
1142         if (total_bytes)
1143                 *total_bytes = totalbytes;
1144
1145         totaltransfers = current->num_reads -
1146                          (previous ? previous->num_reads : 0);
1147         if (total_transfers)
1148                 *total_transfers = totaltransfers;
1149
1150         if (transfers_per_second) {
1151                 if (etime > 0.0) {
1152                         *transfers_per_second = totaltransfers;
1153                         *transfers_per_second /= etime;
1154                 } else
1155                         *transfers_per_second = 0.0;
1156         }
1157
1158         if (kb_per_transfer) {
1159                 *kb_per_transfer = totalbytes;
1160                 *kb_per_transfer /= 1024;
1161                 if (totaltransfers > 0)
1162                         *kb_per_transfer /= totaltransfers;
1163                 else
1164                         *kb_per_transfer = 0.0;
1165         }
1166
1167         if (mb_per_second) {
1168                 *mb_per_second = totalbytes;
1169                 *mb_per_second /= 1024 * 1024;
1170                 if (etime > 0.0)
1171                         *mb_per_second /= etime;
1172                 else
1173                         *mb_per_second = 0.0;
1174         }
1175
1176         totalblocks = totalbytes;
1177         if (current->block_size > 0)
1178                 totalblocks /= current->block_size;
1179         else
1180                 totalblocks /= 512;
1181
1182         if (total_blocks)
1183                 *total_blocks = totalblocks;
1184
1185         if (blocks_per_second) {
1186                 *blocks_per_second = totalblocks;
1187                 if (etime > 0.0)
1188                         *blocks_per_second /= etime;
1189                 else
1190                         *blocks_per_second = 0.0;
1191         }
1192
1193         if (ms_per_transaction) {
1194                 if (totaltransfers > 0) {
1195                         *ms_per_transaction = etime;
1196                         *ms_per_transaction /= totaltransfers;
1197                         *ms_per_transaction *= 1000;
1198                 } else
1199                         *ms_per_transaction = 0.0;
1200         }
1201
1202         return(0);
1203 }
1204
1205 int
1206 compute_stats_write(struct devstat *current, struct devstat *previous,
1207               long double etime, u_int64_t *total_bytes,
1208               u_int64_t *total_transfers, u_int64_t *total_blocks,
1209               long double *kb_per_transfer, long double *transfers_per_second,
1210               long double *mb_per_second, long double *blocks_per_second,
1211               long double *ms_per_transaction)
1212 {
1213         u_int64_t totalbytes, totaltransfers, totalblocks;
1214
1215         /*
1216          * current is the only mandatory field.
1217          */
1218         if (current == NULL) {
1219                 sprintf(devstat_errbuf, "%s: current stats structure was NULL",
1220                         __func__);
1221                 return(-1);
1222         }
1223
1224         totalbytes = current->bytes_written -
1225                      (previous ? previous->bytes_written : 0);
1226
1227         if (total_bytes)
1228                 *total_bytes = totalbytes;
1229
1230         totaltransfers = current->num_writes -
1231                          (previous ? previous->num_writes : 0);
1232         if (total_transfers)
1233                 *total_transfers = totaltransfers;
1234
1235         if (transfers_per_second) {
1236                 if (etime > 0.0) {
1237                         *transfers_per_second = totaltransfers;
1238                         *transfers_per_second /= etime;
1239                 } else
1240                         *transfers_per_second = 0.0;
1241         }
1242
1243         if (kb_per_transfer) {
1244                 *kb_per_transfer = totalbytes;
1245                 *kb_per_transfer /= 1024;
1246                 if (totaltransfers > 0)
1247                         *kb_per_transfer /= totaltransfers;
1248                 else
1249                         *kb_per_transfer = 0.0;
1250         }
1251
1252         if (mb_per_second) {
1253                 *mb_per_second = totalbytes;
1254                 *mb_per_second /= 1024 * 1024;
1255                 if (etime > 0.0)
1256                         *mb_per_second /= etime;
1257                 else
1258                         *mb_per_second = 0.0;
1259         }
1260
1261         totalblocks = totalbytes;
1262         if (current->block_size > 0)
1263                 totalblocks /= current->block_size;
1264         else
1265                 totalblocks /= 512;
1266
1267         if (total_blocks)
1268                 *total_blocks = totalblocks;
1269
1270         if (blocks_per_second) {
1271                 *blocks_per_second = totalblocks;
1272                 if (etime > 0.0)
1273                         *blocks_per_second /= etime;
1274                 else
1275                         *blocks_per_second = 0.0;
1276         }
1277
1278         if (ms_per_transaction) {
1279                 if (totaltransfers > 0) {
1280                         *ms_per_transaction = etime;
1281                         *ms_per_transaction /= totaltransfers;
1282                         *ms_per_transaction *= 1000;
1283                 } else
1284                         *ms_per_transaction = 0.0;
1285         }
1286
1287         return(0);
1288 }
1289
1290 long double
1291 compute_etime(struct timeval cur_time, struct timeval prev_time)
1292 {
1293         struct timeval busy_time;
1294         u_int64_t busy_usec;
1295         long double etime;
1296
1297         timersub(&cur_time, &prev_time, &busy_time);
1298
1299         busy_usec = busy_time.tv_sec;  
1300         busy_usec *= 1000000;          
1301         busy_usec += busy_time.tv_usec;
1302         etime = busy_usec;
1303         etime /= 1000000;
1304
1305         return(etime);
1306 }