OpenSolaris_b135/lib/libfsmgt/common/nfs_mntinfo.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <kvm.h>
#include <kstat.h>
#include <sys/types.h>
#include <sys/mnttab.h>
#include <sys/mntent.h>
#include <nfs/nfs.h>
#include <nfs/nfs_clnt.h>
#include <sys/mkdev.h>
#include <inttypes.h>
#include <sys/stat.h>


#include "libfsmgt.h"
#include "replica.h"

#define	IGNORE	0
#define	DEV	1

/*
 * Private variables
 */

static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL };

/*
 * Private method declarations
 */

static int ignore(char *);
static int get_kstat_info(nfs_mntlist_t *, int *);
static nfs_mntlist_t *get_mount_data(fs_mntlist_t *, int *);
static nfs_mntlist_t *get_nfs_info(fs_mntlist_t *, int *);
static nfs_mntlist_t *kstat_mount(nfs_mntlist_t *, kstat_t *);
static int load_kstat_data(kstat_ctl_t *, nfs_mntlist_t *, kstat_t *, int *);
static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *, int *);

/*
 * Public methods
 */

void
nfs_free_mntinfo_list(nfs_mntlist_t *list)
{
	nfs_mntlist_t *tmp;
	int i;

	while (list != NULL) {
		free(list->nml_resource);
		free(list->nml_mountp);
		free(list->nml_fstype);
		free(list->nml_mntopts);
		free(list->nml_time);
		for (i = 0; i < list->nml_failovercount; i++) {
			if (list->nml_failoverlist[i] != NULL)
				free(list->nml_failoverlist[i]);
		}
		free(list->nml_failoverlist);
		free(list->nml_securitymode);
		tmp = list->next;
		free(list);
		list = tmp;
	}
} /* nfs_free_mntinfo_list */

nfs_mntlist_t *
nfs_get_filtered_mount_list(char *resource, char *mountp, char *mntopts,
	char *time, boolean_t find_overlays, int *errp) {

	fs_mntlist_t	*fs_mount_list;
	nfs_mntlist_t	*nfs_mount_list;

	fs_mount_list = fs_get_filtered_mount_list(resource, mountp,
		MNTTYPE_NFS, mntopts, time, find_overlays, errp);
	if (fs_mount_list == NULL) {
		return (NULL);
	}

	if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
		fs_free_mount_list(fs_mount_list);
		return (NULL);
	}

	fs_free_mount_list(fs_mount_list);
	return (nfs_mount_list);
} /* nfs_get_filtered_mount_list */

nfs_mntlist_t *
nfs_get_mounts_by_mntopt(char *mntopt, boolean_t find_overlays, int *errp)
{
	fs_mntlist_t	*fs_mount_list;
	nfs_mntlist_t	*nfs_mount_list;

	fs_mount_list = fs_get_mounts_by_mntopt(mntopt, find_overlays, errp);
	if (fs_mount_list == NULL) {
		return (NULL);
	}

	if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
		fs_free_mount_list(fs_mount_list);
		return (NULL);
	}

	fs_free_mount_list(fs_mount_list);
	return (nfs_mount_list);
} /* nfs_get_mount_by_mntopt */

nfs_mntlist_t *
nfs_get_mount_list(int *errp)
{
	fs_mntlist_t *fs_mount_list;
	nfs_mntlist_t *nfs_mount_list;
	boolean_t find_overlays = B_TRUE;

	if ((fs_mount_list = fs_get_mount_list(find_overlays, errp)) == NULL) {
		fprintf(stderr, "nfs_mntinfo: Can't access mnttab. %s\n",
		    strerror(*errp));
		return (NULL);
	}

	if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
		fs_free_mount_list(fs_mount_list);
		return (NULL);
	}

	fs_free_mount_list(fs_mount_list);
	return (nfs_mount_list);
} /* nfs_get_mount_list */

/*
 * Private methods
 */

static int
get_kstat_info(nfs_mntlist_t *nfs_mntinfo, int *errp)
{
	kstat_ctl_t *libkstat_cookie = NULL;
	nfs_mntlist_t *mrp;
	kstat_t *ksp;

	if ((libkstat_cookie = kstat_open()) == NULL) {
		*errp = errno;
		fprintf(stderr,
		    "nfs_mntinfo: kstat_open(): can't open /dev/kstat.\n");
		return (-1);
	}
	/*
	 * Each kstat consists of header and data sections that are
	 * connected as a "chain" or linked list of kstat stuctures.
	 * The kc_chain used here is the pointer to the global kstat
	 * chain (or the head of the chain of kstat's).
	 */
	for (ksp = libkstat_cookie->kc_chain; ksp; ksp = ksp->ks_next) {
		if ((ksp->ks_type == KSTAT_TYPE_RAW) &&
		    (strcmp(ksp->ks_module, "nfs") == 0) &&
		    (strcmp(ksp->ks_name, "mntinfo") == 0) &&
		    ((mrp = kstat_mount(nfs_mntinfo, ksp)) != NULL)) {
			if (load_kstat_data(libkstat_cookie, mrp, ksp, errp)
			    == -1) {
				nfs_free_mntinfo_list(mrp);
				return (-1);
			}
		}
	}
	return (0);
} /* get_kstat_info */

static int
load_kstat_data(kstat_ctl_t *libkstat_cookie, nfs_mntlist_t *mrp,
    kstat_t *ksp, int *errp)
{
	struct mntinfo_kstat mik;
	seconfig_t nfs_sec;

	if (mrp == 0) {
		return (0);
	}

	if (safe_kstat_read(libkstat_cookie, ksp, &mik, errp) == -1) {
		return (-1);
	}

	if (strlcpy(mrp->nml_proto, mik.mik_proto, KNC_STRSIZE)
	    >= KNC_STRSIZE) {
		*errp = errno;
		return (-1);
	}
	if (strlcpy(mrp->nml_curserver, mik.mik_curserver, SYS_NMLN)
	    >= SYS_NMLN) {
		*errp = errno;
		return (-1);
	}
	mrp->nml_vers = mik.mik_vers;
	/*
	 *  get the secmode name from /etc/nfssec.conf.
	 */
	if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
		mrp->nml_securitymode = strdup(nfs_sec.sc_name);
	} else {
		mrp->nml_securitymode = NULL;
	}
	mrp->nml_curread = mik.mik_curread;
	mrp->nml_curwrite = mik.mik_curwrite;
	mrp->nml_timeo = mik.mik_timeo;
	mrp->nml_retrans = mik.mik_retrans;
	mrp->nml_acregmin = mik.mik_acregmin;
	mrp->nml_acregmax = mik.mik_acregmax;
	mrp->nml_acdirmin = mik.mik_acdirmin;
	mrp->nml_acdirmax = mik.mik_acdirmax;
	mrp->nml_hard =
	    ((mik.mik_flags & MI_HARD) ? B_TRUE : B_FALSE);
	mrp->nml_intr =
	    ((mik.mik_flags & MI_INT) ? B_TRUE : B_FALSE);
	mrp->nml_noac =
	    ((mik.mik_flags & MI_NOAC) ? B_TRUE : B_FALSE);
	mrp->nml_nocto =
	    ((mik.mik_flags & MI_NOCTO) ? B_TRUE : B_FALSE);
	mrp->nml_grpid =
	    ((mik.mik_flags & MI_GRPID) ? B_TRUE : B_FALSE);
	mrp->nml_directio =
	    ((mik.mik_flags & MI_DIRECTIO) ? B_TRUE : B_FALSE);
	mrp->nml_xattr =
	    ((mik.mik_flags & MI_EXTATTR) ? B_TRUE : B_FALSE);
	return (0);
}

nfs_mntlist_t *
kstat_mount(nfs_mntlist_t *nfs_mntinfo, kstat_t *ksp) {
	nfs_mntlist_t *mrp;
	/*
	 * MAXMIN is used to retrieve the minor number
	 * which is compared to the kstat instance.
	 * If they are the same then this is an instance
	 * for which mount information is needed.
	 * MAXMIN is the maximum minor number and is
	 * defined in mkdev.h.
	 */
	mrp = nfs_mntinfo;
	while ((mrp != NULL) &&
	    ((mrp->nml_fsid & MAXMIN) != ksp->ks_instance)) {
		mrp = mrp->next;
	}
	return (mrp);
}

static nfs_mntlist_t *
get_nfs_info(fs_mntlist_t *fslist, int *errp) {
	nfs_mntlist_t *mrp = NULL;
	nfs_mntlist_t *headptr = NULL;
	nfs_mntlist_t *tailptr = NULL;
	fs_mntlist_t *fsmnt_list;

	for (fsmnt_list = fslist; fsmnt_list; fsmnt_list = fsmnt_list->next) {
		/* ignore non "nfs" and the "ignore" entries */

		if ((strcmp(fsmnt_list->fstype, MNTTYPE_NFS) != 0) ||
		    (ignore(fsmnt_list->mntopts))) {
			continue;
		}

		if ((mrp = get_mount_data(fsmnt_list, errp)) == NULL) {
			nfs_free_mntinfo_list(headptr);
			return (NULL);
		}
		if (tailptr == NULL) {
			headptr = mrp;
			tailptr = mrp;
			tailptr->next = NULL;
		} else {
			tailptr->next = mrp;
			tailptr = mrp;
			tailptr->next = NULL;
		}
	}

	if (get_kstat_info(headptr, errp) == -1) {
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	return (headptr);

} /* get_nfs_info */


static nfs_mntlist_t *
get_mount_data(fs_mntlist_t *fsmnt_list, int *errp) {
	struct replica *rep_list; /* defined in replica.h */
	nfs_mntlist_t *mrp;
	int i, server_count = 0;
	struct stat	stat_buf;

	if ((mrp = malloc(sizeof (nfs_mntlist_t))) == 0) {
		*errp = errno;
		return (NULL);
	}

	if ((stat(fsmnt_list->mountp, &stat_buf) == 0)) {
		mrp->nml_fsid = stat_buf.st_dev;
	} else {
		*errp = errno;
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}

	if ((mrp->nml_resource = strdup(fsmnt_list->resource))
	    == NULL) {
		*errp = errno;
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	if ((rep_list =
	    parse_replica(mrp->nml_resource, &server_count)) == NULL) {
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	if ((mrp->nml_failoverlist =
	    calloc(server_count, sizeof (char *))) == NULL) {
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	for (i = 0; i < server_count; i++) {
		mrp->nml_failoverlist[i] =
		    malloc(strlen(rep_list[i].host) + strlen(":") +
		    strlen(rep_list[i].path) + 2);
		if (!mrp->nml_failoverlist[i]) {
			nfs_free_mntinfo_list(mrp);
			return (NULL);
		}
		sprintf(mrp->nml_failoverlist[i], "%s%s%s",
		    rep_list[i].host, ":", rep_list[i].path);
	}
	/*
	 * If the number of servers is not 1 then resource is
	 * either a failover list or there is an error. In either
	 * case the path can't be determined and curpath is set to
	 * unknown".
	 */
	if (server_count == 1) {
		if (strcmp(rep_list[0].host, "nfs") == 0) {
			char *path;
			char *last;
			path = strdup(rep_list[0].path);
			if ((path = (char *)strtok_r(path, "//",
			    &last)) != NULL) {
				strcpy(mrp->nml_curpath,
				    strcat("/", last));
			} else {
				/*
				 * If NULL is returned this is an
				 * invalid path entry. no path can
				 * be determined.
				 */
				strcpy(mrp->nml_curpath, "unknown");
			}
		} else {
			strcpy(mrp->nml_curpath,
			    (strchr(mrp->nml_failoverlist[0],
			    ':') + 1));
		}
	} else {
		/*
		 * more than one server in the failover list
		 * path can't be determined.
		 */
		strcpy(mrp->nml_curpath, "unknown");
	}

	mrp->nml_failovercount = server_count;

	for (i = 0; i < server_count; i++) {
		if (rep_list[i].host) {
			free(rep_list[i].host);
		}
		if (rep_list[i].path) {
			free(rep_list[i].path);
		}
	}
	free(rep_list);

	if ((mrp->nml_mountp = strdup(fsmnt_list->mountp)) == NULL) {
		*errp = errno;
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	if ((mrp->nml_fstype = strdup(fsmnt_list->fstype)) == NULL) {
		*errp = errno;
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	if ((mrp->nml_mntopts = strdup(fsmnt_list->mntopts)) == NULL) {
		*errp = errno;
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	if ((mrp->nml_time = strdup(fsmnt_list->time)) == NULL) {
		*errp = errno;
		nfs_free_mntinfo_list(mrp);
		return (NULL);
	}
	if (fsmnt_list->overlayed) {
		mrp->nml_overlayed = B_TRUE;
	} else {
		mrp->nml_overlayed = B_FALSE;
	}
	return (mrp);
} /* get_mount_data */

kid_t
safe_kstat_read(
	kstat_ctl_t *libkstat_cookie,
	kstat_t *ksp,
	void *data,
	int *errp)
{

	kid_t kstat_chain_id = kstat_read(libkstat_cookie, ksp, data);

	if (kstat_chain_id == -1) {
		*errp = errno;
		return (-1);
	}
	return (kstat_chain_id);
} /* safe_kstat_read */


/*
 * ignore - Checks for the ignore mount option in the mount opts string.
 * Returns 1 if the ignore option is found and 0 if not.
 */
static int
ignore(char *opts)
{
	char *value;
	char *s;
	char *tmp;

	if (opts == NULL)
		return (0);
	s = strdup(opts);
	if (s == NULL)
		return (0);

	tmp = s;

	while (*s != '\0') {
		if (getsubopt(&s, mntopts, &value) == IGNORE) {
			free(tmp);
			return (1);
		}
	}
	free(tmp);
	return (0);
} /* ignore */