[BACK]Return to glob.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libc/gen/glob.c between version 1.23.8.1 and 1.32

version 1.23.8.1, 2009/05/13 19:18:23 version 1.32, 2012/12/18 01:39:56
Line 87  __RCSID("$NetBSD$");
Line 87  __RCSID("$NetBSD$");
 #define NO_GETPW_R  #define NO_GETPW_R
 #endif  #endif
   
 #if !defined(ARG_MAX)  #define GLOB_LIMIT_STRING       65536   /* number of readdirs */
 #include <limits.h>  #define GLOB_LIMIT_STAT         128     /* number of stat system calls */
 #define ARG_MAX _POSIX_ARG_MAX  #define GLOB_LIMIT_READDIR      16384   /* total buffer size of path strings */
 #endif  #define GLOB_LIMIT_PATH         1024    /* number of path elements */
   #define GLOB_LIMIT_BRACE        128     /* Number of brace calls */
   
   struct glob_limit {
           size_t l_string;
           size_t l_stat;
           size_t l_readdir;
           size_t l_brace;
   };
   
 /*  /*
  * XXX: For NetBSD 1.4.x compatibility. (kill me l8r)   * XXX: For NetBSD 1.4.x compatibility. (kill me l8r)
Line 155  static int  g_lstat(Char *, __gl_stat_t 
Line 163  static int  g_lstat(Char *, __gl_stat_t 
 static DIR      *g_opendir(Char *, glob_t *);  static DIR      *g_opendir(Char *, glob_t *);
 static Char     *g_strchr(const Char *, int);  static Char     *g_strchr(const Char *, int);
 static int       g_stat(Char *, __gl_stat_t *, glob_t *);  static int       g_stat(Char *, __gl_stat_t *, glob_t *);
 static int       glob0(const Char *, glob_t *);  static int       glob0(const char *, const Char *, glob_t *, struct glob_limit *);
 static int       glob1(Char *, glob_t *, size_t *);  static int       glob1(Char *, glob_t *, struct glob_limit *);
 static int       glob2(Char *, Char *, Char *, Char *, glob_t *,  static int       glob2(Char *, Char *, Char *, const Char *, glob_t *,
     size_t *);      struct glob_limit *);
 static int       glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,  static int       glob3(Char *, Char *, Char *, const Char *, const Char *,
     size_t *);      const Char *, glob_t *, struct glob_limit *);
 static int       globextend(const Char *, glob_t *, size_t *);  static int       globextend(const Char *, glob_t *, struct glob_limit *);
 static const Char *globtilde(const Char *, Char *, size_t, glob_t *);  static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
 static int       globexp1(const Char *, glob_t *);  static int       globexp1(const char *, const Char *, glob_t *, struct glob_limit *);
 static int       globexp2(const Char *, const Char *, glob_t *, int *);  static int       globexp2(const char *, const Char *, const Char *, glob_t *, int *,
 static int       match(Char *, Char *, Char *);      struct glob_limit *);
   static int       match(const Char *, const Char *, const Char *);
 #ifdef DEBUG  #ifdef DEBUG
 static void      qprintf(const char *, Char *);  static void      qprintf(const char *, Char *);
 #endif  #endif
   
 int  int
 glob(const char *pattern, int flags, int (*errfunc)(const char *, int),  glob(const char * __restrict pattern, int flags, int (*errfunc)(const char *,
     glob_t *pglob)      int), glob_t * __restrict pglob)
 {  {
         const u_char *patnext;          const u_char *patnext;
         int c;          int c;
         Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];          Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
           struct glob_limit limit = { 0, 0, 0, 0 };
   
         _DIAGASSERT(pattern != NULL);          _DIAGASSERT(pattern != NULL);
   
Line 212  glob(const char *pattern, int flags, int
Line 222  glob(const char *pattern, int flags, int
         *bufnext = EOS;          *bufnext = EOS;
   
         if (flags & GLOB_BRACE)          if (flags & GLOB_BRACE)
             return globexp1(patbuf, pglob);              return globexp1(pattern, patbuf, pglob, &limit);
         else          else
             return glob0(patbuf, pglob);              return glob0(pattern, patbuf, pglob, &limit);
 }  }
   
 /*  /*
Line 223  glob(const char *pattern, int flags, int
Line 233  glob(const char *pattern, int flags, int
  * characters   * characters
  */   */
 static int  static int
 globexp1(const Char *pattern, glob_t *pglob)  globexp1(const char *orig, const Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {  {
         const Char* ptr = pattern;          const Char* ptr = pattern;
         int rv;          int rv;
Line 231  globexp1(const Char *pattern, glob_t *pg
Line 241  globexp1(const Char *pattern, glob_t *pg
         _DIAGASSERT(pattern != NULL);          _DIAGASSERT(pattern != NULL);
         _DIAGASSERT(pglob != NULL);          _DIAGASSERT(pglob != NULL);
   
           if ((pglob->gl_flags & GLOB_LIMIT) &&
               limit->l_brace++ >= GLOB_LIMIT_BRACE) {
                   errno = 0;
                   return GLOB_NOSPACE;
           }
   
         /* Protect a single {}, for find(1), like csh */          /* Protect a single {}, for find(1), like csh */
         if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)          if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
                 return glob0(pattern, pglob);                  return glob0(orig, pattern, pglob, limit);
   
         while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)          while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
                 if (!globexp2(ptr, pattern, pglob, &rv))                  if (!globexp2(orig, ptr, pattern, pglob, &rv, limit))
                         return rv;                          return rv;
   
         return glob0(pattern, pglob);          return glob0(orig, pattern, pglob, limit);
 }  }
   
   
Line 249  globexp1(const Char *pattern, glob_t *pg
Line 265  globexp1(const Char *pattern, glob_t *pg
  * If it fails then it tries to glob the rest of the pattern and returns.   * If it fails then it tries to glob the rest of the pattern and returns.
  */   */
 static int  static int
 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)  globexp2(const char *orig, const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
       struct glob_limit *limit)
 {  {
         int     i;          int     i;
         Char   *lm, *ls;          Char   *lm, *ls;
Line 294  globexp2(const Char *ptr, const Char *pa
Line 311  globexp2(const Char *ptr, const Char *pa
                  * we use `pattern', not `patbuf' here so that that                   * we use `pattern', not `patbuf' here so that that
                  * unbalanced braces are passed to the match                   * unbalanced braces are passed to the match
                  */                   */
                 *rv = glob0(pattern, pglob);                  *rv = glob0(orig, pattern, pglob, limit);
                 return 0;                  return 0;
         }          }
   
Line 339  globexp2(const Char *ptr, const Char *pa
Line 356  globexp2(const Char *ptr, const Char *pa
   
                                 /* Expand the current pattern */                                  /* Expand the current pattern */
 #ifdef DEBUG  #ifdef DEBUG
                                 qprintf("globexp2:", patbuf);                                  qprintf("globexp2", patbuf);
 #endif  #endif
                                 *rv = globexp1(patbuf, pglob);                                  *rv = globexp1(orig, patbuf, pglob, limit);
   
                                 /* move after the comma, to the next string */                                  /* move after the comma, to the next string */
                                 pl = pm + 1;                                  pl = pm + 1;
Line 454  globtilde(const Char *pattern, Char *pat
Line 471  globtilde(const Char *pattern, Char *pat
  * to find no matches.   * to find no matches.
  */   */
 static int  static int
 glob0(const Char *pattern, glob_t *pglob)  glob0(const char *orig, const Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {  {
         const Char *qpatnext;          const Char *qpatnext;
         int c, error;          int c, error;
         __gl_size_t oldpathc;          __gl_size_t oldpathc;
         Char *bufnext, patbuf[MAXPATHLEN+1];          Char *bufnext, patbuf[MAXPATHLEN+1];
         size_t limit = 0;  
   
         _DIAGASSERT(pattern != NULL);          _DIAGASSERT(pattern != NULL);
         _DIAGASSERT(pglob != NULL);          _DIAGASSERT(pglob != NULL);
Line 507  glob0(const Char *pattern, glob_t *pglob
Line 523  glob0(const Char *pattern, glob_t *pglob
                         break;                          break;
                 case STAR:                  case STAR:
                         pglob->gl_flags |= GLOB_MAGCHAR;                          pglob->gl_flags |= GLOB_MAGCHAR;
                         /* collapse adjacent stars to one,                          /* collapse adjacent stars to one [or three if globstar]
                          * to avoid exponential behavior                           * to avoid exponential behavior
                          */                           */
                         if (bufnext == patbuf || bufnext[-1] != M_ALL)                          if (bufnext == patbuf || bufnext[-1] != M_ALL ||
                               ((pglob->gl_flags & GLOB_STAR) != 0 &&
                               (bufnext - 1 == patbuf || bufnext[-2] != M_ALL ||
                               bufnext - 2 == patbuf || bufnext[-3] != M_ALL)))
                                 *bufnext++ = M_ALL;                                  *bufnext++ = M_ALL;
                         break;                          break;
                 default:                  default:
Line 520  glob0(const Char *pattern, glob_t *pglob
Line 539  glob0(const Char *pattern, glob_t *pglob
         }          }
         *bufnext = EOS;          *bufnext = EOS;
 #ifdef DEBUG  #ifdef DEBUG
         qprintf("glob0:", patbuf);          qprintf("glob0", patbuf);
 #endif  #endif
   
         if ((error = glob1(patbuf, pglob, &limit)) != 0)          if ((error = glob1(patbuf, pglob, limit)) != 0)
                 return error;                  return error;
   
         if (pglob->gl_pathc == oldpathc) {          if (pglob->gl_pathc == oldpathc) {
Line 537  glob0(const Char *pattern, glob_t *pglob
Line 556  glob0(const Char *pattern, glob_t *pglob
                 if ((pglob->gl_flags & GLOB_NOCHECK) ||                  if ((pglob->gl_flags & GLOB_NOCHECK) ||
                     ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR))                      ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR))
                      == GLOB_NOMAGIC)) {                       == GLOB_NOMAGIC)) {
                         return globextend(pattern, pglob, &limit);                          const u_char *patnext;
                           Char *bufend;
                           bufend = patbuf + MAXPATHLEN;
                           patnext = (const unsigned char *)orig;
                           bufnext = patbuf;
                           while (bufnext < bufend && (c = *patnext++) != EOS)
                                   *bufnext++ = c;
   
                           *bufnext = EOS;
   
                           return globextend(patbuf, pglob, limit);
                 } else {                  } else {
                         return GLOB_NOMATCH;                          return GLOB_NOMATCH;
                 }                  }
Line 561  compare(const void *p, const void *q)
Line 590  compare(const void *p, const void *q)
 }  }
   
 static int  static int
 glob1(Char *pattern, glob_t *pglob, size_t *limit)  glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {  {
         Char pathbuf[MAXPATHLEN+1];          Char pathbuf[MAXPATHLEN+1];
   
Line 586  glob1(Char *pattern, glob_t *pglob, size
Line 615  glob1(Char *pattern, glob_t *pglob, size
  * meta characters.   * meta characters.
  */   */
 static int  static int
 glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob,  glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
     size_t *limit)      glob_t *pglob, struct glob_limit *limit)
 {  {
         __gl_stat_t sb;          __gl_stat_t sb;
         Char *p, *q;          const Char *p;
           Char *q;
         int anymeta;          int anymeta;
         Char *pend;          Char *pend;
         ptrdiff_t diff;          ptrdiff_t diff;
Line 600  glob2(Char *pathbuf, Char *pathend, Char
Line 630  glob2(Char *pathbuf, Char *pathend, Char
         _DIAGASSERT(pattern != NULL);          _DIAGASSERT(pattern != NULL);
         _DIAGASSERT(pglob != NULL);          _DIAGASSERT(pglob != NULL);
   
   #ifdef DEBUG
           qprintf("glob2", pathbuf);
   #endif
         /*          /*
          * Loop over pattern segments until end of pattern or until           * Loop over pattern segments until end of pattern or until
          * segment with meta character found.           * segment with meta character found.
Line 610  glob2(Char *pathbuf, Char *pathend, Char
Line 643  glob2(Char *pathbuf, Char *pathend, Char
                         if (g_lstat(pathbuf, &sb, pglob))                          if (g_lstat(pathbuf, &sb, pglob))
                                 return 0;                                  return 0;
   
                           if ((pglob->gl_flags & GLOB_LIMIT) &&
                               limit->l_stat++ >= GLOB_LIMIT_STAT) {
                                   errno = 0;
                                   *pathend++ = SEP;
                                   *pathend = EOS;
                                   return GLOB_NOSPACE;
                           }
                         if (((pglob->gl_flags & GLOB_MARK) &&                          if (((pglob->gl_flags & GLOB_MARK) &&
                             pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||                              pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
                             (S_ISLNK(sb.st_mode) &&                              (S_ISLNK(sb.st_mode) &&
Line 664  glob2(Char *pathbuf, Char *pathend, Char
Line 704  glob2(Char *pathbuf, Char *pathend, Char
                         }                          }
                 } else                  /* Need expansion, recurse. */                  } else                  /* Need expansion, recurse. */
                         return glob3(pathbuf, pathend, pathlim, pattern, p,                          return glob3(pathbuf, pathend, pathlim, pattern, p,
                             pglob, limit);                              pattern, pglob, limit);
         }          }
         /* NOTREACHED */          /* NOTREACHED */
 }  }
   
 static int  static int
 glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern,  glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
     Char *restpattern, glob_t *pglob, size_t *limit)      const Char *restpattern, const Char *pglobstar, glob_t *pglob,
       struct glob_limit *limit)
 {  {
         struct dirent *dp;          struct dirent *dp;
         DIR *dirp;          DIR *dirp;
           __gl_stat_t sbuf;
         int error;          int error;
         char buf[MAXPATHLEN];          char buf[MAXPATHLEN];
           int globstar = 0;
           int chase_symlinks = 0;
           const Char *termstar = NULL;
   
         /*          /*
          * The readdirfunc declaration can't be prototyped, because it is           * The readdirfunc declaration can't be prototyped, because it is
Line 695  glob3(Char *pathbuf, Char *pathend, Char
Line 740  glob3(Char *pathbuf, Char *pathend, Char
         *pathend = EOS;          *pathend = EOS;
         errno = 0;          errno = 0;
   
           while (pglobstar < restpattern) {
                   if ((pglobstar[0] & M_MASK) == M_ALL &&
                       (pglobstar[1] & M_MASK) == M_ALL) {
                           globstar = 1;
                           chase_symlinks = (pglobstar[2] & M_MASK) == M_ALL;
                           termstar = pglobstar + (2 + chase_symlinks);
                           break;
                   }
                   pglobstar++;
           }
   
           if (globstar) {
                   error = pglobstar == pattern && termstar == restpattern ?
                       *restpattern == EOS ?
                       glob2(pathbuf, pathend, pathlim, restpattern - 1, pglob,
                       limit) :
                       glob2(pathbuf, pathend, pathlim, restpattern + 1, pglob,
                       limit) :
                       glob3(pathbuf, pathend, pathlim, pattern, restpattern,
                       termstar, pglob, limit);
                   if (error)
                           return error;
                   *pathend = EOS;
           }
   
           if (*pathbuf && (g_lstat(pathbuf, &sbuf, pglob) ||
               !S_ISDIR(sbuf.st_mode)
   #ifdef S_IFLINK
                && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode))
   #endif
               ))
                   return 0;
   
         if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {          if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
                 if (pglob->gl_errfunc) {                  if (pglob->gl_errfunc) {
                         if (g_Ctoc(pathbuf, buf, sizeof(buf)))                          if (g_Ctoc(pathbuf, buf, sizeof(buf)))
Line 721  glob3(Char *pathbuf, Char *pathend, Char
Line 799  glob3(Char *pathbuf, Char *pathend, Char
         if (pglob->gl_flags & GLOB_ALTDIRFUNC)          if (pglob->gl_flags & GLOB_ALTDIRFUNC)
                 readdirfunc = pglob->gl_readdir;                  readdirfunc = pglob->gl_readdir;
         else          else
                 readdirfunc = (struct dirent *(*)__P((void *))) readdir;                  readdirfunc = (struct dirent *(*)(void *)) readdir;
         while ((dp = (*readdirfunc)(dirp)) != NULL) {          while ((dp = (*readdirfunc)(dirp)) != NULL) {
                 u_char *sc;                  u_char *sc;
                 Char *dc;                  Char *dc;
   
                   if ((pglob->gl_flags & GLOB_LIMIT) &&
                       limit->l_readdir++ >= GLOB_LIMIT_READDIR) {
                           errno = 0;
                           *pathend++ = SEP;
                           *pathend = EOS;
                           error = GLOB_NOSPACE;
                           break;
                   }
   
                 /*                  /*
                  * Initial DOT must be matched literally, unless we have                   * Initial DOT must be matched literally, unless we have
                  * GLOB_PERIOD set.                   * GLOB_PERIOD set.
Line 768  glob3(Char *pathbuf, Char *pathend, Char
Line 855  glob3(Char *pathbuf, Char *pathend, Char
                         }                          }
                 }                  }
   
                 if (!match(pathend, pattern, restpattern)) {                  if (globstar) {
   #ifdef S_IFLNK
                           if (!chase_symlinks &&
                               (g_lstat(pathbuf, &sbuf, pglob) ||
                               S_ISLNK(sbuf.st_mode)))
                                   continue;
   #endif
   
                           if (!match(pathend, pattern, termstar))
                                   continue;
   
                           if (--dc < pathlim - 2)
                                   *dc++ = SEP;
                           *dc = EOS;
                           error = glob2(pathbuf, dc, pathlim, pglobstar,
                               pglob, limit);
                           if (error)
                                   break;
                         *pathend = EOS;                          *pathend = EOS;
                         continue;                  } else {
                           if (!match(pathend, pattern, restpattern)) {
                                   *pathend = EOS;
                                   continue;
                           }
                           error = glob2(pathbuf, --dc, pathlim, restpattern,
                               pglob, limit);
                           if (error)
                                   break;
                 }                  }
                 error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, limit);  
                 if (error)  
                         break;  
         }          }
   
         if (pglob->gl_flags & GLOB_ALTDIRFUNC)          if (pglob->gl_flags & GLOB_ALTDIRFUNC)
                 (*pglob->gl_closedir)(dirp);                  (*pglob->gl_closedir)(dirp);
         else          else
Line 807  glob3(Char *pathbuf, Char *pathend, Char
Line 915  glob3(Char *pathbuf, Char *pathend, Char
  *      gl_pathv points to (gl_offs + gl_pathc + 1) items.   *      gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */   */
 static int  static int
 globextend(const Char *path, glob_t *pglob, size_t *limit)  globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
 {  {
         char **pathv;          char **pathv;
         size_t i, newsize, len;          size_t i, newsize, len;
Line 818  globextend(const Char *path, glob_t *pgl
Line 926  globextend(const Char *path, glob_t *pgl
         _DIAGASSERT(pglob != NULL);          _DIAGASSERT(pglob != NULL);
   
         newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);          newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
           if ((pglob->gl_flags & GLOB_LIMIT) &&
               newsize > GLOB_LIMIT_PATH * sizeof(*pathv))
                   goto nospace;
         pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) :          pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) :
             malloc(newsize);              malloc(newsize);
         if (pathv == NULL)          if (pathv == NULL)
Line 834  globextend(const Char *path, glob_t *pgl
Line 945  globextend(const Char *path, glob_t *pgl
         for (p = path; *p++;)          for (p = path; *p++;)
                 continue;                  continue;
         len = (size_t)(p - path);          len = (size_t)(p - path);
         *limit += len;          limit->l_string += len;
         if ((copy = malloc(len)) != NULL) {          if ((copy = malloc(len)) != NULL) {
                 if (g_Ctoc(path, copy, len)) {                  if (g_Ctoc(path, copy, len)) {
                         free(copy);                          free(copy);
Line 844  globextend(const Char *path, glob_t *pgl
Line 955  globextend(const Char *path, glob_t *pgl
         }          }
         pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;          pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
   
         if ((pglob->gl_flags & GLOB_LIMIT) && (newsize + *limit) >= ARG_MAX) {          if ((pglob->gl_flags & GLOB_LIMIT) &&
                 errno = 0;              (newsize + limit->l_string) >= GLOB_LIMIT_STRING)
                 return GLOB_NOSPACE;                  goto nospace;
         }  
   
         return copy == NULL ? GLOB_NOSPACE : 0;          return copy == NULL ? GLOB_NOSPACE : 0;
   nospace:
           errno = 0;
           return GLOB_NOSPACE;
 }  }
   
   
Line 858  globextend(const Char *path, glob_t *pgl
Line 971  globextend(const Char *path, glob_t *pgl
  * pattern causes a recursion level.   * pattern causes a recursion level.
  */   */
 static int  static int
 match(Char *name, Char *pat, Char *patend)  match(const Char *name, const Char *pat, const Char *patend)
 {  {
         int ok, negate_range;          int ok, negate_range;
         Char c, k;          Char c, k;
Line 871  match(Char *name, Char *pat, Char *paten
Line 984  match(Char *name, Char *pat, Char *paten
                 c = *pat++;                  c = *pat++;
                 switch (c & M_MASK) {                  switch (c & M_MASK) {
                 case M_ALL:                  case M_ALL:
                           while (pat < patend && (*pat & M_MASK) == M_ALL)
                                   pat++;  /* eat consecutive '*' */
                         if (pat == patend)                          if (pat == patend)
                                 return 1;                                  return 1;
                         do                          for (; !match(name, pat, patend); name++)
                             if (match(name, pat, patend))                                  if (*name == EOS)
                                     return 1;                                          return 0;
                         while (*name++ != EOS);                          return 1;
                         return 0;  
                 case M_ONE:                  case M_ONE:
                         if (*name++ == EOS)                          if (*name++ == EOS)
                                 return 0;                                  return 0;
Line 940  glob_pattern_p(const char *pattern, int 
Line 1054  glob_pattern_p(const char *pattern, int 
                         return 1;                          return 1;
   
                 case QUOTE:                  case QUOTE:
                         if (quote && pattern[1] != '\0')                          if (quote && pattern[1] != EOS)
                               ++pattern;                                ++pattern;
                         break;                          break;
   

Legend:
Removed from v.1.23.8.1  
changed lines
  Added in v.1.32

CVSweb <webmaster@jp.NetBSD.org>