Annotation of embedaddon/dnsmasq/src/util.c, revision 1.1.1.4
1.1.1.4 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
1.1 misho 2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: /* The SURF random number generator was taken from djbdns-1.05, by
18: Daniel J Bernstein, which is public domain. */
19:
20:
21: #include "dnsmasq.h"
22:
23: #ifdef HAVE_BROKEN_RTC
24: #include <sys/times.h>
25: #endif
26:
1.1.1.4 ! misho 27: #if defined(HAVE_LIBIDN2)
! 28: #include <idn2.h>
! 29: #elif defined(HAVE_IDN)
1.1 misho 30: #include <idna.h>
31: #endif
32:
1.1.1.4 ! misho 33: #ifdef HAVE_LINUX_NETWORK
! 34: #include <sys/utsname.h>
! 35: #endif
! 36:
1.1 misho 37: /* SURF random number generator */
38:
39: static u32 seed[32];
40: static u32 in[12];
41: static u32 out[8];
1.1.1.2 misho 42: static int outleft = 0;
1.1 misho 43:
44: void rand_init()
45: {
46: int fd = open(RANDFILE, O_RDONLY);
47:
48: if (fd == -1 ||
49: !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
50: !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
51: die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
52:
53: close(fd);
54: }
55:
56: #define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
57: #define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
58:
59: static void surf(void)
60: {
61: u32 t[12]; u32 x; u32 sum = 0;
62: int r; int i; int loop;
63:
64: for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
65: for (i = 0;i < 8;++i) out[i] = seed[24 + i];
66: x = t[11];
67: for (loop = 0;loop < 2;++loop) {
68: for (r = 0;r < 16;++r) {
69: sum += 0x9e3779b9;
70: MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
71: MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
72: MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
73: }
74: for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
75: }
76: }
77:
78: unsigned short rand16(void)
79: {
1.1.1.2 misho 80: if (!outleft)
81: {
82: if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
83: surf();
84: outleft = 8;
85: }
86:
87: return (unsigned short) out[--outleft];
88: }
89:
1.1.1.3 misho 90: u32 rand32(void)
91: {
92: if (!outleft)
93: {
94: if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
95: surf();
96: outleft = 8;
97: }
98:
99: return out[--outleft];
100: }
101:
1.1.1.2 misho 102: u64 rand64(void)
103: {
1.1 misho 104: static int outleft = 0;
105:
1.1.1.2 misho 106: if (outleft < 2)
107: {
108: if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
109: surf();
110: outleft = 8;
111: }
112:
113: outleft -= 2;
1.1 misho 114:
1.1.1.2 misho 115: return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
1.1 misho 116: }
117:
1.1.1.4 ! misho 118: /* returns 2 if names is OK but contains one or more underscores */
1.1 misho 119: static int check_name(char *in)
120: {
121: /* remove trailing .
122: also fail empty string and label > 63 chars */
123: size_t dotgap = 0, l = strlen(in);
124: char c;
125: int nowhite = 0;
1.1.1.4 ! misho 126: int hasuscore = 0;
1.1 misho 127:
128: if (l == 0 || l > MAXDNAME) return 0;
129:
130: if (in[l-1] == '.')
131: {
132: in[l-1] = 0;
1.1.1.2 misho 133: nowhite = 1;
1.1 misho 134: }
1.1.1.2 misho 135:
1.1 misho 136: for (; (c = *in); in++)
137: {
138: if (c == '.')
139: dotgap = 0;
140: else if (++dotgap > MAXLABEL)
141: return 0;
142: else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
143: /* iscntrl only gives expected results for ascii */
144: return 0;
1.1.1.4 ! misho 145: #if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
1.1 misho 146: else if (!isascii((unsigned char)c))
147: return 0;
148: #endif
149: else if (c != ' ')
1.1.1.4 ! misho 150: {
! 151: nowhite = 1;
! 152: if (c == '_')
! 153: hasuscore = 1;
! 154: }
1.1 misho 155: }
156:
157: if (!nowhite)
158: return 0;
159:
1.1.1.4 ! misho 160: return hasuscore ? 2 : 1;
1.1 misho 161: }
162:
163: /* Hostnames have a more limited valid charset than domain names
164: so check for legal char a-z A-Z 0-9 - _
165: Note that this may receive a FQDN, so only check the first label
166: for the tighter criteria. */
167: int legal_hostname(char *name)
168: {
169: char c;
1.1.1.2 misho 170: int first;
1.1 misho 171:
172: if (!check_name(name))
173: return 0;
174:
1.1.1.2 misho 175: for (first = 1; (c = *name); name++, first = 0)
1.1 misho 176: /* check for legal char a-z A-Z 0-9 - _ . */
177: {
178: if ((c >= 'A' && c <= 'Z') ||
179: (c >= 'a' && c <= 'z') ||
1.1.1.2 misho 180: (c >= '0' && c <= '9'))
181: continue;
182:
183: if (!first && (c == '-' || c == '_'))
1.1 misho 184: continue;
185:
186: /* end of hostname part */
187: if (c == '.')
188: return 1;
189:
190: return 0;
191: }
192:
193: return 1;
194: }
195:
196: char *canonicalise(char *in, int *nomem)
197: {
198: char *ret = NULL;
199: int rc;
1.1.1.4 ! misho 200:
1.1 misho 201: if (nomem)
202: *nomem = 0;
203:
1.1.1.4 ! misho 204: if (!(rc = check_name(in)))
1.1 misho 205: return NULL;
206:
1.1.1.4 ! misho 207: #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
! 208: /* older libidn2 strips underscores, so don't do IDN processing
! 209: if the name has an underscore (check_name() returned 2) */
! 210: if (rc != 2)
! 211: #endif
! 212: #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
! 213: {
! 214: # ifdef HAVE_LIBIDN2
! 215: rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
! 216: if (rc == IDN2_DISALLOWED)
! 217: rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
! 218: # else
! 219: rc = idna_to_ascii_lz(in, &ret, 0);
! 220: # endif
! 221: if (rc != IDNA_SUCCESS)
1.1 misho 222: {
1.1.1.4 ! misho 223: if (ret)
! 224: free(ret);
! 225:
! 226: if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
! 227: {
! 228: my_syslog(LOG_ERR, _("failed to allocate memory"));
! 229: *nomem = 1;
! 230: }
! 231:
! 232: return NULL;
1.1 misho 233: }
1.1.1.4 ! misho 234:
! 235: return ret;
1.1 misho 236: }
1.1.1.4 ! misho 237: #endif
! 238:
1.1 misho 239: if ((ret = whine_malloc(strlen(in)+1)))
240: strcpy(ret, in);
241: else if (nomem)
242: *nomem = 1;
243:
244: return ret;
245: }
246:
1.1.1.4 ! misho 247: unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
1.1 misho 248: {
249: int j;
250:
251: while (sval && *sval)
252: {
253: unsigned char *cp = p++;
1.1.1.4 ! misho 254:
! 255: if (limit && p > (unsigned char*)limit)
! 256: return NULL;
! 257:
1.1 misho 258: for (j = 0; *sval && (*sval != '.'); sval++, j++)
1.1.1.3 misho 259: {
1.1.1.4 ! misho 260: if (limit && p + 1 > (unsigned char*)limit)
! 261: return NULL;
! 262:
1.1.1.3 misho 263: #ifdef HAVE_DNSSEC
264: if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
265: *p++ = (*(++sval))-1;
266: else
267: #endif
268: *p++ = *sval;
269: }
1.1.1.4 ! misho 270:
1.1 misho 271: *cp = j;
272: if (*sval)
273: sval++;
274: }
1.1.1.4 ! misho 275:
1.1 misho 276: return p;
277: }
278:
279: /* for use during startup */
280: void *safe_malloc(size_t size)
281: {
1.1.1.4 ! misho 282: void *ret = calloc(1, size);
1.1 misho 283:
284: if (!ret)
285: die(_("could not get memory"), NULL, EC_NOMEM);
1.1.1.4 ! misho 286:
1.1 misho 287: return ret;
1.1.1.4 ! misho 288: }
! 289:
! 290: /* Ensure limited size string is always terminated.
! 291: * Can be replaced by (void)strlcpy() on some platforms */
! 292: void safe_strncpy(char *dest, const char *src, size_t size)
! 293: {
! 294: if (size != 0)
! 295: {
! 296: dest[size-1] = '\0';
! 297: strncpy(dest, src, size-1);
! 298: }
! 299: }
1.1 misho 300:
301: void safe_pipe(int *fd, int read_noblock)
302: {
303: if (pipe(fd) == -1 ||
304: !fix_fd(fd[1]) ||
305: (read_noblock && !fix_fd(fd[0])))
306: die(_("cannot create pipe: %s"), NULL, EC_MISC);
307: }
308:
309: void *whine_malloc(size_t size)
310: {
1.1.1.4 ! misho 311: void *ret = calloc(1, size);
1.1 misho 312:
313: if (!ret)
314: my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
1.1.1.4 ! misho 315:
1.1 misho 316: return ret;
317: }
318:
319: int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
320: {
321: if (s1->sa.sa_family == s2->sa.sa_family)
322: {
323: if (s1->sa.sa_family == AF_INET &&
324: s1->in.sin_port == s2->in.sin_port &&
325: s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
326: return 1;
1.1.1.4 ! misho 327:
1.1 misho 328: if (s1->sa.sa_family == AF_INET6 &&
329: s1->in6.sin6_port == s2->in6.sin6_port &&
1.1.1.3 misho 330: s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
1.1 misho 331: IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
332: return 1;
333: }
334: return 0;
335: }
336:
337: int sa_len(union mysockaddr *addr)
338: {
339: #ifdef HAVE_SOCKADDR_SA_LEN
340: return addr->sa.sa_len;
341: #else
342: if (addr->sa.sa_family == AF_INET6)
343: return sizeof(addr->in6);
344: else
345: return sizeof(addr->in);
346: #endif
347: }
348:
349: /* don't use strcasecmp and friends here - they may be messed up by LOCALE */
350: int hostname_isequal(const char *a, const char *b)
351: {
352: unsigned int c1, c2;
353:
354: do {
355: c1 = (unsigned char) *a++;
356: c2 = (unsigned char) *b++;
357:
358: if (c1 >= 'A' && c1 <= 'Z')
359: c1 += 'a' - 'A';
360: if (c2 >= 'A' && c2 <= 'Z')
361: c2 += 'a' - 'A';
362:
363: if (c1 != c2)
364: return 0;
365: } while (c1);
366:
367: return 1;
368: }
1.1.1.4 ! misho 369:
! 370: /* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
! 371: int hostname_issubdomain(char *a, char *b)
! 372: {
! 373: char *ap, *bp;
! 374: unsigned int c1, c2;
! 375:
! 376: /* move to the end */
! 377: for (ap = a; *ap; ap++);
! 378: for (bp = b; *bp; bp++);
! 379:
! 380: /* a shorter than b or a empty. */
! 381: if ((bp - b) < (ap - a) || ap == a)
! 382: return 0;
! 383:
! 384: do
! 385: {
! 386: c1 = (unsigned char) *(--ap);
! 387: c2 = (unsigned char) *(--bp);
! 388:
! 389: if (c1 >= 'A' && c1 <= 'Z')
! 390: c1 += 'a' - 'A';
! 391: if (c2 >= 'A' && c2 <= 'Z')
! 392: c2 += 'a' - 'A';
! 393:
! 394: if (c1 != c2)
! 395: return 0;
! 396: } while (ap != a);
! 397:
! 398: if (bp == b)
! 399: return 2;
! 400:
! 401: if (*(--bp) == '.')
! 402: return 1;
! 403:
! 404: return 0;
! 405: }
! 406:
! 407:
1.1 misho 408: time_t dnsmasq_time(void)
409: {
410: #ifdef HAVE_BROKEN_RTC
411: struct tms dummy;
412: static long tps = 0;
413:
414: if (tps == 0)
415: tps = sysconf(_SC_CLK_TCK);
416:
417: return (time_t)(times(&dummy)/tps);
418: #else
419: return time(NULL);
420: #endif
421: }
422:
1.1.1.3 misho 423: int netmask_length(struct in_addr mask)
424: {
425: int zero_count = 0;
426:
427: while (0x0 == (mask.s_addr & 0x1) && zero_count < 32)
428: {
429: mask.s_addr >>= 1;
430: zero_count++;
431: }
432:
433: return 32 - zero_count;
434: }
435:
1.1 misho 436: int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
437: {
438: return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
439: }
440:
441: int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
442: {
443: int pfbytes = prefixlen >> 3;
444: int pfbits = prefixlen & 7;
445:
446: if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
447: return 0;
448:
449: if (pfbits == 0 ||
450: (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
451: return 1;
452:
453: return 0;
454: }
455:
1.1.1.4 ! misho 456: /* return least significant 64 bits if IPv6 address */
1.1 misho 457: u64 addr6part(struct in6_addr *addr)
458: {
459: int i;
460: u64 ret = 0;
461:
462: for (i = 8; i < 16; i++)
463: ret = (ret << 8) + addr->s6_addr[i];
464:
465: return ret;
466: }
467:
468: void setaddr6part(struct in6_addr *addr, u64 host)
469: {
470: int i;
471:
472: for (i = 15; i >= 8; i--)
473: {
474: addr->s6_addr[i] = host;
475: host = host >> 8;
476: }
477: }
478:
479:
480: /* returns port number from address */
481: int prettyprint_addr(union mysockaddr *addr, char *buf)
482: {
483: int port = 0;
484:
485: if (addr->sa.sa_family == AF_INET)
486: {
487: inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
488: port = ntohs(addr->in.sin_port);
489: }
490: else if (addr->sa.sa_family == AF_INET6)
491: {
492: char name[IF_NAMESIZE];
493: inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
494: if (addr->in6.sin6_scope_id != 0 &&
495: if_indextoname(addr->in6.sin6_scope_id, name) &&
496: strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
497: {
498: strcat(buf, "%");
499: strcat(buf, name);
500: }
501: port = ntohs(addr->in6.sin6_port);
502: }
503:
504: return port;
505: }
506:
507: void prettyprint_time(char *buf, unsigned int t)
508: {
509: if (t == 0xffffffff)
510: sprintf(buf, _("infinite"));
511: else
512: {
513: unsigned int x, p = 0;
514: if ((x = t/86400))
1.1.1.4 ! misho 515: p += sprintf(&buf[p], "%ud", x);
1.1 misho 516: if ((x = (t/3600)%24))
1.1.1.4 ! misho 517: p += sprintf(&buf[p], "%uh", x);
1.1 misho 518: if ((x = (t/60)%60))
1.1.1.4 ! misho 519: p += sprintf(&buf[p], "%um", x);
1.1 misho 520: if ((x = t%60))
1.1.1.4 ! misho 521: p += sprintf(&buf[p], "%us", x);
1.1 misho 522: }
523: }
524:
525:
526: /* in may equal out, when maxlen may be -1 (No max len).
527: Return -1 for extraneous no-hex chars found. */
528: int parse_hex(char *in, unsigned char *out, int maxlen,
529: unsigned int *wildcard_mask, int *mac_type)
530: {
1.1.1.4 ! misho 531: int done = 0, mask = 0, i = 0;
1.1 misho 532: char *r;
533:
534: if (mac_type)
535: *mac_type = 0;
536:
1.1.1.4 ! misho 537: while (!done && (maxlen == -1 || i < maxlen))
1.1 misho 538: {
539: for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
540: if (*r != '*' && !isxdigit((unsigned char)*r))
541: return -1;
542:
543: if (*r == 0)
1.1.1.4 ! misho 544: done = 1;
1.1 misho 545:
546: if (r != in )
547: {
548: if (*r == '-' && i == 0 && mac_type)
549: {
550: *r = 0;
551: *mac_type = strtol(in, NULL, 16);
552: mac_type = NULL;
553: }
554: else
555: {
556: *r = 0;
557: if (strcmp(in, "*") == 0)
558: {
559: mask = (mask << 1) | 1;
560: i++;
561: }
562: else
563: {
564: int j, bytes = (1 + (r - in))/2;
565: for (j = 0; j < bytes; j++)
566: {
1.1.1.2 misho 567: char sav = sav;
1.1 misho 568: if (j < bytes - 1)
569: {
570: sav = in[(j+1)*2];
571: in[(j+1)*2] = 0;
572: }
1.1.1.4 ! misho 573: /* checks above allow mix of hexdigit and *, which
! 574: is illegal. */
! 575: if (strchr(&in[j*2], '*'))
! 576: return -1;
1.1 misho 577: out[i] = strtol(&in[j*2], NULL, 16);
578: mask = mask << 1;
1.1.1.4 ! misho 579: if (++i == maxlen)
! 580: break;
1.1 misho 581: if (j < bytes - 1)
582: in[(j+1)*2] = sav;
583: }
584: }
585: }
586: }
587: in = r+1;
588: }
589:
590: if (wildcard_mask)
591: *wildcard_mask = mask;
592:
593: return i;
594: }
595:
596: /* return 0 for no match, or (no matched octets) + 1 */
597: int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
598: {
599: int i, count;
600: for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
601: if (!(mask & 1))
602: {
603: if (a[i] == b[i])
604: count++;
605: else
606: return 0;
607: }
608: return count;
609: }
610:
611: /* _note_ may copy buffer */
612: int expand_buf(struct iovec *iov, size_t size)
613: {
614: void *new;
615:
616: if (size <= (size_t)iov->iov_len)
617: return 1;
618:
619: if (!(new = whine_malloc(size)))
620: {
621: errno = ENOMEM;
622: return 0;
623: }
624:
625: if (iov->iov_base)
626: {
627: memcpy(new, iov->iov_base, iov->iov_len);
628: free(iov->iov_base);
629: }
630:
631: iov->iov_base = new;
632: iov->iov_len = size;
633:
634: return 1;
635: }
636:
637: char *print_mac(char *buff, unsigned char *mac, int len)
638: {
639: char *p = buff;
640: int i;
641:
642: if (len == 0)
643: sprintf(p, "<null>");
644: else
645: for (i = 0; i < len; i++)
646: p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
647:
648: return buff;
649: }
650:
1.1.1.3 misho 651: /* rc is return from sendto and friends.
652: Return 1 if we should retry.
653: Set errno to zero if we succeeded. */
654: int retry_send(ssize_t rc)
1.1 misho 655: {
1.1.1.3 misho 656: static int retries = 0;
657: struct timespec waiter;
658:
659: if (rc != -1)
660: {
661: retries = 0;
662: errno = 0;
663: return 0;
664: }
665:
666: /* Linux kernels can return EAGAIN in perpetuity when calling
667: sendmsg() and the relevant interface has gone. Here we loop
668: retrying in EAGAIN for 1 second max, to avoid this hanging
669: dnsmasq. */
1.1 misho 670:
1.1.1.3 misho 671: if (errno == EAGAIN || errno == EWOULDBLOCK)
1.1 misho 672: {
673: waiter.tv_sec = 0;
674: waiter.tv_nsec = 10000;
675: nanosleep(&waiter, NULL);
1.1.1.3 misho 676: if (retries++ < 1000)
677: return 1;
1.1 misho 678: }
1.1.1.3 misho 679:
680: retries = 0;
681:
682: if (errno == EINTR)
683: return 1;
684:
685: return 0;
1.1 misho 686: }
687:
688: int read_write(int fd, unsigned char *packet, int size, int rw)
689: {
690: ssize_t n, done;
691:
692: for (done = 0; done < size; done += n)
693: {
1.1.1.3 misho 694: do {
695: if (rw)
696: n = read(fd, &packet[done], (size_t)(size - done));
697: else
698: n = write(fd, &packet[done], (size_t)(size - done));
699:
700: if (n == 0)
701: return 0;
702:
703: } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
704:
705: if (errno != 0)
706: return 0;
1.1 misho 707: }
1.1.1.3 misho 708:
1.1 misho 709: return 1;
710: }
711:
1.1.1.4 ! misho 712: /* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
! 713: void close_fds(long max_fd, int spare1, int spare2, int spare3)
! 714: {
! 715: /* On Linux, use the /proc/ filesystem to find which files
! 716: are actually open, rather than iterate over the whole space,
! 717: for efficiency reasons. If this fails we drop back to the dumb code. */
! 718: #ifdef HAVE_LINUX_NETWORK
! 719: DIR *d;
! 720:
! 721: if ((d = opendir("/proc/self/fd")))
! 722: {
! 723: struct dirent *de;
! 724:
! 725: while ((de = readdir(d)))
! 726: {
! 727: long fd;
! 728: char *e = NULL;
! 729:
! 730: errno = 0;
! 731: fd = strtol(de->d_name, &e, 10);
! 732:
! 733: if (errno != 0 || !e || *e || fd == dirfd(d) ||
! 734: fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO ||
! 735: fd == spare1 || fd == spare2 || fd == spare3)
! 736: continue;
! 737:
! 738: close(fd);
! 739: }
! 740:
! 741: closedir(d);
! 742: return;
! 743: }
! 744: #endif
! 745:
! 746: /* fallback, dumb code. */
! 747: for (max_fd--; max_fd >= 0; max_fd--)
! 748: if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
! 749: max_fd != spare1 && max_fd != spare2 && max_fd != spare3)
! 750: close(max_fd);
! 751: }
! 752:
1.1 misho 753: /* Basically match a string value against a wildcard pattern. */
754: int wildcard_match(const char* wildcard, const char* match)
755: {
756: while (*wildcard && *match)
757: {
758: if (*wildcard == '*')
759: return 1;
760:
761: if (*wildcard != *match)
762: return 0;
763:
764: ++wildcard;
765: ++match;
766: }
767:
768: return *wildcard == *match;
1.1.1.3 misho 769: }
770:
771: /* The same but comparing a maximum of NUM characters, like strncmp. */
772: int wildcard_matchn(const char* wildcard, const char* match, int num)
773: {
774: while (*wildcard && *match && num)
775: {
776: if (*wildcard == '*')
777: return 1;
778:
779: if (*wildcard != *match)
780: return 0;
781:
782: ++wildcard;
783: ++match;
784: --num;
785: }
786:
787: return (!num) || (*wildcard == *match);
1.1 misho 788: }
1.1.1.4 ! misho 789:
! 790: #ifdef HAVE_LINUX_NETWORK
! 791: int kernel_version(void)
! 792: {
! 793: struct utsname utsname;
! 794: int version;
! 795: char *split;
! 796:
! 797: if (uname(&utsname) < 0)
! 798: die(_("failed to find kernel version: %s"), NULL, EC_MISC);
! 799:
! 800: split = strtok(utsname.release, ".");
! 801: version = (split ? atoi(split) : 0);
! 802: split = strtok(NULL, ".");
! 803: version = version * 256 + (split ? atoi(split) : 0);
! 804: split = strtok(NULL, ".");
! 805: return version * 256 + (split ? atoi(split) : 0);
! 806: }
! 807: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>