]> granicus.if.org Git - sysstat/blob - common.c
Replace strcpy() with strncpy() to avoid buffer overflows
[sysstat] / common.c
1 /*
2  * sar, sadc, sadf, mpstat and iostat common routines.
3  * (C) 1999-2016 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <inttypes.h>
27 #include <time.h>
28 #include <errno.h>
29 #include <unistd.h>     /* For STDOUT_FILENO, among others */
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <dirent.h>
33 #include <ctype.h>
34 #include <libgen.h>
35
36 #include "version.h"
37 #include "common.h"
38 #include "ioconf.h"
39 #include "rd_stats.h"
40
41 #ifdef USE_NLS
42 #include <locale.h>
43 #include <libintl.h>
44 #define _(string) gettext(string)
45 #else
46 #define _(string) (string)
47 #endif
48
49 /* Number of ticks per second */
50 unsigned int hz;
51 /* Number of bit shifts to convert pages to kB */
52 unsigned int kb_shift;
53
54 /* Colors strings */
55 char sc_percent_high[MAX_SGR_LEN] = C_BOLD_RED;
56 char sc_percent_low[MAX_SGR_LEN] = C_BOLD_BLUE;
57 char sc_zero_int_stat[MAX_SGR_LEN] = C_LIGHT_YELLOW;
58 char sc_int_stat[MAX_SGR_LEN] = C_BOLD_YELLOW;
59 char sc_item_name[MAX_SGR_LEN] = C_LIGHT_GREEN;
60 char sc_sa_restart[MAX_SGR_LEN] = C_LIGHT_RED;
61 char sc_sa_comment[MAX_SGR_LEN] = C_LIGHT_CYAN;
62 char sc_normal[MAX_SGR_LEN] = C_NORMAL;
63
64 /* Type of persistent device names used in sar and iostat */
65 char persistent_name_type[MAX_FILE_LEN];
66
67 /*
68  ***************************************************************************
69  * Print sysstat version number and exit.
70  ***************************************************************************
71  */
72 void print_version(void)
73 {
74         printf(_("sysstat version %s\n"), VERSION);
75         printf("(C) Sebastien Godard (sysstat <at> orange.fr)\n");
76         exit(0);
77 }
78
79 /*
80  ***************************************************************************
81  * Get local date and time.
82  *
83  * IN:
84  * @d_off       Day offset (number of days to go back in the past).
85  *
86  * OUT:
87  * @rectime     Current local date and time.
88  *
89  * RETURNS:
90  * Value of time in seconds since the Epoch.
91  ***************************************************************************
92  */
93 time_t get_localtime(struct tm *rectime, int d_off)
94 {
95         time_t timer;
96         struct tm *ltm;
97
98         time(&timer);
99         timer -= SEC_PER_DAY * d_off;
100         ltm = localtime(&timer);
101
102         if (ltm) {
103                 *rectime = *ltm;
104         }
105         return timer;
106 }
107
108 /*
109  ***************************************************************************
110  * Get date and time expressed in UTC.
111  *
112  * IN:
113  * @d_off       Day offset (number of days to go back in the past).
114  *
115  * OUT:
116  * @rectime     Current date and time expressed in UTC.
117  *
118  * RETURNS:
119  * Value of time in seconds since the Epoch.
120  ***************************************************************************
121  */
122 time_t get_gmtime(struct tm *rectime, int d_off)
123 {
124         time_t timer;
125         struct tm *ltm;
126
127         time(&timer);
128         timer -= SEC_PER_DAY * d_off;
129         ltm = gmtime(&timer);
130
131         if (ltm) {
132                 *rectime = *ltm;
133         }
134         return timer;
135 }
136
137 /*
138  ***************************************************************************
139  * Get date and time and take into account <ENV_TIME_DEFTM> variable.
140  *
141  * IN:
142  * @d_off       Day offset (number of days to go back in the past).
143  *
144  * OUT:
145  * @rectime     Current date and time.
146  *
147  * RETURNS:
148  * Value of time in seconds since the Epoch.
149  ***************************************************************************
150  */
151 time_t get_time(struct tm *rectime, int d_off)
152 {
153         static int utc = 0;
154         char *e;
155
156         if (!utc) {
157                 /* Read environment variable value once */
158                 if ((e = getenv(ENV_TIME_DEFTM)) != NULL) {
159                         utc = !strcmp(e, K_UTC);
160                 }
161                 utc++;
162         }
163
164         if (utc == 2)
165                 return get_gmtime(rectime, d_off);
166         else
167                 return get_localtime(rectime, d_off);
168 }
169
170 /*
171  ***************************************************************************
172  * Count number of comma-separated values in arguments list. For example,
173  * the number will be 3 for the list "foobar -p 1 -p 2,3,4 2 5".
174  *
175  * IN:
176  * @arg_c       Number of arguments in the list.
177  * @arg_v       Arguments list.
178  *
179  * RETURNS:
180  * Number of comma-separated values in the list.
181  ***************************************************************************
182  */
183 int count_csvalues(int arg_c, char **arg_v)
184 {
185         int opt = 1;
186         int nr = 0;
187         char *t;
188
189         while (opt < arg_c) {
190                 if (strchr(arg_v[opt], ',')) {
191                         for (t = arg_v[opt]; t; t = strchr(t + 1, ',')) {
192                                 nr++;
193                         }
194                 }
195                 opt++;
196         }
197
198         return nr;
199 }
200
201 /*
202  ***************************************************************************
203  * Look for partitions of a given block device in /sys filesystem.
204  *
205  * IN:
206  * @dev_name    Name of the block device.
207  *
208  * RETURNS:
209  * Number of partitions for the given block device.
210  ***************************************************************************
211  */
212 int get_dev_part_nr(char *dev_name)
213 {
214         DIR *dir;
215         struct dirent *drd;
216         char dfile[MAX_PF_NAME], line[MAX_PF_NAME];
217         int part = 0;
218
219         snprintf(dfile, MAX_PF_NAME, "%s/%s", SYSFS_BLOCK, dev_name);
220         dfile[MAX_PF_NAME - 1] = '\0';
221
222         /* Open current device directory in /sys/block */
223         if ((dir = opendir(dfile)) == NULL)
224                 return 0;
225
226         /* Get current file entry */
227         while ((drd = readdir(dir)) != NULL) {
228                 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
229                         continue;
230                 snprintf(line, MAX_PF_NAME, "%s/%s/%s", dfile, drd->d_name, S_STAT);
231                 line[MAX_PF_NAME - 1] = '\0';
232
233                 /* Try to guess if current entry is a directory containing a stat file */
234                 if (!access(line, R_OK)) {
235                         /* Yep... */
236                         part++;
237                 }
238         }
239
240         /* Close directory */
241         closedir(dir);
242
243         return part;
244 }
245
246 /*
247  ***************************************************************************
248  * Look for block devices present in /sys/ filesystem:
249  * Check first that sysfs is mounted (done by trying to open /sys/block
250  * directory), then find number of devices registered.
251  *
252  * IN:
253  * @display_partitions  Set to TRUE if partitions must also be counted.
254  *
255  * RETURNS:
256  * Total number of block devices (and partitions if @display_partitions was
257  * set).
258  ***************************************************************************
259  */
260 int get_sysfs_dev_nr(int display_partitions)
261 {
262         DIR *dir;
263         struct dirent *drd;
264         char line[MAX_PF_NAME];
265         int dev = 0;
266
267         /* Open /sys/block directory */
268         if ((dir = opendir(SYSFS_BLOCK)) == NULL)
269                 /* sysfs not mounted, or perhaps this is an old kernel */
270                 return 0;
271
272         /* Get current file entry in /sys/block directory */
273         while ((drd = readdir(dir)) != NULL) {
274                 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
275                         continue;
276                 snprintf(line, MAX_PF_NAME, "%s/%s/%s", SYSFS_BLOCK, drd->d_name, S_STAT);
277                 line[MAX_PF_NAME - 1] = '\0';
278
279                 /* Try to guess if current entry is a directory containing a stat file */
280                 if (!access(line, R_OK)) {
281                         /* Yep... */
282                         dev++;
283
284                         if (display_partitions) {
285                                 /* We also want the number of partitions for this device */
286                                 dev += get_dev_part_nr(drd->d_name);
287                         }
288                 }
289         }
290
291         /* Close /sys/block directory */
292         closedir(dir);
293
294         return dev;
295 }
296
297 /*
298  ***************************************************************************
299  * Read /proc/devices file and get device-mapper major number.
300  * If device-mapper entry is not found in file, assume it's not active.
301  *
302  * RETURNS:
303  * Device-mapper major number.
304  ***************************************************************************
305  */
306 unsigned int get_devmap_major(void)
307 {
308         FILE *fp;
309         char line[128];
310         /*
311          * Linux uses 12 bits for the major number,
312          * so this shouldn't match any real device.
313          */
314         unsigned int dm_major = ~0U;
315
316         if ((fp = fopen(DEVICES, "r")) == NULL)
317                 return dm_major;
318
319         while (fgets(line, sizeof(line), fp) != NULL) {
320
321                 if (strstr(line, "device-mapper")) {
322                         /* Read device-mapper major number */
323                         sscanf(line, "%u", &dm_major);
324                 }
325         }
326
327         fclose(fp);
328
329         return dm_major;
330 }
331
332 /*
333  ***************************************************************************
334  * Returns whether S_TIME_FORMAT is set to ISO.
335  *
336  * RETURNS:
337  * TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise.
338  ***************************************************************************
339  */
340 int is_iso_time_fmt(void)
341 {
342         static int is_iso = -1;
343         char *e;
344
345         if (is_iso < 0) {
346                 is_iso = (((e = getenv(ENV_TIME_FMT)) != NULL) && !strcmp(e, K_ISO));
347         }
348         return is_iso;
349 }
350
351 /*
352  ***************************************************************************
353  * Print banner.
354  *
355  * IN:
356  * @rectime     Date to display (don't use time fields).
357  * @sysname     System name to display.
358  * @release     System release number to display.
359  * @nodename    Hostname to display.
360  * @machine     Machine architecture to display.
361  * @cpu_nr      Number of CPU.
362  *
363  * RETURNS:
364  * TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise.
365  ***************************************************************************
366  */
367 int print_gal_header(struct tm *rectime, char *sysname, char *release,
368                      char *nodename, char *machine, int cpu_nr)
369 {
370         char cur_date[64];
371         int rc = 0;
372
373         if (rectime == NULL) {
374                 strcpy(cur_date, "?/?/?");
375         }
376         else if (is_iso_time_fmt()) {
377                 strftime(cur_date, sizeof(cur_date), "%Y-%m-%d", rectime);
378                 rc = 1;
379         }
380         else {
381                 strftime(cur_date, sizeof(cur_date), "%x", rectime);
382         }
383
384         printf("%s %s (%s) \t%s \t_%s_\t(%d CPU)\n", sysname, release, nodename,
385                cur_date, machine, cpu_nr);
386
387         return rc;
388 }
389
390 #ifdef USE_NLS
391 /*
392  ***************************************************************************
393  * Init National Language Support.
394  ***************************************************************************
395  */
396 void init_nls(void)
397 {
398         setlocale(LC_MESSAGES, "");
399         setlocale(LC_CTYPE, "");
400         setlocale(LC_TIME, "");
401         setlocale(LC_NUMERIC, "");
402
403         bindtextdomain(PACKAGE, LOCALEDIR);
404         textdomain(PACKAGE);
405 }
406 #endif
407
408 /*
409  ***************************************************************************
410  * Get number of rows for current window.
411  *
412  * RETURNS:
413  * Number of rows.
414  ***************************************************************************
415  */
416 int get_win_height(void)
417 {
418         struct winsize win;
419         /*
420          * This default value will be used whenever STDOUT
421          * is redirected to a pipe or a file
422          */
423         int rows = 3600 * 24;
424
425         if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1) {
426                 if (win.ws_row > 2) {
427                         rows = win.ws_row - 2;
428                 }
429         }
430         return rows;
431 }
432
433 /*
434  ***************************************************************************
435  * Canonicalize and remove /dev from path name.
436  *
437  * IN:
438  * @name        Device name (may begin with "/dev/" or can be a symlink).
439  *
440  * RETURNS:
441  * Device basename.
442  ***************************************************************************
443  */
444 char *device_name(char *name)
445 {
446         static char out[MAX_FILE_LEN];
447         char *resolved_name;
448         int i = 0;
449
450         /* realpath() creates new string, so we need to free it later */
451         resolved_name = realpath(name, NULL);
452
453         /* If path doesn't exist, just return input */
454         if (!resolved_name) {
455                 return name;
456         }
457
458         if (!strncmp(resolved_name, "/dev/", 5)) {
459                 i = 5;
460         }
461         strncpy(out, resolved_name + i, MAX_FILE_LEN);
462         out[MAX_FILE_LEN - 1] = '\0';
463
464         free(resolved_name);
465
466         return out;
467 }
468
469 /*
470  ***************************************************************************
471  * Test whether given name is a device or a partition, using sysfs.
472  * This is more straightforward that using ioc_iswhole() function from
473  * ioconf.c which should be used only with kernels that don't have sysfs.
474  *
475  * IN:
476  * @name                Device or partition name.
477  * @allow_virtual       TRUE if virtual devices are also accepted.
478  *                      The device is assumed to be virtual if no
479  *                      /sys/block/<device>/device link exists.
480  *
481  * RETURNS:
482  * TRUE if @name is not a partition.
483  ***************************************************************************
484  */
485 int is_device(char *name, int allow_virtual)
486 {
487         char syspath[PATH_MAX];
488         char *slash;
489
490         /* Some devices may have a slash in their name (eg. cciss/c0d0...) */
491         while ((slash = strchr(name, '/'))) {
492                 *slash = '!';
493         }
494         snprintf(syspath, sizeof(syspath), "%s/%s%s", SYSFS_BLOCK, name,
495                  allow_virtual ? "" : "/device");
496
497         return !(access(syspath, F_OK));
498 }
499
500 /*
501  ***************************************************************************
502  * Get page shift in kB.
503  ***************************************************************************
504  */
505 void get_kb_shift(void)
506 {
507         int shift = 0;
508         long size;
509
510         /* One can also use getpagesize() to get the size of a page */
511         if ((size = sysconf(_SC_PAGESIZE)) == -1) {
512                 perror("sysconf");
513         }
514
515         size >>= 10;    /* Assume that a page has a minimum size of 1 kB */
516
517         while (size > 1) {
518                 shift++;
519                 size >>= 1;
520         }
521
522         kb_shift = (unsigned int) shift;
523 }
524
525 /*
526  ***************************************************************************
527  * Get number of clock ticks per second.
528  ***************************************************************************
529  */
530 void get_HZ(void)
531 {
532         long ticks;
533
534         if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
535                 perror("sysconf");
536         }
537
538         hz = (unsigned int) ticks;
539 }
540
541 /*
542  ***************************************************************************
543  * Workaround for CPU counters read from /proc/stat: Dyn-tick kernels
544  * have a race issue that can make those counters go backward.
545  ***************************************************************************
546  */
547 double ll_sp_value(unsigned long long value1, unsigned long long value2,
548                    unsigned long long itv)
549 {
550         if (value2 < value1)
551                 return (double) 0;
552         else
553                 return SP_VALUE(value1, value2, itv);
554 }
555
556 /*
557  ***************************************************************************
558  * Compute time interval.
559  *
560  * IN:
561  * @prev_uptime Previous uptime value in jiffies.
562  * @curr_uptime Current uptime value in jiffies.
563  *
564  * RETURNS:
565  * Interval of time in jiffies.
566  ***************************************************************************
567  */
568 unsigned long long get_interval(unsigned long long prev_uptime,
569                                 unsigned long long curr_uptime)
570 {
571         unsigned long long itv;
572
573         /* prev_time=0 when displaying stats since system startup */
574         itv = curr_uptime - prev_uptime;
575
576         if (!itv) {     /* Paranoia checking */
577                 itv = 1;
578         }
579
580         return itv;
581 }
582
583 /*
584  ***************************************************************************
585  * Since ticks may vary slightly from CPU to CPU, we'll want
586  * to recalculate itv based on this CPU's tick count, rather
587  * than that reported by the "cpu" line. Otherwise we
588  * occasionally end up with slightly skewed figures, with
589  * the skew being greater as the time interval grows shorter.
590  *
591  * IN:
592  * @scc Current sample statistics for current CPU.
593  * @scp Previous sample statistics for current CPU.
594  *
595  * RETURNS:
596  * Interval of time based on current CPU.
597  ***************************************************************************
598  */
599 unsigned long long get_per_cpu_interval(struct stats_cpu *scc,
600                                         struct stats_cpu *scp)
601 {
602         unsigned long long ishift = 0LL;
603
604         if ((scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest)) {
605                 /*
606                  * Sometimes the nr of jiffies spent in guest mode given by the guest
607                  * counter in /proc/stat is slightly higher than that included in
608                  * the user counter. Update the interval value accordingly.
609                  */
610                 ishift += (scp->cpu_user - scp->cpu_guest) -
611                           (scc->cpu_user - scc->cpu_guest);
612         }
613         if ((scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice)) {
614                 /*
615                  * Idem for nr of jiffies spent in guest_nice mode.
616                  */
617                 ishift += (scp->cpu_nice - scp->cpu_guest_nice) -
618                           (scc->cpu_nice - scc->cpu_guest_nice);
619         }
620
621         /*
622          * Don't take cpu_guest and cpu_guest_nice into account
623          * because cpu_user and cpu_nice already include them.
624          */
625         return ((scc->cpu_user    + scc->cpu_nice   +
626                  scc->cpu_sys     + scc->cpu_iowait +
627                  scc->cpu_idle    + scc->cpu_steal  +
628                  scc->cpu_hardirq + scc->cpu_softirq) -
629                 (scp->cpu_user    + scp->cpu_nice   +
630                  scp->cpu_sys     + scp->cpu_iowait +
631                  scp->cpu_idle    + scp->cpu_steal  +
632                  scp->cpu_hardirq + scp->cpu_softirq) +
633                  ishift);
634 }
635
636 /*
637  ***************************************************************************
638  * Unhandled situation: Panic and exit. Should never happen.
639  *
640  * IN:
641  * @function    Function name where situation occured.
642  * @error_code  Error code.
643  ***************************************************************************
644  */
645 void sysstat_panic(const char *function, int error_code)
646 {
647         fprintf(stderr, "sysstat: %s[%d]: Internal error...\n",
648                 function, error_code);
649         exit(1);
650 }
651
652 /*
653  ***************************************************************************
654  * Count number of bits set in an array.
655  *
656  * IN:
657  * @ptr         Pointer to array.
658  * @size        Size of array in bytes.
659  *
660  * RETURNS:
661  * Number of bits set in the array.
662  ***************************************************************************
663 */
664 int count_bits(void *ptr, int size)
665 {
666         int nr = 0, i, k;
667         char *p;
668
669         p = ptr;
670         for (i = 0; i < size; i++, p++) {
671                 k = 0x80;
672                 while (k) {
673                         if (*p & k)
674                                 nr++;
675                         k >>= 1;
676                 }
677         }
678
679         return nr;
680 }
681
682 /*
683  ***************************************************************************
684  * Compute "extended" device statistics (service time, etc.).
685  *
686  * IN:
687  * @sdc         Structure with current device statistics.
688  * @sdp         Structure with previous device statistics.
689  * @itv         Interval of time in jiffies.
690  *
691  * OUT:
692  * @xds         Structure with extended statistics.
693  ***************************************************************************
694 */
695 void compute_ext_disk_stats(struct stats_disk *sdc, struct stats_disk *sdp,
696                             unsigned long long itv, struct ext_disk_stats *xds)
697 {
698         double tput
699                 = ((double) (sdc->nr_ios - sdp->nr_ios)) * HZ / itv;
700
701         xds->util  = S_VALUE(sdp->tot_ticks, sdc->tot_ticks, itv);
702         xds->svctm = tput ? xds->util / tput : 0.0;
703         /*
704          * Kernel gives ticks already in milliseconds for all platforms
705          * => no need for further scaling.
706          */
707         xds->await = (sdc->nr_ios - sdp->nr_ios) ?
708                 ((sdc->rd_ticks - sdp->rd_ticks) + (sdc->wr_ticks - sdp->wr_ticks)) /
709                 ((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
710         xds->arqsz = (sdc->nr_ios - sdp->nr_ios) ?
711                 ((sdc->rd_sect - sdp->rd_sect) + (sdc->wr_sect - sdp->wr_sect)) /
712                 ((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
713 }
714
715 /*
716  ***************************************************************************
717  * Convert in-place input string to lowercase.
718  *
719  * IN:
720  * @str         String to be converted.
721  *
722  * OUT:
723  * @str         String in lowercase.
724  *
725  * RETURNS:
726  * String in lowercase.
727  ***************************************************************************
728 */
729 char *strtolower(char *str)
730 {
731         char *cp = str;
732
733         while (*cp) {
734                 *cp = tolower(*cp);
735                 cp++;
736         }
737
738         return(str);
739 }
740
741 /*
742  ***************************************************************************
743  * Get persistent type name directory from type.
744  *
745  * IN:
746  * @type        Persistent type name (UUID, LABEL, etc.)
747  *
748  * RETURNS:
749  * Path to the persistent type name directory, or NULL if access is denied.
750  ***************************************************************************
751 */
752 char *get_persistent_type_dir(char *type)
753 {
754         static char dir[32];
755
756         snprintf(dir, 32, "%s-%s", DEV_DISK_BY, type);
757
758         if (access(dir, R_OK)) {
759                 return (NULL);
760         }
761
762         return (dir);
763 }
764
765 /*
766  ***************************************************************************
767  * Get persistent name absolute path.
768  *
769  * IN:
770  * @name        Persistent name.
771  *
772  * RETURNS:
773  * Path to the persistent name, or NULL if file doesn't exist.
774  ***************************************************************************
775 */
776 char *get_persistent_name_path(char *name)
777 {
778         static char path[PATH_MAX];
779
780         snprintf(path, PATH_MAX, "%s/%s",
781                  get_persistent_type_dir(persistent_name_type), name);
782
783         if (access(path, F_OK)) {
784                 return (NULL);
785         }
786
787         return (path);
788 }
789
790 /*
791  ***************************************************************************
792  * Get files from persistent type name directory.
793  *
794  * RETURNS:
795  * List of files in the persistent type name directory in alphabetical order.
796  ***************************************************************************
797 */
798 char **get_persistent_names(void)
799 {
800         int n, i, k = 0;
801         char *dir;
802         char **files = NULL;
803         struct dirent **namelist;
804
805         /* Get directory name for selected persistent type */
806         dir = get_persistent_type_dir(persistent_name_type);
807         if (!dir)
808                 return (NULL);
809
810         n = scandir(dir, &namelist, NULL, alphasort);
811         if (n < 0)
812                 return (NULL);
813
814         /* If directory is empty, it contains 2 entries: "." and ".." */
815         if (n <= 2)
816                 /* Free list and return NULL */
817                 goto free_list;
818
819         /* Ignore the "." and "..", but keep place for one last NULL. */
820         files = (char **) calloc(n - 1, sizeof(char *));
821         if (!files)
822                 goto free_list;
823
824         /*
825          * i is for traversing namelist, k is for files.
826          * i != k because we are ignoring "." and ".." entries.
827          */
828         for (i = 0; i < n; i++) {
829                 /* Ignore "." and "..". */
830                 if (!strcmp(".", namelist[i]->d_name) ||
831                     !strcmp("..", namelist[i]->d_name))
832                         continue;
833
834                 files[k] = (char *) calloc(strlen(namelist[i]->d_name) + 1, sizeof(char));
835                 if (!files[k])
836                         continue;
837
838                 strcpy(files[k++], namelist[i]->d_name);
839         }
840         files[k] = NULL;
841
842 free_list:
843
844         for (i = 0; i < n; i++) {
845                 free(namelist[i]);
846         }
847         free(namelist);
848
849         return (files);
850 }
851
852 /*
853  ***************************************************************************
854  * Get persistent name from pretty name.
855  *
856  * IN:
857  * @pretty      Pretty name (e.g. sda, sda1, ..).
858  *
859  * RETURNS:
860  * Persistent name.
861  ***************************************************************************
862 */
863 char *get_persistent_name_from_pretty(char *pretty)
864 {
865         int i = -1;
866         ssize_t r;
867         char *link, *name;
868         char **persist_names;
869         char target[PATH_MAX];
870         static char persist_name[FILENAME_MAX];
871
872         persist_name[0] = '\0';
873
874         /* Get list of files from persistent type name directory */
875         persist_names = get_persistent_names();
876         if (!persist_names)
877                 return (NULL);
878
879         while (persist_names[++i]) {
880                 /* Get absolute path for current persistent name */
881                 link = get_persistent_name_path(persist_names[i]);
882                 if (!link)
883                         continue;
884
885                 /* Persistent name is usually a symlink: Read it... */
886                 r = readlink(link, target, PATH_MAX);
887                 if ((r <= 0) || (r >= PATH_MAX))
888                         continue;
889
890                 target[r] = '\0';
891
892                 /* ... and get device pretty name it points at */
893                 name = basename(target);
894                 if (!name || (name[0] == '\0'))
895                         continue;
896
897                 if (!strncmp(name, pretty, FILENAME_MAX)) {
898                         /* We have found pretty name for current persistent one */
899                         strncpy(persist_name, persist_names[i], FILENAME_MAX);
900                         persist_name[FILENAME_MAX - 1] = '\0';
901                         break;
902                 }
903         }
904
905         i = -1;
906         while (persist_names[++i]) {
907                 free (persist_names[i]);
908         }
909         free (persist_names);
910
911         if (strlen(persist_name) <= 0)
912                 return (NULL);
913
914         return persist_name;
915 }
916
917 /*
918  ***************************************************************************
919  * Get pretty name (sda, sda1...) from persistent name.
920  *
921  * IN:
922  * @persistent  Persistent name.
923  *
924  * RETURNS:
925  * Pretty name.
926  ***************************************************************************
927 */
928 char *get_pretty_name_from_persistent(char *persistent)
929 {
930         ssize_t r;
931         char *link, *pretty, target[PATH_MAX];
932
933         /* Get absolute path for persistent name */
934         link = get_persistent_name_path(persistent);
935         if (!link)
936                 return (NULL);
937
938         /* Persistent name is usually a symlink: Read it... */
939         r = readlink(link, target, PATH_MAX);
940         if ((r <= 0) || (r >= PATH_MAX))
941                 return (NULL);
942
943         target[r] = '\0';
944
945         /* ... and get device pretty name it points at */
946         pretty = basename(target);
947         if (!pretty || (pretty[0] == '\0'))
948                 return (NULL);
949
950         return pretty;
951 }
952
953 /*
954  ***************************************************************************
955  * Init color strings.
956  ***************************************************************************
957  */
958 void init_colors(void)
959 {
960         char *e, *p;
961         int len;
962
963         /* Read S_COLORS environment variable */
964         if (((e = getenv(ENV_COLORS)) == NULL) ||
965             !strcmp(e, C_NEVER) ||
966             (strcmp(e, C_ALWAYS) && !isatty(STDOUT_FILENO))) {
967                 /*
968                  * Environment variable not set, or set to "never",
969                  * or set to "auto" and stdout is not a terminal:
970                  * Unset color strings.
971                  */
972                 strcpy(sc_percent_high, "");
973                 strcpy(sc_percent_low, "");
974                 strcpy(sc_zero_int_stat, "");
975                 strcpy(sc_int_stat, "");
976                 strcpy(sc_item_name, "");
977                 strcpy(sc_sa_comment, "");
978                 strcpy(sc_sa_restart, "");
979                 strcpy(sc_normal, "");
980
981                 return;
982         }
983
984         /* Read S_COLORS_SGR environment variable */
985         if ((e = getenv(ENV_COLORS_SGR)) == NULL)
986                 /* Environment variable not set */
987                 return;
988
989         for (p = strtok(e, ":"); p; p =strtok(NULL, ":")) {
990
991                 len = strlen(p);
992                 if ((len > 7) || (len < 3) || (*(p + 1) != '=') ||
993                     (strspn(p + 2, ";0123456789") != (len - 2)))
994                         /* Ignore malformed codes */
995                         continue;
996
997                 switch (*p) {
998                         case 'H':
999                                 snprintf(sc_percent_high, MAX_SGR_LEN, "\e[%sm", p + 2);
1000                                 break;
1001                         case 'M':
1002                                 snprintf(sc_percent_low, MAX_SGR_LEN, "\e[%sm", p + 2);
1003                                 break;
1004                         case 'Z':
1005                                 snprintf(sc_zero_int_stat, MAX_SGR_LEN, "\e[%sm", p + 2);
1006                                 break;
1007                         case 'N':
1008                                 snprintf(sc_int_stat, MAX_SGR_LEN, "\e[%sm", p + 2);
1009                                 break;
1010                         case 'I':
1011                                 snprintf(sc_item_name, MAX_SGR_LEN, "\e[%sm", p + 2);
1012                                 break;
1013                         case 'C':
1014                                 snprintf(sc_sa_comment, MAX_SGR_LEN, "\e[%sm", p + 2);
1015                                 break;
1016                         case 'R':
1017                                 snprintf(sc_sa_restart, MAX_SGR_LEN, "\e[%sm", p + 2);
1018                                 break;
1019                 }
1020         }
1021 }
1022
1023 /*
1024  ***************************************************************************
1025  * Print 64 bit unsigned values using colors.
1026  *
1027  * IN:
1028  * @num         Number of values to print.
1029  * @width       Output width.
1030  ***************************************************************************
1031 */
1032 void cprintf_u64(int num, int width, ...)
1033 {
1034         int i;
1035         uint64_t val;
1036         va_list args;
1037
1038         va_start(args, width);
1039
1040         for (i = 0; i < num; i++) {
1041                 val = va_arg(args, unsigned long long);
1042                 if (!val) {
1043                         printf("%s", sc_zero_int_stat);
1044                 }
1045                 else {
1046                         printf("%s", sc_int_stat);
1047                 }
1048                 printf(" %*"PRIu64, width, val);
1049                 printf("%s", sc_normal);
1050         }
1051
1052         va_end(args);
1053 }
1054
1055 /*
1056  ***************************************************************************
1057  * Print hex values using colors.
1058  *
1059  * IN:
1060  * @num         Number of values to print.
1061  * @width       Output width.
1062  ***************************************************************************
1063 */
1064 void cprintf_x(int num, int width, ...)
1065 {
1066         int i;
1067         unsigned int val;
1068         va_list args;
1069
1070         va_start(args, width);
1071
1072         for (i = 0; i < num; i++) {
1073                 val = va_arg(args, unsigned int);
1074                 printf("%s", sc_int_stat);
1075                 printf(" %*x", width, val);
1076                 printf("%s", sc_normal);
1077         }
1078
1079         va_end(args);
1080 }
1081
1082 /*
1083  ***************************************************************************
1084  * Print "double" statistics values using colors.
1085  *
1086  * IN:
1087  * @num         Number of values to print.
1088  * @width       Output width.
1089  * @wd          Number of decimal places.
1090  ***************************************************************************
1091 */
1092 void cprintf_f(int num, int wi, int wd, ...)
1093 {
1094         int i;
1095         double val;
1096         va_list args;
1097
1098         va_start(args, wd);
1099
1100         for (i = 0; i < num; i++) {
1101                 val = va_arg(args, double);
1102                 if (((val < 0.005) && (val > -0.005)) ||
1103                     ((wd == 0) && (val < 0.5))) {
1104                         printf("%s", sc_zero_int_stat);
1105                 }
1106                 else {
1107                         printf("%s", sc_int_stat);
1108                 }
1109                 printf(" %*.*f", wi, wd, val);
1110                 printf("%s", sc_normal);
1111         }
1112
1113         va_end(args);
1114 }
1115
1116 /*
1117  ***************************************************************************
1118  * Print "percent" statistics values using colors.
1119  *
1120  * IN:
1121  * @num         Number of values to print.
1122  * @width       Output width.
1123  * @wd          Number of decimal places.
1124  ***************************************************************************
1125 */
1126 void cprintf_pc(int num, int wi, int wd, ...)
1127 {
1128         int i;
1129         double val;
1130         va_list args;
1131
1132         va_start(args, wd);
1133
1134         for (i = 0; i < num; i++) {
1135                 val = va_arg(args, double);
1136                 if (val >= PERCENT_LIMIT_HIGH) {
1137                         printf("%s", sc_percent_high);
1138                 }
1139                 else if (val >= PERCENT_LIMIT_LOW) {
1140                         printf("%s", sc_percent_low);
1141                 }
1142                 else if (val < 0.005) {
1143                         printf("%s", sc_zero_int_stat);
1144                 }
1145                 else {
1146                         printf("%s", sc_int_stat);
1147                 }
1148                 printf(" %*.*f", wi, wd, val);
1149                 printf("%s", sc_normal);
1150         }
1151
1152         va_end(args);
1153 }
1154
1155 /*
1156  ***************************************************************************
1157  * Print item name using selected color.
1158  * Only one name can be displayed. Name can be an integer or a string.
1159  *
1160  * IN:
1161  * @type        0 if name is an int, 1 if name is a string
1162  * @format      Output format.
1163  * @item_string Item name (given as a string of characters).
1164  * @item_int    Item name (given as an integer value).
1165  ***************************************************************************
1166 */
1167 void cprintf_in(int type, char *format, char *item_string, int item_int)
1168 {
1169         printf("%s", sc_item_name);
1170         if (type) {
1171                 printf(format, item_string);
1172         }
1173         else {
1174                 printf(format, item_int);
1175         }
1176         printf("%s", sc_normal);
1177 }
1178
1179 /*
1180  ***************************************************************************
1181  * Print a string using selected color.
1182  *
1183  * IN:
1184  * @type        Type of string to display.
1185  * @format      Output format.
1186  * @string      String to display.
1187  ***************************************************************************
1188 */
1189 void cprintf_s(int type, char *format, char *string)
1190 {
1191         if (type == IS_STR) {
1192                 printf("%s", sc_int_stat);
1193         }
1194         else if (type == IS_ZERO) {
1195                 printf("%s", sc_zero_int_stat);
1196         }
1197         else if (type == IS_RESTART) {
1198                 printf("%s", sc_sa_restart);
1199         }
1200         else {
1201                 /* IS_COMMENT */
1202                 printf("%s", sc_sa_comment);
1203         }
1204         printf(format, string);
1205         printf("%s", sc_normal);
1206 }