root/trunk/src/common/misc/pvfs2-util.c @ 9224

Revision 9224, 68.7 KB (checked in by sampson, 15 months ago)

Fixed memory leak with mntent structs

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * Changes by Acxiom Corporation to add relative path support to
5 * PVFS_util_resolve(),
6 * Copyright © Acxiom Corporation, 2005
7 *
8 * See COPYING in top-level directory.
9 */
10
11#include <string.h>
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <ctype.h>
16#include <assert.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <sys/time.h>
20#include <sys/wait.h>
21#include <errno.h>
22#include <signal.h>
23#include <libgen.h>
24
25#ifndef ENABLE_SECURITY
26#include <pwd.h>
27#include <grp.h>
28#ifndef HAVE_GETGROUPLIST
29#include "getugroups.h"
30#endif
31#endif
32
33#define __PINT_REQPROTO_ENCODE_FUNCS_C
34#include "pvfs2-config.h"
35#include "pvfs2-sysint.h"
36#include "pvfs2-util.h"
37#include "pvfs2-debug.h"
38#include "gossip.h"
39#include "pvfs2-attr.h"
40#include "pvfs2-types-debug.h"
41#include "str-utils.h"
42#include "gen-locks.h"
43#include "realpath.h"
44#include "pint-sysint-utils.h"
45#include "pvfs2-internal.h"
46#include "pint-util.h"
47#include "security-util.h"
48
49#ifdef HAVE_MNTENT_H
50
51#include <mntent.h>
52#define PINT_fstab_t FILE
53#define PINT_fstab_entry_t struct mntent
54#define PINT_fstab_open(_fstab, _fname) (_fstab) = setmntent(_fname, "r")
55#define PINT_fstab_close(_tab) endmntent(_tab)
56#define PINT_fstab_next_entry(_tab) getmntent(_tab)
57#define PINT_fstab_entry_destroy(_entry) _entry = NULL
58#define PINT_fstab_entry_hasopt(_entry, _opt) hasmntopt(_entry, _opt)
59
60#define PINT_FSTAB_NAME(_entry) (_entry)->mnt_fsname
61#define PINT_FSTAB_PATH(_entry) (_entry)->mnt_dir
62#define PINT_FSTAB_TYPE(_entry) (_entry)->mnt_type
63#define PINT_FSTAB_OPTS(_entry) (_entry)->mnt_opts
64
65#elif HAVE_FSTAB_H
66
67#include <fstab.h>
68#define PINT_fstab_t FILE
69#define PINT_fstab_entry_t struct fstab
70#define PINT_fstab_open(_fstab, _fname) _fstab = fopen(_fname, "r")
71#define PINT_fstab_close(_tab) fclose(_tab)
72#define PINT_fstab_next_entry(_tab) PINT_util_my_get_next_fsent(_tab)
73#define PINT_fstab_entry_destroy(_entry) PINT_util_fsent_destroy(_entry)
74#define PINT_fstab_entry_hasopt(_entry, _opt) strstr((_entry)->fs_mntops, _opt)
75
76#define PINT_FSTAB_NAME(_entry) (_entry)->fs_spec
77#define PINT_FSTAB_PATH(_entry) (_entry)->fs_file
78#define PINT_FSTAB_TYPE(_entry) (_entry)->fs_vfstype
79#define PINT_FSTAB_OPTS(_entry) (_entry)->fs_mntops
80
81#define DEFINE_MY_GET_NEXT_FSENT
82static struct fstab * PINT_util_my_get_next_fsent(PINT_fstab_t * tab);
83static void PINT_util_fsent_destroy(PINT_fstab_entry_t * entry);
84
85#else
86
87#error OS does not have mntent.h or fstab.h. 
88#error Add your own fstab parser macros to fix.
89
90#endif
91
92#define PVFS2_MAX_INVALID_MNTENTS                     256
93#define PVFS2_MAX_TABFILES                              8
94#define PVFS2_DYNAMIC_TAB_INDEX  (PVFS2_MAX_TABFILES - 1)
95#define PVFS2_DYNAMIC_TAB_NAME              "<DynamicTab>"
96
97static PVFS_util_tab s_stat_tab_array[PVFS2_MAX_TABFILES];
98static int s_stat_tab_count = 0;
99static gen_mutex_t s_stat_tab_mutex = GEN_MUTEX_INITIALIZER;
100
101static int parse_flowproto_string(
102    const char *input,
103    enum PVFS_flowproto_type *flowproto);
104
105static int parse_encoding_string(
106    const char *cp,
107    enum PVFS_encoding_type *et);
108
109static int parse_num_dfiles_string(const char* cp, int* num_dfiles);
110
111int PVFS_util_resolve_absolute(
112    const char* local_path,
113    PVFS_fs_id* out_fs_id,
114    char* out_fs_path,
115    int out_fs_path_max);
116
117struct PVFS_sys_mntent* PVFS_util_gen_mntent(
118    char* config_server,
119    char* fs_name)
120{
121    struct PVFS_sys_mntent* tmp_ent = NULL;
122
123    tmp_ent = (struct PVFS_sys_mntent*)malloc(sizeof(struct
124        PVFS_sys_mntent));
125    if(!tmp_ent)
126    {
127        return(NULL);
128    }
129    memset(tmp_ent, 0, sizeof(struct PVFS_sys_mntent));
130
131    tmp_ent->num_pvfs_config_servers = 1;
132    tmp_ent->pvfs_config_servers = (char**)malloc(sizeof(char*));
133    if(!tmp_ent->pvfs_config_servers)
134    {
135        free(tmp_ent);
136        return(NULL);
137    }
138
139    tmp_ent->pvfs_config_servers[0] = strdup(config_server);
140    if(!tmp_ent->pvfs_config_servers[0])
141    {
142        free(tmp_ent->pvfs_config_servers);
143        free(tmp_ent);
144        return(NULL);
145    }
146
147    tmp_ent->pvfs_fs_name = strdup(fs_name);
148    if(!tmp_ent->pvfs_fs_name)
149    {
150        free(tmp_ent->pvfs_config_servers[0]);
151        free(tmp_ent->pvfs_config_servers);
152        free(tmp_ent);
153        return(NULL);
154    }
155
156    tmp_ent->flowproto = FLOWPROTO_DEFAULT;
157    tmp_ent->encoding = PVFS2_ENCODING_DEFAULT;
158
159    return(tmp_ent);
160}
161
162void PVFS_util_gen_mntent_release(struct PVFS_sys_mntent* mntent)
163{
164    free(mntent->pvfs_config_servers[0]);
165    free(mntent->pvfs_config_servers);
166    free(mntent->pvfs_fs_name);
167    mntent->pvfs_fs_name = NULL;
168    free(mntent);
169    return;
170}
171
172int PVFS_util_gen_credential_defaults(PVFS_credential *cred)
173{
174    return PVFS_util_gen_credential(NULL, NULL,
175                                    PVFS_DEFAULT_CREDENTIAL_TIMEOUT,
176                                    NULL, cred);
177}
178
179#ifdef ENABLE_SECURITY
180int PVFS_util_gen_credential(const char *user, const char *group,
181    unsigned int timeout, const char *keypath, PVFS_credential *cred)
182{
183    struct sigaction newsa, oldsa;
184    pid_t pid;
185    int filedes[2], errordes[2];
186    int ret;
187
188    if (!keypath && getenv("PVFS2KEY_FILE"))
189    {
190        keypath = getenv("PVFS2KEY_FILE");
191    }
192
193    memset(&newsa, 0, sizeof(newsa));
194    newsa.sa_handler = SIG_DFL;
195    sigaction(SIGCHLD, &newsa, &oldsa);
196
197    /* pipe to read credential from stdout of pvfs2-gencred */
198    ret = pipe(filedes);
199    if (ret == -1)
200    {
201        return -PVFS_errno_to_error(errno);
202    }
203    /* pipe to read any error messages from stderr of pvfs2-gencred */
204    ret = pipe(errordes);
205    if (ret == -1)
206    {
207        return -PVFS_errno_to_error(errno);
208    }
209
210    pid = fork();
211    if (pid == 0)
212    {
213        char *args[7];
214        char **ptr = args;
215        char timearg[16];
216        char *envp[] = { NULL };
217
218        close(STDERR_FILENO);
219        dup(errordes[1]);
220        close(STDOUT_FILENO);
221        dup(filedes[1]);
222        close(STDIN_FILENO);
223
224        *ptr++ = BINDIR"/pvfs2-gencred";
225
226        if (user)
227        {
228            *ptr++ = "-u";
229            *ptr++ = (char*)user;
230        }
231        if (group)
232        {
233            *ptr++ = "-g";
234            *ptr++ = (char*)group;
235        }
236        if (timeout != PVFS_DEFAULT_CREDENTIAL_TIMEOUT)
237        {
238           snprintf(timearg, sizeof(timearg), "%u", timeout);
239           *ptr++ = "-t";
240           *ptr++ = timearg;
241        }
242        if (keypath)
243        {
244            *ptr++ = "-k";
245            *ptr++ = (char*)keypath;
246        }
247        *ptr++ = NULL;
248        execve(BINDIR"/pvfs2-gencred", args, envp);
249
250        _exit(100);
251    }
252    else if (pid == -1)
253    {
254        close(filedes[1]);
255        close(errordes[1]);
256        ret = -PVFS_errno_to_error(errno);
257    }
258    else
259    {
260        char buf[sizeof(PVFS_credential)+extra_size_PVFS_credential],
261             ebuf[512];
262        ssize_t total = 0, etotal = 0;
263        ssize_t cnt, ecnt;
264
265        /* close write end so we get EOF when child exits */
266        close(errordes[1]);
267        close(filedes[1]);
268
269        /* read credential */
270        do
271        {
272            do
273            {
274                cnt = read(filedes[0], buf+total, (sizeof(buf) - total));
275            } while (cnt == -1 && errno == EINTR);
276            total += cnt;
277        } while (cnt > 0);
278       
279        if (cnt == -1)
280        {
281            ret = -PVFS_errno_to_error(errno);
282        }
283        else
284        {
285            int rc;
286
287            waitpid(pid, &rc, 0);
288            if (WIFEXITED(rc) && !WEXITSTATUS(rc))
289            {
290                char *ptr = buf;
291                PVFS_credential tmp;
292
293                decode_PVFS_credential(&ptr, &tmp);
294                ret = PINT_copy_credential(&tmp, cred);
295            }
296            else if (WIFEXITED(rc))
297            {               
298                /* error code from pvfs2_gencred */
299                ret = -PVFS_errno_to_error(WEXITSTATUS(rc));
300            }
301            else
302            {
303                /* catch-all error */
304                ret = -PVFS_EINVAL;
305            }
306
307            /* read errors and warnings */
308            do
309            {
310                do
311                {
312                    ecnt = read(errordes[0], ebuf+etotal,
313                                (sizeof(ebuf) - etotal));
314                } while (ecnt == -1 && errno == EINTR);
315                etotal += ecnt;
316            } while (ecnt > 0 && etotal < sizeof(ebuf));
317            /* null terminate */
318            ebuf[(etotal < sizeof(ebuf)) ? etotal : sizeof(ebuf)] = '\0';
319
320            /* print errors */
321            if (etotal > 0)
322            {
323                char gbuf[600];
324                snprintf(gbuf, sizeof(gbuf), "pvfs2_gencred: %s", ebuf);
325                gossip_err(gbuf);
326            }
327        }
328    }
329
330    close(filedes[0]);
331    close(errordes[0]);
332    sigaction(SIGCHLD, &oldsa, NULL);
333
334    return ret;
335}
336#else /* ENABLE_SECURITY */
337/* PINT_gen_unsigned_credential
338 *
339 * Generate unsigned credential in-process instead of calling pvfs2_gencred.
340 *
341 */
342int PINT_gen_unsigned_credential(const char *user, const char *group,
343                                 PVFS_credential *cred)
344{
345    unsigned long uid, gid, bufsize;
346    char *endptr;
347    struct passwd pwd;
348    struct group grp;
349    struct passwd *presult = NULL;
350    struct group *gresult = NULL;
351    char *pwdbuf, *grpbuf;
352    gid_t groups[PVFS_REQ_LIMIT_GROUPS];
353    int ngroups, ret, i;
354
355    /* allocate buffer for pwd functions */
356    bufsize = -1;
357#ifdef _SC_GETPW_R_SIZE_MAX
358    bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
359#endif
360    if (bufsize == -1)
361        bufsize = 16384;  /* adequate amount */
362   
363    pwdbuf = (char *) malloc(bufsize);
364    if (pwdbuf == NULL)
365    {
366        return -PVFS_ENOMEM;
367    }
368
369    /* get info for specified user or calling user */
370    if (user)
371    {
372        uid = strtoul(user, &endptr, 10);
373        if (*endptr == '\0' && *user != '\0')
374        {
375            if (uid > PVFS_UID_MAX)
376            {
377                ret = -1;
378                presult = NULL;
379            }
380            else
381            {
382                ret = getpwuid_r((uid_t) uid, &pwd, pwdbuf, bufsize, &presult);
383                if (presult == NULL)
384                {
385                    gossip_lerr("User %lu lookup error: %d (0 = not found)\n",
386                                uid, ret);
387                }
388            }
389        }
390        else
391        {
392            ret = getpwnam_r(user, &pwd, pwdbuf, bufsize, &presult);
393            if (presult == NULL)
394            {
395                gossip_lerr("User %s lookup error: %d (0 = not found)\n",
396                            user, ret);
397            }
398        }
399    }
400    else
401    {
402        uid = getuid();
403        ret = getpwuid_r((uid_t) uid, &pwd, pwdbuf, bufsize, &presult);
404        if (presult == NULL)
405        {
406            gossip_lerr("User %lu lookup error: %d (0 = not found)\n",
407                        uid, ret);
408        }
409    }
410    if (presult == NULL)
411    {
412        free(pwdbuf);
413        return -PVFS_EINVAL;
414    }
415
416    /* allocate buffer for grp functions */
417    bufsize = -1;
418#ifdef _SC_GETGR_R_SIZE_MAX
419    bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
420#endif
421    if (bufsize == -1)
422    {
423        bufsize = 16384;
424    }
425
426    grpbuf = (char *) malloc(bufsize);
427    if (grpbuf == NULL)
428    {
429        free(pwdbuf);
430        return -PVFS_ENOMEM;
431    }
432
433    /* get info for specified or calling user's group */
434    if (group)
435    {
436        gid = strtoul(group, &endptr, 10);
437        if (*endptr == '\0' && *group != '\0')
438        {
439            if (gid > PVFS_GID_MAX)
440            {
441                ret = -1;
442                gresult = NULL;
443            }
444            else
445            {
446                ret = getgrgid_r((gid_t) gid, &grp, grpbuf, bufsize, &gresult);
447                if (gresult == NULL)
448                {
449                    gossip_lerr("Group %lu lookup error: %d (0 = not found)\n",
450                                gid, ret);
451                }
452            }
453        }
454        else
455        {
456            ret = getgrnam_r(group, &grp, grpbuf, bufsize, &gresult);
457            if (gresult == NULL)
458            {
459                gossip_lerr("Group %s lookup error: %d (0 = not found)\n",
460                            group, ret);
461            }
462        }
463    }
464    else
465    {
466        gid = getgid();
467        ret = getgrgid_r((gid_t) gid, &grp, grpbuf, bufsize, &gresult);
468        if (gresult == NULL)
469        {
470            gossip_lerr("Group %lu lookup error: %d (0 = not found)\n",
471                        gid, ret);
472        }
473    }
474    if (gresult == NULL)
475    {
476        free(pwdbuf);
477        free(grpbuf);
478        return -PVFS_EINVAL;
479    }
480
481    /* Note: without security enabled any user can generate a
482       credential for another user. */
483
484    /* get user group list */
485#ifdef HAVE_GETGROUPLIST
486
487    ngroups = sizeof(groups)/sizeof(*groups);
488    ret = getgrouplist(pwd.pw_name, grp.gr_gid, groups, &ngroups);
489    if (ret == -1)
490    {
491        gossip_lerr("error: unable to get group list for user %s\n",
492                    pwd.pw_name);
493        return -PVFS_EINVAL;
494    }
495    if (groups[0] != grp.gr_gid)
496    {
497        assert(groups[ngroups-1] == grp.gr_gid);
498        groups[ngroups-1] = groups[0];
499        groups[0] = grp.gr_gid;
500    }
501
502#else /* !HAVE_GETGROUPLIST */
503
504    ngroups = sizeof(groups)/sizeof(*groups);
505    ngroups = getugroups(ngroups, groups, pwd.pw_name, grp.gr_gid);
506    if (ngroups == -1)
507    {
508        gossip_lerr("error: unable to get group list for user %s: %s\n",
509                pwd.pw_name, strerror(errno));
510        free(pwdbuf);
511        free(grpbuf);
512        return -PVFS_EINVAL;
513    }
514
515#endif /* HAVE_GETGROUPLIST */
516
517    /* fill in credential struct */
518    cred->userid = (PVFS_uid)pwd.pw_uid;
519    cred->num_groups = (uint32_t)ngroups;
520    cred->group_array = calloc(ngroups, sizeof(PVFS_gid));
521    if (cred->group_array == NULL)
522    {       
523        free(pwdbuf);
524        free(grpbuf);
525        return -PVFS_ENOMEM;
526    }
527    for (i = 0; i < ngroups; i++)
528    {
529        cred->group_array[i] = (PVFS_gid)groups[i];
530    }
531
532    /* insert an issuer and a null signature */
533    cred->issuer = strdup("");
534
535    cred->timeout = PINT_util_get_current_time() + DEFAULT_CREDENTIAL_TIMEOUT;
536
537    cred->sig_size = 0;
538    cred->signature = NULL;
539
540    free(pwdbuf);
541    free(grpbuf);
542
543    return 0;
544}
545
546int PVFS_util_gen_credential(const char *user, const char *group,
547    unsigned int timeout, const char *keypath, PVFS_credential *cred)
548{
549    if (cred == NULL)
550    {
551        gossip_lerr("PVFS_util_gen_credential: credential is null\n");
552        return -PVFS_EINVAL;
553    }
554
555    memset(cred, 0, sizeof(cred));
556
557    return PINT_gen_unsigned_credential(user, group, cred);
558}
559#endif /* ENABLE_SECURITY */
560
561int PVFS_util_refresh_credential(PVFS_credential *cred)
562{
563    int ret;
564
565    /* =if the credential is valid for at least an hour */
566    if (PINT_util_get_current_time() <= cred->timeout - 3600)
567    {
568        ret = 0;
569    }
570    else
571    {
572        PINT_cleanup_credential(cred);
573        ret = PVFS_util_gen_credential_defaults(cred);
574    }
575
576    return ret;
577}
578
579int PVFS_util_get_umask(void)
580{
581    static int mask = 0, set = 0;
582
583    if (set == 0)
584    {
585        mask = (int)umask(0);
586        umask(mask);
587        set = 1;
588    }
589    return mask;
590}
591
592int PVFS_util_copy_sys_attr(
593    PVFS_sys_attr *dest_attr, PVFS_sys_attr *src_attr)
594{
595    int ret = -PVFS_EINVAL;
596
597    if (src_attr && dest_attr)
598    {
599        dest_attr->owner = src_attr->owner;
600        dest_attr->group = src_attr->group;
601        dest_attr->perms = src_attr->perms;
602        dest_attr->atime = src_attr->atime;
603        dest_attr->mtime = src_attr->mtime;
604        dest_attr->ctime = src_attr->ctime;
605        dest_attr->dfile_count = src_attr->dfile_count;
606        dest_attr->objtype = src_attr->objtype;
607        dest_attr->mask = src_attr->mask;
608        dest_attr->flags = src_attr->flags;
609
610        if (src_attr->mask & PVFS_ATTR_SYS_SIZE)
611        {
612            dest_attr->size = src_attr->size;
613        }
614
615        if((src_attr->mask & PVFS_ATTR_SYS_LNK_TARGET) &&
616            src_attr->link_target)
617        {
618            dest_attr->link_target = strdup(src_attr->link_target);
619            if (!dest_attr->link_target)
620            {
621                ret = -PVFS_ENOMEM;
622                return ret;
623            }
624        }
625        else if ((src_attr->mask & PVFS_ATTR_SYS_DIR_HINT))
626        {
627            if (src_attr->dist_name)
628            {
629                dest_attr->dist_name = strdup(src_attr->dist_name);
630                if (dest_attr->dist_name == NULL)
631                {
632                    ret = -PVFS_ENOMEM;
633                    return ret;
634                }
635            }
636            if (src_attr->dist_params)
637            {
638                dest_attr->dist_params = strdup(src_attr->dist_params);
639                if (dest_attr->dist_params == NULL)
640                {
641                    free(dest_attr->dist_name);
642                    ret = -PVFS_ENOMEM;
643                    return ret;
644                }
645            }
646        }
647        ret = 0;
648    }
649    return ret;
650}
651
652void PVFS_util_release_sys_attr(PVFS_sys_attr *attr)
653{
654    if (attr)
655    {
656        if ((attr->mask & PVFS_ATTR_SYS_TYPE) &&
657            (attr->objtype == PVFS_TYPE_SYMLINK) && attr->link_target)
658        {
659            free(attr->link_target);
660            attr->link_target = NULL;
661        }
662        else if ((attr->mask & PVFS_ATTR_SYS_DIR_HINT) &&
663            (attr->objtype == PVFS_TYPE_DIRECTORY))
664        {
665            if (attr->dist_name)
666                free(attr->dist_name);
667            if (attr->dist_params)
668                free(attr->dist_params);
669            attr->dist_name = NULL;
670            attr->dist_params = NULL;
671        }
672    }
673}
674
675/* PVFS_util_parse_pvfstab()
676 *
677 * parses either the file pointed to by the PVFS2TAB_FILE env
678 * variable, or /etc/fstab, or /etc/pvfs2tab or ./pvfs2tab to extract
679 * pvfs2 mount entries.
680 *
681 * NOTE: if tabfile argument is given at runtime to specify which
682 * tabfile to use, then that will be the _only_ file searched for
683 * pvfs2 entries.
684 *
685 * example entry:
686 * tcp://localhost:3334/pvfs2-fs /mnt/pvfs2 pvfs2 defaults 0 0
687 *
688 * returns const pointer to internal tab structure on success, NULL on
689 * failure
690 */
691const PVFS_util_tab *PVFS_util_parse_pvfstab(
692    const char *tabfile)
693{
694    PINT_fstab_t *mnt_fp = NULL;
695    int file_count = 5;
696    /* NOTE: mtab should be last for clean error logic below */
697    const char *file_list[5] =
698        { NULL, "/etc/fstab", "/etc/pvfs2tab", "pvfs2tab", "/etc/mtab" };
699    const char *targetfile = NULL;
700    PINT_fstab_entry_t *tmp_ent;
701    int i, j;
702    int ret = -1;
703    int tmp_mntent_count = 0;
704    PVFS_util_tab *current_tab = NULL;
705    char *epenv, *tmp;
706
707    if((epenv = getenv("PVFS2EP")) != NULL)
708    {
709        struct PVFS_sys_mntent *mntent;
710        current_tab = &s_stat_tab_array[0];
711        current_tab->mntent_array = malloc(sizeof(struct PVFS_sys_mntent));
712        mntent = &current_tab->mntent_array[0];
713        strcpy(current_tab->tabfile_name, "PVFSEP");
714        current_tab->mntent_count = 1;
715        mntent->pvfs_config_servers = malloc(sizeof(char *));
716        mntent->pvfs_config_servers[0] = strdup(index(epenv, '=') + 1);
717        mntent->num_pvfs_config_servers = 1;
718        mntent->the_pvfs_config_server = mntent->pvfs_config_servers[0];
719        mntent->pvfs_fs_name = strdup(rindex(mntent->the_pvfs_config_server, '/'));
720        mntent->pvfs_fs_name++;
721        mntent->flowproto = FLOWPROTO_DEFAULT;
722        mntent->encoding = PVFS2_ENCODING_DEFAULT;
723        mntent->mnt_dir = strdup(epenv);
724        tmp = index(mntent->mnt_dir, '=');
725        *tmp = 0;
726        mntent->mnt_opts = strdup("rw");
727        mntent->fs_id = PVFS_FS_ID_NULL;
728        return &s_stat_tab_array[0];
729    }
730
731    if (tabfile != NULL)
732    {
733        /*
734          caller wants us to look in a specific location for the
735          tabfile
736        */
737        file_list[0] = tabfile;
738        file_count = 1;
739    }
740    else
741    {
742        /*
743          search the system and env vars for tab files;
744          first check for environment variable override
745        */
746        file_list[0] = getenv("PVFS2TAB_FILE");
747    }
748
749    gen_mutex_lock(&s_stat_tab_mutex);
750
751    /* start by checking list of files we have already parsed */
752    for (i = 0; i < s_stat_tab_count; i++)
753    {
754        for (j = 0; j < file_count; j++)
755        {
756            if (file_list[j] &&
757                !strcmp(file_list[j], s_stat_tab_array[i].tabfile_name))
758            {
759                /* already done */
760                gen_mutex_unlock(&s_stat_tab_mutex);
761                return (&s_stat_tab_array[i]);
762            }
763        }
764    }
765
766    assert(s_stat_tab_count < PVFS2_DYNAMIC_TAB_INDEX);
767
768    /* scan our prioritized list of tab files in order, stop when we
769     * find one that has at least one pvfs2 entry
770     */
771    for (i = 0; (i < file_count && !targetfile); i++)
772    {
773        if(file_list[i])
774        {
775            PINT_fstab_open(mnt_fp, file_list[i]);
776            if (mnt_fp)
777            {
778                while ((tmp_ent = PINT_fstab_next_entry(mnt_fp)))
779                {
780                    if(!(PINT_FSTAB_NAME(tmp_ent)) ||
781                       !(strncmp(PINT_FSTAB_NAME(tmp_ent), "#", 1)))
782                    {
783                        PINT_fstab_entry_destroy(tmp_ent);
784                        continue;
785                    }
786
787                    if (strcmp(PINT_FSTAB_TYPE(tmp_ent), "pvfs2") == 0)
788                    {
789                        targetfile = file_list[i];
790                        tmp_mntent_count++;
791                    }
792
793                    PINT_fstab_entry_destroy(tmp_ent);
794                }
795                PINT_fstab_close(mnt_fp);
796            }
797        }
798    }
799
800    if (!targetfile)
801    {
802        gossip_err("Error: could not find any pvfs2 tabfile entries.\n");
803        gossip_err("Error: tried the following tabfiles:\n");
804        for (i = 0; i < file_count; i++)
805        {
806            gossip_err("       %s\n", file_list[i]);
807        }
808        gen_mutex_unlock(&s_stat_tab_mutex);
809        return (NULL);
810    }
811    gossip_debug(GOSSIP_CLIENT_DEBUG,
812                 "Using pvfs2 tab file: %s\n", targetfile);
813
814    /* allocate array of entries */
815    current_tab = &s_stat_tab_array[s_stat_tab_count];
816
817    current_tab->mntent_array = (struct PVFS_sys_mntent *)malloc(
818        (tmp_mntent_count * sizeof(struct PVFS_sys_mntent)));
819
820    if (!current_tab->mntent_array)
821    {
822        gen_mutex_unlock(&s_stat_tab_mutex);
823        return (NULL);
824    }
825    memset(current_tab->mntent_array, 0,
826           (tmp_mntent_count * sizeof(struct PVFS_sys_mntent)));
827    for (i = 0; i < tmp_mntent_count; i++)
828    {
829        current_tab->mntent_array[i].fs_id = PVFS_FS_ID_NULL;
830    }
831    current_tab->mntent_count = tmp_mntent_count;
832
833    /* reopen our chosen fstab file */
834    PINT_fstab_open(mnt_fp, targetfile);
835
836    /* scan through looking for every pvfs2 entry */
837    i = 0;
838    while ((tmp_ent = PINT_fstab_next_entry(mnt_fp)))
839    {
840       if(!(PINT_FSTAB_NAME(tmp_ent)) || !(strncmp(PINT_FSTAB_NAME(tmp_ent), "#", 1)))
841       {
842           PINT_fstab_entry_destroy(tmp_ent);
843           continue;
844        }
845
846        if ((PINT_FSTAB_TYPE(tmp_ent) != NULL) && (strncmp(PINT_FSTAB_TYPE(tmp_ent), "pvfs2", 5) == 0))
847        {
848            struct PVFS_sys_mntent *me = &current_tab->mntent_array[i];
849            char *cp;
850            int cur_server;
851            char *rewrite_pointer;
852
853            /* Entries in mtab may be prefixed by a process name and '#' */
854            /* If detected, remove prefix.  */
855            for(rewrite_pointer=cp=PINT_FSTAB_NAME(tmp_ent); *cp; cp++,rewrite_pointer++) {
856                if (*cp == '#') {
857                    rewrite_pointer = PINT_FSTAB_NAME(tmp_ent) - 1;
858                    continue;
859                }
860                if (rewrite_pointer == cp) continue;
861                *rewrite_pointer = *cp;
862            }
863            *rewrite_pointer = '\0';
864               
865            /* Enable integrity checks by default */
866            me->integrity_check = 1;
867            /* comma-separated list of ways to contact a config server */
868            me->num_pvfs_config_servers = 1;
869            for (cp=PINT_FSTAB_NAME(tmp_ent); *cp; cp++)
870            {
871                if (*cp == ',')
872                {
873                    ++me->num_pvfs_config_servers;
874                }
875            }
876
877            /* allocate room for our copies of the strings */
878            me->pvfs_config_servers = malloc(me->num_pvfs_config_servers
879                                      * sizeof(*me->pvfs_config_servers));
880            if (!me->pvfs_config_servers)
881            {
882                goto error_exit;
883            }
884            memset(me->pvfs_config_servers, 0, me->num_pvfs_config_servers
885                                            * sizeof(*me->pvfs_config_servers));
886            me->mnt_dir = malloc(strlen(PINT_FSTAB_PATH(tmp_ent)) + 1);
887            me->mnt_opts = malloc(strlen(PINT_FSTAB_OPTS(tmp_ent)) + 1);
888
889            /* bail if any mallocs failed */
890            if (!me->mnt_dir || !me->mnt_opts)
891            {
892                goto error_exit;
893            }
894
895            /* parse server list and make sure fsname is same */
896            cp = PINT_FSTAB_NAME(tmp_ent);
897
898            cur_server = 0;
899            for (;;)
900            {
901                char *tok;
902                int slashcount;
903                char *slash;
904                char *last_slash;
905
906                tok = strsep(&cp, ",");
907                if (!tok) break;
908
909                slash = tok;
910                slashcount = 0;
911                while ((slash = index(slash, '/')))
912                {
913                    slash++;
914                    slashcount++;
915                }
916                if (slashcount != 3)
917                {
918                    /* if we are looking at the mtab, then just silently
919                     * treat this error as if we didn't find an entry at
920                     * all; they may have mounted using an odd syntax on a
921                     * 2.4 kernel system
922                     */
923                    if(!strcmp(targetfile, "/etc/mtab"))
924                    {
925                        gossip_err("Error: could not find any pvfs2 tabfile entries.\n");
926                        gossip_err("Error: tried the following tabfiles:\n");
927                        for (j = 0; j < file_count; j++)
928                        {
929                            gossip_err("       %s\n", file_list[j]);
930                        }
931                        goto error_exit;
932                    }
933                    else
934                    {
935                        gossip_err("Error: invalid tab file entry: %s\n",
936                                    PINT_FSTAB_NAME(tmp_ent));
937                        gossip_err("Error: offending tab file: %s\n",
938                                    targetfile);
939                        goto error_exit;
940                    }
941                }
942
943                /* find a reference point in the string */
944                last_slash = rindex(tok, '/');
945                *last_slash = '\0';
946
947                /* config server and fs name are a special case, take one
948                 * string and split it in half on "/" delimiter
949                 */
950                me->pvfs_config_servers[cur_server] = strdup(tok);
951                if (!me->pvfs_config_servers[cur_server])
952                {
953                    goto error_exit;
954                }
955
956                ++last_slash;
957
958                if (cur_server == 0)
959                {
960                    me->pvfs_fs_name = strdup(last_slash);
961                    if (!me->pvfs_fs_name)
962                    {
963                        goto error_exit;
964                    }
965                }
966                else
967                {
968                    if (strcmp(last_slash, me->pvfs_fs_name) != 0)
969                    {
970                        gossip_lerr(
971                          "Error: different fs names in server addresses: %s\n",
972                          PINT_FSTAB_NAME(tmp_ent));
973                        goto error_exit;
974                    }
975                }
976                ++cur_server;
977            }
978
979            /* make our own copy of parameters of interest */
980            /* mnt_dir and mnt_opts are verbatim copies */
981            strcpy(current_tab->mntent_array[i].mnt_dir,
982                                    PINT_FSTAB_PATH(tmp_ent));
983            strcpy(current_tab->mntent_array[i].mnt_opts,
984                                    PINT_FSTAB_OPTS(tmp_ent));
985
986            /* find out if a particular flow protocol was specified */
987            if ((PINT_fstab_entry_hasopt(tmp_ent, "flowproto")))
988            {
989                ret = parse_flowproto_string(
990                                        PINT_FSTAB_OPTS(tmp_ent),
991                                        &(current_tab->
992                                        mntent_array[i].flowproto));
993                if (ret < 0)
994                {
995                    goto error_exit;
996                }
997            }
998            else
999            {
1000                current_tab->mntent_array[i].flowproto =
1001                                        FLOWPROTO_DEFAULT;
1002            }
1003
1004            /* pick an encoding to use with the server */
1005            current_tab->mntent_array[i].encoding =
1006                                    PVFS2_ENCODING_DEFAULT;
1007            cp = PINT_fstab_entry_hasopt(tmp_ent, "encoding");
1008            if (cp)
1009            {
1010                ret = parse_encoding_string(
1011                                   cp, &current_tab->mntent_array[i].encoding);
1012                if (ret < 0)
1013                {
1014                    goto error_exit;
1015                }
1016            }
1017
1018            /* find out if a particular flow protocol was specified */
1019            current_tab->mntent_array[i].default_num_dfiles = 0;
1020            cp = PINT_fstab_entry_hasopt(tmp_ent, "num_dfiles");
1021            if (cp)
1022            {
1023                ret = parse_num_dfiles_string(
1024                    cp,
1025                    &(current_tab->mntent_array[i].default_num_dfiles));
1026
1027                if (ret < 0)
1028                {
1029                    goto error_exit;
1030                }
1031            }
1032
1033            /* Loop counter increment */
1034            i++;
1035
1036            PINT_fstab_entry_destroy(tmp_ent);
1037        }
1038    }
1039    s_stat_tab_count++;
1040    strcpy(s_stat_tab_array[s_stat_tab_count-1].tabfile_name, targetfile);
1041    PINT_fstab_close(mnt_fp);
1042    gen_mutex_unlock(&s_stat_tab_mutex);
1043    return (&s_stat_tab_array[s_stat_tab_count - 1]);
1044
1045error_exit:
1046    for (; i > -1; i--)
1047    {
1048        struct PVFS_sys_mntent *me = &current_tab->mntent_array[i];
1049
1050        if (me->pvfs_config_servers)
1051        {
1052            int j;
1053            for (j=0; j<me->num_pvfs_config_servers; j++)
1054            {
1055                if (me->pvfs_config_servers[j])
1056                {
1057                    free(me->pvfs_config_servers[j]);
1058                }
1059            }
1060            free(me->pvfs_config_servers);
1061            me->pvfs_config_servers = NULL;
1062            me->num_pvfs_config_servers = 0;
1063        }
1064
1065        if (me->mnt_dir)
1066        {
1067            free(me->mnt_dir);
1068            me->mnt_dir = NULL;
1069        }
1070
1071        if (me->mnt_opts)
1072        {
1073            free(me->mnt_opts);
1074            me->mnt_opts = NULL;
1075        }
1076
1077        if (me->pvfs_fs_name)
1078        {
1079            free(me->pvfs_fs_name);
1080            me->pvfs_fs_name = NULL;
1081        }
1082    }
1083    PINT_fstab_close(mnt_fp);
1084    gen_mutex_unlock(&s_stat_tab_mutex);
1085    return (NULL);
1086}
1087
1088/* PVFS_util_get_default_fsid()
1089 *
1090 * fills in the fs identifier for the first active file system that
1091 * the library knows about.  Useful for test programs or admin tools
1092 * that need default file system to access if the user has not
1093 * specified one
1094 *
1095 * returns 0 on success, -PVFS_error on failure
1096 */
1097int PVFS_util_get_default_fsid(PVFS_fs_id* out_fs_id)
1098{
1099    int i = 0, j = 0;
1100
1101    gen_mutex_lock(&s_stat_tab_mutex);
1102
1103    for(i = 0; i < s_stat_tab_count; i++)
1104    {
1105        for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
1106        {
1107            *out_fs_id = s_stat_tab_array[i].mntent_array[j].fs_id;
1108            if(*out_fs_id != PVFS_FS_ID_NULL)
1109            {
1110                gen_mutex_unlock(&s_stat_tab_mutex);
1111                return(0);
1112            }
1113        }
1114    }
1115
1116    /* check the dynamic tab area if we haven't found an fs yet */
1117    for(j = 0; j < s_stat_tab_array[
1118            PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
1119    {
1120        *out_fs_id = s_stat_tab_array[
1121            PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].fs_id;
1122        if(*out_fs_id != PVFS_FS_ID_NULL)
1123        {
1124            gen_mutex_unlock(&s_stat_tab_mutex);
1125            return(0);
1126        }
1127    }
1128
1129    gen_mutex_unlock(&s_stat_tab_mutex);
1130    return(-PVFS_ENOENT);
1131}
1132
1133/*
1134 * PVFS_util_add_dynamic_mntent()
1135 *
1136 * dynamically add mount information to our internally managed mount
1137 * tables (used for quick fs resolution using PVFS_util_resolve).
1138 * dynamic mnt entries can only be added to a particular dynamic
1139 * region of our book keeping, so they're the exception, not the rule.
1140 *
1141 * returns 0 on success, -PVFS_error on failure, and 1 if the mount
1142 * entry already exists as a parsed entry (not dynamic)
1143 */
1144int PVFS_util_add_dynamic_mntent(struct PVFS_sys_mntent *mntent)
1145{
1146    int i = 0, j = 0, new_index = 0;
1147    int ret = -PVFS_EINVAL;
1148    struct PVFS_sys_mntent *current_mnt = NULL;
1149    struct PVFS_sys_mntent *tmp_mnt_array = NULL;
1150
1151    if (mntent)
1152    {
1153        gen_mutex_lock(&s_stat_tab_mutex);
1154
1155        /*
1156          we exhaustively scan to be sure this mnt entry doesn't exist
1157          anywhere in our book keeping; first scan the parsed regions
1158        */
1159        for(i = 0; i < s_stat_tab_count; i++)
1160        {
1161            for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
1162            {
1163                current_mnt = &(s_stat_tab_array[i].mntent_array[j]);
1164
1165                if (current_mnt->fs_id == mntent->fs_id)
1166                {
1167                    /*
1168                      no need to add the dynamic mount information
1169                      because the file system already exists as a
1170                      parsed mount entry
1171                    */
1172                    gen_mutex_unlock(&s_stat_tab_mutex);
1173                    return 1;
1174                }
1175            }
1176        }
1177
1178#if 0
1179        /* check the dynamic region if we haven't found a match yet */
1180        for(j = 0; j < s_stat_tab_array[
1181                PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
1182        {
1183            current_mnt = &(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].
1184                            mntent_array[j]);
1185
1186            if ((current_mnt->fs_id == mntent->fs_id) &&
1187                (strcmp(current_mnt->pvfs_config_servers[0],
1188                        mntent->pvfs_config_servers[0]) != 0))
1189            {
1190                gossip_err("Error: FS with id %d is already mounted using"
1191                           " a different config server.\n", (int)mntent->fs_id);
1192                gossip_err("Error: This could indicate that a duplicate fsid"
1193                           " is being used.\n");
1194                gossip_err("Error: Please check your server configuration.\n");
1195                gen_mutex_unlock(&s_stat_tab_mutex);
1196                return -PVFS_ENXIO;
1197            }
1198        }
1199#endif
1200
1201        /* copy the mntent to our table in the dynamic tab area */
1202        new_index = s_stat_tab_array[
1203            PVFS2_DYNAMIC_TAB_INDEX].mntent_count;
1204
1205        if (new_index == 0)
1206        {
1207            /* allocate and initialize the dynamic tab object */
1208            s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array =
1209                (struct PVFS_sys_mntent *)malloc(
1210                    sizeof(struct PVFS_sys_mntent));
1211            if (!s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array)
1212            {
1213                return -PVFS_ENOMEM;
1214            }
1215            /* should this be PVFS_PATH_MAX? - WBL */
1216            /* need to find def of this field (tabfile_name) first */
1217            strncpy(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].tabfile_name,
1218                    PVFS2_DYNAMIC_TAB_NAME, PVFS_NAME_MAX);
1219        }
1220        else
1221        {
1222            /* we need to re-alloc this guy to add a new array entry */
1223            tmp_mnt_array = (struct PVFS_sys_mntent *)malloc(
1224                ((new_index + 1) * sizeof(struct PVFS_sys_mntent)));
1225            if (!tmp_mnt_array)
1226            {
1227                return -PVFS_ENOMEM;
1228            }
1229
1230            /*
1231              copy all mntent entries into the new array, freeing the
1232              original entries
1233            */
1234            for(i = 0; i < new_index; i++)
1235            {
1236                current_mnt = &s_stat_tab_array[
1237                    PVFS2_DYNAMIC_TAB_INDEX].mntent_array[i];
1238                PVFS_util_copy_mntent(&tmp_mnt_array[i], current_mnt);
1239                PVFS_util_free_mntent(current_mnt);
1240            }
1241
1242            /* finally, swap the mntent arrays */
1243            free(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array);
1244            s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array =
1245                tmp_mnt_array;
1246        }
1247
1248        gossip_debug(GOSSIP_CLIENT_DEBUG, "* Adding new dynamic mount "
1249                     "point %s [%d,%d]\n", mntent->mnt_dir,
1250                     PVFS2_DYNAMIC_TAB_INDEX, new_index);
1251
1252        current_mnt = &s_stat_tab_array[
1253            PVFS2_DYNAMIC_TAB_INDEX].mntent_array[new_index];
1254
1255        ret = PVFS_util_copy_mntent(current_mnt, mntent);
1256
1257        s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_count++;
1258
1259        gen_mutex_unlock(&s_stat_tab_mutex);
1260    }
1261    return ret;
1262}
1263
1264/*
1265 * PVFS_util_remove_internal_mntent()
1266 *
1267 * dynamically remove mount information from our internally managed
1268 * mount tables.
1269 *
1270 * returns 0 on success, -PVFS_error on failure
1271 */
1272int PVFS_util_remove_internal_mntent(
1273    struct PVFS_sys_mntent *mntent)
1274{
1275    int i = 0, j = 0, new_count = 0, found = 0, found_index = 0;
1276    int ret = -PVFS_EINVAL;
1277    struct PVFS_sys_mntent *current_mnt = NULL;
1278    struct PVFS_sys_mntent *tmp_mnt_array = NULL;
1279
1280    if (mntent)
1281    {
1282        gen_mutex_lock(&s_stat_tab_mutex);
1283
1284        /*
1285          we exhaustively scan to be sure this mnt entry *does* exist
1286          somewhere in our book keeping
1287        */
1288        for(i = 0; i < s_stat_tab_count; i++)
1289        {
1290            for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
1291            {
1292                current_mnt = &(s_stat_tab_array[i].mntent_array[j]);
1293                if ((current_mnt->fs_id == mntent->fs_id)
1294                    && (strcmp(current_mnt->mnt_dir, mntent->mnt_dir) == 0))
1295                {
1296                    found_index = i;
1297                    found = 1;
1298                    goto mntent_found;
1299                }
1300            }
1301        }
1302
1303        /* check the dynamic region if we haven't found a match yet */
1304        for(j = 0; j < s_stat_tab_array[
1305                PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
1306        {
1307            current_mnt = &(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].
1308                            mntent_array[j]);
1309
1310            if (current_mnt->fs_id == mntent->fs_id)
1311            {
1312                found_index = PVFS2_DYNAMIC_TAB_INDEX;
1313                found = 1;
1314                goto mntent_found;
1315            }
1316        }
1317
1318      mntent_found:
1319        if (!found)
1320        {
1321            return -PVFS_EINVAL;
1322        }
1323
1324        gossip_debug(GOSSIP_CLIENT_DEBUG, "* Removing mount "
1325                     "point %s [%d,%d]\n", current_mnt->mnt_dir,
1326                     found_index, j);
1327
1328        /* remove the mntent from our table in the found tab area */
1329        if ((s_stat_tab_array[found_index].mntent_count - 1) > 0)
1330        {
1331            /*
1332              this is 1 minus the old count since there will be 1 less
1333              mnt entries after this call
1334            */
1335            new_count = s_stat_tab_array[found_index].mntent_count - 1;
1336
1337            /* we need to re-alloc this guy to remove the array entry */
1338            tmp_mnt_array = (struct PVFS_sys_mntent *)malloc(
1339                (new_count * sizeof(struct PVFS_sys_mntent)));
1340            if (!tmp_mnt_array)
1341            {
1342                return -PVFS_ENOMEM;
1343            }
1344
1345            /*
1346              copy all mntent entries into the new array, freeing the
1347              original entries -- and skipping the one that we're
1348              trying to remove
1349            */
1350            for(i = 0, new_count = 0;
1351                i < s_stat_tab_array[found_index].mntent_count; i++)
1352            {
1353                current_mnt = &s_stat_tab_array[found_index].mntent_array[i];
1354
1355                if ((current_mnt->fs_id == mntent->fs_id)
1356                    && (strcmp(current_mnt->mnt_dir, mntent->mnt_dir) == 0))
1357                {
1358                    PVFS_util_free_mntent(current_mnt);
1359                    continue;
1360                }
1361                PVFS_util_copy_mntent(
1362                            &tmp_mnt_array[new_count++], current_mnt);
1363                PVFS_util_free_mntent(current_mnt);
1364            }
1365
1366            /* finally, swap the mntent arrays */
1367            free(s_stat_tab_array[found_index].mntent_array);
1368            s_stat_tab_array[found_index].mntent_array = tmp_mnt_array;
1369
1370            s_stat_tab_array[found_index].mntent_count--;
1371            ret = 0;
1372        }
1373        else
1374        {
1375            /*
1376              special case: we're removing the last mnt entry in the
1377              array here.  since this is the case, we also free the
1378              array since we know it's now empty.
1379            */
1380            PVFS_util_free_mntent(
1381                        &s_stat_tab_array[found_index].mntent_array[0]);
1382            free(s_stat_tab_array[found_index].mntent_array);
1383            s_stat_tab_array[found_index].mntent_array = NULL;
1384            s_stat_tab_array[found_index].mntent_count = 0;
1385            ret = 0;
1386        }
1387        gen_mutex_unlock(&s_stat_tab_mutex);
1388    }
1389    return ret;
1390}
1391
1392/*
1393 * PVFS_util_get_mntent_copy()
1394 *
1395 * Given a pointer to a valid mount entry, out_mntent, copy the contents of
1396 * the mount entry  for fs_id into out_mntent.
1397 *
1398 * returns 0 on success, -PVFS_error on failure
1399 */
1400int PVFS_util_get_mntent_copy(PVFS_fs_id fs_id,
1401                              struct PVFS_sys_mntent *out_mntent)
1402{
1403    int i = 0;
1404
1405    /* Search for mntent by fsid */
1406    gen_mutex_lock(&s_stat_tab_mutex);
1407    for(i = 0; i < s_stat_tab_count; i++)
1408    {
1409        int j;
1410        for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
1411        {
1412            struct PVFS_sys_mntent* mnt_iter;
1413            mnt_iter = &(s_stat_tab_array[i].mntent_array[j]);
1414
1415            if (mnt_iter->fs_id == fs_id)
1416            {
1417                PVFS_util_copy_mntent(out_mntent, mnt_iter);
1418                gen_mutex_unlock(&s_stat_tab_mutex);
1419                return 0;
1420            }
1421        }
1422    }
1423
1424    /* check the dynamic region if we haven't found a match yet */
1425    for (i = 0; i < s_stat_tab_array[
1426             PVFS2_DYNAMIC_TAB_INDEX].mntent_count; i++)
1427    {
1428        struct PVFS_sys_mntent *mnt_iter;
1429        mnt_iter = &(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].
1430                     mntent_array[i]);
1431
1432        if (mnt_iter->fs_id == fs_id)
1433        {
1434            PVFS_util_copy_mntent(out_mntent, mnt_iter);
1435            gen_mutex_unlock(&s_stat_tab_mutex);
1436            return 0;
1437        }
1438    }
1439
1440    gen_mutex_unlock(&s_stat_tab_mutex);
1441    return -PVFS_EINVAL;
1442}
1443
1444/* PVFS_util_resolve()
1445 *
1446 * given a local path of a file that resides on a pvfs2 volume,
1447 * determine what the fsid and fs relative path is. 
1448 *
1449 * returns 0 on succees, -PVFS_error on failure
1450 */
1451int PVFS_util_resolve(
1452    const char* local_path,
1453    PVFS_fs_id* out_fs_id,
1454    char* out_fs_path,
1455    int out_fs_path_max)
1456{
1457    int ret = -1;
1458    char* tmp_path = NULL;
1459    char* parent_path = NULL;
1460    int base_len = 0;
1461
1462    if(strlen(local_path) > (PVFS_PATH_MAX-1))
1463    {
1464        gossip_err("Error: PVFS_util_resolve() input path too long.\n");
1465        return(-PVFS_ENAMETOOLONG);
1466    }
1467
1468    /* the most common case first; just try to resolve the path that we
1469     * were given
1470     */
1471    ret = PVFS_util_resolve_absolute(local_path, out_fs_id, out_fs_path,
1472                                     out_fs_path_max);
1473    if(ret == 0)
1474    {
1475        /* done */
1476        return(0);
1477    }
1478    if(ret == -PVFS_ENOENT)
1479    {
1480        /* if the path wasn't found, try canonicalizing the path in case it
1481         * refers to a relative path on a mounted volume or contains symlinks
1482         */
1483        tmp_path = (char*)malloc(PVFS_PATH_MAX * sizeof(char));
1484        if(!tmp_path)
1485        {
1486            return(-PVFS_ENOMEM);
1487        }
1488        memset(tmp_path, 0, PVFS_PATH_MAX * sizeof(char));
1489        ret = PINT_realpath(local_path, tmp_path, (PVFS_PATH_MAX - 1));
1490        if(ret == -PVFS_EINVAL)
1491        {
1492            /* one more try; canonicalize the parent in case this function
1493             * is called before object creation; the basename
1494             * doesn't yet exist but we still need to find the PVFS volume
1495             */
1496            parent_path = (char *)malloc(PVFS_PATH_MAX * sizeof(char));
1497            if(!parent_path)
1498            {
1499                free(tmp_path);
1500                return(-PVFS_ENOMEM);
1501            }
1502            /* find size of basename so we can reserve space for it */
1503            /* note: basename() and dirname() modifiy args, thus the strcpy */
1504            strcpy(parent_path, local_path);
1505            base_len = strlen(basename(parent_path));
1506            strcpy(parent_path, local_path);
1507            ret = PINT_realpath(dirname(parent_path), tmp_path,
1508                               (PVFS_PATH_MAX - base_len - 2));
1509            if(ret < 0)
1510            {
1511                free(tmp_path);
1512                free(parent_path);
1513                /* last chance failed; this is not a valid pvfs2 path */
1514                return(-PVFS_ENOENT);
1515            }
1516            /* glue the basename back on */
1517            strcpy(parent_path, local_path);
1518            strcat(tmp_path, "/");
1519            strcat(tmp_path, basename(parent_path));
1520            free(parent_path);
1521        }
1522        else if(ret < 0)
1523        {
1524            /* first canonicalize failed; this is not a valid pvfs2 path */
1525            free(tmp_path);
1526            return(-PVFS_ENOENT);
1527        }
1528
1529        ret = PVFS_util_resolve_absolute(tmp_path, out_fs_id, out_fs_path,
1530                                         out_fs_path_max);
1531        free(tmp_path);
1532
1533        /* fall through and preserve "ret" to be returned */
1534    }
1535
1536    return(ret);
1537}
1538
1539
1540/* PVFS_util_init_defaults()
1541 *
1542 * performs the standard set of initialization steps for the system
1543 * interface, mostly just a wrapper function
1544 *
1545 * returns 0 on success, -PVFS_error on failure
1546 */
1547int PVFS_util_init_defaults(void)
1548{
1549    int ret = -1, i = 0, j = 0, found_one = 0;
1550    int failed_indices[PVFS2_MAX_INVALID_MNTENTS] = {0};
1551
1552    /* use standard system tab files */
1553    const PVFS_util_tab* tab = PVFS_util_parse_pvfstab(NULL);
1554    if (!tab)
1555    {
1556        gossip_err(
1557            "Error: failed to find any pvfs2 file systems in the "
1558            "standard system tab files.\n");
1559        return(-PVFS_ENOENT);
1560    }
1561
1562    /* initialize pvfs system interface */
1563    ret = PVFS_sys_initialize(GOSSIP_NO_DEBUG);
1564    if (ret < 0)
1565    {
1566        return(ret);
1567    }
1568
1569    /* add in any file systems we found in the fstab */
1570    for(i = 0; i < tab->mntent_count; i++)
1571    {
1572        ret = PVFS_sys_fs_add(&tab->mntent_array[i]);
1573        if (ret == 0)
1574        {
1575            found_one = 1;
1576        }
1577        else
1578        {
1579            failed_indices[j++] = i;
1580
1581            if (j > (PVFS2_MAX_INVALID_MNTENTS - 1))
1582            {
1583                gossip_err("*** Failed to initialize %d file systems "
1584                           "from tab file %s.\n ** If this is a valid "
1585                           "tabfile, please remove invalid entries.\n",
1586                           PVFS2_MAX_INVALID_MNTENTS,
1587                           tab->tabfile_name);
1588                gossip_err("Continuing execution without remaining "
1589                           "mount entries\n");
1590               
1591                break;
1592            }
1593        }
1594    }
1595
1596    /* remove any mount entries that couldn't be added here */
1597    for(i = 0; i < PVFS2_MAX_INVALID_MNTENTS; i++)
1598    {
1599        if (failed_indices[i])
1600        {
1601            PVFS_util_remove_internal_mntent(
1602                &tab->mntent_array[failed_indices[i]]);
1603        }
1604        else
1605        {
1606            break;
1607        }
1608    }
1609
1610    if (found_one)
1611    {
1612        return 0;
1613    }
1614
1615    gossip_err("ERROR: could not initialize any file systems "
1616               "in %s.\n", tab->tabfile_name);
1617
1618    PVFS_sys_finalize();
1619    return -PVFS_ENODEV;
1620}
1621
1622/*********************/
1623/* normal size units */
1624/*********************/
1625#define KILOBYTE                1024
1626#define MEGABYTE   (1024 * KILOBYTE)
1627#define GIGABYTE   (1024 * MEGABYTE)
1628#define TERABYTE   (1024llu * GIGABYTE)
1629#define PETABYTE   (1024llu * TERABYTE)
1630#define EXABYTE    (1024llu * PETABYTE)
1631#define ZETTABYTE  (1024llu * EXABYTE)
1632#define YOTTABYTE  (1024llu * ZETTABYTE)
1633
1634/*****************/
1635/* si size units */
1636/*****************/
1637#define SI_KILOBYTE                   1000
1638#define SI_MEGABYTE   (1000 * SI_KILOBYTE)
1639#define SI_GIGABYTE   (1000 * SI_MEGABYTE)
1640#define SI_TERABYTE  (1000llu * SI_GIGABYTE)
1641#define SI_PETABYTE  (1000llu * SI_TERABYTE)
1642#define SI_EXABYTE   (1000llu * SI_PETABYTE)
1643#define SI_ZETTABYTE (1000llu * SI_EXABYTE)
1644#define SI_YOTTABYTE (1000llu * SI_ZETTABYTE)
1645
1646#if SIZEOF_LONG_INT == 8
1647#define NUM_SIZES                  5
1648#else
1649#define NUM_SIZES                  4
1650#endif
1651
1652static PVFS_size PINT_s_size_table[NUM_SIZES] =
1653{
1654    /*YOTTABYTE, ZETTABYTE, EXABYTE, */
1655#if SIZEOF_LONG_INT == 8
1656    PETABYTE,
1657    TERABYTE,
1658#endif
1659    GIGABYTE, MEGABYTE, KILOBYTE
1660};
1661
1662static PVFS_size PINT_s_si_size_table[NUM_SIZES] =
1663{
1664    /*SI_YOTTABYTE, SI_ZETTABYTE, SI_EXABYTE, */
1665#if SIZEOF_LONG_INT == 8
1666    SI_PETABYTE, SI_TERABYTE,
1667#endif
1668    SI_GIGABYTE, SI_MEGABYTE, SI_KILOBYTE
1669};
1670
1671static const char *PINT_s_str_size_table[NUM_SIZES] =
1672{
1673    /*"Y", "Z", "E", */
1674#if SIZEOF_LONG_INT == 8
1675    "P","T",
1676#endif
1677    "G", "M", "K"
1678};
1679
1680/*
1681 * PVFS_util_make_size_human_readable
1682 *
1683 * converts a size value to a human readable string format
1684 *
1685 * size         - numeric size of file
1686 * out_str      - nicely formatted string, like "3.4M"
1687 *                  (caller must allocate this string)
1688 * max_out_len  - maximum lenght of out_str
1689 * use_si_units - use units of 1000, not 1024
1690 */
1691void PVFS_util_make_size_human_readable(
1692    PVFS_size size,
1693    char *out_str,
1694    int max_out_len,
1695    int use_si_units)
1696{
1697    int i = 0;
1698    double tmp = 0.0f;
1699    PVFS_size *size_table =
1700        (use_si_units? PINT_s_si_size_table : PINT_s_size_table);
1701
1702    if (out_str)
1703    {
1704        for (i = 0; i < NUM_SIZES; i++)
1705        {
1706            tmp = (double)size;
1707            if ((PVFS_size) (tmp / size_table[i]) > 0)
1708            {
1709                tmp = (tmp / size_table[i]);
1710                break;
1711            }
1712        }
1713        if (i == NUM_SIZES)
1714        {
1715            snprintf(out_str, 16, "%lld", lld(size));
1716        }
1717        else
1718        {
1719            snprintf(out_str, max_out_len, "%.1f%s",
1720                     tmp, PINT_s_str_size_table[i]);
1721        }
1722    }
1723}
1724
1725/* parse_flowproto_string()
1726 *
1727 * looks in the mount options string for a flowprotocol specifier and
1728 * sets the flowproto type accordingly
1729 *
1730 * returns 0 on success, -PVFS_error on failure
1731 */
1732static int parse_flowproto_string(
1733    const char *input,
1734    enum PVFS_flowproto_type *flowproto)
1735{
1736    int ret = 0;
1737    char *start = NULL;
1738    char flow[256];
1739    char *comma = NULL;
1740
1741    start = strstr(input, "flowproto");
1742    /* we must find a match if this function is being called... */
1743    assert(start);
1744
1745    /* scan out the option */
1746    ret = sscanf(start, "flowproto = %255s ,", flow);
1747    if (ret != 1)
1748    {
1749        gossip_err("Error: malformed flowproto option in tab file.\n");
1750        return (-PVFS_EINVAL);
1751    }
1752
1753    /* chop it off at any trailing comma */
1754    comma = index(flow, ',');
1755    if (comma)
1756    {
1757        comma[0] = '\0';
1758    }
1759
1760    if (!strcmp(flow, "dump_offsets"))
1761    {
1762        *flowproto = FLOWPROTO_DUMP_OFFSETS;
1763    }
1764    else if (!strcmp(flow, "bmi_cache"))
1765    {
1766        *flowproto = FLOWPROTO_BMI_CACHE;
1767    }
1768    else if (!strcmp(flow, "multiqueue"))
1769    {
1770        *flowproto = FLOWPROTO_MULTIQUEUE;
1771    }
1772    else
1773    {
1774        gossip_err("Error: unrecognized flowproto option: %s\n", flow);
1775        return (-PVFS_EINVAL);
1776    }
1777    return 0;
1778}
1779
1780void PVFS_util_free_mntent(
1781    struct PVFS_sys_mntent *mntent)
1782{
1783    if (mntent)
1784    {
1785        if (mntent->pvfs_config_servers)
1786        {
1787            int j;
1788            for (j=0; j<mntent->num_pvfs_config_servers; j++)
1789            {           
1790                if (mntent->pvfs_config_servers[j])
1791                {
1792                    if (mntent->pvfs_config_servers[j] ==
1793                        mntent->the_pvfs_config_server)
1794                    {
1795                        /* don't free further down */
1796                        mntent->the_pvfs_config_server = NULL;
1797                    }
1798                    free(mntent->pvfs_config_servers[j]);
1799                }
1800            }
1801            free(mntent->pvfs_config_servers);
1802            mntent->pvfs_config_servers = NULL;
1803            mntent->num_pvfs_config_servers = 0;
1804        }
1805        if (mntent->pvfs_fs_name)
1806        {
1807            free(mntent->pvfs_fs_name);
1808            mntent->pvfs_fs_name = NULL;
1809        }
1810        if (mntent->mnt_dir)
1811        {
1812            free(mntent->mnt_dir);
1813            mntent->mnt_dir = NULL;
1814        }
1815        if (mntent->mnt_opts)
1816        {
1817            free(mntent->mnt_opts);
1818            mntent->mnt_opts = NULL;
1819        }
1820        if (mntent->the_pvfs_config_server)           
1821        {
1822            free(mntent->the_pvfs_config_server);
1823            mntent->the_pvfs_config_server = NULL;
1824        }
1825
1826        mntent->flowproto = 0;
1827        mntent->encoding = 0;
1828        mntent->fs_id = PVFS_FS_ID_NULL;
1829    }   
1830}
1831
1832int PVFS_util_copy_mntent(
1833    struct PVFS_sys_mntent *dest_mntent,
1834    struct PVFS_sys_mntent *src_mntent)
1835{
1836    int ret = -PVFS_EINVAL, i = 0;
1837
1838    if (dest_mntent && src_mntent)
1839    {
1840        memset(dest_mntent, 0, sizeof(struct PVFS_sys_mntent));
1841
1842        dest_mntent->num_pvfs_config_servers =
1843            src_mntent->num_pvfs_config_servers;
1844
1845        dest_mntent->pvfs_config_servers =
1846            malloc(dest_mntent->num_pvfs_config_servers *
1847                   sizeof(*dest_mntent->pvfs_config_servers));
1848        if (!dest_mntent)
1849        {
1850            return -PVFS_ENOMEM;
1851        }
1852
1853        memset(dest_mntent->pvfs_config_servers, 0,
1854               dest_mntent->num_pvfs_config_servers *
1855               sizeof(*dest_mntent->pvfs_config_servers));
1856
1857        for(i = 0; i < dest_mntent->num_pvfs_config_servers; i++)
1858        {
1859            dest_mntent->pvfs_config_servers[i] =
1860                strdup(src_mntent->pvfs_config_servers[i]);
1861            if (!dest_mntent->pvfs_config_servers[i])
1862            {
1863                ret = -PVFS_ENOMEM;
1864                goto error_exit;
1865            }
1866        }
1867
1868        dest_mntent->the_pvfs_config_server =
1869            strdup(src_mntent->the_pvfs_config_server);
1870        if (!dest_mntent->the_pvfs_config_server)
1871        {
1872            ret = -PVFS_ENOMEM;
1873            goto error_exit;
1874        }
1875
1876        dest_mntent->pvfs_fs_name = strdup(src_mntent->pvfs_fs_name);
1877        if (!dest_mntent->pvfs_fs_name)
1878        {
1879            ret = -PVFS_ENOMEM;
1880            goto error_exit;
1881        }
1882
1883        if (src_mntent->mnt_dir)
1884        {
1885            dest_mntent->mnt_dir = strdup(src_mntent->mnt_dir);
1886            if (!dest_mntent->mnt_dir)
1887            {
1888                ret = -PVFS_ENOMEM;
1889                goto error_exit;
1890            }
1891        }
1892
1893        if (src_mntent->mnt_opts)
1894        {
1895            dest_mntent->mnt_opts = strdup(src_mntent->mnt_opts);
1896            if (!dest_mntent->mnt_opts)
1897            {
1898                ret = -PVFS_ENOMEM;
1899                goto error_exit;
1900            }
1901        }
1902
1903        dest_mntent->flowproto = src_mntent->flowproto;
1904        dest_mntent->encoding = src_mntent->encoding;
1905        dest_mntent->fs_id = src_mntent->fs_id;
1906        dest_mntent->default_num_dfiles = src_mntent->default_num_dfiles;
1907    }
1908    return 0;
1909
1910  error_exit:
1911
1912    for(i = 0; i < dest_mntent->num_pvfs_config_servers; i++)
1913    {
1914        if (dest_mntent->pvfs_config_servers[i])
1915        {
1916            free(dest_mntent->pvfs_config_servers[i]);
1917            dest_mntent->pvfs_config_servers[i] = NULL;
1918        }
1919    }
1920
1921    if (dest_mntent->pvfs_config_servers)
1922    {
1923        free(dest_mntent->pvfs_config_servers);
1924        dest_mntent->pvfs_config_servers = NULL;
1925    }
1926
1927    if (dest_mntent->pvfs_fs_name)
1928    {
1929        free(dest_mntent->pvfs_fs_name);
1930        dest_mntent->pvfs_fs_name = NULL;
1931    }
1932
1933    if (dest_mntent->mnt_dir)
1934    {
1935        free(dest_mntent->mnt_dir);
1936        dest_mntent->mnt_dir = NULL;
1937    }
1938
1939    if (dest_mntent->mnt_opts)
1940    {
1941        free(dest_mntent->mnt_opts);
1942        dest_mntent->mnt_opts = NULL;
1943    }
1944    return ret;
1945}
1946
1947/*
1948 * Pull out the wire encoding specified as a mount option in the tab
1949 * file.
1950 *
1951 * Input string is not modified; result goes into et.
1952 *
1953 * Returns 0 if all okay.
1954 */
1955static int parse_encoding_string(
1956    const char *cp,
1957    enum PVFS_encoding_type *et)
1958{
1959    int i = 0;
1960    const char *cq = NULL;
1961
1962    struct
1963    {
1964        const char *name;
1965        enum PVFS_encoding_type val;
1966    } enc_str[] =
1967        { { "default", PVFS2_ENCODING_DEFAULT },
1968          { "defaults", PVFS2_ENCODING_DEFAULT },
1969          { "direct", ENCODING_DIRECT },
1970          { "le_bfield", ENCODING_LE_BFIELD },
1971          { "xdr", ENCODING_XDR } };
1972
1973    gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: input is %s\n",
1974                 __func__, cp);
1975    cp += strlen("encoding");
1976    for (; isspace(*cp); cp++);        /* optional spaces */
1977    if (*cp != '=')
1978    {
1979        gossip_err("Error: %s: malformed encoding option in tab file.\n",
1980                   __func__);
1981        return -PVFS_EINVAL;
1982    }
1983    for (++cp; isspace(*cp); cp++);        /* optional spaces */
1984    for (cq = cp; *cq && *cq != ','; cq++);/* find option end */
1985
1986    *et = -1;
1987    for (i = 0; i < sizeof(enc_str) / sizeof(enc_str[0]); i++)
1988    {
1989        int n = strlen(enc_str[i].name);
1990        if (cq - cp > n)
1991            n = cq - cp;
1992        if (!strncmp(enc_str[i].name, cp, n))
1993        {
1994            *et = enc_str[i].val;
1995            break;
1996        }
1997    }
1998    if (*et == -1)
1999    {
2000        gossip_err("Error: %s: unknown encoding type in tab file.\n",
2001                   __func__);
2002        return -PVFS_EINVAL;
2003    }
2004    return 0;
2005}
2006
2007/* PINT_release_pvfstab()
2008 *
2009 * frees up any resources associated with previously parsed tabfiles
2010 *
2011 * no return value
2012 */
2013void PINT_release_pvfstab(void)
2014{
2015    int i, j;
2016
2017    gen_mutex_lock(&s_stat_tab_mutex);
2018    for(i = 0; i < s_stat_tab_count; i++)
2019    {
2020        for (j = 0; j < s_stat_tab_array[i].mntent_count; j++)
2021        {
2022            if (s_stat_tab_array[i].mntent_array[j].fs_id !=
2023                PVFS_FS_ID_NULL)
2024            {
2025                PVFS_util_free_mntent(
2026                    &s_stat_tab_array[i].mntent_array[j]);
2027            }
2028        }
2029        free(s_stat_tab_array[i].mntent_array);
2030    }
2031    s_stat_tab_count = 0;
2032
2033    for (j = 0; j < s_stat_tab_array[
2034             PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
2035    {
2036        if (s_stat_tab_array[
2037                PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].fs_id !=
2038            PVFS_FS_ID_NULL)
2039        {
2040            PVFS_util_free_mntent(
2041                &s_stat_tab_array[
2042                    PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j]);
2043        }
2044    }
2045    if (s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array)
2046    {
2047        free(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array);
2048    }
2049
2050    gen_mutex_unlock(&s_stat_tab_mutex);
2051}
2052
2053uint32_t PVFS_util_sys_to_object_attr_mask(
2054    uint32_t sys_attrmask)
2055{
2056
2057    /*
2058      adjust parameters as necessary; what's happening here
2059      is that we're converting sys_attr masks to obj_attr masks
2060      before passing the getattr request to the server.
2061    */
2062    uint32_t attrmask = 0;
2063    if (sys_attrmask & PVFS_ATTR_SYS_SIZE)
2064    {
2065        /* need datafile handles and distribution in order to get
2066         * datafile handles and know what function to call to get
2067         * the file size.
2068         */
2069        attrmask |= (PVFS_ATTR_META_ALL | PVFS_ATTR_DATA_SIZE);
2070    }
2071
2072    if (sys_attrmask & PVFS_ATTR_SYS_DFILE_COUNT)
2073    {
2074        attrmask |= (PVFS_ATTR_META_DFILES | PVFS_ATTR_META_MIRROR_DFILES);
2075    }
2076    if (sys_attrmask & PVFS_ATTR_SYS_MIRROR_COPIES_COUNT)
2077    {
2078        attrmask |= PVFS_ATTR_META_MIRROR_DFILES;
2079    }
2080
2081    if (sys_attrmask & PVFS_ATTR_SYS_DIRENT_COUNT)
2082    {
2083        attrmask |= PVFS_ATTR_DIR_DIRENT_COUNT;
2084    }
2085
2086    if (sys_attrmask & PVFS_ATTR_SYS_DIR_HINT)
2087    {
2088        attrmask |= PVFS_ATTR_DIR_HINT;
2089    }
2090
2091    if (sys_attrmask & PVFS_ATTR_SYS_LNK_TARGET)
2092    {
2093        attrmask |= PVFS_ATTR_SYMLNK_TARGET;
2094    }
2095
2096    /* we need the distribution in order to calculate block size */
2097    if (sys_attrmask & PVFS_ATTR_SYS_BLKSIZE)
2098    {
2099        attrmask |= PVFS_ATTR_META_DIST;
2100    }
2101
2102    if (sys_attrmask & PVFS_ATTR_SYS_CAPABILITY)
2103    {
2104        attrmask |= PVFS_ATTR_CAPABILITY;
2105    }
2106
2107    if(sys_attrmask & PVFS_ATTR_SYS_UID)
2108        attrmask |= PVFS_ATTR_COMMON_UID;
2109    if(sys_attrmask & PVFS_ATTR_SYS_GID)
2110        attrmask |= PVFS_ATTR_COMMON_GID;
2111    if(sys_attrmask & PVFS_ATTR_SYS_PERM)
2112        attrmask |= PVFS_ATTR_COMMON_PERM;
2113    if(sys_attrmask & PVFS_ATTR_SYS_ATIME)
2114        attrmask |= PVFS_ATTR_COMMON_ATIME;
2115    if(sys_attrmask & PVFS_ATTR_SYS_CTIME)
2116        attrmask |= PVFS_ATTR_COMMON_CTIME;
2117    if(sys_attrmask & PVFS_ATTR_SYS_MTIME)
2118        attrmask |= PVFS_ATTR_COMMON_MTIME;
2119    if(sys_attrmask & PVFS_ATTR_SYS_TYPE)
2120        attrmask |= PVFS_ATTR_COMMON_TYPE;
2121    if(sys_attrmask & PVFS_ATTR_SYS_ATIME_SET)
2122        attrmask |= PVFS_ATTR_COMMON_ATIME_SET;
2123    if(sys_attrmask & PVFS_ATTR_SYS_MTIME_SET)
2124        attrmask |= PVFS_ATTR_COMMON_MTIME_SET;
2125
2126    gossip_debug(GOSSIP_GETATTR_DEBUG,
2127                 "attrmask being passed to server: ");
2128    PINT_attrmask_print(GOSSIP_GETATTR_DEBUG, attrmask);
2129
2130    return attrmask;
2131}
2132
2133uint32_t PVFS_util_object_to_sys_attr_mask(
2134    uint32_t obj_mask)
2135{
2136    int sys_mask = 0;
2137
2138    if (obj_mask & PVFS_ATTR_COMMON_UID)
2139    {
2140        sys_mask |= PVFS_ATTR_SYS_UID;
2141    }
2142    if (obj_mask & PVFS_ATTR_COMMON_GID)
2143    {
2144        sys_mask |= PVFS_ATTR_SYS_GID;
2145    }
2146    if (obj_mask & PVFS_ATTR_COMMON_PERM)
2147    {
2148        sys_mask |= PVFS_ATTR_SYS_PERM;
2149    }
2150    if (obj_mask & PVFS_ATTR_COMMON_ATIME)
2151    {
2152        sys_mask |= PVFS_ATTR_SYS_ATIME;
2153    }
2154    if (obj_mask & PVFS_ATTR_COMMON_CTIME)
2155    {
2156        sys_mask |= PVFS_ATTR_SYS_CTIME;
2157    }
2158    if (obj_mask & PVFS_ATTR_COMMON_MTIME)
2159    {
2160        sys_mask |= PVFS_ATTR_SYS_MTIME;
2161    }
2162    if (obj_mask & PVFS_ATTR_COMMON_TYPE)
2163    {
2164        sys_mask |= PVFS_ATTR_SYS_TYPE;
2165    }
2166    if (obj_mask & PVFS_ATTR_DATA_SIZE)
2167    {
2168        sys_mask |= PVFS_ATTR_DATA_SIZE;
2169    }
2170    if (obj_mask & PVFS_ATTR_SYMLNK_TARGET)
2171    {
2172        sys_mask |= PVFS_ATTR_SYS_LNK_TARGET;
2173    }
2174    if (obj_mask & PVFS_ATTR_DIR_DIRENT_COUNT)
2175    {
2176        sys_mask |= PVFS_ATTR_SYS_DIRENT_COUNT;
2177    }
2178    if (obj_mask & PVFS_ATTR_META_DFILES)
2179    {
2180        sys_mask |= PVFS_ATTR_SYS_DFILE_COUNT;
2181    }
2182    if (obj_mask & PVFS_ATTR_META_MIRROR_DFILES)
2183    {
2184        sys_mask |= PVFS_ATTR_SYS_MIRROR_COPIES_COUNT;
2185    }
2186    if (obj_mask & PVFS_ATTR_META_DIST)
2187    {
2188        sys_mask |= PVFS_ATTR_SYS_BLKSIZE;
2189    }
2190    if (obj_mask & PVFS_ATTR_DIR_HINT)
2191    {
2192        sys_mask |= PVFS_ATTR_SYS_DIR_HINT;
2193    }
2194    if (obj_mask & PVFS_ATTR_CAPABILITY)
2195    {
2196        sys_mask |= PVFS_ATTR_SYS_CAPABILITY;
2197    }
2198
2199    /* NOTE: the PVFS_ATTR_META_UNSTUFFED is intentionally not exposed
2200     * outside of the system interface
2201     */
2202    return sys_mask;
2203}
2204
2205/*
2206 * Pull out the wire encoding specified as a mount option in the tab
2207 * file.
2208 *
2209 * Input string is not modified; result goes into et.
2210 *
2211 * Returns 0 if all okay.
2212 */
2213static int parse_num_dfiles_string(const char* cp, int* num_dfiles)
2214{
2215    int parsed_value = 0;
2216    char* end_ptr = NULL;
2217
2218    gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: input is %s\n",
2219                 __func__, cp);
2220   
2221    cp += strlen("num_dfiles");
2222
2223    /* Skip optional spacing */
2224    for (; isspace(*cp); cp++);
2225   
2226    if (*cp != '=')
2227    {
2228        gossip_err("Error: %s: malformed num_dfiles option in tab file.\n",
2229                   __func__);
2230        return -PVFS_EINVAL;
2231    }
2232   
2233    /* Skip optional spacing */
2234    for (++cp; isspace(*cp); cp++);
2235
2236    parsed_value = strtol(cp, &end_ptr, 10);
2237
2238    /* If a numerica value was found, continue
2239       else, report an error */
2240    if (end_ptr != cp)
2241    {
2242        *num_dfiles = parsed_value;
2243    }
2244    else
2245    {
2246        gossip_err("Error: %s: malformed num_dfiles option in tab file.\n",
2247                   __func__);
2248        return -PVFS_EINVAL;
2249    }
2250
2251    return 0;
2252}
2253
2254/* PVFS_util_resolve_absolute()
2255 *
2256 * given a local path of a file that may reside on a pvfs2 volume,
2257 * determine what the fsid and fs relative path is. Makes no attempt
2258 * to canonicalize the path.
2259 *
2260 * returns 0 on succees, -PVFS_error on failure
2261 */
2262int PVFS_util_resolve_absolute(const char *local_path,
2263                               PVFS_fs_id *out_fs_id,
2264                               char *out_fs_path,
2265                               int out_fs_path_max)
2266{
2267    int i = 0, j = 0;
2268    int ret = -PVFS_EINVAL;
2269
2270    gen_mutex_lock(&s_stat_tab_mutex);
2271
2272    for(i = 0; i < s_stat_tab_count; i++)
2273    {
2274        for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
2275        {
2276            ret = PINT_remove_dir_prefix(
2277                           local_path,
2278                           s_stat_tab_array[i].mntent_array[j].mnt_dir,
2279                           out_fs_path,
2280                           out_fs_path_max);
2281            if(ret == 0)
2282            {
2283                *out_fs_id = s_stat_tab_array[i].mntent_array[j].fs_id;
2284                if(*out_fs_id == PVFS_FS_ID_NULL)
2285                {
2286                    gossip_err("Error: %s resides on a PVFS2 file system "
2287                    "that has not yet been initialized.\n", local_path);
2288
2289                    gen_mutex_unlock(&s_stat_tab_mutex);
2290                    return(-PVFS_ENXIO);
2291                }
2292                gen_mutex_unlock(&s_stat_tab_mutex);
2293                return(0);
2294            }
2295        }
2296    }
2297
2298    /* check the dynamic tab area if we haven't resolved anything yet */
2299    for(j = 0; j < s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
2300    {
2301        ret = PINT_remove_dir_prefix(
2302             local_path,
2303             s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].mnt_dir,
2304             out_fs_path,
2305             out_fs_path_max);
2306        if (ret == 0)
2307        {
2308            *out_fs_id =
2309                s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].fs_id;
2310            if(*out_fs_id == PVFS_FS_ID_NULL)
2311            {
2312                gossip_err("Error: %s resides on a PVFS2 file system "
2313                           "that has not yet been initialized.\n",
2314                           local_path);
2315
2316                gen_mutex_unlock(&s_stat_tab_mutex);
2317                return(-PVFS_ENXIO);
2318            }
2319            gen_mutex_unlock(&s_stat_tab_mutex);
2320            return(0);
2321        }
2322    }
2323
2324    gen_mutex_unlock(&s_stat_tab_mutex);
2325    return(-PVFS_ENOENT);
2326}
2327
2328#ifdef DEFINE_MY_GET_NEXT_FSENT
2329
2330static struct fstab *PINT_util_my_get_next_fsent(PINT_fstab_t *tab)
2331{
2332    char linestr[500];
2333    int linelen = 0;
2334    char *strtok_ctx;
2335    char *nexttok;
2336    PINT_fstab_entry_t *fsentry;
2337    if (!fgets(linestr, 500, tab))
2338    {
2339        return NULL;
2340    }
2341
2342    fsentry = malloc(sizeof(PINT_fstab_entry_t));
2343    if (!fsentry)
2344    {
2345        return NULL;
2346    }
2347    memset(fsentry, 0, sizeof(PINT_fstab_entry_t));
2348
2349    linelen = strlen(linestr);
2350    if (linestr[linelen - 1] == '\n')
2351    {
2352        linestr[linelen - 1] = 0;
2353    }
2354
2355    /* get the path string */
2356    nexttok = strtok_r(linestr, " \t", &strtok_ctx);
2357    if(!nexttok)
2358    {
2359        goto exit;
2360    }
2361    fsentry->fs_spec = strdup(nexttok);
2362
2363   
2364    /* get the mount point */
2365
2366    nexttok = strtok_r(NULL, " \t", &strtok_ctx);
2367    if(!nexttok)
2368    {
2369        goto exit;
2370    }
2371    fsentry->fs_file = strdup(nexttok);
2372
2373    /* get the fs type */
2374    nexttok = strtok_r(NULL, " \t", &strtok_ctx);
2375    if(!nexttok)
2376    {
2377        goto exit;
2378    }
2379    fsentry->fs_vfstype = strdup(nexttok);
2380
2381    /* get the mount opts */
2382    nexttok = strtok_r(NULL, " \t", &strtok_ctx);
2383    if(!nexttok)
2384    {
2385        goto exit;
2386    }
2387    fsentry->fs_mntops = strdup(nexttok);
2388
2389 exit:
2390    return fsentry;
2391}
2392
2393static void PINT_util_fsent_destroy(PINT_fstab_entry_t * entry)
2394{
2395    if(entry)
2396    {
2397        if(entry->fs_spec)
2398        {
2399            free(entry->fs_spec);
2400        }
2401
2402        if(entry->fs_file)
2403        {
2404            free(entry->fs_file);
2405        }
2406       
2407        if(entry->fs_vfstype)
2408        {
2409            free(entry->fs_vfstype);
2410        }
2411
2412        if(entry->fs_mntops)
2413        {
2414            free(entry->fs_mntops);
2415        }
2416
2417        if(entry->fs_type)
2418        {
2419            free(entry->fs_type);
2420        }
2421   
2422        free(entry);
2423    }
2424}
2425#endif /* DEFINE_MY_GET_NEXT_FSENT */
2426
2427int32_t PVFS_util_translate_mode(int mode, int suid)
2428{
2429    int ret = 0, i = 0;
2430#define NUM_MODES 11
2431    static int modes[NUM_MODES] =
2432    {
2433        S_IXOTH, S_IWOTH, S_IROTH,
2434        S_IXGRP, S_IWGRP, S_IRGRP,
2435        S_IXUSR, S_IWUSR, S_IRUSR,
2436        S_ISGID, S_ISUID
2437    };
2438    static int pvfs2_modes[NUM_MODES] =
2439    {
2440        PVFS_O_EXECUTE, PVFS_O_WRITE, PVFS_O_READ,
2441        PVFS_G_EXECUTE, PVFS_G_WRITE, PVFS_G_READ,
2442        PVFS_U_EXECUTE, PVFS_U_WRITE, PVFS_U_READ,
2443        PVFS_G_SGID,    PVFS_U_SUID
2444    };
2445
2446    for(i = 0; i < NUM_MODES; i++)
2447    {
2448        if (mode & modes[i])
2449        {
2450            ret |= pvfs2_modes[i];
2451        }
2452    }
2453    if (suid == 0 && (ret & PVFS_U_SUID))
2454    {
2455         ret &= ~PVFS_U_SUID;
2456    }
2457    return ret;
2458#undef NUM_MODES
2459}
2460
2461/*
2462 * Local variables:
2463 *  mode: c
2464 *  c-indent-level: 4
2465 *  c-basic-offset: 4
2466 * End:
2467 *
2468 * vim: ts=8 sts=4 sw=4 expandtab
2469 */
Note: See TracBrowser for help on using the browser.