source: gpfs_3.1_ker2.6.20/lpp/mmfs/samples/util/tsfindinode.c @ 195

Last change on this file since 195 was 16, checked in by rock, 17 years ago
File size: 16.3 KB
Line 
1/* IBM_PROLOG_BEGIN_TAG                                                   */
2/* This is an automatically generated prolog.                             */
3/*                                                                        */
4/*                                                                        */
5/*                                                                        */
6/* Licensed Materials - Property of IBM                                   */
7/*                                                                        */
8/* (C) COPYRIGHT International Business Machines Corp. 2003,2006          */
9/* All Rights Reserved                                                    */
10/*                                                                        */
11/* US Government Users Restricted Rights - Use, duplication or            */
12/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
13/*                                                                        */
14/* IBM_PROLOG_END_TAG                                                     */
15
16/*====================================================================
17 *
18 * tsfindinode command: Recursively traverse the directory structure
19 *                    to list all files/directories in the file system
20 *                    that have any of the inode numbers listed.
21 *
22 * Syntax: tsfindinode {-i {inum | inumfile}} [-0] [-t nThreads] [--] <pathname>
23 *
24 *   The "pathname" parameter should be the directory where the root of
25 *   the file system is found.
26 *
27 *==================================================================*/
28
29#ifdef GPFS_LINUX
30/* Use 64 bit version of stat, etc. */
31#define _LARGEFILE_SOURCE
32#define _FILE_OFFSET_BITS 64
33
34typedef long long offset_t;
35#endif
36
37#ifdef GPFS_AIX
38/* Use 64 bit version of stat, etc. */
39#ifndef _LARGE_FILES
40#define _LARGE_FILES
41#endif
42#endif
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <fcntl.h>
47#include <errno.h>
48#include <string.h>
49#include <sys/types.h>
50#include <sys/stat.h>
51#include <unistd.h>
52#include <pthread.h>
53
54#include <gpfs.h>
55
56extern char *basename(char *);
57
58int optcheck = 1;
59char *RootFsDirP;
60
61/* Define the number of threads used to read the directories */
62#define DEFAULT_THREADS 16
63int nThreads = DEFAULT_THREADS;
64char *print0 = "\n";
65
66/* Define wait queue for threads */
67static pthread_mutex_t QueueMutex;
68static pthread_cond_t QueueCond;
69static int NWorkersWaiting = 0;
70static int NWorkersRunning = 0;
71
72typedef struct queue_element
73{
74  struct queue_element *nextP;
75  ino_t ino;
76  char path[4];
77} QueueElement;
78
79static QueueElement *WorkQueueP = NULL;
80
81/* Define mutex to serialize the output */
82static pthread_mutex_t OutputMutex;
83
84#define MAX_INODE_INCREMENT 1000
85static numInodes = 0;
86static maxInodes = 0;
87static ino_t *Inode = NULL;
88static unsigned char *InodeSeen = NULL;
89
90/* error code set while in threads to control final error code */
91int exitrc = 0;
92
93/* print usage message and exit */
94void usage(char *argv0)
95{
96  fprintf(stderr,
97          "Usage: %s {-i {inum | inumfile}} [-0] [-t nThreads (def=%d)] [--] pathname\n"
98            "       (-i can be used multiple times to specify another inode number or file of inode numbers)\n",
99          basename(argv0), DEFAULT_THREADS);
100  exit(1);
101}
102
103void addInum(ino_t inode)
104{
105  int i, j;
106  int low, high;
107  ino_t *newInode = NULL;
108
109  if (numInodes >= maxInodes)
110  {
111    newInode = (ino_t *)malloc((maxInodes+MAX_INODE_INCREMENT) * sizeof(ino_t));
112    if (newInode == NULL)
113    {
114      fprintf(stderr, "Too many inodes (%d)\n", maxInodes);
115      exit(1);
116    }
117    if (Inode != NULL)
118    {
119      /* Copy old list of inodes and delete the old array */
120      memcpy(newInode, Inode, maxInodes * sizeof(ino_t));
121      free(Inode);
122    }
123    Inode = newInode;
124    maxInodes += MAX_INODE_INCREMENT;
125  }
126
127  /* Binary search the list */
128  i = 0;
129  low = 0;
130  high = numInodes - 1;
131  while (low <= high)
132  {
133    i = (low + high)/2;
134    if (inode == Inode[i])
135      return;  /* ignore duplicate entry */
136    if (low == high)
137    {
138      if (inode > Inode[i])
139        i++;
140      break;
141    }
142    if (inode < Inode[i])
143      high = i - 1;
144    else
145      low = i + 1;
146  }
147
148  /* move all entries down one slot */
149  for (j=numInodes; j > i; j--)
150    Inode[j] = Inode[j-1];
151
152  /* insert entry in sorted array */
153  Inode[i] = inode;
154  numInodes++;
155}
156
157void getinodes(char * listorname)
158{
159  FILE *fd;
160  long inum;
161  char linebuf[256];
162
163  memset(linebuf, 0, sizeof(linebuf));
164
165  if ((listorname[0]>='0') & (listorname[0]<='9'))
166  {
167    /* If arg starts with a digit, assume it is a number for sscanf to parse */
168    if (sscanf(listorname, "%ld", &inum) == 1)
169      addInum(inum);
170  }
171  else
172  {
173    /* Otherwise, assume the arg is a filename.
174       Read inode numbers from the file until scanf fails to find a number */
175    if (listorname[0] == '-')
176    {
177      while (scanf("%ld", &inum) == 1)
178        addInum(inum);
179    }
180    else
181    {
182      fd = fopen(listorname, "r");
183      if (fd != NULL)
184      {
185        /* while (fscanf(fd, "%ld", &inum) == 1) */
186        while (fgets(linebuf, sizeof(linebuf), fd) != NULL)
187        {
188          if ((linebuf[0]>='0') & (linebuf[0]<='9'))
189          {
190            if (sscanf(linebuf, "%ld", &inum) == 1)
191              addInum(inum);
192          }
193          else
194            fprintf(stdout, "%s\n", linebuf); /* disregard mesg or comment line */
195          memset(linebuf, 0, sizeof(linebuf));
196        }
197        fclose(fd);
198      }
199      else
200      {
201        int rc = errno;
202        fprintf(stderr, "Error opening %s: %s\n", listorname, strerror(rc));
203        exit(1);
204      }
205    }
206  }
207}
208
209/* If there is no list return 1,
210   or if inode is in the list return its index,
211   else return -1. */
212int testinode(ino_t inode)
213{
214  int low, mid, high;
215
216  /* Binary search the list */
217  low = 0;
218  high = numInodes - 1;
219  while (low <= high)
220  {
221    mid = (low + high)/2;
222    if (inode == Inode[mid])
223      return mid;
224    if (low == high)
225      return -1;
226    if (inode < Inode[mid])
227      high = mid - 1;
228    else
229      low = mid + 1;
230  }
231  return -1;
232}
233
234/* Add an element to the work queue
235   and signal any thread waiting for work. */
236int EnqueueWork(const char *pathP, const char *dirP, ino_t inode)
237{
238  int rc;
239  int pathLen = strlen(pathP);
240  QueueElement *qP = NULL;
241
242  /* Allocate a work queue element and space for the path.  */
243  qP = (QueueElement *) malloc((sizeof(*qP) - sizeof(qP->path))
244                                + pathLen + strlen(dirP) + 2);
245  if (qP == NULL)
246  {
247    fprintf(stderr, "Out of memory.\n");
248    return(ENOMEM);
249  }
250
251  /* Initialize element */
252  qP->ino = inode;
253  if (pathLen > 0)
254  {
255    strcpy(qP->path, pathP);
256    if (strlen(dirP) > 0)
257    {
258      strcat(qP->path, "/");
259      strcat(qP->path, dirP);
260    }
261  }
262  else
263    strcpy(qP->path, dirP);
264
265  /* Acquire mutex protecting the work queue */
266  rc = pthread_mutex_lock(&QueueMutex);
267  if (rc != 0)
268  {
269    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
270    return rc;
271  }
272
273  /* Add work element to the list */
274  qP->nextP = WorkQueueP;
275  WorkQueueP = qP;
276
277  /* Signal a waiting worker thread */
278  if (NWorkersWaiting > 0)
279  {
280    NWorkersWaiting -= 1;
281    rc = pthread_cond_signal(&QueueCond);
282    if (rc != 0)
283    {
284      fprintf(stderr, "Error in pthread_cond_signal: %s\n", strerror(rc));
285      return rc;
286    }
287  }
288
289  /* Release mutex before returning */
290  rc = pthread_mutex_unlock(&QueueMutex);
291  if (rc != 0)
292  {
293    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
294    return rc;
295  }
296
297  /* Success! */
298  return 0;
299}
300
301
302/* Dequeue the next work element from the queue
303   or if the queue is empty, wait for more work to become available */
304QueueElement *DequeueWork(void)
305{
306  int rc;
307  QueueElement *qP;
308
309  /* Acquire mutex protecting the work queue */
310  rc = pthread_mutex_lock(&QueueMutex);
311  if (rc != 0)
312  {
313    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
314    if (exitrc == 0)
315      exitrc = rc;
316    return NULL;
317  }
318
319  /* One less thread working */
320  NWorkersRunning -= 1;
321
322  /* Loop waiting for work to become available */
323  while ((WorkQueueP == NULL) && (NWorkersRunning > 0))
324  {
325    NWorkersWaiting += 1;       /* One more thread waiting */
326    rc = pthread_cond_wait(&QueueCond, &QueueMutex);
327    if (rc != 0)
328    {
329      fprintf(stderr, "Error in pthread_cond_wait: %s\n", strerror(rc));
330      if (exitrc == 0)
331        exitrc = rc;
332      return NULL;
333    }
334  }
335
336  /* Check if we are done */
337  if (WorkQueueP == NULL)
338  {
339    qP = NULL;                  /* Nothing more to do. */
340
341    /* signal any waiting threads */
342    if (NWorkersWaiting > 0)
343    {
344      NWorkersWaiting = 0;
345      rc = pthread_cond_broadcast(&QueueCond);
346      if (rc != 0)
347      {
348        fprintf(stderr, "Error in pthread_cond_broadcast: %s\n", strerror(rc));
349        if (exitrc == 0)
350          exitrc = rc;
351      }
352    }
353  }
354  else
355  {
356    /* Remove the first element from the queue */
357    qP = WorkQueueP;
358    WorkQueueP = qP->nextP;
359    qP->nextP = NULL;
360
361    /* One more thread working */
362    NWorkersRunning += 1;
363  }
364
365  /* Release mutex before returning */
366  rc = pthread_mutex_unlock(&QueueMutex);
367  if (rc != 0)
368  {
369    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
370    if (exitrc == 0)
371      exitrc = rc;
372    return NULL;
373  }
374
375  return qP;
376}
377
378/* Main body for each thread.
379   Loop until there is no more work to do. */
380void* ThreadBody(void *parmP)
381{
382  int rc;
383  QueueElement *qP;
384  int read_dir(const char *, ino_t);
385
386  /* Count this thread as a worker thread */
387  rc = pthread_mutex_lock(&QueueMutex);
388  if (rc != 0)
389  {
390    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
391    if (exitrc == 0)
392      exitrc = rc;
393    return NULL;
394  }
395  NWorkersRunning += 1;
396  rc = pthread_mutex_unlock(&QueueMutex);
397  if (rc != 0)
398  {
399    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
400    NWorkersRunning -= 1;
401    if (exitrc == 0)
402      exitrc = rc;
403    return NULL;
404  }
405
406  /* Loop while there is work to do */
407  do
408  {
409    /* Wait for work */
410    qP = DequeueWork();
411    if (qP == NULL)
412      break;
413
414    /* Read this directory */
415    rc = read_dir(qP->path, qP->ino);
416    if (exitrc == 0)
417      exitrc = rc;
418
419    /* Free work queue element */
420    free(qP);
421
422  } while (rc == 0);
423
424  rc = pthread_mutex_lock(&QueueMutex);
425  if (rc != 0)
426  {
427    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
428    if (exitrc == 0)
429      exitrc = rc;
430    return NULL;
431  }
432  NWorkersRunning -= 1;
433  rc = pthread_mutex_unlock(&QueueMutex);
434  if (rc != 0)
435  {
436    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
437    if (exitrc == 0)
438      exitrc = rc;
439  }
440
441  return NULL;
442}
443
444/* Read all entries from the current directory */
445int read_dir(const char *pathP, ino_t inode)
446{
447  int rc = 0, ind;
448  const gpfs_direntx_t *direntxP;
449  gpfs_fssnap_handle_t *fsP = NULL;
450  gpfs_ifile_t *dirxP = NULL;
451  char *typeP, *slashP;
452
453  /* Check if we need a "/"  */
454  if (strlen(pathP) > 0)
455    slashP = "/";
456  else
457    slashP = "";
458
459  /* Open the file system */
460  fsP = gpfs_get_fssnaphandle_by_path(RootFsDirP);
461  if (fsP == NULL)
462  {
463    rc = errno;
464    fprintf(stderr, "gpfs_get_fssnaphandle_by_path(%s): %s\n",
465            RootFsDirP, strerror(rc));
466    goto exit;
467  }
468
469  /* If there is only one inode in the list and is one of the reserved inode
470     it cannot possibly be found, so stop the nonsense now.
471     Calling tsfindinode -i 1 can be a fast test as to whether the filesystem
472     is mounted and ready to use. */
473  if (numInodes == 1 && Inode[0] < 3)
474    goto exit;
475
476  /* Open the directory's file */
477  dirxP = gpfs_iopen(fsP, inode, O_RDONLY, NULL, NULL);
478  if (dirxP == NULL)
479  {
480    rc = errno;
481    fprintf(stderr, "gpfs_iopen(%s/%s): %s\n", RootFsDirP, pathP, strerror(rc));
482    goto exit;
483  }
484
485  /* Loop reading the directory entries */
486  while (1)
487  {
488    rc = gpfs_ireaddir(dirxP, &direntxP);
489    if (rc != 0)
490    {
491      int saveerrno = errno;
492      fprintf(stderr, "gpfs_ireaddir(%s/%s): rc %d %s\n",
493              RootFsDirP, pathP, rc, strerror(saveerrno));
494      rc = saveerrno;
495      goto exit;
496    }
497    if (direntxP == NULL)
498      break;
499
500    /* Get directory entry type */
501    switch (direntxP->d_type)
502    {
503      case GPFS_DE_DIR:
504        /* Skip . and .. entries */
505        if ((strcmp(direntxP->d_name, ".") == 0) ||
506            (strcmp(direntxP->d_name, "..") == 0))
507          continue;
508
509        typeP = "DIR";
510        break;
511
512      case GPFS_DE_REG:
513        typeP = "REG";
514        break;
515
516      case GPFS_DE_LNK:
517        typeP = "LNK";
518        break;
519
520      default:
521        typeP = "UNK";
522    }
523
524    ind = testinode(direntxP->d_ino);
525    if (ind >= 0)
526    {
527      int plen;
528
529      /* Print file info on stdout.
530         Serialize output with all other threads */
531      rc = pthread_mutex_lock(&OutputMutex);
532      if (rc != 0)
533      {
534        fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
535        goto exit;
536      }
537      /* Print: inodenumber pathname */
538      plen = printf("%10d\t%s%s%s%s",
539                    direntxP->d_ino, pathP, slashP, direntxP->d_name, print0);
540      InodeSeen[ind] = 1;
541      rc = pthread_mutex_unlock(&OutputMutex);
542      if (rc != 0)
543      {
544        fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
545        goto exit;
546      }
547      if (plen < 0)
548      {
549        rc = errno;
550        goto exit;
551      }
552    }
553
554    /* Check if this entry is a directory */
555    if (direntxP->d_type == GPFS_DE_DIR)
556    {
557      /* Add this directory to the work queue */
558      rc = EnqueueWork(pathP, direntxP->d_name, direntxP->d_ino);
559      if (rc != 0)
560      {
561        if (exitrc == 0)
562          exitrc = rc;
563        goto exit;
564      }
565    }
566  }
567
568
569exit:
570  /* Close open file, if necessary */
571  if (dirxP)
572    gpfs_iclose(dirxP);
573  if (fsP)
574    gpfs_free_fssnaphandle(fsP);
575
576  return rc;
577}
578
579/* main */
580int main(int argc, char *argv[])
581{
582  int i, rc, filearg, ind;
583  struct stat statBuf;
584  pthread_t pThread;
585
586  /* Scan for options and single directory name */
587  filearg = 0;
588  for (i = 1; i < argc; i++)
589  {
590    if (0 == strcmp(argv[i], "-i"))
591    {
592      i += 1;
593      if (i < argc)
594        getinodes(argv[i]);
595      else
596        usage(argv[0]);
597    }
598    else if (0 == strcmp(argv[i], "-t"))
599    {
600      i += 1;
601      if (i < argc)
602        nThreads = atoi(argv[i]);
603      else
604        usage(argv[0]);
605    }
606    else if (0 == strcmp(argv[i], "-0"))
607      print0 = "\0";
608    else if (0 == strcmp(argv[i], "--"))
609      optcheck = 0;
610    else if (optcheck && *argv[i] == '-')
611      usage(argv[0]);
612    else if (filearg == 0)
613      filearg = i;
614    else
615      usage(argv[0]);
616  }
617
618  /* if no directory was specified, there is nothing to do */
619  if (filearg == 0 || numInodes == 0)
620    usage(argv[0]);
621  RootFsDirP = argv[filearg];
622
623  /* Initialize pthread variables */
624  rc = pthread_mutex_init(&QueueMutex, NULL);
625  if (rc != 0)
626  {
627    fprintf(stderr, "Error from pthread_mutex_init: %s\n", strerror(rc));
628    exit(rc);
629  }
630  rc = pthread_cond_init(&QueueCond, NULL);
631  if (rc != 0)
632  {
633    fprintf(stderr, "Error from pthread_cond_init: %s\n", strerror(rc));
634    exit(rc);
635  }
636  rc = pthread_mutex_init(&OutputMutex, NULL);
637  if (rc != 0)
638  {
639    fprintf(stderr, "Error from pthread_mutex_init: %s\n", strerror(rc));
640    exit(rc);
641  }
642
643  /* Get the inode number of the root directory */
644  rc = stat(RootFsDirP, &statBuf);
645  if (rc)
646  {
647    rc = errno;
648    perror(RootFsDirP);
649    return rc;
650  }
651
652  /* Verify this is a directory */
653  if (!S_ISDIR(statBuf.st_mode))
654  {
655    errno = ENOTDIR;
656    perror(RootFsDirP);
657    return ENOTDIR;
658  }
659
660  InodeSeen = (unsigned char *) malloc(maxInodes);
661  if (InodeSeen == NULL)
662  {
663    fprintf(stderr, "Out of memory.\n");
664    return ENOMEM;
665  }
666  memset(InodeSeen, 0, maxInodes);
667
668  ind = testinode(statBuf.st_ino);
669  if (ind >= 0)
670  {
671    /* Print file info on stdout */
672    rc = printf("%10d\t%s%s", statBuf.st_ino, RootFsDirP, print0);
673    if (rc < 0)
674      return errno;
675    InodeSeen[ind] = 1;
676  }
677
678  /* Add the root directory to the work queue */
679  rc = EnqueueWork(RootFsDirP, "", statBuf.st_ino);
680  if (rc != 0)
681    return rc;
682
683  /* Start the requested number of threads */
684  for (i = 1; i < nThreads; i++)
685  {
686    rc = pthread_create(&pThread, NULL, ThreadBody, NULL);
687    if (rc != 0)
688    {
689      fprintf(stderr, "Error from pthread_create(%d): %s\n", i, strerror(rc));
690      exit(rc);
691    }
692  }
693
694  /* This thread can work too */
695  (void) ThreadBody(NULL);
696
697  for (ind=0; ind < numInodes; ind++)
698    if (!InodeSeen[ind])
699      fprintf(stderr, "%10d\t(notfound)\n", Inode[ind]);
700
701  return exitrc;
702}
703
704
Note: See TracBrowser for help on using the repository browser.