2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <errno.h>
2N/A#include <fcntl.h>
2N/A#include <kvm.h>
2N/A#include <kstat.h>
2N/A#include <sys/types.h>
2N/A#include <sys/mnttab.h>
2N/A#include <sys/mntent.h>
2N/A#include <nfs/nfs.h>
2N/A#include <nfs/nfs_clnt.h>
2N/A#include <sys/mkdev.h>
2N/A#include <inttypes.h>
2N/A#include <sys/stat.h>
2N/A
2N/A
2N/A#include "libfsmgt.h"
2N/A#include "replica.h"
2N/A
2N/A#define IGNORE 0
2N/A#define DEV 1
2N/A
2N/A/*
2N/A * Private variables
2N/A */
2N/A
2N/Astatic char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL };
2N/A
2N/A/*
2N/A * Private method declarations
2N/A */
2N/A
2N/Astatic int ignore(char *);
2N/Astatic int get_kstat_info(nfs_mntlist_t *, int *);
2N/Astatic nfs_mntlist_t *get_mount_data(fs_mntlist_t *, int *);
2N/Astatic nfs_mntlist_t *get_nfs_info(fs_mntlist_t *, int *);
2N/Astatic nfs_mntlist_t *kstat_mount(nfs_mntlist_t *, kstat_t *);
2N/Astatic int load_kstat_data(kstat_ctl_t *, nfs_mntlist_t *, kstat_t *, int *);
2N/Astatic kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *, int *);
2N/A
2N/A/*
2N/A * Public methods
2N/A */
2N/A
2N/Avoid
2N/Anfs_free_mntinfo_list(nfs_mntlist_t *list)
2N/A{
2N/A nfs_mntlist_t *tmp;
2N/A int i;
2N/A
2N/A while (list != NULL) {
2N/A free(list->nml_resource);
2N/A free(list->nml_mountp);
2N/A free(list->nml_fstype);
2N/A free(list->nml_mntopts);
2N/A free(list->nml_time);
2N/A for (i = 0; i < list->nml_failovercount; i++) {
2N/A if (list->nml_failoverlist[i] != NULL)
2N/A free(list->nml_failoverlist[i]);
2N/A }
2N/A free(list->nml_failoverlist);
2N/A free(list->nml_securitymode);
2N/A tmp = list->next;
2N/A free(list);
2N/A list = tmp;
2N/A }
2N/A} /* nfs_free_mntinfo_list */
2N/A
2N/Anfs_mntlist_t *
2N/Anfs_get_filtered_mount_list(char *resource, char *mountp, char *mntopts,
2N/A char *time, boolean_t find_overlays, int *errp) {
2N/A
2N/A fs_mntlist_t *fs_mount_list;
2N/A nfs_mntlist_t *nfs_mount_list;
2N/A
2N/A fs_mount_list = fs_get_filtered_mount_list(resource, mountp,
2N/A MNTTYPE_NFS, mntopts, time, find_overlays, errp);
2N/A if (fs_mount_list == NULL) {
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
2N/A fs_free_mount_list(fs_mount_list);
2N/A return (NULL);
2N/A }
2N/A
2N/A fs_free_mount_list(fs_mount_list);
2N/A return (nfs_mount_list);
2N/A} /* nfs_get_filtered_mount_list */
2N/A
2N/Anfs_mntlist_t *
2N/Anfs_get_mounts_by_mntopt(char *mntopt, boolean_t find_overlays, int *errp)
2N/A{
2N/A fs_mntlist_t *fs_mount_list;
2N/A nfs_mntlist_t *nfs_mount_list;
2N/A
2N/A fs_mount_list = fs_get_mounts_by_mntopt(mntopt, find_overlays, errp);
2N/A if (fs_mount_list == NULL) {
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
2N/A fs_free_mount_list(fs_mount_list);
2N/A return (NULL);
2N/A }
2N/A
2N/A fs_free_mount_list(fs_mount_list);
2N/A return (nfs_mount_list);
2N/A} /* nfs_get_mount_by_mntopt */
2N/A
2N/Anfs_mntlist_t *
2N/Anfs_get_mount_list(int *errp)
2N/A{
2N/A fs_mntlist_t *fs_mount_list;
2N/A nfs_mntlist_t *nfs_mount_list;
2N/A boolean_t find_overlays = B_TRUE;
2N/A
2N/A if ((fs_mount_list = fs_get_mount_list(find_overlays, errp)) == NULL) {
2N/A fprintf(stderr, "nfs_mntinfo: Can't access mnttab. %s\n",
2N/A strerror(*errp));
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
2N/A fs_free_mount_list(fs_mount_list);
2N/A return (NULL);
2N/A }
2N/A
2N/A fs_free_mount_list(fs_mount_list);
2N/A return (nfs_mount_list);
2N/A} /* nfs_get_mount_list */
2N/A
2N/A/*
2N/A * Private methods
2N/A */
2N/A
2N/Astatic int
2N/Aget_kstat_info(nfs_mntlist_t *nfs_mntinfo, int *errp)
2N/A{
2N/A kstat_ctl_t *libkstat_cookie = NULL;
2N/A nfs_mntlist_t *mrp;
2N/A kstat_t *ksp;
2N/A
2N/A if ((libkstat_cookie = kstat_open()) == NULL) {
2N/A *errp = errno;
2N/A fprintf(stderr,
2N/A "nfs_mntinfo: kstat_open(): can't open /dev/kstat.\n");
2N/A return (-1);
2N/A }
2N/A /*
2N/A * Each kstat consists of header and data sections that are
2N/A * connected as a "chain" or linked list of kstat stuctures.
2N/A * The kc_chain used here is the pointer to the global kstat
2N/A * chain (or the head of the chain of kstat's).
2N/A */
2N/A for (ksp = libkstat_cookie->kc_chain; ksp; ksp = ksp->ks_next) {
2N/A if ((ksp->ks_type == KSTAT_TYPE_RAW) &&
2N/A (strcmp(ksp->ks_module, "nfs") == 0) &&
2N/A (strcmp(ksp->ks_name, "mntinfo") == 0) &&
2N/A ((mrp = kstat_mount(nfs_mntinfo, ksp)) != NULL)) {
2N/A if (load_kstat_data(libkstat_cookie, mrp, ksp, errp)
2N/A == -1) {
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (-1);
2N/A }
2N/A }
2N/A }
2N/A return (0);
2N/A} /* get_kstat_info */
2N/A
2N/Astatic int
2N/Aload_kstat_data(kstat_ctl_t *libkstat_cookie, nfs_mntlist_t *mrp,
2N/A kstat_t *ksp, int *errp)
2N/A{
2N/A struct mntinfo_kstat mik;
2N/A seconfig_t nfs_sec;
2N/A
2N/A if (mrp == 0) {
2N/A return (0);
2N/A }
2N/A
2N/A if (safe_kstat_read(libkstat_cookie, ksp, &mik, errp) == -1) {
2N/A return (-1);
2N/A }
2N/A
2N/A if (strlcpy(mrp->nml_proto, mik.mik_proto, KNC_STRSIZE)
2N/A >= KNC_STRSIZE) {
2N/A *errp = errno;
2N/A return (-1);
2N/A }
2N/A if (strlcpy(mrp->nml_curserver, mik.mik_curserver, SYS_NMLN)
2N/A >= SYS_NMLN) {
2N/A *errp = errno;
2N/A return (-1);
2N/A }
2N/A mrp->nml_vers = mik.mik_vers;
2N/A /*
2N/A * get the secmode name from /etc/nfssec.conf.
2N/A */
2N/A if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
2N/A mrp->nml_securitymode = strdup(nfs_sec.sc_name);
2N/A } else {
2N/A mrp->nml_securitymode = NULL;
2N/A }
2N/A mrp->nml_curread = mik.mik_curread;
2N/A mrp->nml_curwrite = mik.mik_curwrite;
2N/A mrp->nml_timeo = mik.mik_timeo;
2N/A mrp->nml_retrans = mik.mik_retrans;
2N/A mrp->nml_acregmin = mik.mik_acregmin;
2N/A mrp->nml_acregmax = mik.mik_acregmax;
2N/A mrp->nml_acdirmin = mik.mik_acdirmin;
2N/A mrp->nml_acdirmax = mik.mik_acdirmax;
2N/A mrp->nml_hard =
2N/A ((mik.mik_flags & MI_HARD) ? B_TRUE : B_FALSE);
2N/A mrp->nml_intr =
2N/A ((mik.mik_flags & MI_INT) ? B_TRUE : B_FALSE);
2N/A mrp->nml_noac =
2N/A ((mik.mik_flags & MI_NOAC) ? B_TRUE : B_FALSE);
2N/A mrp->nml_nocto =
2N/A ((mik.mik_flags & MI_NOCTO) ? B_TRUE : B_FALSE);
2N/A mrp->nml_grpid =
2N/A ((mik.mik_flags & MI_GRPID) ? B_TRUE : B_FALSE);
2N/A mrp->nml_directio =
2N/A ((mik.mik_flags & MI_DIRECTIO) ? B_TRUE : B_FALSE);
2N/A mrp->nml_xattr =
2N/A ((mik.mik_flags & MI_EXTATTR) ? B_TRUE : B_FALSE);
2N/A return (0);
2N/A}
2N/A
2N/Anfs_mntlist_t *
2N/Akstat_mount(nfs_mntlist_t *nfs_mntinfo, kstat_t *ksp) {
2N/A nfs_mntlist_t *mrp;
2N/A /*
2N/A * MAXMIN is used to retrieve the minor number
2N/A * which is compared to the kstat instance.
2N/A * If they are the same then this is an instance
2N/A * for which mount information is needed.
2N/A * MAXMIN is the maximum minor number and is
2N/A * defined in mkdev.h.
2N/A */
2N/A mrp = nfs_mntinfo;
2N/A while ((mrp != NULL) &&
2N/A ((mrp->nml_fsid & MAXMIN) != ksp->ks_instance)) {
2N/A mrp = mrp->next;
2N/A }
2N/A return (mrp);
2N/A}
2N/A
2N/Astatic nfs_mntlist_t *
2N/Aget_nfs_info(fs_mntlist_t *fslist, int *errp) {
2N/A nfs_mntlist_t *mrp = NULL;
2N/A nfs_mntlist_t *headptr = NULL;
2N/A nfs_mntlist_t *tailptr = NULL;
2N/A fs_mntlist_t *fsmnt_list;
2N/A
2N/A for (fsmnt_list = fslist; fsmnt_list; fsmnt_list = fsmnt_list->next) {
2N/A /* ignore non "nfs" and the "ignore" entries */
2N/A
2N/A if ((strcmp(fsmnt_list->fstype, MNTTYPE_NFS) != 0) ||
2N/A (ignore(fsmnt_list->mntopts))) {
2N/A continue;
2N/A }
2N/A
2N/A if ((mrp = get_mount_data(fsmnt_list, errp)) == NULL) {
2N/A nfs_free_mntinfo_list(headptr);
2N/A return (NULL);
2N/A }
2N/A if (tailptr == NULL) {
2N/A headptr = mrp;
2N/A tailptr = mrp;
2N/A tailptr->next = NULL;
2N/A } else {
2N/A tailptr->next = mrp;
2N/A tailptr = mrp;
2N/A tailptr->next = NULL;
2N/A }
2N/A }
2N/A
2N/A if (get_kstat_info(headptr, errp) == -1) {
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A return (headptr);
2N/A
2N/A} /* get_nfs_info */
2N/A
2N/A
2N/Astatic nfs_mntlist_t *
2N/Aget_mount_data(fs_mntlist_t *fsmnt_list, int *errp) {
2N/A struct replica *rep_list; /* defined in replica.h */
2N/A nfs_mntlist_t *mrp;
2N/A int i, server_count = 0;
2N/A struct stat stat_buf;
2N/A
2N/A if ((mrp = malloc(sizeof (nfs_mntlist_t))) == 0) {
2N/A *errp = errno;
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((stat(fsmnt_list->mountp, &stat_buf) == 0)) {
2N/A mrp->nml_fsid = stat_buf.st_dev;
2N/A } else {
2N/A *errp = errno;
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((mrp->nml_resource = strdup(fsmnt_list->resource))
2N/A == NULL) {
2N/A *errp = errno;
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A if ((rep_list =
2N/A parse_replica(mrp->nml_resource, &server_count)) == NULL) {
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A if ((mrp->nml_failoverlist =
2N/A calloc(server_count, sizeof (char *))) == NULL) {
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A for (i = 0; i < server_count; i++) {
2N/A mrp->nml_failoverlist[i] =
2N/A malloc(strlen(rep_list[i].host) + strlen(":") +
2N/A strlen(rep_list[i].path) + 2);
2N/A if (!mrp->nml_failoverlist[i]) {
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A sprintf(mrp->nml_failoverlist[i], "%s%s%s",
2N/A rep_list[i].host, ":", rep_list[i].path);
2N/A }
2N/A /*
2N/A * If the number of servers is not 1 then resource is
2N/A * either a failover list or there is an error. In either
2N/A * case the path can't be determined and curpath is set to
2N/A * unknown".
2N/A */
2N/A if (server_count == 1) {
2N/A if (strcmp(rep_list[0].host, "nfs") == 0) {
2N/A char *path;
2N/A char *last;
2N/A path = strdup(rep_list[0].path);
2N/A if ((path = (char *)strtok_r(path, "//",
2N/A &last)) != NULL) {
2N/A strcpy(mrp->nml_curpath,
2N/A strcat("/", last));
2N/A } else {
2N/A /*
2N/A * If NULL is returned this is an
2N/A * invalid path entry. no path can
2N/A * be determined.
2N/A */
2N/A strcpy(mrp->nml_curpath, "unknown");
2N/A }
2N/A } else {
2N/A strcpy(mrp->nml_curpath,
2N/A (strchr(mrp->nml_failoverlist[0],
2N/A ':') + 1));
2N/A }
2N/A } else {
2N/A /*
2N/A * more than one server in the failover list
2N/A * path can't be determined.
2N/A */
2N/A strcpy(mrp->nml_curpath, "unknown");
2N/A }
2N/A
2N/A mrp->nml_failovercount = server_count;
2N/A
2N/A for (i = 0; i < server_count; i++) {
2N/A if (rep_list[i].host) {
2N/A free(rep_list[i].host);
2N/A }
2N/A if (rep_list[i].path) {
2N/A free(rep_list[i].path);
2N/A }
2N/A }
2N/A free(rep_list);
2N/A
2N/A if ((mrp->nml_mountp = strdup(fsmnt_list->mountp)) == NULL) {
2N/A *errp = errno;
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A if ((mrp->nml_fstype = strdup(fsmnt_list->fstype)) == NULL) {
2N/A *errp = errno;
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A if ((mrp->nml_mntopts = strdup(fsmnt_list->mntopts)) == NULL) {
2N/A *errp = errno;
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A if ((mrp->nml_time = strdup(fsmnt_list->time)) == NULL) {
2N/A *errp = errno;
2N/A nfs_free_mntinfo_list(mrp);
2N/A return (NULL);
2N/A }
2N/A if (fsmnt_list->overlayed) {
2N/A mrp->nml_overlayed = B_TRUE;
2N/A } else {
2N/A mrp->nml_overlayed = B_FALSE;
2N/A }
2N/A return (mrp);
2N/A} /* get_mount_data */
2N/A
2N/Akid_t
2N/Asafe_kstat_read(
2N/A kstat_ctl_t *libkstat_cookie,
2N/A kstat_t *ksp,
2N/A void *data,
2N/A int *errp)
2N/A{
2N/A
2N/A kid_t kstat_chain_id = kstat_read(libkstat_cookie, ksp, data);
2N/A
2N/A if (kstat_chain_id == -1) {
2N/A *errp = errno;
2N/A return (-1);
2N/A }
2N/A return (kstat_chain_id);
2N/A} /* safe_kstat_read */
2N/A
2N/A
2N/A/*
2N/A * ignore - Checks for the ignore mount option in the mount opts string.
2N/A * Returns 1 if the ignore option is found and 0 if not.
2N/A */
2N/Astatic int
2N/Aignore(char *opts)
2N/A{
2N/A char *value;
2N/A char *s;
2N/A char *tmp;
2N/A
2N/A if (opts == NULL)
2N/A return (0);
2N/A s = strdup(opts);
2N/A if (s == NULL)
2N/A return (0);
2N/A
2N/A tmp = s;
2N/A
2N/A while (*s != '\0') {
2N/A if (getsubopt(&s, mntopts, &value) == IGNORE) {
2N/A free(tmp);
2N/A return (1);
2N/A }
2N/A }
2N/A free(tmp);
2N/A return (0);
2N/A} /* ignore */