utils.c revision d21e88354b2a42b026384730a767f2108bcf8efe
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 * Changes:
13 *
14 * Rani Assaf <rani@magic.metawire.com> 980929:	resolve addresses
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <syslog.h>
21#include <fcntl.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <string.h>
25#include <netdb.h>
26#include <arpa/inet.h>
27#include <resolv.h>
28#include <asm/types.h>
29#include <linux/pkt_sched.h>
30#include <time.h>
31#include <sys/time.h>
32
33
34#include "utils.h"
35
36int get_integer(int *val, const char *arg, int base)
37{
38	long res;
39	char *ptr;
40
41	if (!arg || !*arg)
42		return -1;
43	res = strtol(arg, &ptr, base);
44	if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
45		return -1;
46	*val = res;
47	return 0;
48}
49
50int get_unsigned(unsigned *val, const char *arg, int base)
51{
52	unsigned long res;
53	char *ptr;
54
55	if (!arg || !*arg)
56		return -1;
57	res = strtoul(arg, &ptr, base);
58	if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
59		return -1;
60	*val = res;
61	return 0;
62}
63
64/*
65 * get_jiffies is "translated" from a similar routine "get_time" in
66 * tc_util.c.  we don't use the exact same routine because tc passes
67 * microseconds to the kernel and the callers of get_jiffies want
68 * to pass jiffies, and have a different assumption for the units of
69 * a "raw" number.
70 */
71
72int get_jiffies(unsigned *jiffies, const char *arg, int base, int *raw)
73{
74	double t;
75	unsigned long res;
76	char *p;
77
78	if (strchr(arg,'.') != NULL) {
79		t = strtod(arg,&p);
80		if (t < 0.0)
81			return -1;
82	}
83	else {
84		res = strtoul(arg,&p,base);
85		if (res > UINT_MAX)
86			return -1;
87		t = (double)res;
88	}
89	if (p == arg)
90		return -1;
91
92	if (__iproute2_hz_internal == 0)
93                __iproute2_hz_internal = __get_hz();
94
95	*raw = 1;
96
97	if (*p) {
98		*raw = 0;
99                if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
100                    strcasecmp(p, "secs")==0)
101                        t *= __iproute2_hz_internal;
102                else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
103                         strcasecmp(p, "msecs") == 0)
104                        t *= __iproute2_hz_internal/1000.0;
105                else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
106                         strcasecmp(p, "usecs") == 0)
107                        t *= __iproute2_hz_internal/1000000.0;
108                else if (strcasecmp(p, "ns") == 0 || strcasecmp(p, "nsec")==0 ||
109                         strcasecmp(p, "nsecs") == 0)
110                        t *= __iproute2_hz_internal/1000000000.0;
111		else if (strcasecmp(p, "j") == 0 || strcasecmp(p, "hz") == 0 ||
112			 strcasecmp(p,"jiffies") == 0)
113			t *= 1.0; /* allow suffix, do nothing */
114                else
115                        return -1;
116        }
117
118	/* emulate ceil() without having to bring-in -lm and always be >= 1 */
119
120	*jiffies = t;
121	if (*jiffies < t)
122		*jiffies += 1;
123
124        return 0;
125
126}
127
128int get_u64(__u64 *val, const char *arg, int base)
129{
130	unsigned long long res;
131	char *ptr;
132
133	if (!arg || !*arg)
134		return -1;
135	res = strtoull(arg, &ptr, base);
136	if (!ptr || ptr == arg || *ptr || res == 0xFFFFFFFFULL)
137 		return -1;
138 	*val = res;
139 	return 0;
140}
141
142int get_u32(__u32 *val, const char *arg, int base)
143{
144	unsigned long res;
145	char *ptr;
146
147	if (!arg || !*arg)
148		return -1;
149	res = strtoul(arg, &ptr, base);
150	if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
151		return -1;
152	*val = res;
153	return 0;
154}
155
156int get_u16(__u16 *val, const char *arg, int base)
157{
158	unsigned long res;
159	char *ptr;
160
161	if (!arg || !*arg)
162		return -1;
163	res = strtoul(arg, &ptr, base);
164	if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
165		return -1;
166	*val = res;
167	return 0;
168}
169
170int get_u8(__u8 *val, const char *arg, int base)
171{
172	unsigned long res;
173	char *ptr;
174
175	if (!arg || !*arg)
176		return -1;
177	res = strtoul(arg, &ptr, base);
178	if (!ptr || ptr == arg || *ptr || res > 0xFF)
179		return -1;
180	*val = res;
181	return 0;
182}
183
184int get_s16(__s16 *val, const char *arg, int base)
185{
186	long res;
187	char *ptr;
188
189	if (!arg || !*arg)
190		return -1;
191	res = strtol(arg, &ptr, base);
192	if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
193		return -1;
194	*val = res;
195	return 0;
196}
197
198int get_s8(__s8 *val, const char *arg, int base)
199{
200	long res;
201	char *ptr;
202
203	if (!arg || !*arg)
204		return -1;
205	res = strtol(arg, &ptr, base);
206	if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
207		return -1;
208	*val = res;
209	return 0;
210}
211
212int get_addr_1(inet_prefix *addr, const char *name, int family)
213{
214	const char *cp;
215	unsigned char *ap = (unsigned char*)addr->data;
216	int i;
217
218	memset(addr, 0, sizeof(*addr));
219
220	if (strcmp(name, "default") == 0 ||
221	    strcmp(name, "all") == 0 ||
222	    strcmp(name, "any") == 0) {
223		if (family == AF_DECnet)
224			return -1;
225		addr->family = family;
226		addr->bytelen = (family == AF_INET6 ? 16 : 4);
227		addr->bitlen = -1;
228		return 0;
229	}
230
231	if (strchr(name, ':')) {
232		addr->family = AF_INET6;
233		if (family != AF_UNSPEC && family != AF_INET6)
234			return -1;
235		if (inet_pton(AF_INET6, name, addr->data) <= 0)
236			return -1;
237		addr->bytelen = 16;
238		addr->bitlen = -1;
239		return 0;
240	}
241
242	if (family == AF_DECnet) {
243		struct dn_naddr dna;
244		addr->family = AF_DECnet;
245		if (dnet_pton(AF_DECnet, name, &dna) <= 0)
246			return -1;
247		memcpy(addr->data, dna.a_addr, 2);
248		addr->bytelen = 2;
249		addr->bitlen = -1;
250		return 0;
251	}
252
253	addr->family = AF_INET;
254	if (family != AF_UNSPEC && family != AF_INET)
255		return -1;
256	addr->bytelen = 4;
257	addr->bitlen = -1;
258	for (cp=name, i=0; *cp; cp++) {
259		if (*cp <= '9' && *cp >= '0') {
260			ap[i] = 10*ap[i] + (*cp-'0');
261			continue;
262		}
263		if (*cp == '.' && ++i <= 3)
264			continue;
265		return -1;
266	}
267	return 0;
268}
269
270int get_prefix_1(inet_prefix *dst, char *arg, int family)
271{
272	int err;
273	unsigned plen;
274	char *slash;
275
276	memset(dst, 0, sizeof(*dst));
277
278	if (strcmp(arg, "default") == 0 ||
279	    strcmp(arg, "any") == 0 ||
280	    strcmp(arg, "all") == 0) {
281		if (family == AF_DECnet)
282			return -1;
283		dst->family = family;
284		dst->bytelen = 0;
285		dst->bitlen = 0;
286		return 0;
287	}
288
289	slash = strchr(arg, '/');
290	if (slash)
291		*slash = 0;
292
293	err = get_addr_1(dst, arg, family);
294	if (err == 0) {
295		switch(dst->family) {
296			case AF_INET6:
297				dst->bitlen = 128;
298				break;
299			case AF_DECnet:
300				dst->bitlen = 16;
301				break;
302			default:
303			case AF_INET:
304				dst->bitlen = 32;
305		}
306		if (slash) {
307			if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) {
308				err = -1;
309				goto done;
310			}
311			dst->flags |= PREFIXLEN_SPECIFIED;
312			dst->bitlen = plen;
313		}
314	}
315done:
316	if (slash)
317		*slash = '/';
318	return err;
319}
320
321int get_addr(inet_prefix *dst, const char *arg, int family)
322{
323	if (family == AF_PACKET) {
324		fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg);
325		exit(1);
326	}
327	if (get_addr_1(dst, arg, family)) {
328		fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg);
329		exit(1);
330	}
331	return 0;
332}
333
334int get_prefix(inet_prefix *dst, char *arg, int family)
335{
336	if (family == AF_PACKET) {
337		fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg);
338		exit(1);
339	}
340	if (get_prefix_1(dst, arg, family)) {
341		fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg);
342		exit(1);
343	}
344	return 0;
345}
346
347__u32 get_addr32(const char *name)
348{
349	inet_prefix addr;
350	if (get_addr_1(&addr, name, AF_INET)) {
351		fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name);
352		exit(1);
353	}
354	return addr.data[0];
355}
356
357void incomplete_command(void)
358{
359	fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
360	exit(-1);
361}
362
363void missarg(const char *key)
364{
365	fprintf(stderr, "Error: argument \"%s\" is required\n", key);
366	exit(-1);
367}
368
369void invarg(const char *msg, const char *arg)
370{
371	fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
372	exit(-1);
373}
374
375void duparg(const char *key, const char *arg)
376{
377	fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
378	exit(-1);
379}
380
381void duparg2(const char *key, const char *arg)
382{
383	fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
384	exit(-1);
385}
386
387int matches(const char *cmd, const char *pattern)
388{
389	int len = strlen(cmd);
390	if (len > strlen(pattern))
391		return -1;
392	return memcmp(pattern, cmd, len);
393}
394
395int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
396{
397	const __u32 *a1 = a->data;
398	const __u32 *a2 = b->data;
399	int words = bits >> 0x05;
400
401	bits &= 0x1f;
402
403	if (words)
404		if (memcmp(a1, a2, words << 2))
405			return -1;
406
407	if (bits) {
408		__u32 w1, w2;
409		__u32 mask;
410
411		w1 = a1[words];
412		w2 = a2[words];
413
414		mask = htonl((0xffffffff) << (0x20 - bits));
415
416		if ((w1 ^ w2) & mask)
417			return 1;
418	}
419
420	return 0;
421}
422
423int __iproute2_hz_internal;
424
425int __get_hz(void)
426{
427	char name[1024];
428	int hz = 0;
429	FILE *fp;
430
431	if (getenv("HZ"))
432		return atoi(getenv("HZ")) ? : HZ;
433
434	if (getenv("PROC_NET_PSCHED")) {
435		snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED"));
436	} else if (getenv("PROC_ROOT")) {
437		snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT"));
438	} else {
439		strcpy(name, "/proc/net/psched");
440	}
441	fp = fopen(name, "r");
442
443	if (fp) {
444		unsigned nom, denom;
445		if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
446			if (nom == 1000000)
447				hz = denom;
448		fclose(fp);
449	}
450	if (hz)
451		return hz;
452	return HZ;
453}
454
455int __iproute2_user_hz_internal;
456
457int __get_user_hz(void)
458{
459	return sysconf(_SC_CLK_TCK);
460}
461
462const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
463{
464	switch (af) {
465	case AF_INET:
466	case AF_INET6:
467		return inet_ntop(af, addr, buf, buflen);
468	case AF_IPX:
469		return ipx_ntop(af, addr, buf, buflen);
470	case AF_DECnet:
471	{
472		struct dn_naddr dna = { 2, { 0, 0, }};
473		memcpy(dna.a_addr, addr, 2);
474		return dnet_ntop(af, &dna, buf, buflen);
475	}
476	default:
477		return "???";
478	}
479}
480
481#ifdef RESOLVE_HOSTNAMES
482struct namerec
483{
484	struct namerec *next;
485	inet_prefix addr;
486	char	    *name;
487};
488
489static struct namerec *nht[256];
490
491char *resolve_address(const char *addr, int len, int af)
492{
493	struct namerec *n;
494	struct hostent *h_ent;
495	unsigned hash;
496	static int notfirst;
497
498
499	if (af == AF_INET6 && ((__u32*)addr)[0] == 0 &&
500	    ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) {
501		af = AF_INET;
502		addr += 12;
503		len = 4;
504	}
505
506	hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4];
507
508	for (n = nht[hash]; n; n = n->next) {
509		if (n->addr.family == af &&
510		    n->addr.bytelen == len &&
511		    memcmp(n->addr.data, addr, len) == 0)
512			return n->name;
513	}
514	if ((n = malloc(sizeof(*n))) == NULL)
515		return NULL;
516	n->addr.family = af;
517	n->addr.bytelen = len;
518	n->name = NULL;
519	memcpy(n->addr.data, addr, len);
520	n->next = nht[hash];
521	nht[hash] = n;
522	if (++notfirst == 1)
523		sethostent(1);
524	fflush(stdout);
525
526	if ((h_ent = gethostbyaddr(addr, len, af)) != NULL)
527		n->name = strdup(h_ent->h_name);
528
529	/* Even if we fail, "negative" entry is remembered. */
530	return n->name;
531}
532#endif
533
534
535const char *format_host(int af, int len, const void *addr,
536			char *buf, int buflen)
537{
538#ifdef RESOLVE_HOSTNAMES
539	if (resolve_hosts) {
540		char *n;
541		if (len <= 0) {
542			switch (af) {
543			case AF_INET:
544				len = 4;
545				break;
546			case AF_INET6:
547				len = 16;
548				break;
549			case AF_IPX:
550				len = 10;
551				break;
552#ifdef AF_DECnet
553			/* I see no reasons why gethostbyname
554			   may not work for DECnet */
555			case AF_DECnet:
556				len = 2;
557				break;
558#endif
559			default: ;
560			}
561		}
562		if (len > 0 &&
563		    (n = resolve_address(addr, len, af)) != NULL)
564			return n;
565	}
566#endif
567	return rt_addr_n2a(af, len, addr, buf, buflen);
568}
569
570
571char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen)
572{
573	char *ptr = buf;
574	int i;
575
576	for (i=0; i<len; i++) {
577		if (blen < 3)
578			break;
579		sprintf(ptr, "%02x", str[i]);
580		ptr += 2;
581		blen -= 2;
582		if (i != len-1 && blen > 1) {
583			*ptr++ = ':';
584			blen--;
585		}
586	}
587	return buf;
588}
589
590__u8* hexstring_a2n(const char *str, __u8 *buf, int blen)
591{
592	int cnt = 0;
593
594	for (;;) {
595		unsigned acc;
596		char ch;
597
598		acc = 0;
599
600		while ((ch = *str) != ':' && ch != 0) {
601			if (ch >= '0' && ch <= '9')
602				ch -= '0';
603			else if (ch >= 'a' && ch <= 'f')
604				ch -= 'a'-10;
605			else if (ch >= 'A' && ch <= 'F')
606				ch -= 'A'-10;
607			else
608				return NULL;
609			acc = (acc<<4) + ch;
610			str++;
611		}
612
613		if (acc > 255)
614			return NULL;
615		if (cnt < blen) {
616			buf[cnt] = acc;
617			cnt++;
618		}
619		if (ch == 0)
620			break;
621		++str;
622	}
623	if (cnt < blen)
624		memset(buf+cnt, 0, blen-cnt);
625	return buf;
626}
627
628int print_timestamp(FILE *fp)
629{
630	struct timeval tv;
631	char *tstr;
632
633	memset(&tv, 0, sizeof(tv));
634	gettimeofday(&tv, NULL);
635
636	tstr = asctime(localtime(&tv.tv_sec));
637	tstr[strlen(tstr)-1] = 0;
638	fprintf(fp, "Timestamp: %s %lu usec\n", tstr, tv.tv_usec);
639	return 0;
640}
641
642int cmdlineno;
643
644/* Like glibc getline but handle continuation lines and comments */
645ssize_t getcmdline(char **linep, size_t *lenp, FILE *in)
646{
647	ssize_t cc;
648	char *cp;
649
650	if ((cc = getline(linep, lenp, in)) < 0)
651		return cc;	/* eof or error */
652	++cmdlineno;
653
654	cp = strchr(*linep, '#');
655	if (cp)
656		*cp = '\0';
657
658	while ((cp = strstr(*linep, "\\\n")) != NULL) {
659		char *line1 = NULL;
660		size_t len1 = 0;
661		size_t cc1;
662
663		if ((cc1 = getline(&line1, &len1, in)) < 0) {
664			fprintf(stderr, "Missing continuation line\n");
665			return cc1;
666		}
667
668		++cmdlineno;
669		*cp = 0;
670
671		cp = strchr(line1, '#');
672		if (cp)
673			*cp = '\0';
674
675		*lenp = strlen(*linep) + strlen(line1) + 1;
676		*linep = realloc(*linep, *lenp);
677		if (!*linep) {
678			fprintf(stderr, "Out of memory\n");
679			*lenp = 0;
680			return -1;
681		}
682		cc += cc1 - 2;
683		strcat(*linep, line1);
684		free(line1);
685	}
686	return cc;
687}
688
689/* split command line into argument vector */
690int makeargs(char *line, char *argv[], int maxargs)
691{
692	static const char ws[] = " \t\r\n";
693	char *cp;
694	int argc = 0;
695
696	for (cp = strtok(line, ws); cp; cp = strtok(NULL, ws)) {
697		if (argc >= (maxargs - 1)) {
698			fprintf(stderr, "Too many arguments to command\n");
699			exit(1);
700		}
701		argv[argc++] = cp;
702	}
703	argv[argc] = NULL;
704
705	return argc;
706}
707