]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/utils.c
vdpa: add .gitignore
[mirror_iproute2.git] / lib / utils.c
1 /*
2 * utils.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <math.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <limits.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <netdb.h>
24 #include <arpa/inet.h>
25 #include <asm/types.h>
26 #include <linux/pkt_sched.h>
27 #include <linux/param.h>
28 #include <linux/if_arp.h>
29 #include <linux/mpls.h>
30 #include <linux/snmp.h>
31 #include <time.h>
32 #include <sys/time.h>
33 #include <errno.h>
34 #ifdef HAVE_LIBCAP
35 #include <sys/capability.h>
36 #endif
37
38 #include "rt_names.h"
39 #include "utils.h"
40 #include "ll_map.h"
41 #include "namespace.h"
42
43 int resolve_hosts;
44 int timestamp_short;
45 int pretty;
46 const char *_SL_ = "\n";
47
48 static int af_byte_len(int af);
49 static void print_time(char *buf, int len, __u32 time);
50 static void print_time64(char *buf, int len, __s64 time);
51
52 int read_prop(const char *dev, char *prop, long *value)
53 {
54 char fname[128], buf[80], *endp, *nl;
55 FILE *fp;
56 long result;
57 int ret;
58
59 ret = snprintf(fname, sizeof(fname), "/sys/class/net/%s/%s",
60 dev, prop);
61
62 if (ret <= 0 || ret >= sizeof(fname)) {
63 fprintf(stderr, "could not build pathname for property\n");
64 return -1;
65 }
66
67 fp = fopen(fname, "r");
68 if (fp == NULL) {
69 fprintf(stderr, "fopen %s: %s\n", fname, strerror(errno));
70 return -1;
71 }
72
73 if (!fgets(buf, sizeof(buf), fp)) {
74 fprintf(stderr, "property \"%s\" in file %s is currently unknown\n", prop, fname);
75 fclose(fp);
76 goto out;
77 }
78
79 nl = strchr(buf, '\n');
80 if (nl)
81 *nl = '\0';
82
83 fclose(fp);
84 result = strtol(buf, &endp, 0);
85
86 if (*endp || buf == endp) {
87 fprintf(stderr, "value \"%s\" in file %s is not a number\n",
88 buf, fname);
89 goto out;
90 }
91
92 if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE) {
93 fprintf(stderr, "strtol %s: %s", fname, strerror(errno));
94 goto out;
95 }
96
97 *value = result;
98 return 0;
99 out:
100 fprintf(stderr, "Failed to parse %s\n", fname);
101 return -1;
102 }
103
104 /* Parse a percent e.g: '30%'
105 * return: 0 = ok, -1 = error, 1 = out of range
106 */
107 int parse_percent(double *val, const char *str)
108 {
109 char *p;
110
111 *val = strtod(str, &p) / 100.;
112 if (*val == HUGE_VALF || *val == HUGE_VALL)
113 return 1;
114 if (*p && strcmp(p, "%"))
115 return -1;
116
117 return 0;
118 }
119
120 int get_hex(char c)
121 {
122 if (c >= 'A' && c <= 'F')
123 return c - 'A' + 10;
124 if (c >= 'a' && c <= 'f')
125 return c - 'a' + 10;
126 if (c >= '0' && c <= '9')
127 return c - '0';
128
129 return -1;
130 }
131
132 int get_integer(int *val, const char *arg, int base)
133 {
134 long res;
135 char *ptr;
136
137 if (!arg || !*arg)
138 return -1;
139
140 res = strtol(arg, &ptr, base);
141
142 /* If there were no digits at all, strtol() stores
143 * the original value of nptr in *endptr (and returns 0).
144 * In particular, if *nptr is not '\0' but **endptr is '\0' on return,
145 * the entire string is valid.
146 */
147 if (!ptr || ptr == arg || *ptr)
148 return -1;
149
150 /* If an underflow occurs, strtol() returns LONG_MIN.
151 * If an overflow occurs, strtol() returns LONG_MAX.
152 * In both cases, errno is set to ERANGE.
153 */
154 if ((res == LONG_MAX || res == LONG_MIN) && errno == ERANGE)
155 return -1;
156
157 /* Outside range of int */
158 if (res < INT_MIN || res > INT_MAX)
159 return -1;
160
161 *val = res;
162 return 0;
163 }
164
165 int mask2bits(__u32 netmask)
166 {
167 unsigned int bits = 0;
168 __u32 mask = ntohl(netmask);
169 __u32 host = ~mask;
170
171 /* a valid netmask must be 2^n - 1 */
172 if ((host & (host + 1)) != 0)
173 return -1;
174
175 for (; mask; mask <<= 1)
176 ++bits;
177 return bits;
178 }
179
180 static int get_netmask(unsigned int *val, const char *arg, int base)
181 {
182 inet_prefix addr;
183
184 if (!get_unsigned(val, arg, base))
185 return 0;
186
187 /* try coverting dotted quad to CIDR */
188 if (!get_addr_1(&addr, arg, AF_INET) && addr.family == AF_INET) {
189 int b = mask2bits(addr.data[0]);
190
191 if (b >= 0) {
192 *val = b;
193 return 0;
194 }
195 }
196
197 return -1;
198 }
199
200 int get_unsigned(unsigned int *val, const char *arg, int base)
201 {
202 unsigned long res;
203 char *ptr;
204
205 if (!arg || !*arg)
206 return -1;
207
208 res = strtoul(arg, &ptr, base);
209
210 /* empty string or trailing non-digits */
211 if (!ptr || ptr == arg || *ptr)
212 return -1;
213
214 /* overflow */
215 if (res == ULONG_MAX && errno == ERANGE)
216 return -1;
217
218 /* out side range of unsigned */
219 if (res > UINT_MAX)
220 return -1;
221
222 *val = res;
223 return 0;
224 }
225
226 /*
227 * get_time_rtt is "translated" from a similar routine "get_time" in
228 * tc_util.c. We don't use the exact same routine because tc passes
229 * microseconds to the kernel and the callers of get_time_rtt want to
230 * pass milliseconds (standard unit for rtt values since 2.6.27), and
231 * have a different assumption for the units of a "raw" number.
232 */
233 int get_time_rtt(unsigned int *val, const char *arg, int *raw)
234 {
235 double t;
236 unsigned long res;
237 char *p;
238
239 if (strchr(arg, '.') != NULL) {
240 t = strtod(arg, &p);
241 if (t < 0.0)
242 return -1;
243
244 /* no digits? */
245 if (!p || p == arg)
246 return -1;
247
248 /* over/underflow */
249 if ((t == HUGE_VALF || t == HUGE_VALL) && errno == ERANGE)
250 return -1;
251 } else {
252 res = strtoul(arg, &p, 0);
253
254 /* empty string? */
255 if (!p || p == arg)
256 return -1;
257
258 /* overflow */
259 if (res == ULONG_MAX && errno == ERANGE)
260 return -1;
261
262 t = (double)res;
263 }
264
265 if (p == arg)
266 return -1;
267 *raw = 1;
268
269 if (*p) {
270 *raw = 0;
271 if (strcasecmp(p, "s") == 0 ||
272 strcasecmp(p, "sec") == 0 ||
273 strcasecmp(p, "secs") == 0)
274 t *= 1000;
275 else if (strcasecmp(p, "ms") == 0 ||
276 strcasecmp(p, "msec") == 0 ||
277 strcasecmp(p, "msecs") == 0)
278 t *= 1.0; /* allow suffix, do nothing */
279 else
280 return -1;
281 }
282
283 /* emulate ceil() without having to bring-in -lm and always be >= 1 */
284 *val = t;
285 if (*val < t)
286 *val += 1;
287
288 return 0;
289
290 }
291
292 int get_u64(__u64 *val, const char *arg, int base)
293 {
294 unsigned long long res;
295 char *ptr;
296
297 if (!arg || !*arg)
298 return -1;
299
300 res = strtoull(arg, &ptr, base);
301
302 /* empty string or trailing non-digits */
303 if (!ptr || ptr == arg || *ptr)
304 return -1;
305
306 /* overflow */
307 if (res == ULLONG_MAX && errno == ERANGE)
308 return -1;
309
310 /* in case ULL is 128 bits */
311 if (res > 0xFFFFFFFFFFFFFFFFULL)
312 return -1;
313
314 *val = res;
315 return 0;
316 }
317
318 int get_u32(__u32 *val, const char *arg, int base)
319 {
320 unsigned long res;
321 char *ptr;
322
323 if (!arg || !*arg)
324 return -1;
325 res = strtoul(arg, &ptr, base);
326
327 /* empty string or trailing non-digits */
328 if (!ptr || ptr == arg || *ptr)
329 return -1;
330
331 /* overflow */
332 if (res == ULONG_MAX && errno == ERANGE)
333 return -1;
334
335 /* in case UL > 32 bits */
336 if (res > 0xFFFFFFFFUL)
337 return -1;
338
339 *val = res;
340 return 0;
341 }
342
343 int get_u16(__u16 *val, const char *arg, int base)
344 {
345 unsigned long res;
346 char *ptr;
347
348 if (!arg || !*arg)
349 return -1;
350 res = strtoul(arg, &ptr, base);
351
352 /* empty string or trailing non-digits */
353 if (!ptr || ptr == arg || *ptr)
354 return -1;
355
356 /* overflow */
357 if (res == ULONG_MAX && errno == ERANGE)
358 return -1;
359
360 if (res > 0xFFFFUL)
361 return -1;
362
363 *val = res;
364 return 0;
365 }
366
367 int get_u8(__u8 *val, const char *arg, int base)
368 {
369 unsigned long res;
370 char *ptr;
371
372 if (!arg || !*arg)
373 return -1;
374
375 res = strtoul(arg, &ptr, base);
376 /* empty string or trailing non-digits */
377 if (!ptr || ptr == arg || *ptr)
378 return -1;
379
380 /* overflow */
381 if (res == ULONG_MAX && errno == ERANGE)
382 return -1;
383
384 if (res > 0xFFUL)
385 return -1;
386
387 *val = res;
388 return 0;
389 }
390
391 int get_s64(__s64 *val, const char *arg, int base)
392 {
393 long res;
394 char *ptr;
395
396 errno = 0;
397
398 if (!arg || !*arg)
399 return -1;
400 res = strtoll(arg, &ptr, base);
401 if (!ptr || ptr == arg || *ptr)
402 return -1;
403 if ((res == LLONG_MIN || res == LLONG_MAX) && errno == ERANGE)
404 return -1;
405 if (res > INT64_MAX || res < INT64_MIN)
406 return -1;
407
408 *val = res;
409 return 0;
410 }
411
412 int get_s32(__s32 *val, const char *arg, int base)
413 {
414 long res;
415 char *ptr;
416
417 errno = 0;
418
419 if (!arg || !*arg)
420 return -1;
421 res = strtol(arg, &ptr, base);
422 if (!ptr || ptr == arg || *ptr)
423 return -1;
424 if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
425 return -1;
426 if (res > INT32_MAX || res < INT32_MIN)
427 return -1;
428
429 *val = res;
430 return 0;
431 }
432
433 int get_be64(__be64 *val, const char *arg, int base)
434 {
435 __u64 v;
436 int ret = get_u64(&v, arg, base);
437
438 if (!ret)
439 *val = htonll(v);
440
441 return ret;
442 }
443
444 int get_be32(__be32 *val, const char *arg, int base)
445 {
446 __u32 v;
447 int ret = get_u32(&v, arg, base);
448
449 if (!ret)
450 *val = htonl(v);
451
452 return ret;
453 }
454
455 int get_be16(__be16 *val, const char *arg, int base)
456 {
457 __u16 v;
458 int ret = get_u16(&v, arg, base);
459
460 if (!ret)
461 *val = htons(v);
462
463 return ret;
464 }
465
466 /* This uses a non-standard parsing (ie not inet_aton, or inet_pton)
467 * because of legacy choice to parse 10.8 as 10.8.0.0 not 10.0.0.8
468 */
469 static int get_addr_ipv4(__u8 *ap, const char *cp)
470 {
471 int i;
472
473 for (i = 0; i < 4; i++) {
474 unsigned long n;
475 char *endp;
476
477 n = strtoul(cp, &endp, 0);
478 if (n > 255)
479 return -1; /* bogus network value */
480
481 if (endp == cp) /* no digits */
482 return -1;
483
484 ap[i] = n;
485
486 if (*endp == '\0')
487 break;
488
489 if (i == 3 || *endp != '.')
490 return -1; /* extra characters */
491 cp = endp + 1;
492 }
493
494 return 1;
495 }
496
497 int get_addr64(__u64 *ap, const char *cp)
498 {
499 int i;
500
501 union {
502 __u16 v16[4];
503 __u64 v64;
504 } val;
505
506 for (i = 0; i < 4; i++) {
507 unsigned long n;
508 char *endp;
509
510 n = strtoul(cp, &endp, 16);
511 if (n > 0xffff)
512 return -1; /* bogus network value */
513
514 if (endp == cp) /* no digits */
515 return -1;
516
517 val.v16[i] = htons(n);
518
519 if (*endp == '\0')
520 break;
521
522 if (i == 3 || *endp != ':')
523 return -1; /* extra characters */
524 cp = endp + 1;
525 }
526
527 *ap = val.v64;
528
529 return 1;
530 }
531
532 static void set_address_type(inet_prefix *addr)
533 {
534 switch (addr->family) {
535 case AF_INET:
536 if (!addr->data[0])
537 addr->flags |= ADDRTYPE_INET_UNSPEC;
538 else if (IN_MULTICAST(ntohl(addr->data[0])))
539 addr->flags |= ADDRTYPE_INET_MULTI;
540 else
541 addr->flags |= ADDRTYPE_INET;
542 break;
543 case AF_INET6:
544 if (IN6_IS_ADDR_UNSPECIFIED(addr->data))
545 addr->flags |= ADDRTYPE_INET_UNSPEC;
546 else if (IN6_IS_ADDR_MULTICAST(addr->data))
547 addr->flags |= ADDRTYPE_INET_MULTI;
548 else
549 addr->flags |= ADDRTYPE_INET;
550 break;
551 }
552 }
553
554 static int __get_addr_1(inet_prefix *addr, const char *name, int family)
555 {
556 memset(addr, 0, sizeof(*addr));
557
558 if (strcmp(name, "default") == 0) {
559 if ((family == AF_DECnet) || (family == AF_MPLS))
560 return -1;
561 addr->family = family;
562 addr->bytelen = af_byte_len(addr->family);
563 addr->bitlen = -2;
564 addr->flags |= PREFIXLEN_SPECIFIED;
565 return 0;
566 }
567
568 if (strcmp(name, "all") == 0 ||
569 strcmp(name, "any") == 0) {
570 if ((family == AF_DECnet) || (family == AF_MPLS))
571 return -1;
572 addr->family = family;
573 addr->bytelen = 0;
574 addr->bitlen = -2;
575 return 0;
576 }
577
578 if (family == AF_PACKET) {
579 int len;
580
581 len = ll_addr_a2n((char *) &addr->data, sizeof(addr->data),
582 name);
583 if (len < 0)
584 return -1;
585
586 addr->family = AF_PACKET;
587 addr->bytelen = len;
588 addr->bitlen = len * 8;
589 return 0;
590 }
591
592 if (strchr(name, ':')) {
593 addr->family = AF_INET6;
594 if (family != AF_UNSPEC && family != AF_INET6)
595 return -1;
596 if (inet_pton(AF_INET6, name, addr->data) <= 0)
597 return -1;
598 addr->bytelen = 16;
599 addr->bitlen = -1;
600 return 0;
601 }
602
603 if (family == AF_MPLS) {
604 unsigned int maxlabels;
605 int i;
606
607 addr->family = AF_MPLS;
608 if (mpls_pton(AF_MPLS, name, addr->data,
609 sizeof(addr->data)) <= 0)
610 return -1;
611 addr->bytelen = 4;
612 addr->bitlen = 20;
613 /* How many bytes do I need? */
614 maxlabels = sizeof(addr->data) / sizeof(struct mpls_label);
615 for (i = 0; i < maxlabels; i++) {
616 if (ntohl(addr->data[i]) & MPLS_LS_S_MASK) {
617 addr->bytelen = (i + 1)*4;
618 break;
619 }
620 }
621 return 0;
622 }
623
624 addr->family = AF_INET;
625 if (family != AF_UNSPEC && family != AF_INET)
626 return -1;
627
628 if (get_addr_ipv4((__u8 *)addr->data, name) <= 0)
629 return -1;
630
631 addr->bytelen = 4;
632 addr->bitlen = -1;
633 return 0;
634 }
635
636 int get_addr_1(inet_prefix *addr, const char *name, int family)
637 {
638 int ret;
639
640 ret = __get_addr_1(addr, name, family);
641 if (ret)
642 return ret;
643
644 set_address_type(addr);
645 return 0;
646 }
647
648 int af_bit_len(int af)
649 {
650 switch (af) {
651 case AF_INET6:
652 return 128;
653 case AF_INET:
654 return 32;
655 case AF_DECnet:
656 return 16;
657 case AF_IPX:
658 return 80;
659 case AF_MPLS:
660 return 20;
661 }
662
663 return 0;
664 }
665
666 static int af_byte_len(int af)
667 {
668 return af_bit_len(af) / 8;
669 }
670
671 int get_prefix_1(inet_prefix *dst, char *arg, int family)
672 {
673 char *slash;
674 int err, bitlen, flags;
675
676 slash = strchr(arg, '/');
677 if (slash)
678 *slash = 0;
679
680 err = get_addr_1(dst, arg, family);
681
682 if (slash)
683 *slash = '/';
684
685 if (err)
686 return err;
687
688 bitlen = af_bit_len(dst->family);
689
690 flags = 0;
691 if (slash) {
692 unsigned int plen;
693
694 if (dst->bitlen == -2)
695 return -1;
696 if (get_netmask(&plen, slash + 1, 0))
697 return -1;
698 if (plen > bitlen)
699 return -1;
700
701 flags |= PREFIXLEN_SPECIFIED;
702 bitlen = plen;
703 } else {
704 if (dst->bitlen == -2)
705 bitlen = 0;
706 }
707
708 dst->flags |= flags;
709 dst->bitlen = bitlen;
710
711 return 0;
712 }
713
714 static const char *family_name_verbose(int family)
715 {
716 if (family == AF_UNSPEC)
717 return "any valid";
718 return family_name(family);
719 }
720
721 int get_addr(inet_prefix *dst, const char *arg, int family)
722 {
723 if (get_addr_1(dst, arg, family)) {
724 fprintf(stderr,
725 "Error: %s address is expected rather than \"%s\".\n",
726 family_name_verbose(family), arg);
727 exit(1);
728 }
729 return 0;
730 }
731
732 int get_addr_rta(inet_prefix *dst, const struct rtattr *rta, int family)
733 {
734 const int len = RTA_PAYLOAD(rta);
735 const void *data = RTA_DATA(rta);
736
737 switch (len) {
738 case 4:
739 dst->family = AF_INET;
740 dst->bytelen = 4;
741 memcpy(dst->data, data, 4);
742 break;
743 case 16:
744 dst->family = AF_INET6;
745 dst->bytelen = 16;
746 memcpy(dst->data, data, 16);
747 break;
748 case 2:
749 dst->family = AF_DECnet;
750 dst->bytelen = 2;
751 memcpy(dst->data, data, 2);
752 break;
753 case 10:
754 dst->family = AF_IPX;
755 dst->bytelen = 10;
756 memcpy(dst->data, data, 10);
757 break;
758 default:
759 return -1;
760 }
761
762 if (family != AF_UNSPEC && family != dst->family)
763 return -2;
764
765 dst->bitlen = -1;
766 dst->flags = 0;
767
768 set_address_type(dst);
769 return 0;
770 }
771
772 int get_prefix(inet_prefix *dst, char *arg, int family)
773 {
774 if (family == AF_PACKET) {
775 fprintf(stderr,
776 "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n",
777 arg);
778 exit(1);
779 }
780
781 if (get_prefix_1(dst, arg, family)) {
782 fprintf(stderr,
783 "Error: %s prefix is expected rather than \"%s\".\n",
784 family_name_verbose(family), arg);
785 exit(1);
786 }
787 return 0;
788 }
789
790 __u32 get_addr32(const char *name)
791 {
792 inet_prefix addr;
793
794 if (get_addr_1(&addr, name, AF_INET)) {
795 fprintf(stderr,
796 "Error: an IP address is expected rather than \"%s\"\n",
797 name);
798 exit(1);
799 }
800 return addr.data[0];
801 }
802
803 void incomplete_command(void)
804 {
805 fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
806 exit(-1);
807 }
808
809 void missarg(const char *key)
810 {
811 fprintf(stderr, "Error: argument \"%s\" is required\n", key);
812 exit(-1);
813 }
814
815 void invarg(const char *msg, const char *arg)
816 {
817 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
818 exit(-1);
819 }
820
821 void duparg(const char *key, const char *arg)
822 {
823 fprintf(stderr,
824 "Error: duplicate \"%s\": \"%s\" is the second value.\n",
825 key, arg);
826 exit(-1);
827 }
828
829 void duparg2(const char *key, const char *arg)
830 {
831 fprintf(stderr,
832 "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n",
833 key, arg);
834 exit(-1);
835 }
836
837 int nodev(const char *dev)
838 {
839 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
840 return -1;
841 }
842
843 int check_ifname(const char *name)
844 {
845 /* These checks mimic kernel checks in dev_valid_name */
846 if (*name == '\0')
847 return -1;
848 if (strlen(name) >= IFNAMSIZ)
849 return -1;
850
851 while (*name) {
852 if (*name == '/' || isspace(*name))
853 return -1;
854 ++name;
855 }
856 return 0;
857 }
858
859 /* buf is assumed to be IFNAMSIZ */
860 int get_ifname(char *buf, const char *name)
861 {
862 int ret;
863
864 ret = check_ifname(name);
865 if (ret == 0)
866 strncpy(buf, name, IFNAMSIZ);
867
868 return ret;
869 }
870
871 const char *get_ifname_rta(int ifindex, const struct rtattr *rta)
872 {
873 const char *name;
874
875 if (rta) {
876 name = rta_getattr_str(rta);
877 } else {
878 fprintf(stderr,
879 "BUG: device with ifindex %d has nil ifname\n",
880 ifindex);
881 name = ll_idx_n2a(ifindex);
882 }
883
884 if (check_ifname(name))
885 return NULL;
886
887 return name;
888 }
889
890 int matches(const char *cmd, const char *pattern)
891 {
892 int len = strlen(cmd);
893
894 if (len > strlen(pattern))
895 return -1;
896 return memcmp(pattern, cmd, len);
897 }
898
899 int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
900 {
901 const __u32 *a1 = a->data;
902 const __u32 *a2 = b->data;
903 int words = bits >> 0x05;
904
905 bits &= 0x1f;
906
907 if (words)
908 if (memcmp(a1, a2, words << 2))
909 return -1;
910
911 if (bits) {
912 __u32 w1, w2;
913 __u32 mask;
914
915 w1 = a1[words];
916 w2 = a2[words];
917
918 mask = htonl((0xffffffff) << (0x20 - bits));
919
920 if ((w1 ^ w2) & mask)
921 return 1;
922 }
923
924 return 0;
925 }
926
927 int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta)
928 {
929 inet_prefix dst;
930
931 if (!rta || m->family == AF_UNSPEC || m->bitlen <= 0)
932 return 0;
933
934 if (get_addr_rta(&dst, rta, m->family))
935 return -1;
936
937 return inet_addr_match(&dst, m, m->bitlen);
938 }
939
940 int __iproute2_hz_internal;
941
942 int __get_hz(void)
943 {
944 char name[1024];
945 int hz = 0;
946 FILE *fp;
947
948 if (getenv("HZ"))
949 return atoi(getenv("HZ")) ? : HZ;
950
951 if (getenv("PROC_NET_PSCHED"))
952 snprintf(name, sizeof(name)-1,
953 "%s", getenv("PROC_NET_PSCHED"));
954 else if (getenv("PROC_ROOT"))
955 snprintf(name, sizeof(name)-1,
956 "%s/net/psched", getenv("PROC_ROOT"));
957 else
958 strcpy(name, "/proc/net/psched");
959
960 fp = fopen(name, "r");
961
962 if (fp) {
963 unsigned int nom, denom;
964
965 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
966 if (nom == 1000000)
967 hz = denom;
968 fclose(fp);
969 }
970 if (hz)
971 return hz;
972 return HZ;
973 }
974
975 int __iproute2_user_hz_internal;
976
977 int __get_user_hz(void)
978 {
979 return sysconf(_SC_CLK_TCK);
980 }
981
982 const char *rt_addr_n2a_r(int af, int len,
983 const void *addr, char *buf, int buflen)
984 {
985 switch (af) {
986 case AF_INET:
987 case AF_INET6:
988 return inet_ntop(af, addr, buf, buflen);
989 case AF_MPLS:
990 return mpls_ntop(af, addr, buf, buflen);
991 case AF_PACKET:
992 return ll_addr_n2a(addr, len, ARPHRD_VOID, buf, buflen);
993 case AF_BRIDGE:
994 {
995 const union {
996 struct sockaddr sa;
997 struct sockaddr_in sin;
998 struct sockaddr_in6 sin6;
999 } *sa = addr;
1000
1001 switch (sa->sa.sa_family) {
1002 case AF_INET:
1003 return inet_ntop(AF_INET, &sa->sin.sin_addr,
1004 buf, buflen);
1005 case AF_INET6:
1006 return inet_ntop(AF_INET6, &sa->sin6.sin6_addr,
1007 buf, buflen);
1008 }
1009
1010 /* fallthrough */
1011 }
1012 default:
1013 return "???";
1014 }
1015 }
1016
1017 const char *rt_addr_n2a(int af, int len, const void *addr)
1018 {
1019 static char buf[256];
1020
1021 return rt_addr_n2a_r(af, len, addr, buf, 256);
1022 }
1023
1024 int read_family(const char *name)
1025 {
1026 int family = AF_UNSPEC;
1027
1028 if (strcmp(name, "inet") == 0)
1029 family = AF_INET;
1030 else if (strcmp(name, "inet6") == 0)
1031 family = AF_INET6;
1032 else if (strcmp(name, "link") == 0)
1033 family = AF_PACKET;
1034 else if (strcmp(name, "ipx") == 0)
1035 family = AF_IPX;
1036 else if (strcmp(name, "mpls") == 0)
1037 family = AF_MPLS;
1038 else if (strcmp(name, "bridge") == 0)
1039 family = AF_BRIDGE;
1040 return family;
1041 }
1042
1043 const char *family_name(int family)
1044 {
1045 if (family == AF_INET)
1046 return "inet";
1047 if (family == AF_INET6)
1048 return "inet6";
1049 if (family == AF_PACKET)
1050 return "link";
1051 if (family == AF_IPX)
1052 return "ipx";
1053 if (family == AF_MPLS)
1054 return "mpls";
1055 if (family == AF_BRIDGE)
1056 return "bridge";
1057 return "???";
1058 }
1059
1060 #ifdef RESOLVE_HOSTNAMES
1061 struct namerec {
1062 struct namerec *next;
1063 const char *name;
1064 inet_prefix addr;
1065 };
1066
1067 #define NHASH 257
1068 static struct namerec *nht[NHASH];
1069
1070 static const char *resolve_address(const void *addr, int len, int af)
1071 {
1072 struct namerec *n;
1073 struct hostent *h_ent;
1074 unsigned int hash;
1075 static int notfirst;
1076
1077
1078 if (af == AF_INET6 && ((__u32 *)addr)[0] == 0 &&
1079 ((__u32 *)addr)[1] == 0 && ((__u32 *)addr)[2] == htonl(0xffff)) {
1080 af = AF_INET;
1081 addr += 12;
1082 len = 4;
1083 }
1084
1085 hash = *(__u32 *)(addr + len - 4) % NHASH;
1086
1087 for (n = nht[hash]; n; n = n->next) {
1088 if (n->addr.family == af &&
1089 n->addr.bytelen == len &&
1090 memcmp(n->addr.data, addr, len) == 0)
1091 return n->name;
1092 }
1093 n = malloc(sizeof(*n));
1094 if (n == NULL)
1095 return NULL;
1096 n->addr.family = af;
1097 n->addr.bytelen = len;
1098 n->name = NULL;
1099 memcpy(n->addr.data, addr, len);
1100 n->next = nht[hash];
1101 nht[hash] = n;
1102 if (++notfirst == 1)
1103 sethostent(1);
1104 fflush(stdout);
1105
1106 h_ent = gethostbyaddr(addr, len, af);
1107 if (h_ent != NULL)
1108 n->name = strdup(h_ent->h_name);
1109
1110 /* Even if we fail, "negative" entry is remembered. */
1111 return n->name;
1112 }
1113 #endif
1114
1115 const char *format_host_r(int af, int len, const void *addr,
1116 char *buf, int buflen)
1117 {
1118 #ifdef RESOLVE_HOSTNAMES
1119 if (resolve_hosts) {
1120 const char *n;
1121
1122 len = len <= 0 ? af_byte_len(af) : len;
1123
1124 if (len > 0 &&
1125 (n = resolve_address(addr, len, af)) != NULL)
1126 return n;
1127 }
1128 #endif
1129 return rt_addr_n2a_r(af, len, addr, buf, buflen);
1130 }
1131
1132 const char *format_host(int af, int len, const void *addr)
1133 {
1134 static char buf[256];
1135
1136 return format_host_r(af, len, addr, buf, 256);
1137 }
1138
1139
1140 char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen)
1141 {
1142 char *ptr = buf;
1143 int i;
1144
1145 for (i = 0; i < len; i++) {
1146 if (blen < 3)
1147 break;
1148 sprintf(ptr, "%02x", str[i]);
1149 ptr += 2;
1150 blen -= 2;
1151 }
1152 return buf;
1153 }
1154
1155 __u8 *hexstring_a2n(const char *str, __u8 *buf, int blen, unsigned int *len)
1156 {
1157 unsigned int cnt = 0;
1158 char *endptr;
1159
1160 if (strlen(str) % 2)
1161 return NULL;
1162 while (cnt < blen && strlen(str) > 1) {
1163 unsigned int tmp;
1164 char tmpstr[3];
1165
1166 strncpy(tmpstr, str, 2);
1167 tmpstr[2] = '\0';
1168 errno = 0;
1169 tmp = strtoul(tmpstr, &endptr, 16);
1170 if (errno != 0 || tmp > 0xFF || *endptr != '\0')
1171 return NULL;
1172 buf[cnt++] = tmp;
1173 str += 2;
1174 }
1175
1176 if (len)
1177 *len = cnt;
1178
1179 return buf;
1180 }
1181
1182 int hex2mem(const char *buf, uint8_t *mem, int count)
1183 {
1184 int i, j;
1185 int c;
1186
1187 for (i = 0, j = 0; i < count; i++, j += 2) {
1188 c = get_hex(buf[j]);
1189 if (c < 0)
1190 return -1;
1191
1192 mem[i] = c << 4;
1193
1194 c = get_hex(buf[j + 1]);
1195 if (c < 0)
1196 return -1;
1197
1198 mem[i] |= c;
1199 }
1200
1201 return 0;
1202 }
1203
1204 int addr64_n2a(__u64 addr, char *buff, size_t len)
1205 {
1206 __u16 *words = (__u16 *)&addr;
1207 __u16 v;
1208 int i, ret;
1209 size_t written = 0;
1210 char *sep = ":";
1211
1212 for (i = 0; i < 4; i++) {
1213 v = ntohs(words[i]);
1214
1215 if (i == 3)
1216 sep = "";
1217
1218 ret = snprintf(&buff[written], len - written, "%x%s", v, sep);
1219 if (ret < 0)
1220 return ret;
1221
1222 written += ret;
1223 }
1224
1225 return written;
1226 }
1227
1228 /* Print buffer and escape bytes that are !isprint or among 'escape' */
1229 void print_escape_buf(const __u8 *buf, size_t len, const char *escape)
1230 {
1231 size_t i;
1232
1233 for (i = 0; i < len; ++i) {
1234 if (isprint(buf[i]) && buf[i] != '\\' &&
1235 !strchr(escape, buf[i]))
1236 printf("%c", buf[i]);
1237 else
1238 printf("\\%03o", buf[i]);
1239 }
1240 }
1241
1242 int print_timestamp(FILE *fp)
1243 {
1244 struct timeval tv;
1245 struct tm *tm;
1246
1247 gettimeofday(&tv, NULL);
1248 tm = localtime(&tv.tv_sec);
1249
1250 if (timestamp_short) {
1251 char tshort[40];
1252
1253 strftime(tshort, sizeof(tshort), "%Y-%m-%dT%H:%M:%S", tm);
1254 fprintf(fp, "[%s.%06ld] ", tshort, tv.tv_usec);
1255 } else {
1256 char *tstr = asctime(tm);
1257
1258 tstr[strlen(tstr)-1] = 0;
1259 fprintf(fp, "Timestamp: %s %ld usec\n",
1260 tstr, tv.tv_usec);
1261 }
1262
1263 return 0;
1264 }
1265
1266 unsigned int print_name_and_link(const char *fmt,
1267 const char *name, struct rtattr *tb[])
1268 {
1269 const char *link = NULL;
1270 unsigned int m_flag = 0;
1271 SPRINT_BUF(b1);
1272
1273 if (tb[IFLA_LINK]) {
1274 int iflink = rta_getattr_u32(tb[IFLA_LINK]);
1275
1276 if (iflink) {
1277 if (tb[IFLA_LINK_NETNSID]) {
1278 if (is_json_context()) {
1279 print_int(PRINT_JSON,
1280 "link_index", NULL, iflink);
1281 } else {
1282 link = ll_idx_n2a(iflink);
1283 }
1284 } else {
1285 link = ll_index_to_name(iflink);
1286
1287 if (is_json_context()) {
1288 print_string(PRINT_JSON,
1289 "link", NULL, link);
1290 link = NULL;
1291 }
1292
1293 m_flag = ll_index_to_flags(iflink);
1294 m_flag = !(m_flag & IFF_UP);
1295 }
1296 } else {
1297 if (is_json_context())
1298 print_null(PRINT_JSON, "link", NULL, NULL);
1299 else
1300 link = "NONE";
1301 }
1302
1303 if (link) {
1304 snprintf(b1, sizeof(b1), "%s@%s", name, link);
1305 name = b1;
1306 }
1307 }
1308
1309 print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt, name);
1310
1311 return m_flag;
1312 }
1313
1314 int cmdlineno;
1315
1316 /* Like glibc getline but handle continuation lines and comments */
1317 ssize_t getcmdline(char **linep, size_t *lenp, FILE *in)
1318 {
1319 ssize_t cc;
1320 char *cp;
1321
1322 cc = getline(linep, lenp, in);
1323 if (cc < 0)
1324 return cc; /* eof or error */
1325 ++cmdlineno;
1326
1327 cp = strchr(*linep, '#');
1328 if (cp)
1329 *cp = '\0';
1330
1331 while ((cp = strstr(*linep, "\\\n")) != NULL) {
1332 char *line1 = NULL;
1333 size_t len1 = 0;
1334 ssize_t cc1;
1335
1336 cc1 = getline(&line1, &len1, in);
1337 if (cc1 < 0) {
1338 fprintf(stderr, "Missing continuation line\n");
1339 return cc1;
1340 }
1341
1342 ++cmdlineno;
1343 *cp = 0;
1344
1345 cp = strchr(line1, '#');
1346 if (cp)
1347 *cp = '\0';
1348
1349 *lenp = strlen(*linep) + strlen(line1) + 1;
1350 *linep = realloc(*linep, *lenp);
1351 if (!*linep) {
1352 fprintf(stderr, "Out of memory\n");
1353 *lenp = 0;
1354 return -1;
1355 }
1356 cc += cc1 - 2;
1357 strcat(*linep, line1);
1358 free(line1);
1359 }
1360 return cc;
1361 }
1362
1363 /* split command line into argument vector */
1364 int makeargs(char *line, char *argv[], int maxargs)
1365 {
1366 static const char ws[] = " \t\r\n";
1367 char *cp = line;
1368 int argc = 0;
1369
1370 while (*cp) {
1371 /* skip leading whitespace */
1372 cp += strspn(cp, ws);
1373
1374 if (*cp == '\0')
1375 break;
1376
1377 if (argc >= (maxargs - 1)) {
1378 fprintf(stderr, "Too many arguments to command\n");
1379 exit(1);
1380 }
1381
1382 /* word begins with quote */
1383 if (*cp == '\'' || *cp == '"') {
1384 char quote = *cp++;
1385
1386 argv[argc++] = cp;
1387 /* find ending quote */
1388 cp = strchr(cp, quote);
1389 if (cp == NULL) {
1390 fprintf(stderr, "Unterminated quoted string\n");
1391 exit(1);
1392 }
1393 } else {
1394 argv[argc++] = cp;
1395
1396 /* find end of word */
1397 cp += strcspn(cp, ws);
1398 if (*cp == '\0')
1399 break;
1400 }
1401
1402 /* separate words */
1403 *cp++ = 0;
1404 }
1405 argv[argc] = NULL;
1406
1407 return argc;
1408 }
1409
1410 void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n)
1411 {
1412 char *tstr;
1413 time_t secs = ((__u32 *)NLMSG_DATA(n))[0];
1414 long usecs = ((__u32 *)NLMSG_DATA(n))[1];
1415
1416 tstr = asctime(localtime(&secs));
1417 tstr[strlen(tstr)-1] = 0;
1418 fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs);
1419 }
1420
1421 static int on_netns(char *nsname, void *arg)
1422 {
1423 struct netns_func *f = arg;
1424
1425 if (netns_switch(nsname))
1426 return -1;
1427
1428 return f->func(nsname, f->arg);
1429 }
1430
1431 static int on_netns_label(char *nsname, void *arg)
1432 {
1433 printf("\nnetns: %s\n", nsname);
1434 return on_netns(nsname, arg);
1435 }
1436
1437 int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
1438 bool show_label)
1439 {
1440 struct netns_func nsf = { .func = func, .arg = arg };
1441
1442 if (show_label)
1443 return netns_foreach(on_netns_label, &nsf);
1444
1445 return netns_foreach(on_netns, &nsf);
1446 }
1447
1448 char *int_to_str(int val, char *buf)
1449 {
1450 sprintf(buf, "%d", val);
1451 return buf;
1452 }
1453
1454 int get_guid(__u64 *guid, const char *arg)
1455 {
1456 unsigned long tmp;
1457 char *endptr;
1458 int i;
1459
1460 #define GUID_STR_LEN 23
1461 /* Verify strict format: format string must be
1462 * xx:xx:xx:xx:xx:xx:xx:xx where xx can be an arbitrary
1463 * hex digit
1464 */
1465
1466 if (strlen(arg) != GUID_STR_LEN)
1467 return -1;
1468
1469 /* make sure columns are in place */
1470 for (i = 0; i < 7; i++)
1471 if (arg[2 + i * 3] != ':')
1472 return -1;
1473
1474 *guid = 0;
1475 for (i = 0; i < 8; i++) {
1476 tmp = strtoul(arg + i * 3, &endptr, 16);
1477 if (endptr != arg + i * 3 + 2)
1478 return -1;
1479
1480 if (tmp > 255)
1481 return -1;
1482
1483 *guid |= tmp << (56 - 8 * i);
1484 }
1485
1486 return 0;
1487 }
1488
1489 /* This is a necessary workaround for multicast route dumps */
1490 int get_real_family(int rtm_type, int rtm_family)
1491 {
1492 if (rtm_type != RTN_MULTICAST)
1493 return rtm_family;
1494
1495 if (rtm_family == RTNL_FAMILY_IPMR)
1496 return AF_INET;
1497
1498 if (rtm_family == RTNL_FAMILY_IP6MR)
1499 return AF_INET6;
1500
1501 return rtm_family;
1502 }
1503
1504 /* Based on copy_rtnl_link_stats() from kernel at net/core/rtnetlink.c */
1505 static void copy_rtnl_link_stats64(struct rtnl_link_stats64 *stats64,
1506 const struct rtnl_link_stats *stats)
1507 {
1508 __u64 *a = (__u64 *)stats64;
1509 const __u32 *b = (const __u32 *)stats;
1510 const __u32 *e = b + sizeof(*stats) / sizeof(*b);
1511
1512 while (b < e)
1513 *a++ = *b++;
1514 }
1515
1516 #define IPSTATS_MIB_MAX_LEN (__IPSTATS_MIB_MAX * sizeof(__u64))
1517 static void get_snmp_counters(struct rtnl_link_stats64 *stats64,
1518 struct rtattr *s)
1519 {
1520 __u64 *mib = (__u64 *)RTA_DATA(s);
1521
1522 memset(stats64, 0, sizeof(*stats64));
1523
1524 stats64->rx_packets = mib[IPSTATS_MIB_INPKTS];
1525 stats64->rx_bytes = mib[IPSTATS_MIB_INOCTETS];
1526 stats64->tx_packets = mib[IPSTATS_MIB_OUTPKTS];
1527 stats64->tx_bytes = mib[IPSTATS_MIB_OUTOCTETS];
1528 stats64->rx_errors = mib[IPSTATS_MIB_INDISCARDS];
1529 stats64->tx_errors = mib[IPSTATS_MIB_OUTDISCARDS];
1530 stats64->multicast = mib[IPSTATS_MIB_INMCASTPKTS];
1531 stats64->rx_frame_errors = mib[IPSTATS_MIB_CSUMERRORS];
1532 }
1533
1534 int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
1535 struct rtattr *tb[])
1536 {
1537 struct rtnl_link_stats stats;
1538 void *s;
1539 struct rtattr *rta;
1540 int size, len;
1541
1542 if (tb[IFLA_STATS64]) {
1543 rta = tb[IFLA_STATS64];
1544 size = sizeof(struct rtnl_link_stats64);
1545 s = stats64;
1546 } else if (tb[IFLA_STATS]) {
1547 rta = tb[IFLA_STATS];
1548 size = sizeof(struct rtnl_link_stats);
1549 s = &stats;
1550 } else if (tb[IFLA_PROTINFO]) {
1551 struct rtattr *ptb[IPSTATS_MIB_MAX_LEN + 1];
1552
1553 parse_rtattr_nested(ptb, IPSTATS_MIB_MAX_LEN,
1554 tb[IFLA_PROTINFO]);
1555 if (ptb[IFLA_INET6_STATS])
1556 get_snmp_counters(stats64, ptb[IFLA_INET6_STATS]);
1557 return sizeof(*stats64);
1558 } else {
1559 return -1;
1560 }
1561
1562 len = RTA_PAYLOAD(rta);
1563 if (len < size)
1564 memset(s + len, 0, size - len);
1565 else
1566 len = size;
1567
1568 memcpy(s, RTA_DATA(rta), len);
1569
1570 if (s != stats64)
1571 copy_rtnl_link_stats64(stats64, s);
1572 return size;
1573 }
1574
1575 #ifdef NEED_STRLCPY
1576 size_t strlcpy(char *dst, const char *src, size_t size)
1577 {
1578 size_t srclen = strlen(src);
1579
1580 if (size) {
1581 size_t minlen = min(srclen, size - 1);
1582
1583 memcpy(dst, src, minlen);
1584 dst[minlen] = '\0';
1585 }
1586 return srclen;
1587 }
1588
1589 size_t strlcat(char *dst, const char *src, size_t size)
1590 {
1591 size_t dlen = strlen(dst);
1592
1593 if (dlen >= size)
1594 return dlen + strlen(src);
1595
1596 return dlen + strlcpy(dst + dlen, src, size - dlen);
1597 }
1598 #endif
1599
1600 void drop_cap(void)
1601 {
1602 #ifdef HAVE_LIBCAP
1603 /* don't harmstring root/sudo */
1604 if (getuid() != 0 && geteuid() != 0) {
1605 cap_t capabilities;
1606 cap_value_t net_admin = CAP_NET_ADMIN;
1607 cap_flag_t inheritable = CAP_INHERITABLE;
1608 cap_flag_value_t is_set;
1609
1610 capabilities = cap_get_proc();
1611 if (!capabilities)
1612 exit(EXIT_FAILURE);
1613 if (cap_get_flag(capabilities, net_admin, inheritable,
1614 &is_set) != 0)
1615 exit(EXIT_FAILURE);
1616 /* apps with ambient caps can fork and call ip */
1617 if (is_set == CAP_CLEAR) {
1618 if (cap_clear(capabilities) != 0)
1619 exit(EXIT_FAILURE);
1620 if (cap_set_proc(capabilities) != 0)
1621 exit(EXIT_FAILURE);
1622 }
1623 cap_free(capabilities);
1624 }
1625 #endif
1626 }
1627
1628 int get_time(unsigned int *time, const char *str)
1629 {
1630 double t;
1631 char *p;
1632
1633 t = strtod(str, &p);
1634 if (p == str)
1635 return -1;
1636
1637 if (*p) {
1638 if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec") == 0 ||
1639 strcasecmp(p, "secs") == 0)
1640 t *= TIME_UNITS_PER_SEC;
1641 else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec") == 0 ||
1642 strcasecmp(p, "msecs") == 0)
1643 t *= TIME_UNITS_PER_SEC/1000;
1644 else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec") == 0 ||
1645 strcasecmp(p, "usecs") == 0)
1646 t *= TIME_UNITS_PER_SEC/1000000;
1647 else
1648 return -1;
1649 }
1650
1651 *time = t;
1652 return 0;
1653 }
1654
1655 static void print_time(char *buf, int len, __u32 time)
1656 {
1657 double tmp = time;
1658
1659 if (tmp >= TIME_UNITS_PER_SEC)
1660 snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
1661 else if (tmp >= TIME_UNITS_PER_SEC/1000)
1662 snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
1663 else
1664 snprintf(buf, len, "%uus", time);
1665 }
1666
1667 char *sprint_time(__u32 time, char *buf)
1668 {
1669 print_time(buf, SPRINT_BSIZE-1, time);
1670 return buf;
1671 }
1672
1673 /* 64 bit times are represented internally in nanoseconds */
1674 int get_time64(__s64 *time, const char *str)
1675 {
1676 double nsec;
1677 char *p;
1678
1679 nsec = strtod(str, &p);
1680 if (p == str)
1681 return -1;
1682
1683 if (*p) {
1684 if (strcasecmp(p, "s") == 0 ||
1685 strcasecmp(p, "sec") == 0 ||
1686 strcasecmp(p, "secs") == 0)
1687 nsec *= NSEC_PER_SEC;
1688 else if (strcasecmp(p, "ms") == 0 ||
1689 strcasecmp(p, "msec") == 0 ||
1690 strcasecmp(p, "msecs") == 0)
1691 nsec *= NSEC_PER_MSEC;
1692 else if (strcasecmp(p, "us") == 0 ||
1693 strcasecmp(p, "usec") == 0 ||
1694 strcasecmp(p, "usecs") == 0)
1695 nsec *= NSEC_PER_USEC;
1696 else if (strcasecmp(p, "ns") == 0 ||
1697 strcasecmp(p, "nsec") == 0 ||
1698 strcasecmp(p, "nsecs") == 0)
1699 nsec *= 1;
1700 else
1701 return -1;
1702 }
1703
1704 *time = nsec;
1705 return 0;
1706 }
1707
1708 static void print_time64(char *buf, int len, __s64 time)
1709 {
1710 double nsec = time;
1711
1712 if (time >= NSEC_PER_SEC)
1713 snprintf(buf, len, "%.3fs", nsec/NSEC_PER_SEC);
1714 else if (time >= NSEC_PER_MSEC)
1715 snprintf(buf, len, "%.3fms", nsec/NSEC_PER_MSEC);
1716 else if (time >= NSEC_PER_USEC)
1717 snprintf(buf, len, "%.3fus", nsec/NSEC_PER_USEC);
1718 else
1719 snprintf(buf, len, "%lldns", time);
1720 }
1721
1722 char *sprint_time64(__s64 time, char *buf)
1723 {
1724 print_time64(buf, SPRINT_BSIZE-1, time);
1725 return buf;
1726 }