1 /*
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <inttypes.h>
9 #include <ctype.h>
10 #include <errno.h>
11 #include <sys/stat.h>
12 #include <string.h>
13 #include <assert.h>
14
15 #include "c.h"
16 #include "nls.h"
17 #include "strutils.h"
18 #include "bitops.h"
19
do_scale_by_power(uintmax_t * x,int base,int power)20 static int do_scale_by_power (uintmax_t *x, int base, int power)
21 {
22 while (power--) {
23 if (UINTMAX_MAX / base < *x)
24 return -ERANGE;
25 *x *= base;
26 }
27 return 0;
28 }
29
30 /*
31 * strtosize() - convert string to size (uintmax_t).
32 *
33 * Supported suffixes:
34 *
35 * XiB or X for 2^N
36 * where X = {K,M,G,T,P,E,Z,Y}
37 * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only)
38 * for example:
39 * 10KiB = 10240
40 * 10K = 10240
41 *
42 * XB for 10^N
43 * where X = {K,M,G,T,P,E,Z,Y}
44 * for example:
45 * 10KB = 10000
46 *
47 * The optinal 'power' variable returns number associated with used suffix
48 * {K,M,G,T,P,E,Z,Y} = {1,2,3,4,5,6,7,8}.
49 *
50 * The function also supports decimal point, for example:
51 * 0.5MB = 500000
52 * 0.5MiB = 512000
53 *
54 * Note that the function does not accept numbers with '-' (negative sign)
55 * prefix.
56 */
parse_size(const char * str,uintmax_t * res,int * power)57 int parse_size(const char *str, uintmax_t *res, int *power)
58 {
59 char *p;
60 uintmax_t x, frac = 0;
61 int base = 1024, rc = 0, pwr = 0, frac_zeros = 0;
62
63 static const char *suf = "KMGTPEYZ";
64 static const char *suf2 = "kmgtpeyz";
65 const char *sp;
66
67 *res = 0;
68
69 if (!str || !*str) {
70 rc = -EINVAL;
71 goto err;
72 }
73
74 /* Only positive numbers are acceptable
75 *
76 * Note that this check is not perfect, it would be better to
77 * use lconv->negative_sign. But coreutils use the same solution,
78 * so it's probably good enough...
79 */
80 p = (char *) str;
81 while (isspace((unsigned char) *p))
82 p++;
83 if (*p == '-') {
84 rc = -EINVAL;
85 goto err;
86 }
87 p = NULL;
88
89 errno = 0;
90 x = strtoumax(str, &p, 0);
91
92 if (p == str ||
93 (errno != 0 && (x == UINTMAX_MAX || x == 0))) {
94 rc = errno ? -errno : -1;
95 goto err;
96 }
97 if (!p || !*p)
98 goto done; /* without suffix */
99
100 /*
101 * Check size suffixes
102 */
103 check_suffix:
104 if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3))
105 base = 1024; /* XiB, 2^N */
106 else if (*(p + 1) == 'B' && !*(p + 2))
107 base = 1000; /* XB, 10^N */
108 else if (*(p + 1)) {
109 struct lconv const *l = localeconv();
110 char *dp = l ? l->decimal_point : NULL;
111 size_t dpsz = dp ? strlen(dp) : 0;
112
113 if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) {
114 char *fstr = p + dpsz;
115
116 for (p = fstr; *p && *p == '0'; p++)
117 frac_zeros++;
118 errno = 0, p = NULL;
119 frac = strtoumax(fstr, &p, 0);
120 if (p == fstr ||
121 (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) {
122 rc = errno ? -errno : -1;
123 goto err;
124 }
125 if (frac && (!p || !*p)) {
126 rc = -EINVAL;
127 goto err; /* without suffix, but with frac */
128 }
129 goto check_suffix;
130 }
131 rc = -EINVAL;
132 goto err; /* unexpected suffix */
133 }
134
135 sp = strchr(suf, *p);
136 if (sp)
137 pwr = (sp - suf) + 1;
138 else {
139 sp = strchr(suf2, *p);
140 if (sp)
141 pwr = (sp - suf2) + 1;
142 else {
143 rc = -EINVAL;
144 goto err;
145 }
146 }
147
148 rc = do_scale_by_power(&x, base, pwr);
149 if (power)
150 *power = pwr;
151 if (frac && pwr) {
152 int zeros_in_pwr = frac_zeros % 3;
153 int frac_pwr = pwr - (frac_zeros / 3) - 1;
154 uintmax_t y = frac * (zeros_in_pwr == 0 ? 100 :
155 zeros_in_pwr == 1 ? 10 : 1);
156
157 if (frac_pwr < 0) {
158 rc = -EINVAL;
159 goto err;
160 }
161 do_scale_by_power(&y, base, frac_pwr);
162 x += y;
163 }
164 done:
165 *res = x;
166 err:
167 return rc;
168 }
169
strtosize(const char * str,uintmax_t * res)170 int strtosize(const char *str, uintmax_t *res)
171 {
172 return parse_size(str, res, NULL);
173 }
174
isdigit_string(const char * str)175 int isdigit_string(const char *str)
176 {
177 const char *p;
178
179 for (p = str; p && *p && isdigit((unsigned char) *p); p++);
180
181 return p && p > str && !*p;
182 }
183
184
185 #ifndef HAVE_MEMPCPY
mempcpy(void * restrict dest,const void * restrict src,size_t n)186 void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
187 {
188 return ((char *)memcpy(dest, src, n)) + n;
189 }
190 #endif
191
192 #ifndef HAVE_STRNLEN
strnlen(const char * s,size_t maxlen)193 size_t strnlen(const char *s, size_t maxlen)
194 {
195 int i;
196
197 for (i = 0; i < maxlen; i++) {
198 if (s[i] == '\0')
199 return i + 1;
200 }
201 return maxlen;
202 }
203 #endif
204
205 #ifndef HAVE_STRNCHR
strnchr(const char * s,size_t maxlen,int c)206 char *strnchr(const char *s, size_t maxlen, int c)
207 {
208 for (; maxlen-- && *s != '\0'; ++s)
209 if (*s == (char)c)
210 return (char *)s;
211 return NULL;
212 }
213 #endif
214
215 #ifndef HAVE_STRNDUP
strndup(const char * s,size_t n)216 char *strndup(const char *s, size_t n)
217 {
218 size_t len = strnlen(s, n);
219 char *new = (char *) malloc((len + 1) * sizeof(char));
220 if (!new)
221 return NULL;
222 new[len] = '\0';
223 return (char *) memcpy(new, s, len);
224 }
225 #endif
226
strtos16_or_err(const char * str,const char * errmesg)227 int16_t strtos16_or_err(const char *str, const char *errmesg)
228 {
229 int32_t num = strtos32_or_err(str, errmesg);
230
231 if (num < INT16_MIN || num > INT16_MAX)
232 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
233
234 return num;
235 }
236
strtou16_or_err(const char * str,const char * errmesg)237 uint16_t strtou16_or_err(const char *str, const char *errmesg)
238 {
239 uint32_t num = strtou32_or_err(str, errmesg);
240
241 if (num > UINT16_MAX)
242 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
243
244 return num;
245 }
246
strtos32_or_err(const char * str,const char * errmesg)247 int32_t strtos32_or_err(const char *str, const char *errmesg)
248 {
249 int64_t num = strtos64_or_err(str, errmesg);
250
251 if (num < INT32_MIN || num > INT32_MAX)
252 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
253
254 return num;
255 }
256
strtou32_or_err(const char * str,const char * errmesg)257 uint32_t strtou32_or_err(const char *str, const char *errmesg)
258 {
259 uint64_t num = strtou64_or_err(str, errmesg);
260
261 if (num > UINT32_MAX)
262 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
263
264 return num;
265 }
266
strtos64_or_err(const char * str,const char * errmesg)267 int64_t strtos64_or_err(const char *str, const char *errmesg)
268 {
269 int64_t num;
270 char *end = NULL;
271
272 if (str == NULL || *str == '\0')
273 goto err;
274 errno = 0;
275 num = strtoimax(str, &end, 10);
276
277 if (errno || str == end || (end && *end))
278 goto err;
279
280 return num;
281 err:
282 if (errno)
283 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
284
285 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
286 }
287
strtou64_or_err(const char * str,const char * errmesg)288 uint64_t strtou64_or_err(const char *str, const char *errmesg)
289 {
290 uintmax_t num;
291 char *end = NULL;
292
293 if (str == NULL || *str == '\0')
294 goto err;
295 errno = 0;
296 num = strtoumax(str, &end, 10);
297
298 if (errno || str == end || (end && *end))
299 goto err;
300
301 return num;
302 err:
303 if (errno)
304 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
305
306 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
307 }
308
309
strtod_or_err(const char * str,const char * errmesg)310 double strtod_or_err(const char *str, const char *errmesg)
311 {
312 double num;
313 char *end = NULL;
314
315 if (str == NULL || *str == '\0')
316 goto err;
317 errno = 0;
318 num = strtod(str, &end);
319
320 if (errno || str == end || (end && *end))
321 goto err;
322
323 return num;
324 err:
325 if (errno)
326 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
327
328 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
329 }
330
strtol_or_err(const char * str,const char * errmesg)331 long strtol_or_err(const char *str, const char *errmesg)
332 {
333 long num;
334 char *end = NULL;
335
336 if (str == NULL || *str == '\0')
337 goto err;
338 errno = 0;
339 num = strtol(str, &end, 10);
340
341 if (errno || str == end || (end && *end))
342 goto err;
343
344 return num;
345 err:
346 if (errno)
347 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
348 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
349 }
350
strtoul_or_err(const char * str,const char * errmesg)351 unsigned long strtoul_or_err(const char *str, const char *errmesg)
352 {
353 unsigned long num;
354 char *end = NULL;
355
356 if (str == NULL || *str == '\0')
357 goto err;
358 errno = 0;
359 num = strtoul(str, &end, 10);
360
361 if (errno || str == end || (end && *end))
362 goto err;
363
364 return num;
365 err:
366 if (errno)
367 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
368
369 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
370 }
371
strtosize_or_err(const char * str,const char * errmesg)372 uintmax_t strtosize_or_err(const char *str, const char *errmesg)
373 {
374 uintmax_t num;
375
376 if (strtosize(str, &num) == 0)
377 return num;
378
379 if (errno)
380 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
381
382 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
383 }
384
385
strtotimeval_or_err(const char * str,struct timeval * tv,const char * errmesg)386 void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg)
387 {
388 double user_input;
389
390 user_input = strtod_or_err(str, errmesg);
391 tv->tv_sec = (time_t) user_input;
392 tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000);
393 }
394
395 /*
396 * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
397 * be 11 bytes.
398 */
strmode(mode_t mode,char * str)399 void strmode(mode_t mode, char *str)
400 {
401 if (S_ISDIR(mode))
402 str[0] = 'd';
403 else if (S_ISLNK(mode))
404 str[0] = 'l';
405 else if (S_ISCHR(mode))
406 str[0] = 'c';
407 else if (S_ISBLK(mode))
408 str[0] = 'b';
409 else if (S_ISSOCK(mode))
410 str[0] = 's';
411 else if (S_ISFIFO(mode))
412 str[0] = 'p';
413 else if (S_ISREG(mode))
414 str[0] = '-';
415
416 str[1] = mode & S_IRUSR ? 'r' : '-';
417 str[2] = mode & S_IWUSR ? 'w' : '-';
418 str[3] = (mode & S_ISUID
419 ? (mode & S_IXUSR ? 's' : 'S')
420 : (mode & S_IXUSR ? 'x' : '-'));
421 str[4] = mode & S_IRGRP ? 'r' : '-';
422 str[5] = mode & S_IWGRP ? 'w' : '-';
423 str[6] = (mode & S_ISGID
424 ? (mode & S_IXGRP ? 's' : 'S')
425 : (mode & S_IXGRP ? 'x' : '-'));
426 str[7] = mode & S_IROTH ? 'r' : '-';
427 str[8] = mode & S_IWOTH ? 'w' : '-';
428 str[9] = (mode & S_ISVTX
429 ? (mode & S_IXOTH ? 't' : 'T')
430 : (mode & S_IXOTH ? 'x' : '-'));
431 str[10] = '\0';
432 }
433
434 /*
435 * returns exponent (2^x=n) in range KiB..PiB
436 */
get_exp(uint64_t n)437 static int get_exp(uint64_t n)
438 {
439 int shft;
440
441 for (shft = 10; shft <= 60; shft += 10) {
442 if (n < (1ULL << shft))
443 break;
444 }
445 return shft - 10;
446 }
447
size_to_human_string(int options,uint64_t bytes)448 char *size_to_human_string(int options, uint64_t bytes)
449 {
450 char buf[32];
451 int dec, exp;
452 uint64_t frac;
453 const char *letters = "BKMGTPE";
454 char suffix[sizeof(" KiB")], *psuf = suffix;
455 char c;
456
457 if (options & SIZE_SUFFIX_SPACE)
458 *psuf++ = ' ';
459
460 exp = get_exp(bytes);
461 c = *(letters + (exp ? exp / 10 : 0));
462 dec = exp ? bytes / (1ULL << exp) : bytes;
463 frac = exp ? bytes % (1ULL << exp) : 0;
464
465 *psuf++ = c;
466
467 if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) {
468 *psuf++ = 'i';
469 *psuf++ = 'B';
470 }
471
472 *psuf = '\0';
473
474 /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n",
475 * exp, suffix[0], dec, frac);
476 */
477
478 if (frac) {
479 /* round */
480 frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
481 if (frac == 10)
482 dec++, frac = 0;
483 }
484
485 if (frac) {
486 struct lconv const *l = localeconv();
487 char *dp = l ? l->decimal_point : NULL;
488
489 if (!dp || !*dp)
490 dp = ".";
491 snprintf(buf, sizeof(buf), "%d%s%jd%s", dec, dp, frac, suffix);
492 } else
493 snprintf(buf, sizeof(buf), "%d%s", dec, suffix);
494
495 return strdup(buf);
496 }
497
498 /*
499 * Parses comma delimited list to array with IDs, for example:
500 *
501 * "aaa,bbb,ccc" --> ary[0] = FOO_AAA;
502 * ary[1] = FOO_BBB;
503 * ary[3] = FOO_CCC;
504 *
505 * The function name2id() provides conversion from string to ID.
506 *
507 * Returns: >= 0 : number of items added to ary[]
508 * -1 : parse error or unknown item
509 * -2 : arysz reached
510 */
string_to_idarray(const char * list,int ary[],size_t arysz,int (name2id)(const char *,size_t))511 int string_to_idarray(const char *list, int ary[], size_t arysz,
512 int (name2id)(const char *, size_t))
513 {
514 const char *begin = NULL, *p;
515 size_t n = 0;
516
517 if (!list || !*list || !ary || !arysz || !name2id)
518 return -1;
519
520 for (p = list; p && *p; p++) {
521 const char *end = NULL;
522 int id;
523
524 if (n >= arysz)
525 return -2;
526 if (!begin)
527 begin = p; /* begin of the column name */
528 if (*p == ',')
529 end = p; /* terminate the name */
530 if (*(p + 1) == '\0')
531 end = p + 1; /* end of string */
532 if (!begin || !end)
533 continue;
534 if (end <= begin)
535 return -1;
536
537 id = name2id(begin, end - begin);
538 if (id == -1)
539 return -1;
540 ary[ n++ ] = id;
541 begin = NULL;
542 if (end && !*end)
543 break;
544 }
545 return n;
546 }
547
548 /*
549 * Parses the array like string_to_idarray but if format is "+aaa,bbb"
550 * it adds fields to array instead of replacing them.
551 */
string_add_to_idarray(const char * list,int ary[],size_t arysz,int * ary_pos,int (name2id)(const char *,size_t))552 int string_add_to_idarray(const char *list, int ary[], size_t arysz,
553 int *ary_pos, int (name2id)(const char *, size_t))
554 {
555 const char *list_add;
556 int r;
557
558 if (!list || !*list || !ary_pos ||
559 *ary_pos < 0 || (size_t) *ary_pos > arysz)
560 return -1;
561
562 if (list[0] == '+')
563 list_add = &list[1];
564 else {
565 list_add = list;
566 *ary_pos = 0;
567 }
568
569 r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id);
570 if (r > 0)
571 *ary_pos += r;
572 return r;
573 }
574
575 /*
576 * LIST ::= <item> [, <item>]
577 *
578 * The <item> is translated to 'id' by name2id() function and the 'id' is used
579 * as a position in the 'ary' bit array. It means that the 'id' has to be in
580 * range <0..N> where N < sizeof(ary) * NBBY.
581 *
582 * Returns: 0 on success, <0 on error.
583 */
string_to_bitarray(const char * list,char * ary,int (* name2bit)(const char *,size_t))584 int string_to_bitarray(const char *list,
585 char *ary,
586 int (*name2bit)(const char *, size_t))
587 {
588 const char *begin = NULL, *p;
589
590 if (!list || !name2bit || !ary)
591 return -EINVAL;
592
593 for (p = list; p && *p; p++) {
594 const char *end = NULL;
595 int bit;
596
597 if (!begin)
598 begin = p; /* begin of the level name */
599 if (*p == ',')
600 end = p; /* terminate the name */
601 if (*(p + 1) == '\0')
602 end = p + 1; /* end of string */
603 if (!begin || !end)
604 continue;
605 if (end <= begin)
606 return -1;
607
608 bit = name2bit(begin, end - begin);
609 if (bit < 0)
610 return bit;
611 setbit(ary, bit);
612 begin = NULL;
613 if (end && !*end)
614 break;
615 }
616 return 0;
617 }
618
619 /*
620 * LIST ::= <item> [, <item>]
621 *
622 * The <item> is translated to 'id' by name2flag() function and the flags is
623 * set to the 'mask'
624 *
625 * Returns: 0 on success, <0 on error.
626 */
string_to_bitmask(const char * list,unsigned long * mask,long (* name2flag)(const char *,size_t))627 int string_to_bitmask(const char *list,
628 unsigned long *mask,
629 long (*name2flag)(const char *, size_t))
630 {
631 const char *begin = NULL, *p;
632
633 if (!list || !name2flag || !mask)
634 return -EINVAL;
635
636 for (p = list; p && *p; p++) {
637 const char *end = NULL;
638 long flag;
639
640 if (!begin)
641 begin = p; /* begin of the level name */
642 if (*p == ',')
643 end = p; /* terminate the name */
644 if (*(p + 1) == '\0')
645 end = p + 1; /* end of string */
646 if (!begin || !end)
647 continue;
648 if (end <= begin)
649 return -1;
650
651 flag = name2flag(begin, end - begin);
652 if (flag < 0)
653 return flag; /* error */
654 *mask |= flag;
655 begin = NULL;
656 if (end && !*end)
657 break;
658 }
659 return 0;
660 }
661
662 /*
663 * Parse the lower and higher values in a string containing
664 * "lower:higher" or "lower-higher" format. Note that either
665 * the lower or the higher values may be missing, and the def
666 * value will be assigned to it by default.
667 *
668 * Returns: 0 on success, <0 on error.
669 */
parse_range(const char * str,int * lower,int * upper,int def)670 int parse_range(const char *str, int *lower, int *upper, int def)
671 {
672 char *end = NULL;
673
674 if (!str)
675 return 0;
676
677 *upper = *lower = def;
678 errno = 0;
679
680 if (*str == ':') { /* <:N> */
681 str++;
682 *upper = strtol(str, &end, 10);
683 if (errno || !end || *end || end == str)
684 return -1;
685 } else {
686 *upper = *lower = strtol(str, &end, 10);
687 if (errno || !end || end == str)
688 return -1;
689
690 if (*end == ':' && !*(end + 1)) /* <M:> */
691 *upper = 0;
692 else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
693 str = end + 1;
694 end = NULL;
695 errno = 0;
696 *upper = strtol(str, &end, 10);
697
698 if (errno || !end || *end || end == str)
699 return -1;
700 }
701 }
702 return 0;
703 }
704
705 /*
706 * Compare two strings for equality, ignoring at most one trailing
707 * slash.
708 */
streq_except_trailing_slash(const char * s1,const char * s2)709 int streq_except_trailing_slash(const char *s1, const char *s2)
710 {
711 int equal;
712
713 if (!s1 && !s2)
714 return 1;
715 if (!s1 || !s2)
716 return 0;
717
718 equal = !strcmp(s1, s2);
719
720 if (!equal) {
721 size_t len1 = strlen(s1);
722 size_t len2 = strlen(s2);
723
724 if (len1 && *(s1 + len1 - 1) == '/')
725 len1--;
726 if (len2 && *(s2 + len2 - 1) == '/')
727 len2--;
728 if (len1 != len2)
729 return 0;
730
731 equal = !strncmp(s1, s2, len1);
732 }
733
734 return equal;
735 }
736
737
738 #ifdef TEST_PROGRAM
739
main(int argc,char * argv[])740 int main(int argc, char *argv[])
741 {
742 uintmax_t size = 0;
743 char *hum, *hum2;
744
745 if (argc < 2) {
746 fprintf(stderr, "usage: %s <number>[suffix]\n", argv[0]);
747 exit(EXIT_FAILURE);
748 }
749
750 if (strtosize(argv[1], &size))
751 errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
752
753 hum = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
754 hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER |
755 SIZE_SUFFIX_SPACE, size);
756
757 printf("%25s : %20ju : %8s : %12s\n", argv[1], size, hum, hum2);
758 free(hum);
759 free(hum2);
760
761 return EXIT_SUCCESS;
762 }
763 #endif /* TEST_PROGRAM */
764