root/branches/orange-next/src/common/misc/fsck-utils.c @ 8960

Revision 8960, 51.0 KB (checked in by mtmoore, 23 months ago)

client/server builds, much to fix

  • Property svn:executable set to *
Line 
1/*
2 * Copyright © Acxiom Corporation, 2005
3 *
4 * See COPYING in top-level directory.
5 */
6#include <stdio.h>
7#include <string.h>
8#include <time.h>
9#include <unistd.h>
10#include <ctype.h>
11#include <assert.h>
12
13#include "fsck-utils.h"
14
15#define HANDLE_BATCH 1000
16#define MAX_DIR_ENTS 64
17
18#define SERVER_CONFIG_BUFFER_SIZE 5000
19#define FS_CONFIG_BUFFER_SIZE 10000
20
21/** \file
22 *  \ingroup fsckutils
23 * Implementation of the fsck-utils component.
24 *
25 * TODO's:
26 * - What action should be taken to recover broken on missing PVFS2 objects? Can
27 *   we recover pieces and zero out unknown? Can we create missing metadata
28 *   for data files that are orphaned? Do we automatically move to lost+found
29 *   directory, and/or allow option to simply remove and delete?
30 * - What needs to be done for extended attributes
31 * - What needs to be done for access control lists (extended attributes &
32 *   accounts)
33 * .
34 *
35 * Terminology:
36 * - Orphaned bstreams: bstreams with no dfiles/attributes
37 * - Stranded Object: An object exists with no way to get to it
38 *      - Datafile missing metadata
39 *      - Metadata missing directory entry
40 *      - Dirdata missing directory object
41 * - Dangling directory entry: directory entry exists, but object/attributes don't
42 * .
43 */
44
45static void set_return_code(
46    int *ret,               
47    const int retval);
48   
49static int compare_handles(
50    const void *handle1,
51    const void *handle2);
52
53/** The following declarations deal with the option to check for stranded objects */
54struct PINT_handle_wrangler_handlelist
55{
56    int num_servers;
57    PVFS_handle **list_array;
58    char **list_array_seen;
59    int *size_array;
60    int *used_array;
61    int *stranded_array;
62    PVFS_BMI_addr_t *addr_array;
63} PINT_handle_wrangler_handlelist;
64
65#if 0
66/* not used yet */
67static int PINT_handle_wrangler_get_stranded_handles(
68    const PVFS_fs_id * cur_fs,
69    int *num_stranded_handles,
70    PVFS_handle ** stranded_handles);
71#endif
72
73static int PINT_handle_wrangler_display_stranded_handles(
74    const struct PINT_fsck_options *fsck_options,
75    const PVFS_fs_id * cur_fs,                   
76    const PVFS_credentials * creds);
77
78static int PINT_handle_wrangler_load_handles(
79    const struct PINT_fsck_options *fsck_options,
80    const PVFS_fs_id * cur_fs,                   
81    const PVFS_credentials * creds);
82
83static int PINT_handle_wrangler_remove_handle(
84    const PVFS_handle * handle,
85    const PVFS_fs_id * cur_fs);
86
87/**
88 * Initializes API and checks options for correctness
89 *
90 * \retval 0 on success
91 * \retval -PVFS_error on failure
92 */
93int PVFS_fsck_initialize(
94    const struct PINT_fsck_options *fsck_options,   /**< Populated options */
95    const PVFS_credentials * creds,                 /**< Populated creditials structure */
96    const PVFS_fs_id * cur_fs)                      /**< filesystem id */
97{
98    int ret = 0;
99
100    if(fsck_options->fix_errors)
101    {
102        return(-PVFS_ENOSYS);
103    }
104
105    /* If check stranded objects... Setup handle stuff */
106    if (fsck_options->check_stranded_objects)
107    {
108        /* get all handles from all servers */
109        ret = PINT_handle_wrangler_load_handles(fsck_options, cur_fs, creds);
110    }
111
112    return ret;
113}
114
115/**
116 * Verifies the same fs config is present on each pvfs2 server.
117 * Ignores extraneous whitespace and comments begining with #.  Does not stop
118 * on the first problem- will show any config differences, using the first
119 * server as the golden standard.
120 *
121 * \retval 0 on success
122 * \retval -PVFS_error on failure
123 */
124int PVFS_fsck_check_server_configs(
125    const struct PINT_fsck_options *fsck_options,   /**< Populated options */
126    const PVFS_credentials * creds,                 /**< pvfs2 credentials structure */
127    const PVFS_fs_id * cur_fs)                      /**< the current fs */
128{
129    int ret = 0;
130    int num_servers = 0;
131    int i = 0;
132    PVFS_BMI_addr_t *addresses = NULL;
133    char *fs_config = NULL;
134    char *fs_config_diff = NULL;
135    char *reference_config_server = NULL;
136    const char *server_name = NULL;
137    FILE *pin = NULL;
138    char line[130] = { 0 };
139    char *cmd = NULL;
140    /* temp file name and file descriptor to store our reference config */
141    char reference_fs_config_tmp_file[] = "/tmp/pvfs2-fsck.XXXXXX";
142    int fout = 0;
143    int final_ret = 0;
144
145    /* count how many servers we have */
146    ret = PVFS_mgmt_count_servers(*cur_fs,
147                                (PVFS_credentials *) creds,
148                                &num_servers);
149    if(ret < 0)
150    {
151        PVFS_perror_gossip("PVFS_mgmt_count_servers", ret);
152        return ret;
153    }
154
155    addresses =
156        (PVFS_BMI_addr_t *) calloc(num_servers, sizeof(PVFS_BMI_addr_t));
157    if (addresses == NULL)
158    {
159        return -PVFS_ENOMEM;
160    }
161
162    /* get a list of the pvfs2 servers */
163    ret = PVFS_mgmt_get_server_array(
164        *cur_fs,
165        (PVFS_credentials *) creds,
166        addresses, &num_servers);
167    if(ret < 0)
168    {
169        free(addresses);
170        PVFS_perror_gossip("PVFS_mgmt_get_server_array", ret);
171        return ret;
172    }
173
174    for (i = 0; i < num_servers; i++)
175    {
176        server_name = NULL;
177
178        /* get the pretty server name */
179        server_name = PINT_cached_config_map_addr( *cur_fs, addresses[i]);
180        assert(server_name);
181
182        fs_config = calloc(FS_CONFIG_BUFFER_SIZE, sizeof(char));
183        if (fs_config == NULL)
184        {
185            free(addresses);
186            return -PVFS_ENOMEM;
187        }
188       
189        ret = PVFS_mgmt_get_config(cur_fs,
190                                 &addresses[i],
191                                 fs_config,
192                                 FS_CONFIG_BUFFER_SIZE);
193        if (ret < 0)
194        {
195            PVFS_perror_gossip("PVFS_mgmt_get_config", ret);
196            gossip_err("Error: failed to retrieve configuration on server %d of %d.\n",
197                i, num_servers);
198            free(addresses);
199            free(fs_config);
200            return(ret);
201        }
202
203        if (i == 0)
204        {
205            /* store the "reference" server name for nice output later */
206            reference_config_server = calloc(1, strlen(server_name) + 1);
207            if (reference_config_server == NULL)
208            {
209                free(addresses);
210                free(fs_config);
211                return -PVFS_ENOMEM;
212            }
213            strcpy(reference_config_server, server_name);
214
215            /* store the first server config as the reference */
216            fout = mkstemp(reference_fs_config_tmp_file);
217            if (fout < 0)
218            {
219                ret = -errno;
220                gossip_err("Error opening temp file [%s]\n",
221                        reference_fs_config_tmp_file);
222                free(addresses);
223                free(fs_config);
224                free(reference_config_server);
225                return ret;
226            }
227
228            ret = write(fout, fs_config, strlen(fs_config));
229            if (ret < 0)
230            {
231                ret = -errno;
232                gossip_err("Error: could not write reference configuration.\n");
233                free(addresses);
234                free(fs_config);
235                free(reference_config_server);
236                return(ret);
237            }
238
239            close(fout);
240        }
241        else
242        {
243            /* allocate enough space to hold our diff command */
244            cmd = calloc(1,
245                    strlen(fs_config) + strlen(reference_config_server) +
246                    strlen(server_name) + 1000);
247            if (cmd == NULL)
248            {
249                free(addresses);
250                free(fs_config);
251                free(reference_config_server);
252                return -PVFS_ENOMEM;
253            }
254
255            /* build the diff command */
256            sprintf(cmd,
257                    "echo \"%s\"| diff -EbBu -I '^#.*' -L %s -L %s %s -",
258                    fs_config,
259                    reference_config_server,
260                    server_name, reference_fs_config_tmp_file);
261
262            pin = popen(cmd, "r");
263            if (pin == NULL)
264            {
265                ret = -errno;
266                gossip_err("Error: failed popen() for command: %s\n", cmd);
267                free(addresses);
268                free(fs_config);
269                free(reference_config_server);
270                free(cmd);
271                return ret;
272            }
273
274            fs_config_diff = calloc(1, strlen(fs_config) + 100);
275            if (fs_config_diff == NULL)
276            {
277                free(addresses);
278                free(fs_config);
279                free(reference_config_server);
280                free(cmd);
281                return -PVFS_ENOMEM;
282            }
283
284            /* get the output from diff */
285            while (fgets(line, sizeof line, pin))
286            {
287                strcat(fs_config_diff, line);
288            }
289           
290            ret = pclose(pin);
291            if(ret != 0)
292            {
293                gossip_err("Error: failed popen() for command: %s\n", cmd);
294                free(addresses);
295                free(fs_config);
296                free(reference_config_server);
297                free(cmd);
298                free(fs_config_diff);
299                return(-PVFS_EINVAL);
300            }
301
302            /* if diff shows any problems, display it but keep going (we want
303             * to see all config file problems if there is more than one)
304             */
305            if (strlen(fs_config_diff) > 0)
306            {
307                gossip_err("Error: File system config on [%s] doesn't\n",
308                       server_name);
309                gossip_err("   match reference config from [%s]:\n\n%s\n",
310                       reference_config_server, fs_config_diff);
311
312                final_ret = -PVFS_EINVAL;
313            }
314
315            free(fs_config_diff);
316            free(cmd);
317        }
318
319        free(fs_config);
320    }
321
322    unlink(reference_fs_config_tmp_file);
323    free(reference_config_server);
324    free(addresses);
325
326    return final_ret;
327}
328
329/**
330 * Performs sanity checking on the PVFS_TYPE_DATAFILE PVFS_Object type
331 * Checks the following:
332 * - Existence of attributes
333 * .
334 *
335 * \retval 0 on success
336 * \retval -PVFS_error on failure
337 */
338int PVFS_fsck_validate_dfile(
339    const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
340    const PVFS_handle * handle,                   /**< The dfile handle */
341    const PVFS_fs_id * cur_fs,        /**< The fsid the handle belongs to */
342    const PVFS_credentials * creds,   /**< Populated creditials structure */
343    PVFS_size * dfiles_total_size)    /**< Total size of all dfiles */
344{
345    int ret = 0;
346    PVFS_object_ref obj_ref;
347    PVFS_sysresp_getattr dfile_attributes;
348    int err = 0;
349   
350    memset(&dfile_attributes, 0, sizeof(dfile_attributes));
351
352    if (fsck_options->check_stranded_objects)
353    {
354        if (PINT_handle_wrangler_remove_handle(handle, cur_fs))
355        {
356            gossip_err("WARNING: unable to remove handle [%llu] from handle list while verifying stranded objects\n",
357                    llu(*handle));
358        }
359    }
360
361    /* Build the needed PVFS_Object reference needed for API calls */
362    PVFS_handle_copy(obj_ref.handle, *handle);
363    obj_ref.fs_id = *cur_fs;
364
365    /* Check for existence of attributes */
366    err = PVFS_fsck_get_attributes(fsck_options, &obj_ref, creds,
367        &dfile_attributes);
368    if(err < 0)
369    {
370        gossip_err("Error: unable to get dfile attributes\n");
371        return(err);
372    }
373    set_return_code(&ret, err);
374
375    /* total up the dfile sizes. */
376    *dfiles_total_size += dfile_attributes.attr.size;
377
378    /* Do attributes contain valid data */
379    err = PVFS_fsck_validate_dfile_attr(fsck_options, &dfile_attributes);
380    if(err < 0)
381    {
382        gossip_err("Error: dfile has invalid attributes\n");
383        return(err);
384    }
385    set_return_code(&ret, err);
386
387    return ret;
388}
389
390/**
391 * Performs validity checking for the attributes for PVFS_TYPE_DATAFILE
392 * Checks the following:
393 * - Object Type must be PVFS_TYPE_DFILE
394 * - size >=  0
395 * .
396 * \retval 0 on success
397 * \retval -PVFS_error on failure
398 */
399int PVFS_fsck_validate_dfile_attr(
400    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
401    const PVFS_sysresp_getattr * getattr_resp)      /**< DFILE attributes */
402{
403    int ret = 0;
404
405    if (getattr_resp->attr.objtype != PVFS_TYPE_DATAFILE)
406    {
407        gossip_err(
408                "dfile object type [%d] does not match expected type PVFS_TYPE_DATAFILE %d\n",
409                getattr_resp->attr.objtype, PVFS_TYPE_DATAFILE);
410
411        set_return_code(&ret, -PVFS_EINVAL);
412    }
413
414    if (getattr_resp->attr.size < 0)
415    {
416        /* invalid size attribute */
417        gossip_err("Error: dfile size [%lld] is invalid.\n",
418                lld(getattr_resp->attr.size));
419
420        set_return_code(&ret, -PVFS_EINVAL);
421    }
422
423    return ret;
424}
425
426/**
427 * Performs sanity checking on the PVFS_TYPE_METAFILE PVFS_Object type
428 *
429 * \retval 0 on success
430 * \retval -PVFS_error on failure
431 */
432int PVFS_fsck_validate_metafile(
433    const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
434    const PVFS_object_ref * obj_ref,              /**< PVFS_Object reference */
435    const PVFS_sysresp_getattr * attributes,      /**< METAFILE attributes */
436    const PVFS_credentials * creds)               /**< Populated creditials structure */
437{
438    int ret = 0;
439    int i = 0;
440    PVFS_handle *df_handles;
441    PVFS_size dfiles_total_size = 0;
442    int err = 0;
443
444    if (fsck_options->check_stranded_objects)
445    {
446        if (PINT_handle_wrangler_remove_handle
447            (&obj_ref->handle, &obj_ref->fs_id))
448        {
449            gossip_err("WARNING: unable to remove handle [%llu] from \
450                handle list while verifying stranded objects\n", llu(obj_ref->handle));
451        }
452    }
453
454    /* Check for validity of attributes */
455    err = PVFS_fsck_validate_metafile_attr(fsck_options, attributes);
456    if(err < 0)
457    {
458        gossip_err("Error: metafile has invalid attributes\n");
459        return(err);
460    }
461    set_return_code(&ret, err);
462
463    df_handles = (PVFS_handle *) calloc(attributes->attr.dfile_count,
464                                        sizeof(PVFS_handle));
465    if (df_handles == NULL)
466    {
467        return -PVFS_ENOMEM;
468    }
469
470    err = PVFS_mgmt_get_dfile_array(*obj_ref,
471                                  (PVFS_credentials *) creds,
472                                  df_handles, attributes->attr.dfile_count, NULL);
473    if(err < 0)
474    {
475        PVFS_perror("PVFS_mgmt_get_dfile_array", err);
476        free(df_handles);
477        return(err);
478    }
479
480    /* verify dfiles */
481    for (i = 0; i < attributes->attr.dfile_count; i++)
482    {
483        err = PVFS_fsck_validate_dfile(fsck_options,
484                                     (const PVFS_handle *)&df_handles[i],
485                                     &obj_ref->fs_id,
486                                     creds, &dfiles_total_size);
487        if(err < 0)
488        {
489            gossip_err("Error: metafile dfile [%d] is invalid\n", i);
490            free(df_handles);
491            return(err);
492        }
493        set_return_code(&ret, err);
494    }
495
496    if (dfiles_total_size > attributes->attr.size)
497    {
498        gossip_err(
499                "Error: sum size of dfiles [%lld] is greater than expected size of [%lld]\n",
500                lld(dfiles_total_size), lld(attributes->attr.size));
501
502        free(df_handles);
503        return(-PVFS_EINVAL);
504    }
505
506    free(df_handles);
507    return ret;
508}
509
510/**
511 * Performs validity checking for the attributes for PVFS_TYPE_METAFILE
512 * Checks the following:
513 * - Object type must be PVFS_TYPE_METAFILE
514 * - Existence of dfiles
515 * - Existence of distribution
516 * - size >= 0
517 * .
518 * \retval 0 on success
519 * \retval -PVFS_error on failure
520 */
521int PVFS_fsck_validate_metafile_attr(
522    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
523    const PVFS_sysresp_getattr * attributes)        /**< METAFILE attributes */
524{
525    int ret = 0;
526
527    /* check attributes */
528    if (attributes->attr.objtype != PVFS_TYPE_METAFILE)
529    {
530        gossip_err(
531                "Error: metafile type [%d] does not match expected type PVFS_TYPE_METAFILE %d\n",
532                attributes->attr.objtype, PVFS_TYPE_METAFILE);
533
534        set_return_code(&ret, -PVFS_EINVAL);
535    }
536
537    /* verify we have dfiles */
538    if (attributes->attr.dfile_count <= 0)
539    {
540        gossip_err("Error: metafile has an invalid number of dfiles [%d]\n",
541                attributes->attr.dfile_count);
542
543        set_return_code(&ret, -PVFS_EINVAL);
544    }
545
546    /* TODO: check to make sure that dfile array and dist is present. */
547
548    return ret;
549}
550
551/**
552 * Performs sanity checking on the PVFS_TYPE_SYMLINK PVFS_Object type
553 *
554 * \retval 0 on success
555 * \retval -PVFS_error on failure
556 */
557int PVFS_fsck_validate_symlink(
558    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
559    const PVFS_object_ref * obj_ref,                /**< PVFS_Object reference */
560    const PVFS_sysresp_getattr * attributes)        /**< SYMLINK attributes */
561{
562    int ret = 0;
563
564    if (fsck_options->check_stranded_objects)
565    {
566        if (PINT_handle_wrangler_remove_handle
567            (&obj_ref->handle, &obj_ref->fs_id))
568        {
569            gossip_err("WARNING: unable to remove handle [%llu] from handle \
570                    list while verifying stranded objects\n", llu(obj_ref->handle));
571        }
572    }
573
574    ret = PVFS_fsck_validate_symlink_attr(fsck_options, attributes);
575
576    return ret;
577}
578
579/**
580 * Performs validity checking for the attributes for PVFS_TYPE_SYMLINK
581 * Checks the following:
582 * - Object type must be PVFS_TYPE_SYMLINK
583 * - Target must be non-null
584 * .
585 * \retval 0 on success
586 * \retval -PVFS_error on failure
587 */
588int PVFS_fsck_validate_symlink_attr(
589    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
590    const PVFS_sysresp_getattr * attributes)        /**< SYMLINK attributes */
591{
592    int ret = 0;
593    int err = 0;
594
595    /* check attributes */
596    if (attributes->attr.objtype != PVFS_TYPE_SYMLINK)
597    {
598        gossip_err(
599                "Error: symlink type [%d] does not match expected type PVFS_TYPE_SYMLINK [%d]\n",
600                attributes->attr.objtype, PVFS_TYPE_SYMLINK);
601
602        set_return_code(&ret, -PVFS_EINVAL);
603    }
604
605    if (attributes->attr.link_target)
606    {
607        if (fsck_options->check_symlink_target)
608        {
609            /* we do have a target, make sure it's valid */
610            err = PVFS_fsck_validate_symlink_target(fsck_options, attributes);
611            if (err < 0)
612            {
613                gossip_err("Error: symlink target [%s] is invalid\n",
614                        attributes->attr.link_target);
615                return(err);
616            }
617            set_return_code(&ret, err);
618        }
619    }
620    else
621    {
622        gossip_err("Error: symlink missing target attribute\n");
623        set_return_code(&ret, -PVFS_EINVAL);
624    }
625
626    return ret;
627}
628
629/**
630 * Performs "bad practice" warning checks for the target attributes for
631 * PVFS_TYPE_SYMLINK. Checks the following:
632 * - Does target exist
633 * - Does target back out of PVFS2 filesystem
634 * - Does target use absolute path
635 * .
636 * \retval 0 on success
637 * \retval -PVFS_error on failure
638 */
639int PVFS_fsck_validate_symlink_target(
640    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
641    const PVFS_sysresp_getattr * attributes)        /**< SYMLINK attributes */
642{
643    int ret = 0;
644
645    /* TODO: finish other tests */
646
647    if (attributes->attr.link_target[0] == '/')
648    {
649        gossip_err("WARNING: symlink target [%s] uses absolute path\n",
650                attributes->attr.link_target);
651    }
652
653    return ret;
654}
655
656/**
657 * Performs sanity checking on the PVFS_TYPE_DIRDATA PVFS_Object type.
658 * Checks the following:
659 * - Do attributes exist
660 * .
661 * \retval 0 on success
662 * \retval -PVFS_error on failure
663 */
664int PVFS_fsck_validate_dirdata(
665    const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
666    const PVFS_handle * handle,     /**< The dirdata handle */
667    const PVFS_fs_id * cur_fs,      /**< The fsid the handle belongs to */
668    const PVFS_credentials * creds) /**< Populated creditials structure */
669{
670    int ret = 0;
671    int err = 0;
672    PVFS_sysresp_getattr dirdata_attributes;
673    PVFS_object_ref obj_ref;
674
675    memset(&dirdata_attributes, 0, sizeof(dirdata_attributes));
676
677    PVFS_handle_copy(obj_ref.handle, *handle);
678    obj_ref.fs_id = *cur_fs;
679
680    if (fsck_options->check_stranded_objects)
681    {
682        if (PINT_handle_wrangler_remove_handle(handle, cur_fs))
683        {
684            gossip_err("WARNING: unable to remove handle [%llu] from handle \
685                    list while verifying stranded objects\n", llu(*handle));
686        }
687    }
688
689    err = PVFS_fsck_get_attributes
690        (fsck_options, &obj_ref, creds, &dirdata_attributes);
691    if(err < 0)
692    {
693        gossip_err("Error: failed to get attributes for dirdata object\n");
694        return(err);
695    }
696    set_return_code(&ret, err);
697
698    err = PVFS_fsck_validate_dirdata_attr(fsck_options, &dirdata_attributes);
699    if(err < 0)
700    {
701        gossip_err("Error: dirdata entry has invalid attributes\n");
702        return(err);
703    }
704    set_return_code(&ret, err);
705
706    return ret;
707}
708
709/**
710 * Performs validity checking for the attributes for PVFS_TYPE_DIRDATA.
711 * Checks the following:
712 * - Object type must be PVFS_TYPE_DIRDATA
713 * .
714 * \retval 0 on success
715 * \retval -PVFS_error on failure
716 */
717int PVFS_fsck_validate_dirdata_attr(
718    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
719    const PVFS_sysresp_getattr * attributes)        /**< DIRDATA attributes */
720{
721    int ret = 0;
722
723    if (attributes->attr.objtype != PVFS_TYPE_DIRDATA)
724    {
725        gossip_err(
726                "Error: dirdata type [%d] does not match expected type PVFS_TYPE_DIRDATA %d\n",
727                attributes->attr.objtype, PVFS_TYPE_DIRDATA);
728
729        set_return_code(&ret, -PVFS_EINVAL);
730    }
731
732    return ret;
733}
734
735/**
736 * Performs sanity checking on the PVFS_TYPE_DIRECTORY PVFS_Object type.
737 * Checks the following:
738 * - gets and validates directory entry filenames
739 * .
740 * \retval 0 on success
741 * \retval -PVFS_error on failure
742 */
743int PVFS_fsck_validate_dir(
744    const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
745    const PVFS_object_ref * obj_ref,         /**< DIRECTORY object reference */
746    const PVFS_sysresp_getattr * attributes, /**< DIRECTORY attributes */
747    const PVFS_credentials * creds,          /**< populated creditials structure */
748    PVFS_dirent * directory_entries)         /**< \return readdir response */
749{
750    int ret = 0;
751    int i = 0;
752    int err = 0;
753    int current_dir_entry = 0;
754    PVFS_kv_position token;
755    unsigned int token_flag = PVFS_READDIR_START;
756    PVFS_sysresp_readdir readdir_resp;
757    PVFS_handle dirdata_handle;
758
759    if (fsck_options->check_stranded_objects)
760    {
761        if (PINT_handle_wrangler_remove_handle
762            (&obj_ref->handle, &obj_ref->fs_id))
763        {
764            gossip_err("WARNING: unable to remove handle [%llu] from \
765                    handle list while verifying stranded objects\n", llu(obj_ref->handle));
766        }
767    }
768
769    err = PVFS_fsck_validate_dir_attr(fsck_options, attributes);
770    if(err < 0)
771    {
772        gossip_err("Error: directory has invalid attributes\n");
773        return(err);
774    }
775    set_return_code(&ret, err);
776
777    /* get the dirdata handle and validate */
778    err = PVFS_mgmt_get_dirdata_handle
779        (*obj_ref, &dirdata_handle, (PVFS_credentials *) creds, NULL);
780    if(err < 0)
781    {
782        gossip_err("Error: unable to get dirdata handle\n");
783        return(err);
784    }
785
786    err = PVFS_fsck_validate_dirdata(fsck_options,
787        (const PVFS_handle *)&dirdata_handle, &obj_ref->fs_id, creds);
788    if(err < 0)
789    {
790        gossip_err("Error: directory dirdata is invalid\n");
791        return(err);
792    }
793    set_return_code(&ret, err);
794
795    /* get and validate all directory entries */
796    do
797    {
798        memset(&readdir_resp, 0, sizeof(PVFS_sysresp_readdir));
799
800        err = PVFS_sys_readdir(*obj_ref,
801                               token,
802                               &token_flag,
803                               MAX_DIR_ENTS,
804                               (PVFS_credentials *) creds, &readdir_resp, NULL);
805        if(err < 0)
806        {
807            gossip_err("Error: could not read directory entries\n");
808            return(err);
809        }
810
811        for (i = 0; i < readdir_resp.pvfs_dirent_outcount; i++)
812        {
813            strncpy(directory_entries[current_dir_entry].d_name,
814                    readdir_resp.dirent_array[i].d_name, PVFS_NAME_MAX + 1);
815
816            PVFS_handle_copy(directory_entries[current_dir_entry].handle,
817                             readdir_resp.dirent_array[i].handle);
818            current_dir_entry++;
819
820            if (fsck_options->check_dir_entry_names)
821            {
822                err = PVFS_fsck_validate_dir_ent(fsck_options,
823                                                    readdir_resp.
824                                                    dirent_array[i].d_name);
825                /* continue even if we hit errors; we want to see all entries */
826                if (err < 0)
827                {
828                    gossip_err("Error: directory entry [%s] is invalid\n",
829                            readdir_resp.dirent_array[i].d_name);
830                }
831                set_return_code(&ret, err);
832            }
833        }
834
835        free(readdir_resp.dirent_array);
836        memcpy(&token, &readdir_resp.token, sizeof(PVFS_kv_position));
837
838    } while (readdir_resp.pvfs_dirent_outcount == MAX_DIR_ENTS);
839
840    return ret;
841}
842
843/**
844 * Performs validity checking for the attributes for PVFS_TYPE_DIRECTORY.
845 * Checks the following:
846 * - Object type must be PVFS_TYPE_DIRECTORY
847 * - dirent_count must be >= 0
848 * .
849 * \retval 0 on success
850 * \retval -PVFS_error on failure
851 */
852int PVFS_fsck_validate_dir_attr(
853    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
854    const PVFS_sysresp_getattr * attributes)        /**< DIRECTORY attributes */
855{
856    int ret = 0;
857
858    if (attributes->attr.objtype != PVFS_TYPE_DIRECTORY)
859    {
860        gossip_err("Error: directory type [%d] does not \
861            match expected type PVFS_TYPE_DIRECTORY %d\n", attributes->attr.objtype, PVFS_TYPE_DIRECTORY);
862
863        set_return_code(&ret, -PVFS_EINVAL);
864    }
865
866    if (attributes->attr.dirent_count < 0)
867    {
868        gossip_err("Error: directory entry count [%lld] is invalid\n",
869                lld(attributes->attr.dirent_count));
870
871        set_return_code(&ret, -PVFS_EINVAL);
872    }
873
874    return ret;
875}
876
877/**
878 * Performs validity checking for the PVFS_TYPE_DIRECTORY directory entries
879 * Checks the following:
880 * - invalid characters in entry names
881 * - entry_names <= PVFS2_SEGMENT_MAX
882 * - warnings for characters that tend to confuse shells
883 * .
884 * \retval 0 on success
885 * \retval -PVFS_error on failure
886 */
887int PVFS_fsck_validate_dir_ent(
888    const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
889    const char *filename)              /**< Filename associated with handle */
890{
891    const char *cp;
892    int ret = 0;
893
894    if (strlen(filename) > PVFS_SEGMENT_MAX)
895    {
896        gossip_err(
897                "Error: directory entry [%s] length is > PVFS_SEGMENT_MAX [%d]\n",
898                filename, PVFS_SEGMENT_MAX);
899        set_return_code(&ret, -PVFS_EINVAL);
900    }
901
902    if (strspn(filename, "/") > 0)
903    {
904        gossip_err("Error: directory entry [%s] contains invalid / character \n",
905                filename);
906        set_return_code(&ret, -PVFS_EINVAL);
907    }
908
909    cp = filename;
910    while (*cp)
911    {
912        /* isprint is ' ' through ~ in ASCII; no tabs or newlines */
913        if (!isprint(*cp))
914        {
915            gossip_err("WARNING: directory entry [%s] contains odd character\n",
916                       filename);
917            break;
918        }
919        cp++;
920    }
921
922    return ret;
923}
924
925/**
926 * Get a pvfs2 objects attributes.
927 *
928 * \retval 0 on success
929 * \retval -PVFS_error on failure
930 */
931int PVFS_fsck_get_attributes(
932    const struct PINT_fsck_options *fsck_options,   /**< generic fsck options */
933    const PVFS_object_ref * pref, /**< object reference requesting attributes */
934    const PVFS_credentials * creds,      /**< populated credentials structure */
935    PVFS_sysresp_getattr * getattr_resp) /**< attribute structure to populate */
936{
937    time_t r_atime, r_mtime, r_ctime;
938    int ret = 0;
939
940    ret = PVFS_sys_getattr
941        (*pref, PVFS_ATTR_SYS_ALL, (PVFS_credentials *) creds, getattr_resp, NULL);
942    if(ret < 0)
943    {
944        gossip_err("Error: unable to retrieve attributes\n");
945        return(ret);
946    }
947
948    r_atime = (time_t) getattr_resp->attr.atime;
949    r_mtime = (time_t) getattr_resp->attr.mtime;
950    r_ctime = (time_t) getattr_resp->attr.ctime;
951
952    /* if the gossip fsck debug mask is enabled, then print detailed
953     * information about the attributes
954     */
955    gossip_debug(GOSSIP_FSCK_DEBUG, "\tFSID        : %d\n", (int) pref->fs_id);
956    gossip_debug(GOSSIP_FSCK_DEBUG, "\tHandle      : %llu\n", llu(pref->handle));
957
958    if (getattr_resp->attr.mask & PVFS_ATTR_SYS_COMMON_ALL)
959    {
960        gossip_debug(GOSSIP_FSCK_DEBUG,
961            "\tuid         : %d\n", getattr_resp->attr.owner);
962        gossip_debug(GOSSIP_FSCK_DEBUG,
963            "\tgid         : %d\n", getattr_resp->attr.group);
964        gossip_debug(GOSSIP_FSCK_DEBUG,
965            "\tperms       : %o\n", getattr_resp->attr.perms);
966        gossip_debug(GOSSIP_FSCK_DEBUG,
967            "\tatime       : %s", ctime(&r_atime));
968        gossip_debug(GOSSIP_FSCK_DEBUG,
969            "\tmtime       : %s", ctime(&r_mtime));
970        gossip_debug(GOSSIP_FSCK_DEBUG,
971            "\tctime       : %s", ctime(&r_ctime));
972
973    }
974
975    if (getattr_resp->attr.objtype == PVFS_TYPE_SYMLINK)
976    {
977        gossip_debug(GOSSIP_FSCK_DEBUG,
978            "\ttarget:     : %s\n", getattr_resp->attr.link_target);
979    }
980
981    if (getattr_resp->attr.mask & PVFS_ATTR_SYS_SIZE)
982    {
983        gossip_debug(GOSSIP_FSCK_DEBUG,
984            "\tfile size   : %lld\n", lld(getattr_resp->attr.size));
985    }
986
987    if (getattr_resp->attr.mask & PVFS_ATTR_SYS_DFILE_COUNT)
988    {
989        gossip_debug(GOSSIP_FSCK_DEBUG,
990            "\tdfile count : %d\n", getattr_resp->attr.dfile_count);
991    }
992
993    gossip_debug(GOSSIP_FSCK_DEBUG, "\tobject type : ");
994
995    switch (getattr_resp->attr.objtype)
996    {
997    case PVFS_TYPE_NONE:
998        gossip_debug(GOSSIP_FSCK_DEBUG, "none\n");
999        break;
1000    case PVFS_TYPE_METAFILE:
1001        gossip_debug(GOSSIP_FSCK_DEBUG, "meta file\n");
1002        break;
1003    case PVFS_TYPE_DATAFILE:
1004        gossip_debug(GOSSIP_FSCK_DEBUG, "data file\n");
1005        break;
1006    case PVFS_TYPE_DIRECTORY:
1007        gossip_debug(GOSSIP_FSCK_DEBUG, "directory\n");
1008        break;
1009    case PVFS_TYPE_SYMLINK:
1010        gossip_debug(GOSSIP_FSCK_DEBUG, "symlink\n");
1011        break;
1012    case PVFS_TYPE_DIRDATA:
1013        gossip_debug(GOSSIP_FSCK_DEBUG, "dirdata\n");
1014        break;
1015    case PVFS_TYPE_INTERNAL:
1016        gossip_debug(GOSSIP_FSCK_DEBUG, "internal\n");
1017        break;
1018    }
1019    gossip_debug(GOSSIP_FSCK_DEBUG, "\n");
1020
1021    return ret;
1022}
1023
1024/**
1025 * Performs final steps of fsck.  If option was enabled to check for stranded
1026 * objects, then it will print any leftover objects.
1027 *
1028 * \retval 0 on success
1029 * \retval -PVFS_error on failure
1030 */
1031int PVFS_fsck_finalize(
1032    const struct PINT_fsck_options *fsck_options,     /**< Populated options */
1033    const PVFS_fs_id * cur_fs,           /**< The fsid the handle belongs to */
1034    const PVFS_credentials * creds)     /**< populated credentials structure */
1035{
1036    /* display leftover handles */
1037    if (fsck_options->check_stranded_objects)
1038    {
1039        PINT_handle_wrangler_display_stranded_handles(fsck_options, cur_fs,
1040                                                      creds);
1041    }
1042
1043    return(0);
1044}
1045
1046/**
1047 * Gets a list of all the handles used from the PVFS2 servers. The PVFS2 system
1048 * interface must have already been initialized.
1049 *
1050 * \retval 0 on success
1051 * \retval -PVFS_error on failure
1052 */
1053static int PINT_handle_wrangler_load_handles(
1054    const struct PINT_fsck_options *fsck_options, /**< Populated options */
1055    const PVFS_fs_id * cur_fs,                    /**< fs_id */
1056    const PVFS_credentials * creds)   /**< populdated credentials structure */
1057{
1058    int ret = 0;
1059    int server_count;
1060    struct PVFS_mgmt_server_stat *stat_array = NULL;
1061    PVFS_handle **handle_matrix = NULL;
1062    int i = 0;
1063    int *handle_count_array = NULL;
1064    PVFS_ds_position *position_array = NULL;
1065    unsigned int *position_flag_array = NULL;
1066    int more_handles = 0;
1067    int err = 0;
1068
1069    gossip_debug(GOSSIP_FSCK_DEBUG,
1070        "getting all file handles from filesystem\n");
1071
1072    memset(&PINT_handle_wrangler_handlelist, 0,
1073        sizeof(PINT_handle_wrangler_handlelist));
1074
1075    /* count how many servers we have */
1076    err = PVFS_mgmt_count_servers(*cur_fs,
1077                                (PVFS_credentials *) creds,
1078                                &server_count);
1079    if(err < 0)
1080    {
1081        PVFS_perror_gossip("PVFS_mgmt_count_servers", err);
1082        return err;
1083    }
1084
1085    PINT_handle_wrangler_handlelist.num_servers = server_count;
1086
1087    PINT_handle_wrangler_handlelist.addr_array =
1088        (PVFS_BMI_addr_t *) calloc(server_count, sizeof(PVFS_BMI_addr_t));
1089    if (PINT_handle_wrangler_handlelist.addr_array == NULL)
1090    {
1091        ret = -PVFS_ENOMEM;
1092        goto load_handles_error;
1093    }
1094
1095    /* get a list of the pvfs2 servers */
1096    err = PVFS_mgmt_get_server_array(*cur_fs,
1097                               (PVFS_credentials *) creds,
1098                               PINT_handle_wrangler_handlelist.addr_array,
1099                               &server_count);
1100    if(err < 0)
1101    {
1102        PVFS_perror_gossip("PVFS_mgmt_get_server_array", err);
1103        ret = err;
1104        goto load_handles_error;
1105    }
1106
1107    stat_array = (struct PVFS_mgmt_server_stat *)
1108        calloc(server_count, sizeof(struct PVFS_mgmt_server_stat));
1109    if (stat_array == NULL)
1110    {
1111        ret = -PVFS_ENOMEM;
1112        goto load_handles_error;
1113    }
1114
1115    /* this gives us a count of the handles on each server */
1116    err = PVFS_mgmt_statfs_list(*cur_fs,
1117                          (PVFS_credentials *) creds,
1118                          stat_array,
1119                          PINT_handle_wrangler_handlelist.addr_array,
1120                          server_count, NULL, NULL);
1121    if(err < 0)
1122    {
1123        ret = -PVFS_ENOMEM;
1124        goto load_handles_error;
1125    }
1126
1127    /* allocate big chunks of memory to keep up with handles */
1128    handle_count_array = (int *) calloc(server_count, sizeof(int));
1129    if (handle_count_array == NULL)
1130    {
1131        ret = -PVFS_ENOMEM;
1132        goto load_handles_error;
1133    }
1134
1135    position_array = (PVFS_ds_position *) calloc(server_count,
1136                                                 sizeof(PVFS_ds_position));
1137    if (position_array == NULL)
1138    {       
1139        ret = -PVFS_ENOMEM;
1140        goto load_handles_error;
1141    }
1142
1143    position_flag_array = (unsigned int *) calloc(server_count,
1144                                                  sizeof(unsigned int));
1145    if( position_flag_array == NULL )
1146    {
1147        ret = -PVFS_ENOMEM;
1148        goto load_handles_error;
1149    }
1150
1151    PINT_handle_wrangler_handlelist.list_array =
1152        (PVFS_handle **) calloc(server_count, sizeof(PVFS_handle *));
1153    if (PINT_handle_wrangler_handlelist.list_array == NULL)
1154    {
1155        ret = -PVFS_ENOMEM;
1156        goto load_handles_error;
1157    }
1158    memset(PINT_handle_wrangler_handlelist.list_array, 0,
1159        server_count*sizeof(PVFS_handle*));
1160
1161    PINT_handle_wrangler_handlelist.list_array_seen =
1162        (char **) calloc(server_count, sizeof(char *));
1163    if (PINT_handle_wrangler_handlelist.list_array_seen == NULL)
1164    {
1165        ret = -PVFS_ENOMEM;
1166        goto load_handles_error;
1167    }
1168    memset(PINT_handle_wrangler_handlelist.list_array_seen, 0,
1169        server_count*sizeof(char*));
1170
1171    PINT_handle_wrangler_handlelist.size_array =
1172        (int *) calloc(server_count, sizeof(int));
1173    if (PINT_handle_wrangler_handlelist.size_array == NULL)
1174    {
1175        ret = -PVFS_ENOMEM;
1176        goto load_handles_error;
1177    }
1178
1179    PINT_handle_wrangler_handlelist.used_array =
1180        (int *) calloc(server_count, sizeof(int));
1181    if (PINT_handle_wrangler_handlelist.used_array == NULL)
1182    {
1183        ret = -PVFS_ENOMEM;
1184        goto load_handles_error;
1185    }
1186
1187    PINT_handle_wrangler_handlelist.stranded_array =
1188        (int *) calloc(server_count, sizeof(int));
1189    if (PINT_handle_wrangler_handlelist.stranded_array == NULL)
1190    {
1191        ret = -PVFS_ENOMEM;
1192        goto load_handles_error;
1193    }
1194
1195    /* temporary array to keep state while fetching handles */
1196    handle_matrix =
1197        (PVFS_handle **) calloc(server_count, sizeof(PVFS_handle *));
1198    if (handle_matrix == NULL)
1199    {
1200        ret = -PVFS_ENOMEM;
1201        goto load_handles_error;
1202    }
1203    memset(handle_matrix, 0, server_count*sizeof(PVFS_handle*));
1204
1205    /* populating a nice "handlelist" struct with all this various handle
1206     * data */
1207    for (i = 0; i < server_count; i++)
1208    {
1209        PINT_handle_wrangler_handlelist.size_array[i] =
1210            stat_array[i].handles_total_count -
1211            stat_array[i].handles_available_count;
1212
1213        PINT_handle_wrangler_handlelist.used_array[i] = 0;
1214
1215        PINT_handle_wrangler_handlelist.list_array[i] =
1216            (PVFS_handle *) calloc(PINT_handle_wrangler_handlelist.size_array[i],
1217                                   sizeof(PVFS_handle));
1218        if (PINT_handle_wrangler_handlelist.list_array[i] == NULL)
1219        {
1220            ret = -PVFS_ENOMEM;
1221            goto load_handles_error;
1222        }
1223
1224        PINT_handle_wrangler_handlelist.list_array_seen[i] =
1225            (char *) calloc(PINT_handle_wrangler_handlelist.size_array[i],
1226                            sizeof(char));
1227        if (PINT_handle_wrangler_handlelist.list_array_seen[i] == NULL)
1228        {
1229            ret = -PVFS_ENOMEM;
1230            goto load_handles_error;
1231        }
1232
1233        handle_matrix[i] =
1234            (PVFS_handle *) calloc(PINT_handle_wrangler_handlelist.size_array[i],
1235                                   sizeof(PVFS_handle));
1236        if (handle_matrix[i] == NULL)
1237        {
1238            ret = -PVFS_ENOMEM;
1239            goto load_handles_error;
1240        }
1241
1242        /* FIX: position stuff changed to use small int and flag */
1243        position_flag_array[i] = PVFS_ITERATE_START;
1244        handle_count_array[i] = HANDLE_BATCH;
1245    }
1246
1247    /* repeatedly grab handles until we get them all */
1248    do
1249    {
1250        /* mgmt call to get block of handles */
1251        err = PVFS_mgmt_iterate_handles_list(*cur_fs,
1252                                             (PVFS_credentials *) creds,
1253                                             handle_matrix,
1254                                             handle_count_array,
1255                                             position_array,
1256                                             NULL,
1257                                             position_flag_array,
1258                                             PINT_handle_wrangler_handlelist.addr_array,
1259                                             server_count,
1260                                             0,
1261                                             NULL,
1262                                             NULL);
1263        if(err < 0)
1264        {
1265            PVFS_perror_gossip("PVFS_mgmt_iterate_handles", err);
1266            ret = err;
1267            goto load_handles_error;
1268        }
1269
1270        more_handles = 0;
1271
1272        for (i = 0; i < server_count; i++)
1273        {
1274            /* add this block of handles to the full list */
1275            int j = 0;
1276            for (j = 0; j < handle_count_array[i]; j++)
1277            {
1278                PVFS_handle_copy(PINT_handle_wrangler_handlelist.list_array[i]
1279                    [PINT_handle_wrangler_handlelist.used_array[i] + j],
1280                    handle_matrix[i][j]);
1281            }
1282
1283            PINT_handle_wrangler_handlelist.used_array[i] +=
1284                handle_count_array[i];
1285
1286            /* are there more handles? */
1287            /* FIX: position stuff changed to use small int and flag */
1288            if (position_flag_array[i] != PVFS_ITERATE_END)
1289            {
1290                more_handles = 1;
1291            }
1292        }
1293    } while (more_handles != 0);
1294
1295    for (i = 0; i < server_count; i++)
1296    {
1297        /* sort the list of handles */
1298        qsort(PINT_handle_wrangler_handlelist.list_array[i],
1299              PINT_handle_wrangler_handlelist.used_array[i],
1300              sizeof(PVFS_size), compare_handles);
1301
1302        /* we will decrement this during the actual fsck as we check each handle */
1303        PINT_handle_wrangler_handlelist.stranded_array[i] =
1304            PINT_handle_wrangler_handlelist.used_array[i];
1305    }
1306
1307    /* now look for reserved handles from each server */
1308    for (i = 0; i < server_count; i++)
1309    {
1310        /* FIX: position stuff changed to use small int and flag */
1311        position_flag_array[i] = PVFS_ITERATE_START;
1312        handle_count_array[i] = HANDLE_BATCH;
1313    }
1314
1315    do
1316    {
1317        err = PVFS_mgmt_iterate_handles_list(*cur_fs,
1318                                             (PVFS_credentials *) creds,
1319                                             handle_matrix,
1320                                             handle_count_array,
1321                                             position_array,
1322                                             NULL,
1323                                             position_flag_array,
1324                                             PINT_handle_wrangler_handlelist.addr_array,
1325                                             server_count,
1326                                             PVFS_MGMT_RESERVED,
1327                                             NULL,
1328                                             NULL);
1329        if(err < 0)
1330        {
1331            PVFS_perror_gossip("PVFS_mgmt_iterate_handles", err);
1332            ret = err;
1333            goto load_handles_error;
1334        }
1335
1336        more_handles = 0;
1337
1338        for (i = 0; i < server_count; i++)
1339        {
1340            /* remove these handles */
1341            int j = 0;
1342            for (j = 0; j < handle_count_array[i]; j++)
1343            {
1344                PINT_handle_wrangler_remove_handle(
1345                    (const PVFS_handle *)&(handle_matrix[i][j]), cur_fs);
1346            }
1347
1348            /* are there more handles? */
1349            /* FIX: position stuff changed to use small int and flag */
1350            if (position_flag_array[i] != PVFS_ITERATE_END)
1351            {
1352                more_handles = 1;
1353                handle_count_array[i] = HANDLE_BATCH;
1354            }
1355        }
1356    } while (more_handles != 0);
1357
1358    ret = 0;
1359    goto load_handles_success;
1360
1361load_handles_error:
1362    if(PINT_handle_wrangler_handlelist.stranded_array)
1363        free(PINT_handle_wrangler_handlelist.stranded_array);
1364    if(PINT_handle_wrangler_handlelist.used_array)
1365        free(PINT_handle_wrangler_handlelist.used_array);
1366    if(PINT_handle_wrangler_handlelist.size_array)
1367        free(PINT_handle_wrangler_handlelist.size_array);
1368    if(PINT_handle_wrangler_handlelist.addr_array)
1369        free(PINT_handle_wrangler_handlelist.addr_array);
1370    if(PINT_handle_wrangler_handlelist.list_array)
1371    {
1372        for(i=0; i<server_count; i++)
1373        {
1374            if(PINT_handle_wrangler_handlelist.list_array[i])
1375                free(PINT_handle_wrangler_handlelist.list_array[i]);
1376        }
1377        free(PINT_handle_wrangler_handlelist.list_array);
1378    }
1379    if(PINT_handle_wrangler_handlelist.list_array_seen)
1380    {
1381        for(i=0; i<server_count; i++)
1382        {
1383            if(PINT_handle_wrangler_handlelist.list_array_seen[i])
1384                free(PINT_handle_wrangler_handlelist.list_array_seen[i]);
1385        }
1386        free(PINT_handle_wrangler_handlelist.list_array_seen);
1387    }
1388
1389    /* fall through on purpose */
1390
1391load_handles_success:
1392    if(handle_matrix)
1393    {
1394        for(i=0; i<server_count; i++)
1395        {
1396            if(handle_matrix[i])
1397                free(handle_matrix[i]);
1398        }
1399        free(handle_matrix);
1400    }
1401    if(position_array)
1402        free(position_array);
1403    if(position_flag_array)
1404        free(position_flag_array);
1405    if(handle_count_array)
1406        free(handle_count_array);
1407    if(stat_array)
1408        free(stat_array);
1409
1410    return ret;
1411}
1412
1413/**
1414 * Removes the given handle from the list of handles stored.  Each check in
1415 * the fsck calls this function as it sees a handle.  The end result is a
1416 * list of left over "stranded" handles.
1417 *
1418 * \retval 0 on success
1419 * \retval -PVFS_error on failure
1420 */
1421static int PINT_handle_wrangler_remove_handle(
1422    const PVFS_handle * handle,     /**< handle to remove */
1423    const PVFS_fs_id * cur_fs)      /**< fs_id */
1424{
1425    int ret = 0;
1426    int i = 0;
1427    int j = 0;
1428    PVFS_BMI_addr_t server_addr;
1429    int found = 0;
1430
1431    /* find which server the handle is on */
1432    ret = PINT_cached_config_map_to_server(&server_addr,
1433        *(PVFS_handle *)handle, *cur_fs);
1434    if(ret < 0)
1435    {
1436        PVFS_perror_gossip("PINT_cached_config_map_to_server", ret);
1437        gossip_err("Error: could not resolve handle [%llu] to server\n",
1438            llu(*handle));
1439        return(ret);
1440    }
1441
1442    /* get the index of the server this handle is located on */
1443    for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
1444    {
1445        if (PINT_handle_wrangler_handlelist.addr_array[i] == server_addr)
1446        {
1447            found = 1;
1448            break;
1449        }
1450    }
1451    if(!found)
1452    {
1453        gossip_err("Error: could not find matching server for handle [%llu]\n",
1454            llu(*handle));
1455        return(-PVFS_EINVAL);
1456    }
1457
1458    /* keep up with which handles have been "seen" */
1459    found = 0;
1460    for (j = 0; j < PINT_handle_wrangler_handlelist.used_array[i]; j++)
1461    {
1462        if (PINT_handle_wrangler_handlelist.list_array[i][j] == *handle)
1463        {
1464            PINT_handle_wrangler_handlelist.list_array_seen[i][j] = 'x';
1465            PINT_handle_wrangler_handlelist.stranded_array[i]--;
1466            found = 1;
1467            break;
1468        }
1469    }
1470    if(!found)
1471    {
1472        gossip_err("Error: could not find handle [%llu]\n",
1473            llu(*handle));
1474        return(-PVFS_EINVAL);
1475    }
1476
1477    return ret;
1478}
1479
1480#if 0
1481/**
1482  * Returns the handles left over from the fsck
1483 */
1484static int PINT_handle_wrangler_get_stranded_handles(
1485    const PVFS_fs_id * cur_fs,                  /**< filesystem id */
1486    int *num_stranded_handles,                  /**< number of handles in array of handles returned */
1487    PVFS_handle ** stranded_handles)            /**< array of stranded handles on fs cur_fs */
1488{
1489    int ret = 0;
1490    int i = 0;
1491    int j = 0;
1492    int position = 0;
1493
1494    *num_stranded_handles = 0;
1495
1496    for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
1497    {
1498        (*num_stranded_handles) +=
1499            PINT_handle_wrangler_handlelist.stranded_array[i];
1500    }
1501
1502    *stranded_handles = (PVFS_handle *) calloc((*num_stranded_handles), sizeof(PVFS_handle));
1503    if (*stranded_handles == NULL)
1504    {
1505        return -PVFS_ENOMEM;
1506    }
1507
1508    for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
1509    {
1510        for (j = 0; j < PINT_handle_wrangler_handlelist.used_array[i]; j++)
1511        {
1512            if (!PINT_handle_wrangler_handlelist.list_array_seen[i][j])
1513            {
1514                (*stranded_handles)[position] =
1515                    PINT_handle_wrangler_handlelist.list_array[i][j];
1516                position++;
1517            }
1518        }
1519    }
1520
1521    return ret;
1522}
1523#endif
1524
1525/**
1526 * Displays the handles left over from the fsck
1527 *
1528 * \retval 0 on success
1529 * \retval -PVFS_error on failure
1530 */
1531static int PINT_handle_wrangler_display_stranded_handles(
1532    const struct PINT_fsck_options *fsck_options, /**< populated fsck options */
1533    const PVFS_fs_id * cur_fs,                             /**< filesystem id */
1534    const PVFS_credentials * creds)      /**< populated credentials structure */
1535{
1536    int ret = 0;
1537    int i = 0;
1538    int j = 0;
1539    PVFS_sysresp_getattr attributes;
1540    PVFS_object_ref pref;
1541    const char *server_name = NULL;
1542    int header = 0;
1543    char buf[128] = {0};
1544
1545    for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
1546    {
1547        /* get the pretty server name */
1548        server_name = PINT_cached_config_map_addr(*cur_fs,
1549            PINT_handle_wrangler_handlelist.addr_array[i]);
1550
1551        for (j = 0; j < PINT_handle_wrangler_handlelist.size_array[i]; j++)
1552        {
1553            if (!PINT_handle_wrangler_handlelist.list_array_seen[i][j])
1554            {
1555                PVFS_handle_copy(pref.handle,
1556                    PINT_handle_wrangler_handlelist.list_array[i][j]);
1557                pref.fs_id = *cur_fs;
1558
1559                if(!header)
1560                {
1561                    printf("\n");
1562                    printf("Stranded Objects:\n");
1563                    printf
1564                        ("[  Handle  ] [  FSID  ] [    Size    ] [File Type] [      PVFS2 Server     ]\n");
1565                    header = 1;
1566                }
1567
1568                /* get this objects attributes */
1569                ret = PVFS_fsck_get_attributes(fsck_options, &pref, creds,
1570                                         &attributes);
1571               
1572                printf(" %llu   %d  ",
1573                       llu(PINT_handle_wrangler_handlelist.list_array[i][j]),
1574                       *cur_fs);
1575
1576                if(ret < 0)
1577                {
1578                    PVFS_strerror_r(ret, buf, 127);
1579                    printf("Unknown: getattr error: %s)\n", buf);
1580                }
1581                else
1582                {
1583
1584                    if (attributes.attr.mask & PVFS_ATTR_SYS_SIZE)
1585                    {
1586                        printf("%13lld   ", lld(attributes.attr.size));
1587                    }
1588
1589                    switch (attributes.attr.objtype)
1590                    {
1591                    case PVFS_TYPE_NONE:
1592                        printf("none     ");
1593                        break;
1594                    case PVFS_TYPE_METAFILE:
1595                        printf("meta file");
1596                        break;
1597                    case PVFS_TYPE_DATAFILE:
1598                        printf("data file");
1599                        break;
1600                    case PVFS_TYPE_DIRECTORY:
1601                        printf("directory");
1602                        break;
1603                    case PVFS_TYPE_SYMLINK:
1604                        printf("symlink  ");
1605                        free(attributes.attr.link_target);
1606                        break;
1607                    case PVFS_TYPE_DIRDATA:
1608                        printf("dirdata  ");
1609                        break;
1610                    case PVFS_TYPE_INTERNAL:
1611                        printf("internal  ");
1612                        break;
1613                    }
1614                    printf("   %s\n", server_name);
1615                }
1616            }
1617        }
1618    }
1619
1620    if(!header)
1621    {
1622        printf("No stranded objects found.\n");
1623    }
1624
1625    return ret;
1626}
1627
1628/**
1629 * Compares two handles, for qsort()
1630 *
1631 * \retval 0 if equal
1632 * \retval <0 if handle1 less than handle2
1633 * \retval >0 if handle1 greater than handle2
1634 */
1635static int compare_handles(
1636    const void *handle1,    /**< handle 1*/
1637    const void *handle2)    /**< handle 2*/
1638{
1639    PVFS_size temp_handle =
1640        *((PVFS_handle *) handle1) - *((PVFS_handle *) handle2);
1641
1642    if (temp_handle > 0)
1643    {
1644        return 1;
1645    }
1646    else if (temp_handle < 0)
1647    {
1648        return -1;
1649    }
1650    else
1651    {
1652        return 0;
1653    }
1654}
1655
1656/**
1657 * Set the return code for a function, taking previous return values into
1658 * account.  The purpose of this is to make sure when we are propigating
1659 * errors that warnings do not take precident over standard error codes.
1660 */
1661static void set_return_code(
1662    int *ret,         /**< error code to populate */
1663    const int retval) /**< the value we are proposing to set the error code to */
1664{
1665    if (*ret >= 0)
1666    {
1667        *ret = retval;
1668    }
1669    else if (retval != 0)
1670    {
1671        *ret = retval;
1672    }
1673}
1674
1675/* @} */
1676
1677/*
1678 * Local variables:
1679 *  c-indent-level: 4
1680 *  c-basic-offset: 4
1681 * End:
1682 *
1683 * vim: ts=8 sts=4 sw=4 expandtab
1684 */
Note: See TracBrowser for help on using the browser.