Diff for /embedaddon/dnsmasq/src/util.c between versions 1.1.1.1 and 1.1.1.5

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 24 Line 24
 #include <sys/times.h>  #include <sys/times.h>
 #endif  #endif
   
#if defined(LOCALEDIR) || defined(HAVE_IDN)#if defined(HAVE_LIBIDN2)
 #include <idn2.h>
 #elif defined(HAVE_IDN)
 #include <idna.h>  #include <idna.h>
 #endif  #endif
   
#ifdef HAVE_ARC4RANDOM#ifdef HAVE_LINUX_NETWORK
void rand_init(void)#include <sys/utsname.h>
{#endif
  return; 
} 
   
 unsigned short rand16(void)  
 {  
    return (unsigned short) (arc4random() >> 15);  
 }  
   
 #else  
   
 /* SURF random number generator */  /* SURF random number generator */
   
 static u32 seed[32];  static u32 seed[32];
 static u32 in[12];  static u32 in[12];
 static u32 out[8];  static u32 out[8];
   static int outleft = 0;
   
 void rand_init()  void rand_init()
 {  {
Line 83  static void surf(void) Line 77  static void surf(void)
   
 unsigned short rand16(void)  unsigned short rand16(void)
 {  {
     if (!outleft) 
       {
         if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
         surf();
         outleft = 8;
       }
     
     return (unsigned short) out[--outleft];
   }
   
   u32 rand32(void)
   {
    if (!outleft) 
       {
         if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
         surf();
         outleft = 8;
       }
     
     return out[--outleft]; 
   }
   
   u64 rand64(void)
   {
   static int outleft = 0;    static int outleft = 0;
   
  if (!outleft) {  if (outleft < 2)
    if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];    {
    surf();      if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
    outleft = 8;      surf();
  }      outleft = 8;
     }
   
   outleft -= 2;
   
  return (unsigned short) out[--outleft];  return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
 }  }
   
#endif/* returns 1 if name is OK and ascii printable
 * returns 2 if name should be processed by IDN */
 static int check_name(char *in)  static int check_name(char *in)
 {  {
   /* remove trailing .     /* remove trailing . 
Line 103  static int check_name(char *in) Line 124  static int check_name(char *in)
   size_t dotgap = 0, l = strlen(in);    size_t dotgap = 0, l = strlen(in);
   char c;    char c;
   int nowhite = 0;    int nowhite = 0;
     int idn_encode = 0;
     int hasuscore = 0;
     int hasucase = 0;
       
   if (l == 0 || l > MAXDNAME) return 0;    if (l == 0 || l > MAXDNAME) return 0;
       
   if (in[l-1] == '.')    if (in[l-1] == '.')
     {      {
       if (l == 1) return 0;  
       in[l-1] = 0;        in[l-1] = 0;
         nowhite = 1;
     }      }
  
   for (; (c = *in); in++)    for (; (c = *in); in++)
     {      {
       if (c == '.')        if (c == '.')
        dotgap = 0;        dotgap = 0;
       else if (++dotgap > MAXLABEL)        else if (++dotgap > MAXLABEL)
        return 0;        return 0;
       else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))         else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) 
        /* iscntrl only gives expected results for ascii */        /* iscntrl only gives expected results for ascii */
        return 0;        return 0;
#if !defined(LOCALEDIR) && !defined(HAVE_IDN) 
       else if (!isascii((unsigned char)c))        else if (!isascii((unsigned char)c))
        return 0;#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
         return 0;
 #else
         idn_encode = 1;
 #endif  #endif
       else if (c != ' ')        else if (c != ' ')
        nowhite = 1;        {
           nowhite = 1;
 #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
           if (c == '_')
             hasuscore = 1;
 #else
           (void)hasuscore;
 #endif
 
 #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
           if (c >= 'A' && c <= 'Z')
             hasucase = 1;
 #else
           (void)hasucase;
 #endif
         }
     }      }
   
   if (!nowhite)    if (!nowhite)
     return 0;      return 0;
   
  return 1;#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
   /* Older libidn2 strips underscores, so don't do IDN processing
      if the name has an underscore unless it also has non-ascii characters. */
   idn_encode = idn_encode || (hasucase && !hasuscore);
 #else
   idn_encode = idn_encode || hasucase;
 #endif
 
   return (idn_encode) ? 2 : 1;
 }  }
   
 /* Hostnames have a more limited valid charset than domain names  /* Hostnames have a more limited valid charset than domain names
Line 142  static int check_name(char *in) Line 191  static int check_name(char *in)
 int legal_hostname(char *name)  int legal_hostname(char *name)
 {  {
   char c;    char c;
     int first;
   
   if (!check_name(name))    if (!check_name(name))
     return 0;      return 0;
   
  for (; (c = *name); name++)  for (first = 1; (c = *name); name++, first = 0)
     /* check for legal char a-z A-Z 0-9 - _ . */      /* check for legal char a-z A-Z 0-9 - _ . */
     {      {
       if ((c >= 'A' && c <= 'Z') ||        if ((c >= 'A' && c <= 'Z') ||
           (c >= 'a' && c <= 'z') ||            (c >= 'a' && c <= 'z') ||
          (c >= '0' && c <= '9') ||          (c >= '0' && c <= '9'))
          c == '-' || c == '_') 
         continue;          continue;
   
         if (!first && (c == '-' || c == '_'))
           continue;
               
       /* end of hostname part */        /* end of hostname part */
       if (c == '.')        if (c == '.')
Line 168  int legal_hostname(char *name) Line 220  int legal_hostname(char *name)
 char *canonicalise(char *in, int *nomem)  char *canonicalise(char *in, int *nomem)
 {  {
   char *ret = NULL;    char *ret = NULL;
 #if defined(LOCALEDIR) || defined(HAVE_IDN)  
   int rc;    int rc;
#endif  
 
   if (nomem)    if (nomem)
     *nomem = 0;      *nomem = 0;
       
  if (!check_name(in))  if (!(rc = check_name(in)))
     return NULL;      return NULL;
       
#if defined(LOCALEDIR) || defined(HAVE_IDN)#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
  if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)  if (rc == 2)
     {      {
      if (ret)#  ifdef HAVE_LIBIDN2
        free(ret);      rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
#  else
      if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))      rc = idna_to_ascii_lz(in, &ret, 0);
 #  endif
       if (rc != IDNA_SUCCESS)
         {          {
          my_syslog(LOG_ERR, _("failed to allocate memory"));          if (ret)
          *nomem = 1;            free(ret);
           
           if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
             {
               my_syslog(LOG_ERR, _("failed to allocate memory"));
               *nomem = 1;
             }
           
           return NULL;
         }          }
          
      return NULL;      return ret;
     }      }
 #else  #else
     (void)rc;
   #endif
     
   if ((ret = whine_malloc(strlen(in)+1)))    if ((ret = whine_malloc(strlen(in)+1)))
     strcpy(ret, in);      strcpy(ret, in);
   else if (nomem)    else if (nomem)
    *nomem = 1;        *nomem = 1;
#endif 
   
   return ret;    return ret;
 }  }
   
unsigned char *do_rfc1035_name(unsigned char *p, char *sval)unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
 {  {
   int j;    int j;
       
   while (sval && *sval)    while (sval && *sval)
     {      {
       unsigned char *cp = p++;        unsigned char *cp = p++;
   
         if (limit && p > (unsigned char*)limit)
           return NULL;
   
       for (j = 0; *sval && (*sval != '.'); sval++, j++)        for (j = 0; *sval && (*sval != '.'); sval++, j++)
        *p++ = *sval;        {
           if (limit && p + 1 > (unsigned char*)limit)
             return NULL;
 
 #ifdef HAVE_DNSSEC
           if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
             *p++ = (*(++sval))-1;
           else
 #endif                
             *p++ = *sval;
         }
       
       *cp  = j;        *cp  = j;
       if (*sval)        if (*sval)
         sval++;          sval++;
     }      }
     
   return p;    return p;
 }  }
   
 /* for use during startup */  /* for use during startup */
 void *safe_malloc(size_t size)  void *safe_malloc(size_t size)
 {  {
  void *ret = malloc(size);  void *ret = calloc(1, size);
       
   if (!ret)    if (!ret)
     die(_("could not get memory"), NULL, EC_NOMEM);      die(_("could not get memory"), NULL, EC_NOMEM);
           
   return ret;    return ret;
}    }
   
   /* Ensure limited size string is always terminated.
    * Can be replaced by (void)strlcpy() on some platforms */
   void safe_strncpy(char *dest, const char *src, size_t size)
   {
     if (size != 0)
       {
         dest[size-1] = '\0';
         strncpy(dest, src, size-1);
       }
   }
   
 void safe_pipe(int *fd, int read_noblock)  void safe_pipe(int *fd, int read_noblock)
 {  {
   if (pipe(fd) == -1 ||     if (pipe(fd) == -1 || 
Line 239  void safe_pipe(int *fd, int read_noblock) Line 328  void safe_pipe(int *fd, int read_noblock)
   
 void *whine_malloc(size_t size)  void *whine_malloc(size_t size)
 {  {
  void *ret = malloc(size);  void *ret = calloc(1, size);
   
   if (!ret)    if (!ret)
     my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);      my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
     
     return ret;
   }
   
   void *whine_realloc(void *ptr, size_t size)
   {
     void *ret = realloc(ptr, size);
   
     if (!ret)
       my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
   
   return ret;    return ret;
 }  }
   
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
 {  {
   if (s1->sa.sa_family == s2->sa.sa_family)    if (s1->sa.sa_family == s2->sa.sa_family)
     {       { 
Line 255  int sockaddr_isequal(union mysockaddr *s1, union mysoc Line 354  int sockaddr_isequal(union mysockaddr *s1, union mysoc
           s1->in.sin_port == s2->in.sin_port &&            s1->in.sin_port == s2->in.sin_port &&
           s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)            s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
         return 1;          return 1;
#ifdef HAVE_IPV6            
       if (s1->sa.sa_family == AF_INET6 &&        if (s1->sa.sa_family == AF_INET6 &&
           s1->in6.sin6_port == s2->in6.sin6_port &&            s1->in6.sin6_port == s2->in6.sin6_port &&
             s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
           IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))            IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
         return 1;          return 1;
 #endif  
     }      }
   return 0;    return 0;
 }  }
   
   int sockaddr_isnull(const union mysockaddr *s)
   {
     if (s->sa.sa_family == AF_INET &&
         s->in.sin_addr.s_addr == 0)
       return 1;
     
     if (s->sa.sa_family == AF_INET6 &&
         IN6_IS_ADDR_UNSPECIFIED(&s->in6.sin6_addr))
       return 1;
     
     return 0;
   }
   
 int sa_len(union mysockaddr *addr)  int sa_len(union mysockaddr *addr)
 {  {
 #ifdef HAVE_SOCKADDR_SA_LEN  #ifdef HAVE_SOCKADDR_SA_LEN
   return addr->sa.sa_len;    return addr->sa.sa_len;
 #else  #else
 #ifdef HAVE_IPV6  
   if (addr->sa.sa_family == AF_INET6)    if (addr->sa.sa_family == AF_INET6)
     return sizeof(addr->in6);      return sizeof(addr->in6);
   else    else
 #endif  
     return sizeof(addr->in);       return sizeof(addr->in); 
 #endif  #endif
 }  }
   
 /* don't use strcasecmp and friends here - they may be messed up by LOCALE */  /* don't use strcasecmp and friends here - they may be messed up by LOCALE */
int hostname_isequal(const char *a, const char *b)int hostname_order(const char *a, const char *b)
 {  {
   unsigned int c1, c2;    unsigned int c1, c2;
       
Line 293  int hostname_isequal(const char *a, const char *b) Line 403  int hostname_isequal(const char *a, const char *b)
     if (c2 >= 'A' && c2 <= 'Z')      if (c2 >= 'A' && c2 <= 'Z')
       c2 += 'a' - 'A';        c2 += 'a' - 'A';
           
    if (c1 != c2)    if (c1 < c2)
      return 0;      return -1;
     else if (c1 > c2)
       return 1;
     
   } while (c1);    } while (c1);
       
  return 1;  return 0;
 }  }
    
 int hostname_isequal(const char *a, const char *b)
 {
   return hostname_order(a, b) == 0;
 }
 
 /* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
 int hostname_issubdomain(char *a, char *b)
 {
   char *ap, *bp;
   unsigned int c1, c2;
   
   /* move to the end */
   for (ap = a; *ap; ap++); 
   for (bp = b; *bp; bp++);
 
   /* a shorter than b or a empty. */
   if ((bp - b) < (ap - a) || ap == a)
     return 0;
 
   do
     {
       c1 = (unsigned char) *(--ap);
       c2 = (unsigned char) *(--bp);
   
        if (c1 >= 'A' && c1 <= 'Z')
          c1 += 'a' - 'A';
        if (c2 >= 'A' && c2 <= 'Z')
          c2 += 'a' - 'A';
 
        if (c1 != c2)
          return 0;
     } while (ap != a);
 
   if (bp == b)
     return 2;
 
   if (*(--bp) == '.')
     return 1;
 
   return 0;
 }
  
   
 time_t dnsmasq_time(void)  time_t dnsmasq_time(void)
 {  {
 #ifdef HAVE_BROKEN_RTC  #ifdef HAVE_BROKEN_RTC
  struct tms dummy;  struct timespec ts;
  static long tps = 0; 
   
  if (tps == 0)  if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
    tps = sysconf(_SC_CLK_TCK);    die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
   
  return (time_t)(times(&dummy)/tps);  return ts.tv_sec;
 #else  #else
   return time(NULL);    return time(NULL);
 #endif  #endif
 }  }
   
   u32 dnsmasq_milliseconds(void)
   {
     struct timeval tv;
   
     gettimeofday(&tv, NULL);
   
     return (tv.tv_sec) * 1000 + (tv.tv_usec / 1000);
   }
   
   int netmask_length(struct in_addr mask)
   {
     int zero_count = 0;
   
     while (0x0 == (mask.s_addr & 0x1) && zero_count < 32) 
       {
         mask.s_addr >>= 1;
         zero_count++;
       }
     
     return 32 - zero_count;
   }
   
 int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)  int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
 {  {
   return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);    return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}
   
#ifdef HAVE_IPV6int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix)
 {
   struct in_addr mask;
 
   mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
 
   return is_same_net(a, b, mask);
 }
 
 
 int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)  int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
 {  {
   int pfbytes = prefixlen >> 3;    int pfbytes = prefixlen >> 3;
Line 336  int is_same_net6(struct in6_addr *a, struct in6_addr * Line 522  int is_same_net6(struct in6_addr *a, struct in6_addr *
   return 0;    return 0;
 }  }
   
/* return least signigicant 64 bits if IPv6 address *//* return least significant 64 bits if IPv6 address */
 u64 addr6part(struct in6_addr *addr)  u64 addr6part(struct in6_addr *addr)
 {  {
   int i;    int i;
Line 359  void setaddr6part(struct in6_addr *addr, u64 host) Line 545  void setaddr6part(struct in6_addr *addr, u64 host)
     }      }
 }  }
   
 #endif  
    
   
 /* returns port number from address */  /* returns port number from address */
 int prettyprint_addr(union mysockaddr *addr, char *buf)  int prettyprint_addr(union mysockaddr *addr, char *buf)
 {  {
   int port = 0;    int port = 0;
       
 #ifdef HAVE_IPV6  
   if (addr->sa.sa_family == AF_INET)    if (addr->sa.sa_family == AF_INET)
     {      {
       inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);        inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
Line 386  int prettyprint_addr(union mysockaddr *addr, char *buf Line 569  int prettyprint_addr(union mysockaddr *addr, char *buf
         }          }
       port = ntohs(addr->in6.sin6_port);        port = ntohs(addr->in6.sin6_port);
     }      }
 #else  
   strcpy(buf, inet_ntoa(addr->in.sin_addr));  
   port = ntohs(addr->in.sin_port);   
 #endif  
       
   return port;    return port;
 }  }
Line 402  void prettyprint_time(char *buf, unsigned int t) Line 581  void prettyprint_time(char *buf, unsigned int t)
     {      {
       unsigned int x, p = 0;        unsigned int x, p = 0;
        if ((x = t/86400))         if ((x = t/86400))
        p += sprintf(&buf[p], "%dd", x);        p += sprintf(&buf[p], "%ud", x);
        if ((x = (t/3600)%24))         if ((x = (t/3600)%24))
        p += sprintf(&buf[p], "%dh", x);        p += sprintf(&buf[p], "%uh", x);
       if ((x = (t/60)%60))        if ((x = (t/60)%60))
        p += sprintf(&buf[p], "%dm", x);        p += sprintf(&buf[p], "%um", x);
       if ((x = t%60))        if ((x = t%60))
        p += sprintf(&buf[p], "%ds", x);        sprintf(&buf[p], "%us", x);
     }      }
 }  }
   
Line 418  void prettyprint_time(char *buf, unsigned int t) Line 597  void prettyprint_time(char *buf, unsigned int t)
 int parse_hex(char *in, unsigned char *out, int maxlen,   int parse_hex(char *in, unsigned char *out, int maxlen, 
               unsigned int *wildcard_mask, int *mac_type)                unsigned int *wildcard_mask, int *mac_type)
 {  {
  int mask = 0, i = 0;  int done = 0, mask = 0, i = 0;
   char *r;    char *r;
           
   if (mac_type)    if (mac_type)
     *mac_type = 0;      *mac_type = 0;
       
  while (maxlen == -1 || i < maxlen)  while (!done && (maxlen == -1 || i < maxlen))
     {      {
       for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)        for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
         if (*r != '*' && !isxdigit((unsigned char)*r))          if (*r != '*' && !isxdigit((unsigned char)*r))
           return -1;            return -1;
               
       if (*r == 0)        if (*r == 0)
        maxlen = i;        done = 1;
               
       if (r != in )        if (r != in )
         {          {
Line 460  int parse_hex(char *in, unsigned char *out, int maxlen Line 639  int parse_hex(char *in, unsigned char *out, int maxlen
                           sav = in[(j+1)*2];                            sav = in[(j+1)*2];
                           in[(j+1)*2] = 0;                            in[(j+1)*2] = 0;
                         }                          }
                         /* checks above allow mix of hexdigit and *, which
                            is illegal. */
                         if (strchr(&in[j*2], '*'))
                           return -1;
                       out[i] = strtol(&in[j*2], NULL, 16);                        out[i] = strtol(&in[j*2], NULL, 16);
                       mask = mask << 1;                        mask = mask << 1;
                      i++;                      if (++i == maxlen)
                         break; 
                       if (j < bytes - 1)                        if (j < bytes - 1)
                         in[(j+1)*2] = sav;                          in[(j+1)*2] = sav;
                     }                      }
Line 533  char *print_mac(char *buff, unsigned char *mac, int le Line 717  char *print_mac(char *buff, unsigned char *mac, int le
   return buff;    return buff;
 }  }
   
void bump_maxfd(int fd, int *max)/* rc is return from sendto and friends.
    Return 1 if we should retry.
    Set errno to zero if we succeeded. */
 int retry_send(ssize_t rc)
 {  {
  if (fd > *max)  static int retries = 0;
    *max = fd;  struct timespec waiter;
}  
   if (rc != -1)
     {
       retries = 0;
       errno = 0;
       return 0;
     }
   
   /* Linux kernels can return EAGAIN in perpetuity when calling
      sendmsg() and the relevant interface has gone. Here we loop
      retrying in EAGAIN for 1 second max, to avoid this hanging 
      dnsmasq. */
   
int retry_send(void)  if (errno == EAGAIN || errno == EWOULDBLOCK)
{ 
   struct timespec waiter; 
   if (errno == EAGAIN || errno == EWOULDBLOCK) 
      {       {
        waiter.tv_sec = 0;         waiter.tv_sec = 0;
        waiter.tv_nsec = 10000;         waiter.tv_nsec = 10000;
        nanosleep(&waiter, NULL);         nanosleep(&waiter, NULL);
       return 1;       if (retries++ < 1000)
          return 1;
      }       }
     
   if (errno == EINTR)  retries = 0;
     return 1;  
  if (errno == EINTR)
   return 0;    return 1;
   
   return 0;
 }  }
   
 int read_write(int fd, unsigned char *packet, int size, int rw)  int read_write(int fd, unsigned char *packet, int size, int rw)
Line 562  int read_write(int fd, unsigned char *packet, int size Line 760  int read_write(int fd, unsigned char *packet, int size
       
   for (done = 0; done < size; done += n)    for (done = 0; done < size; done += n)
     {      {
    retry:      do { 
      if (rw)        if (rw)
        n = read(fd, &packet[done], (size_t)(size - done));          n = read(fd, &packet[done], (size_t)(size - done));
      else        else
        n = write(fd, &packet[done], (size_t)(size - done));          n = write(fd, &packet[done], (size_t)(size - done));
         
         if (n == 0)
           return 0;
         
       } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
   
      if (n == 0)      if (errno != 0)
        return 0;        return 0;
      else if (n == -1) 
        { 
          if (retry_send() || errno == ENOMEM || errno == ENOBUFS) 
            goto retry; 
          else 
            return 0; 
        } 
     }      }
        
   return 1;    return 1;
 }  }
   
   /* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
   void close_fds(long max_fd, int spare1, int spare2, int spare3) 
   {
     /* On Linux, use the /proc/ filesystem to find which files
        are actually open, rather than iterate over the whole space,
        for efficiency reasons. If this fails we drop back to the dumb code. */
   #ifdef HAVE_LINUX_NETWORK 
     DIR *d;
     
     if ((d = opendir("/proc/self/fd")))
       {
         struct dirent *de;
   
         while ((de = readdir(d)))
           {
             long fd;
             char *e = NULL;
             
             errno = 0;
             fd = strtol(de->d_name, &e, 10);
                     
             if (errno != 0 || !e || *e || fd == dirfd(d) ||
                 fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO ||
                 fd == spare1 || fd == spare2 || fd == spare3)
               continue;
             
             close(fd);
           }
         
         closedir(d);
         return;
     }
   #endif
   
     /* fallback, dumb code. */
     for (max_fd--; max_fd >= 0; max_fd--)
       if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
           max_fd != spare1 && max_fd != spare2 && max_fd != spare3)
         close(max_fd);
   }
   
 /* Basically match a string value against a wildcard pattern.  */  /* Basically match a string value against a wildcard pattern.  */
 int wildcard_match(const char* wildcard, const char* match)  int wildcard_match(const char* wildcard, const char* match)
 {  {
Line 598  int wildcard_match(const char* wildcard, const char* m Line 836  int wildcard_match(const char* wildcard, const char* m
   
   return *wildcard == *match;    return *wildcard == *match;
 }  }
   
   /* The same but comparing a maximum of NUM characters, like strncmp.  */
   int wildcard_matchn(const char* wildcard, const char* match, int num)
   {
     while (*wildcard && *match && num)
       {
         if (*wildcard == '*')
           return 1;
   
         if (*wildcard != *match)
           return 0; 
   
         ++wildcard;
         ++match;
         --num;
       }
   
     return (!num) || (*wildcard == *match);
   }
   
   #ifdef HAVE_LINUX_NETWORK
   int kernel_version(void)
   {
     struct utsname utsname;
     int version;
     char *split;
     
     if (uname(&utsname) < 0)
       die(_("failed to find kernel version: %s"), NULL, EC_MISC);
     
     split = strtok(utsname.release, ".");
     version = (split ? atoi(split) : 0);
     split = strtok(NULL, ".");
     version = version * 256 + (split ? atoi(split) : 0);
     split = strtok(NULL, ".");
     return version * 256 + (split ? atoi(split) : 0);
   }
   #endif

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>