Print this page
5292 findunref is both slow and broken

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/findunref/findunref.c
          +++ new/usr/src/tools/findunref/findunref.c
↓ open down ↓ 45 lines elided ↑ open up ↑
  46   46   * for checking whether a given pathname is matched by a pattern glob in
  47   47   * the set.
  48   48   */
  49   49  typedef struct {
  50   50          char            **paths;
  51   51          unsigned int    npath;
  52   52          unsigned int    maxpaths;
  53   53  } pnset_t;
  54   54  
  55   55  /*
  56      - * Data associated with the current Mercurial manifest.
       56 + * Data associated with the current SCM manifest.
  57   57   */
  58      -typedef struct hgdata {
       58 +typedef struct scmdata {
  59   59          pnset_t         *manifest;
  60      -        char            hgpath[MAXPATHLEN];
       60 +        char            metapath[MAXPATHLEN];
  61   61          char            root[MAXPATHLEN];
  62   62          unsigned int    rootlen;
  63   63          boolean_t       rootwarn;
  64      -} hgdata_t;
       64 +} scmdata_t;
  65   65  
  66   66  /*
  67   67   * Hooks used to check if a given unreferenced file is known to an SCM
  68      - * (currently Mercurial and TeamWare).
       68 + * (currently Git, Mercurial and TeamWare).
  69   69   */
  70   70  typedef int checkscm_func_t(const char *, const struct FTW *);
  71   71  typedef void chdirscm_func_t(const char *);
  72   72  
  73   73  typedef struct {
  74   74          const char      *name;
  75   75          checkscm_func_t *checkfunc;
  76   76          chdirscm_func_t *chdirfunc;
  77   77  } scm_t;
  78   78  
  79      -static checkscm_func_t check_tw, check_hg, check_git;
       79 +static checkscm_func_t check_tw, check_scmdata;
  80   80  static chdirscm_func_t chdir_hg, chdir_git;
  81   81  static int      pnset_add(pnset_t *, const char *);
  82   82  static int      pnset_check(const pnset_t *, const char *);
  83   83  static void     pnset_empty(pnset_t *);
  84   84  static void     pnset_free(pnset_t *);
  85   85  static int      checkpath(const char *, const struct stat *, int, struct FTW *);
  86   86  static pnset_t  *make_exset(const char *);
  87   87  static void     warn(const char *, ...);
  88   88  static void     die(const char *, ...);
  89   89  
  90   90  static const scm_t scms[] = {
  91   91          { "tw",         check_tw,       NULL            },
  92   92          { "teamware",   check_tw,       NULL            },
  93      -        { "hg",         check_hg,       chdir_hg        },
  94      -        { "mercurial",  check_hg,       chdir_hg        },
  95      -        { "git",        check_git,      chdir_git       },
       93 +        { "hg",         check_scmdata,  chdir_hg        },
       94 +        { "mercurial",  check_scmdata,  chdir_hg        },
       95 +        { "git",        check_scmdata,  chdir_git       },
  96   96          { NULL,         NULL,           NULL            }
  97   97  };
  98   98  
  99   99  static const scm_t      *scm;
 100      -static hgdata_t         hgdata;
 101      -static pnset_t          *gitmanifest = NULL;
      100 +static scmdata_t        scmdata;
 102  101  static time_t           tstamp;         /* timestamp to compare files to */
 103  102  static pnset_t          *exsetp;        /* pathname globs to ignore */
 104  103  static const char       *progname;
 105  104  
 106  105  int
 107  106  main(int argc, char *argv[])
 108  107  {
 109  108          int c;
 110  109          char path[MAXPATHLEN];
 111  110          char subtree[MAXPATHLEN] = "./";
↓ open down ↓ 74 lines elided ↑ open up ↑
 186  185                  die("cannot walk tree rooted at \"%s\"\n", argv[0]);
 187  186  
 188  187          pnset_empty(exsetp);
 189  188          return (EXIT_SUCCESS);
 190  189  }
 191  190  
 192  191  /*
 193  192   * Load and return a pnset for the manifest for the Mercurial repo at `hgroot'.
 194  193   */
 195  194  static pnset_t *
 196      -load_manifest(const char *hgroot)
      195 +hg_manifest(const char *hgroot)
 197  196  {
 198  197          FILE    *fp = NULL;
 199  198          char    *hgcmd = NULL;
 200  199          char    *newline;
 201  200          pnset_t *pnsetp;
 202  201          char    path[MAXPATHLEN];
 203  202  
 204  203          pnsetp = calloc(sizeof (pnset_t), 1);
 205  204          if (pnsetp == NULL ||
 206  205              asprintf(&hgcmd, "hg manifest -R %s", hgroot) == -1)
↓ open down ↓ 17 lines elided ↑ open up ↑
 224  223          return (pnsetp);
 225  224  fail:
 226  225          warn("cannot load hg manifest at %s", hgroot);
 227  226          if (fp != NULL)
 228  227                  (void) pclose(fp);
 229  228          free(hgcmd);
 230  229          pnset_free(pnsetp);
 231  230          return (NULL);
 232  231  }
 233  232  
 234      -static void
 235      -chdir_git(const char *path)
      233 +/*
      234 + * Load and return a pnset for the manifest for the Git repo at `gitroot'.
      235 + */
      236 +static pnset_t *
      237 +git_manifest(const char *gitroot)
 236  238  {
 237      -        FILE *fp = NULL;
 238      -        char *gitcmd = NULL;
 239      -        char *newline;
 240      -        char fn[MAXPATHLEN];
 241      -        pnset_t *pnsetp;
      239 +        FILE    *fp = NULL;
      240 +        char    *gitcmd = NULL;
      241 +        char    *newline;
      242 +        pnset_t *pnsetp;
      243 +        char    path[MAXPATHLEN];
 242  244  
 243  245          pnsetp = calloc(sizeof (pnset_t), 1);
 244      -        if ((pnsetp == NULL) ||
 245      -            (asprintf(&gitcmd, "git ls-files %s", path) == -1))
      246 +        if (pnsetp == NULL ||
      247 +            asprintf(&gitcmd, "git --git-dir=%s/.git ls-files", gitroot) == -1)
 246  248                  goto fail;
 247  249  
 248      -        if ((fp = popen(gitcmd, "r")) == NULL)
      250 +        fp = popen(gitcmd, "r");
      251 +        if (fp == NULL)
 249  252                  goto fail;
 250  253  
 251      -        while (fgets(fn, sizeof (fn), fp) != NULL) {
 252      -                if ((newline = strrchr(fn, '\n')) != NULL)
      254 +        while (fgets(path, sizeof (path), fp) != NULL) {
      255 +                newline = strrchr(path, '\n');
      256 +                if (newline != NULL)
 253  257                          *newline = '\0';
 254  258  
 255      -                if (pnset_add(pnsetp, fn) == 0)
      259 +                if (pnset_add(pnsetp, path) == 0)
 256  260                          goto fail;
 257  261          }
 258  262  
 259  263          (void) pclose(fp);
 260  264          free(gitcmd);
 261      -        gitmanifest = pnsetp;
 262      -        return;
      265 +        return (pnsetp);
 263  266  fail:
 264      -        warn("cannot load git manifest");
      267 +        warn("cannot load git manifest at %s", gitroot);
 265  268          if (fp != NULL)
 266  269                  (void) pclose(fp);
 267      -        if (pnsetp != NULL)
 268      -                free(pnsetp);
 269      -        if (gitcmd != NULL)
 270      -                free(gitcmd);
      270 +        free(gitcmd);
      271 +        pnset_free(pnsetp);
      272 +        return (NULL);
 271  273  }
 272  274  
 273  275  /*
 274  276   * If necessary, change our active manifest to be appropriate for `path'.
 275  277   */
 276  278  static void
 277      -chdir_hg(const char *path)
      279 +chdir_scmdata(const char *path, const char *meta,
      280 +    pnset_t *(*manifest_func)(const char *path))
 278  281  {
 279      -        char hgpath[MAXPATHLEN];
      282 +        char scmpath[MAXPATHLEN];
 280  283          char basepath[MAXPATHLEN];
 281  284          char *slash;
 282  285  
 283      -        (void) snprintf(hgpath, MAXPATHLEN, "%s/.hg", path);
      286 +        (void) snprintf(scmpath, MAXPATHLEN, "%s/%s", path, meta);
 284  287  
 285  288          /*
 286  289           * Change our active manifest if any one of the following is true:
 287  290           *
 288      -         *   1. No manifest is loaded.  Find the nearest hgroot to load from.
      291 +         *   1. No manifest is loaded.  Find the nearest SCM root to load from.
 289  292           *
 290  293           *   2. A manifest is loaded, but we've moved into a directory with
 291      -         *      its own hgroot (e.g., usr/closed).  Load from its hgroot.
      294 +         *      its own metadata directory (e.g., usr/closed).  Load from its
      295 +         *      root.
 292  296           *
 293  297           *   3. A manifest is loaded, but no longer applies (e.g., the manifest
 294  298           *      under usr/closed is loaded, but we've moved to usr/src).
 295  299           */
 296      -        if (hgdata.manifest == NULL ||
 297      -            strcmp(hgpath, hgdata.hgpath) != 0 && access(hgpath, X_OK) == 0 ||
 298      -            strncmp(path, hgdata.root, hgdata.rootlen - 1) != 0) {
 299      -                pnset_free(hgdata.manifest);
 300      -                hgdata.manifest = NULL;
      300 +        if (scmdata.manifest == NULL ||
      301 +            (strcmp(scmpath, scmdata.metapath) != 0 &&
      302 +            access(scmpath, X_OK) == 0) ||
      303 +            strncmp(path, scmdata.root, scmdata.rootlen - 1) != 0) {
      304 +                pnset_free(scmdata.manifest);
      305 +                scmdata.manifest = NULL;
 301  306  
 302  307                  (void) strlcpy(basepath, path, MAXPATHLEN);
 303  308  
 304  309                  /*
 305      -                 * Walk up the directory tree looking for .hg subdirectories.
      310 +                 * Walk up the directory tree looking for metadata
      311 +                 * subdirectories.
 306  312                   */
 307      -                while (access(hgpath, X_OK) == -1) {
      313 +                while (access(scmpath, X_OK) == -1) {
 308  314                          slash = strrchr(basepath, '/');
 309  315                          if (slash == NULL) {
 310      -                                if (!hgdata.rootwarn) {
 311      -                                        warn("no hg root for \"%s\"\n", path);
 312      -                                        hgdata.rootwarn = B_TRUE;
      316 +                                if (!scmdata.rootwarn) {
      317 +                                        warn("no metadata directory "
      318 +                                            "for \"%s\"\n", path);
      319 +                                        scmdata.rootwarn = B_TRUE;
 313  320                                  }
 314  321                                  return;
 315  322                          }
 316  323                          *slash = '\0';
 317      -                        (void) snprintf(hgpath, MAXPATHLEN, "%s/.hg", basepath);
      324 +                        (void) snprintf(scmpath, MAXPATHLEN, "%s/%s", basepath,
      325 +                            meta);
 318  326                  }
 319  327  
 320  328                  /*
 321      -                 * We found a directory with an .hg subdirectory; record it
 322      -                 * and load its manifest.
      329 +                 * We found a directory with an SCM metadata directory; record
      330 +                 * it and load its manifest.
 323  331                   */
 324      -                (void) strlcpy(hgdata.hgpath, hgpath, MAXPATHLEN);
 325      -                (void) strlcpy(hgdata.root, basepath, MAXPATHLEN);
 326      -                hgdata.manifest = load_manifest(hgdata.root);
      332 +                (void) strlcpy(scmdata.metapath, scmpath, MAXPATHLEN);
      333 +                (void) strlcpy(scmdata.root, basepath, MAXPATHLEN);
      334 +                scmdata.manifest = manifest_func(scmdata.root);
 327  335  
 328  336                  /*
 329      -                 * The logic in check_hg() depends on hgdata.root having a
 330      -                 * single trailing slash, so only add it if it's missing.
      337 +                 * The logic in check_scmdata() depends on scmdata.root having
      338 +                 * a single trailing slash, so only add it if it's missing.
 331  339                   */
 332      -                if (hgdata.root[strlen(hgdata.root) - 1] != '/')
 333      -                        (void) strlcat(hgdata.root, "/", MAXPATHLEN);
 334      -                hgdata.rootlen = strlen(hgdata.root);
      340 +                if (scmdata.root[strlen(scmdata.root) - 1] != '/')
      341 +                        (void) strlcat(scmdata.root, "/", MAXPATHLEN);
      342 +                scmdata.rootlen = strlen(scmdata.root);
 335  343          }
 336  344  }
 337  345  
      346 +static void
      347 +chdir_git(const char *path)
      348 +{
      349 +        chdir_scmdata(path, ".git", git_manifest);
      350 +}
      351 +
 338  352  /*
 339      - * Check if a file is under Mercurial control by checking against the manifest.
      353 + * If necessary, change our active manifest to be appropriate for `path'.
 340  354   */
      355 +static void
      356 +chdir_hg(const char *path)
      357 +{
      358 +        chdir_scmdata(path, ".hg", hg_manifest);
      359 +}
      360 +
 341  361  /* ARGSUSED */
 342  362  static int
 343      -check_hg(const char *path, const struct FTW *ftwp)
      363 +check_scmdata(const char *path, const struct FTW *ftwp)
 344  364  {
 345  365          /*
 346  366           * The manifest paths are relative to the manifest root; skip past it.
 347  367           */
 348      -        path += hgdata.rootlen;
      368 +        path += scmdata.rootlen;
 349  369  
 350      -        return (hgdata.manifest != NULL && pnset_check(hgdata.manifest, path));
 351      -}
 352      -/* ARGSUSED */
 353      -static int
 354      -check_git(const char *path, const struct FTW *ftwp)
 355      -{
 356      -        path += 2;              /* Skip "./" */
 357      -        return (gitmanifest != NULL && pnset_check(gitmanifest, path));
      370 +        return (scmdata.manifest != NULL && pnset_check(scmdata.manifest,
      371 +            path));
 358  372  }
 359  373  
 360  374  /*
 361  375   * Check if a file is under TeamWare control by checking for its corresponding
 362  376   * SCCS "s-dot" file.
 363  377   */
 364  378  static int
 365  379  check_tw(const char *path, const struct FTW *ftwp)
 366  380  {
 367  381          char sccspath[MAXPATHLEN];
↓ open down ↓ 220 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX