source: gpfs_3.1_ker2.6.20/lpp/mmfs/samples/util/tsreaddir.c @ 90

Last change on this file since 90 was 16, checked in by rock, 17 years ago
File size: 12.6 KB
RevLine 
[16]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. 2002,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 * tsreaddir command: Recursively traverse the directory structure
19 *                    to list all files/directories in the file system.
20 *
21 * Syntax: tsreaddir [-d] [-n] [-t nThreads] [--] <pathname>
22 *
23 *   The "pathname" parameter should be the directory where the root of
24 *   the file system is found.
25 *
26 *==================================================================*/
27
28#ifdef GPFS_LINUX
29/* Use 64 bit version of stat, etc. */
30#define _LARGEFILE_SOURCE
31#define _FILE_OFFSET_BITS 64
32
33typedef long long offset_t;
34#endif
35
36#ifdef GPFS_AIX
37/* Use 64 bit version of stat, etc. */
38#ifndef _LARGE_FILES
39#define _LARGE_FILES
40#endif
41#endif
42
43#include <stdlib.h>
44#include <stdio.h>
45#include <fcntl.h>
46#include <errno.h>
47#include <string.h>
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <unistd.h>
51#include <pthread.h>
52
53#include <gpfs.h>
54
55extern char *basename(char *);
56
57int noDIR = 0;
58int onlyDIR = 0;
59int optcheck = 1;
60char *RootFsDirP;
61
62/* Define the number of threads used to read the directories */
63#define DEFAULT_THREADS 16
64int nThreads = DEFAULT_THREADS;
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/* error code set while in threads to control final error code */
85int exitrc = 0;
86
87
88
89/* print usage message and exit */
90void usage(char *argv0)
91{
92  fprintf(stderr, "Usage: %s [-d] [-n] [-t nThreads (def=%d)] [--] pathname\n",
93          basename(argv0), DEFAULT_THREADS);
94  exit(1);
95}
96
97/* Add an element to the work queue
98   and signal any thread waiting for work. */
99int EnqueueWork(const char *pathP, const char *dirP, ino_t inode)
100{
101  int rc;
102  int pathLen = strlen(pathP);
103  QueueElement *qP = NULL;
104
105  /* Allocate a work queue element and space for the path.  */
106  qP = (QueueElement *) malloc((sizeof(*qP) - sizeof(qP->path))
107                                + pathLen + strlen(dirP) + 2);
108  if (qP == NULL)
109  {
110    fprintf(stderr, "Out of memory.\n");
111    return(ENOMEM);
112  }
113
114  /* Initialize element */
115  qP->ino = inode;
116  if (pathLen > 0)
117  {
118    strcpy(qP->path, pathP);
119    strcat(qP->path, "/");
120    strcat(qP->path, dirP);
121  }
122  else
123    strcpy(qP->path, dirP);
124
125  /* Acquire mutex protecting the work queue */
126  rc = pthread_mutex_lock(&QueueMutex);
127  if (rc != 0)
128  {
129    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
130    return rc;
131  }
132
133  /* Add work element to the list */
134  qP->nextP = WorkQueueP;
135  WorkQueueP = qP;
136
137  /* Signal a waiting worker thread */
138  if (NWorkersWaiting > 0)
139  {
140    NWorkersWaiting -= 1;
141    rc = pthread_cond_signal(&QueueCond);
142    if (rc != 0)
143    {
144      fprintf(stderr, "Error in pthread_cond_signal: %s\n", strerror(rc));
145      return rc;
146    }
147  }
148
149  /* Release mutex before returning */
150  rc = pthread_mutex_unlock(&QueueMutex);
151  if (rc != 0)
152  {
153    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
154    return rc;
155  }
156
157  /* Success! */
158  return 0;
159}
160
161
162/* Dequeue the next work element from the queue
163   or if the queue is empty, wait for more work to become available */
164QueueElement *DequeueWork(void)
165{
166  int rc;
167  QueueElement *qP;
168
169  /* Acquire mutex protecting the work queue */
170  rc = pthread_mutex_lock(&QueueMutex);
171  if (rc != 0)
172  {
173    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
174    if (exitrc == 0)
175      exitrc = rc;
176    return NULL;
177  }
178
179  /* One less thread working */
180  NWorkersRunning -= 1;
181
182  /* Loop waiting for work to become available */
183  while ((WorkQueueP == NULL) && (NWorkersRunning > 0))
184  {
185    NWorkersWaiting += 1;       /* One more thread waiting */
186    rc = pthread_cond_wait(&QueueCond, &QueueMutex);
187    if (rc != 0)
188    {
189      fprintf(stderr, "Error in pthread_cond_wait: %s\n", strerror(rc));
190      if (exitrc == 0)
191        exitrc = rc;
192      return NULL;
193    }
194  }
195
196  /* Check if we are done */
197  if (WorkQueueP == NULL)
198  {
199    qP = NULL;                  /* Nothing more to do. */
200
201    /* signal any waiting threads */
202    if (NWorkersWaiting > 0)
203    {
204      NWorkersWaiting = 0;
205      rc = pthread_cond_broadcast(&QueueCond);
206      if (rc != 0)
207      {
208        fprintf(stderr, "Error in pthread_cond_broadcast: %s\n", strerror(rc));
209        if (exitrc == 0)
210          exitrc = rc;
211      }
212    }
213  }
214  else
215  {
216    /* Remove the first element from the queue */
217    qP = WorkQueueP;
218    WorkQueueP = qP->nextP;
219    qP->nextP = NULL;
220
221    /* One more thread working */
222    NWorkersRunning += 1;
223  }
224
225  /* Release mutex before returning */
226  rc = pthread_mutex_unlock(&QueueMutex);
227  if (rc != 0)
228  {
229    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
230    if (exitrc == 0)
231      exitrc = rc;
232    return NULL;
233  }
234
235  return qP;
236}
237
238/* Main body for each thread.
239   Loop until there is no more work to do. */
240void* ThreadBody(void *parmP)
241{
242  int rc;
243  QueueElement *qP;
244  int read_dir(const char *, ino_t);
245
246  /* Count this thread as a worker thread */
247  rc = pthread_mutex_lock(&QueueMutex);
248  if (rc != 0)
249  {
250    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
251    if (exitrc == 0)
252      exitrc = rc;
253    return NULL;
254  }
255  NWorkersRunning += 1;
256  rc = pthread_mutex_unlock(&QueueMutex);
257  if (rc != 0)
258  {
259    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
260    NWorkersRunning -= 1;
261    if (exitrc == 0)
262      exitrc = rc;
263    return NULL;
264  }
265
266  /* Loop while there is work to do */
267  do
268  {
269    /* Wait for work */
270    qP = DequeueWork();
271    if (qP == NULL)
272      break;
273
274    /* Read this directory */
275    rc = read_dir(qP->path, qP->ino);
276    if (exitrc == 0)
277      exitrc = rc;
278
279    /* Free work queue element */
280    free(qP);
281
282  } while (rc == 0);
283
284  rc = pthread_mutex_lock(&QueueMutex);
285  if (rc != 0)
286  {
287    fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
288    if (exitrc == 0)
289      exitrc = rc;
290    return NULL;
291  }
292  NWorkersRunning -= 1;
293  rc = pthread_mutex_unlock(&QueueMutex);
294  if (rc != 0)
295  {
296    fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
297    if (exitrc == 0)
298      exitrc = rc;
299  }
300
301  return NULL;
302}
303
304/* Read all entries from the current directory */
305int read_dir(const char *pathP, ino_t inode)
306{
307  int rc = 0;
308  const gpfs_direntx_t *direntxP;
309  gpfs_fssnap_handle_t *fsP = NULL;
310  gpfs_ifile_t *dirxP = NULL;
311  char *typeP, *slashP;
312  int doprint;
313
314  /* Check if we need a "/"  */
315  if (strlen(pathP) > 0)
316    slashP = "/";
317  else
318    slashP = "";
319
320  /* Open the file system */
321  fsP = gpfs_get_fssnaphandle_by_path(RootFsDirP);
322  if (fsP == NULL)
323  {
324    rc = errno;
325    fprintf(stderr, "gpfs_get_fssnaphandle_by_path(%s): %s\n",
326            RootFsDirP, strerror(rc));
327    goto exit;
328  }
329
330  /* Open the directory's file */
331  dirxP = gpfs_iopen(fsP, inode, O_RDONLY, NULL, NULL);
332  if (dirxP == NULL)
333  {
334    rc = errno;
335    fprintf(stderr, "gpfs_iopen(%s/%s): %s\n", RootFsDirP, pathP, strerror(rc));
336    goto exit;
337  }
338
339  /* Loop reading the directory entries */
340  while (1)
341  {
342    rc = gpfs_ireaddir(dirxP, &direntxP);
343    if (rc != 0)
344    {
345      int saveerrno = errno;
346      fprintf(stderr, "gpfs_ireaddir(%s/%s): rc %d %s\n",
347              RootFsDirP, pathP, rc, strerror(saveerrno));
348      rc = saveerrno;
349      goto exit;
350    }
351    if (direntxP == NULL)
352      break;
353
354    /* Get directory entry type */
355    switch (direntxP->d_type)
356    {
357      case GPFS_DE_DIR:
358        /* Skip . and .. entries */
359        if ((strcmp(direntxP->d_name, ".") == 0) ||
360            (strcmp(direntxP->d_name, "..") == 0))
361          continue;
362
363        typeP = "DIR";
364        doprint = !noDIR;
365        break;
366
367      case GPFS_DE_REG:
368        typeP = "REG";
369        doprint = !onlyDIR;
370        break;
371
372      case GPFS_DE_LNK:
373        typeP = "LNK";
374        doprint = !onlyDIR;
375        break;
376
377      default:
378        typeP = "UNK";
379        doprint = !onlyDIR;
380    }
381
382    if (doprint)
383    {
384      int plen;
385
386      /* Print file info on stdout.
387         Serialize output with all other threads */
388      rc = pthread_mutex_lock(&OutputMutex);
389      if (rc != 0)
390      {
391        fprintf(stderr, "Error in pthread_mutex_lock: %s\n", strerror(rc));
392        goto exit;
393      }
394      /* Print: inodenumber/generation type pathname
395         (leading 0s on inodenumber/generation allow join command
396          to do character sort to merge output with tstimes.) */
397      plen = printf("%010d/%010d\t%s\t%s%s%s\n",
398                    direntxP->d_ino, direntxP->d_gen, typeP,
399                    pathP, slashP, direntxP->d_name);
400      rc = pthread_mutex_unlock(&OutputMutex);
401      if (rc != 0)
402      {
403        fprintf(stderr, "Error in pthread_mutex_unlock: %s\n", strerror(rc));
404        goto exit;
405      }
406      if (plen < 0)
407      {
408        rc = errno;
409        goto exit;
410      }
411    }
412
413    /* Check if this entry is a directory */
414    if (direntxP->d_type == GPFS_DE_DIR)
415    {
416      /* Add this directory to the work queue */
417      rc = EnqueueWork(pathP, direntxP->d_name, direntxP->d_ino);
418      if (rc != 0)
419      {
420        if (exitrc == 0)
421          exitrc = rc;
422        goto exit;
423      }
424    }
425  }
426
427
428exit:
429  /* Close open file, if necessary */
430  if (dirxP)
431    gpfs_iclose(dirxP);
432  if (fsP)
433    gpfs_free_fssnaphandle(fsP);
434
435  return rc;
436}
437
438/* main */
439int main(int argc, char *argv[])
440{
441  int i, rc, filearg;
442  struct stat statBuf;
443  pthread_t pThread;
444
445  /* Scan for options and single directory name */
446  filearg = 0;
447  for (i = 1; i < argc; i++)
448  {
449    if (0 == strcmp(argv[i], "-n"))
450      noDIR = 1;
451    else if (0 == strcmp(argv[i], "-d"))
452      onlyDIR = 1;
453    else if (0 == strcmp(argv[i], "-t"))
454    {
455      i += 1;
456      if (i < argc)
457        nThreads = atoi(argv[i]);
458      else
459        usage(argv[0]);
460    }
461    else if (0 == strcmp(argv[i], "--"))
462      optcheck = 0;
463    else if (optcheck && *argv[i] == '-')
464      usage(argv[0]);
465    else if (filearg == 0)
466      filearg = i;
467    else
468      usage(argv[0]);
469  }
470
471  /* if no directory was specified, there is nothing to do */
472  if (filearg == 0)
473    usage(argv[0]);
474  RootFsDirP = argv[filearg];
475
476  /* Initialize pthread variables */
477  rc = pthread_mutex_init(&QueueMutex, NULL);
478  if (rc != 0)
479  {
480    fprintf(stderr, "Error from pthread_mutex_init: %s\n", strerror(rc));
481    exit(rc);
482  }
483  rc = pthread_cond_init(&QueueCond, NULL);
484  if (rc != 0)
485  {
486    fprintf(stderr, "Error from pthread_cond_init: %s\n", strerror(rc));
487    exit(rc);
488  }
489  rc = pthread_mutex_init(&OutputMutex, NULL);
490  if (rc != 0)
491  {
492    fprintf(stderr, "Error from pthread_mutex_init: %s\n", strerror(rc));
493    exit(rc);
494  }
495
496  /* Get the inode number of the root directory */
497  rc = stat(RootFsDirP, &statBuf);
498  if (rc)
499  {
500    rc = errno;
501    perror(RootFsDirP);
502    return rc;
503  }
504
505  /* Verify this is a directory */
506  if (!S_ISDIR(statBuf.st_mode))
507  {
508    errno = ENOTDIR;
509    perror(RootFsDirP);
510    return ENOTDIR;
511  }
512
513  if (!noDIR)
514  {
515    /* Print file info on stdout */
516    rc = printf("%010d/%010d\tDIR\t%s\n", statBuf.st_ino, 1, RootFsDirP);
517    if (rc < 0)
518      return errno;
519  }
520
521  /* Add the root directory to the work queue */
522  rc = EnqueueWork("", "", statBuf.st_ino);
523  if (rc != 0)
524    return rc;
525
526  /* Start the requested number of threads */
527  for (i = 1; i < nThreads; i++)
528  {
529    rc = pthread_create(&pThread, NULL, ThreadBody, NULL);
530    if (rc != 0)
531    {
532      fprintf(stderr, "Error from pthread_create(%d): %s\n", i, strerror(rc));
533      exit(rc);
534    }
535  }
536
537  /* This thread can work too */
538  (void) ThreadBody(NULL);
539
540  return exitrc;
541}
542
543
Note: See TracBrowser for help on using the repository browser.