blob: ffef6fed91481bbeca0995e7d9904d6f2d517e2d [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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>
osdl.org!shemminger5dfe5562004-06-08 23:50:43 +000028#include <asm/types.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000029#include <linux/pkt_sched.h>
shemminger90f93022005-06-07 21:55:55 +000030#include <time.h>
31#include <sys/time.h>
32
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000033
34#include "utils.h"
35
osdl.org!shemminger4094db72004-06-02 20:22:08 +000036int get_integer(int *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000037{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +000050int get_unsigned(unsigned *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000051{
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
Rick Jones54e0b2e2007-10-11 13:04:11 -070064/*
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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000128int 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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000142int get_u32(__u32 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000143{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000156int get_u16(__u16 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000157{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000170int get_u8(__u8 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000171{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000184int get_s16(__s16 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000185{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000198int get_s8(__s8 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000199{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000212int get_addr_1(inet_prefix *addr, const char *name, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000213{
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000214 const char *cp;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000215 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
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000270int get_prefix_1(inet_prefix *dst, char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000271{
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;
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000292
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000293 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) {
shemmingerf332d162005-07-05 22:37:15 +0000307 if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000308 err = -1;
309 goto done;
310 }
net[shemminger]!shemmingerf082b642005-03-30 18:16:10 +0000311 dst->flags |= PREFIXLEN_SPECIFIED;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000312 dst->bitlen = plen;
313 }
314 }
315done:
316 if (slash)
317 *slash = '/';
318 return err;
319}
320
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000321int get_addr(inet_prefix *dst, const char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000322{
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
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000334int get_prefix(inet_prefix *dst, char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000335{
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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000347__u32 get_addr32(const char *name)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000348{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000357void incomplete_command(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000358{
359 fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
360 exit(-1);
361}
362
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000363void missarg(const char *key)
364{
365 fprintf(stderr, "Error: argument \"%s\" is required\n", key);
366 exit(-1);
367}
368
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000369void invarg(const char *msg, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000370{
371 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
372 exit(-1);
373}
374
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000375void duparg(const char *key, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000376{
377 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
378 exit(-1);
379}
380
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000381void duparg2(const char *key, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000382{
383 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
384 exit(-1);
385}
386
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000387int matches(const char *cmd, const char *pattern)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000388{
389 int len = strlen(cmd);
390 if (len > strlen(pattern))
391 return -1;
392 return memcmp(pattern, cmd, len);
393}
394
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000395int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000396{
Stephen Hemminger9626dfd2006-12-05 09:59:59 -0800397 const __u32 *a1 = a->data;
398 const __u32 *a2 = b->data;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000399 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"));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000436 } else if (getenv("PROC_ROOT")) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000437 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
net[shemminger]!shemminger5e8bc632005-03-14 18:44:54 +0000455int __iproute2_user_hz_internal;
456
457int __get_user_hz(void)
458{
459 return sysconf(_SC_CLK_TCK);
460}
461
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000462const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000463{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000491char *resolve_address(const char *addr, int len, int af)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000492{
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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000526 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000527 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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000535const char *format_host(int af, int len, const void *addr,
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000536 char *buf, int buflen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000537{
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
shemmingerf332d162005-07-05 22:37:15 +0000571char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000572{
shemmingerf332d162005-07-05 22:37:15 +0000573 char *ptr = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000574 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
shemmingerf332d162005-07-05 22:37:15 +0000590__u8* hexstring_a2n(const char *str, __u8 *buf, int blen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000591{
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}
shemminger90f93022005-06-07 21:55:55 +0000627
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}
shemminger351efcd2005-09-01 19:21:50 +0000641
642int cmdlineno;
643
644/* Like glibc getline but handle continuation lines and comments */
Andreas Henrikssond21e8832007-10-12 10:56:42 +0200645ssize_t getcmdline(char **linep, size_t *lenp, FILE *in)
shemminger351efcd2005-09-01 19:21:50 +0000646{
Andreas Henrikssond21e8832007-10-12 10:56:42 +0200647 ssize_t cc;
shemminger351efcd2005-09-01 19:21:50 +0000648 char *cp;
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800649
shemminger351efcd2005-09-01 19:21:50 +0000650 if ((cc = getline(linep, lenp, in)) < 0)
651 return cc; /* eof or error */
652 ++cmdlineno;
653
654 cp = strchr(*linep, '#');
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800655 if (cp)
shemminger351efcd2005-09-01 19:21:50 +0000656 *cp = '\0';
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800657
shemminger351efcd2005-09-01 19:21:50 +0000658 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, '#');
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800672 if (cp)
shemminger351efcd2005-09-01 19:21:50 +0000673 *cp = '\0';
674
Andreas Henrikssond21e8832007-10-12 10:56:42 +0200675 *lenp = strlen(*linep) + strlen(line1) + 1;
676 *linep = realloc(*linep, *lenp);
shemminger351efcd2005-09-01 19:21:50 +0000677 if (!*linep) {
678 fprintf(stderr, "Out of memory\n");
Andreas Henrikssond21e8832007-10-12 10:56:42 +0200679 *lenp = 0;
shemminger351efcd2005-09-01 19:21:50 +0000680 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}