xref: /illumos-gate/usr/src/lib/libfsmgt/common/nfs_mntinfo.c (revision 2aeafac3612e19716bf8164f89c3c9196342979c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <kvm.h>
35 #include <kstat.h>
36 #include <sys/types.h>
37 #include <sys/mnttab.h>
38 #include <sys/mntent.h>
39 #include <nfs/nfs.h>
40 #include <nfs/nfs_clnt.h>
41 #include <sys/mkdev.h>
42 #include <inttypes.h>
43 #include <sys/stat.h>
44 
45 
46 #include "libfsmgt.h"
47 #include "replica.h"
48 
49 #define	IGNORE	0
50 #define	DEV	1
51 
52 /*
53  * Private variables
54  */
55 
56 static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL };
57 
58 /*
59  * Private method declarations
60  */
61 
62 static int ignore(char *);
63 static int get_kstat_info(nfs_mntlist_t *, int *);
64 static nfs_mntlist_t *get_mount_data(fs_mntlist_t *, int *);
65 static nfs_mntlist_t *get_nfs_info(fs_mntlist_t *, int *);
66 static nfs_mntlist_t *kstat_mount(nfs_mntlist_t *, kstat_t *);
67 static int load_kstat_data(kstat_ctl_t *, nfs_mntlist_t *, kstat_t *, int *);
68 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *, int *);
69 
70 /*
71  * Public methods
72  */
73 
74 void
75 nfs_free_mntinfo_list(nfs_mntlist_t *list)
76 {
77 	nfs_mntlist_t *tmp;
78 	int i;
79 
80 	while (list != NULL) {
81 		free(list->nml_resource);
82 		free(list->nml_mountp);
83 		free(list->nml_fstype);
84 		free(list->nml_mntopts);
85 		free(list->nml_time);
86 		for (i = 0; i < list->nml_failovercount; i++) {
87 			if (list->nml_failoverlist[i] != NULL)
88 				free(list->nml_failoverlist[i]);
89 		}
90 		free(list->nml_failoverlist);
91 		free(list->nml_securitymode);
92 		tmp = list->next;
93 		free(list);
94 		list = tmp;
95 	}
96 } /* nfs_free_mntinfo_list */
97 
98 nfs_mntlist_t *
99 nfs_get_filtered_mount_list(char *resource, char *mountp, char *mntopts,
100 	char *time, boolean_t find_overlays, int *errp) {
101 
102 	fs_mntlist_t	*fs_mount_list;
103 	nfs_mntlist_t	*nfs_mount_list;
104 
105 	fs_mount_list = fs_get_filtered_mount_list(resource, mountp,
106 		MNTTYPE_NFS, mntopts, time, find_overlays, errp);
107 	if (fs_mount_list == NULL) {
108 		return (NULL);
109 	}
110 
111 	if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
112 		fs_free_mount_list(fs_mount_list);
113 		return (NULL);
114 	}
115 
116 	fs_free_mount_list(fs_mount_list);
117 	return (nfs_mount_list);
118 } /* nfs_get_filtered_mount_list */
119 
120 nfs_mntlist_t *
121 nfs_get_mounts_by_mntopt(char *mntopt, boolean_t find_overlays, int *errp)
122 {
123 	fs_mntlist_t	*fs_mount_list;
124 	nfs_mntlist_t	*nfs_mount_list;
125 
126 	fs_mount_list = fs_get_mounts_by_mntopt(mntopt, find_overlays, errp);
127 	if (fs_mount_list == NULL) {
128 		return (NULL);
129 	}
130 
131 	if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
132 		fs_free_mount_list(fs_mount_list);
133 		return (NULL);
134 	}
135 
136 	fs_free_mount_list(fs_mount_list);
137 	return (nfs_mount_list);
138 } /* nfs_get_mount_by_mntopt */
139 
140 nfs_mntlist_t *
141 nfs_get_mount_list(int *errp)
142 {
143 	fs_mntlist_t *fs_mount_list;
144 	nfs_mntlist_t *nfs_mount_list;
145 	boolean_t find_overlays = B_TRUE;
146 
147 	if ((fs_mount_list = fs_get_mount_list(find_overlays, errp)) == NULL) {
148 		fprintf(stderr, "nfs_mntinfo: Can't access mnttab. %s\n",
149 		    strerror(*errp));
150 		return (NULL);
151 	}
152 
153 	if ((nfs_mount_list = get_nfs_info(fs_mount_list, errp)) == NULL) {
154 		fs_free_mount_list(fs_mount_list);
155 		return (NULL);
156 	}
157 
158 	fs_free_mount_list(fs_mount_list);
159 	return (nfs_mount_list);
160 } /* nfs_get_mount_list */
161 
162 /*
163  * Private methods
164  */
165 
166 static int
167 get_kstat_info(nfs_mntlist_t *nfs_mntinfo, int *errp)
168 {
169 	kstat_ctl_t *libkstat_cookie = NULL;
170 	nfs_mntlist_t *mrp;
171 	kstat_t *ksp;
172 
173 	if ((libkstat_cookie = kstat_open()) == NULL) {
174 		*errp = errno;
175 		fprintf(stderr,
176 		    "nfs_mntinfo: kstat_open(): can't open /dev/kstat.\n");
177 		return (-1);
178 	}
179 	/*
180 	 * Each kstat consists of header and data sections that are
181 	 * connected as a "chain" or linked list of kstat stuctures.
182 	 * The kc_chain used here is the pointer to the global kstat
183 	 * chain (or the head of the chain of kstat's).
184 	 */
185 	for (ksp = libkstat_cookie->kc_chain; ksp; ksp = ksp->ks_next) {
186 		if ((ksp->ks_type == KSTAT_TYPE_RAW) &&
187 		    (strcmp(ksp->ks_module, "nfs") == 0) &&
188 		    (strcmp(ksp->ks_name, "mntinfo") == 0) &&
189 		    ((mrp = kstat_mount(nfs_mntinfo, ksp)) != NULL)) {
190 			if (load_kstat_data(libkstat_cookie, mrp, ksp, errp)
191 			    == -1) {
192 				nfs_free_mntinfo_list(mrp);
193 				return (-1);
194 			}
195 		}
196 	}
197 	return (0);
198 } /* get_kstat_info */
199 
200 static int
201 load_kstat_data(kstat_ctl_t *libkstat_cookie, nfs_mntlist_t *mrp,
202     kstat_t *ksp, int *errp)
203 {
204 	struct mntinfo_kstat mik;
205 	seconfig_t nfs_sec;
206 
207 	if (mrp == 0) {
208 		return (0);
209 	}
210 
211 	if (safe_kstat_read(libkstat_cookie, ksp, &mik, errp) == -1) {
212 		return (-1);
213 	}
214 
215 	if (strlcpy(mrp->nml_proto, mik.mik_proto, KNC_STRSIZE)
216 	    >= KNC_STRSIZE) {
217 		*errp = errno;
218 		return (-1);
219 	}
220 	if (strlcpy(mrp->nml_curserver, mik.mik_curserver, SYS_NMLN)
221 	    >= SYS_NMLN) {
222 		*errp = errno;
223 		return (-1);
224 	}
225 	mrp->nml_vers = mik.mik_vers;
226 	/*
227 	 *  get the secmode name from /etc/nfssec.conf.
228 	 */
229 	if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
230 		mrp->nml_securitymode = strdup(nfs_sec.sc_name);
231 	} else {
232 		mrp->nml_securitymode = NULL;
233 	}
234 	mrp->nml_curread = mik.mik_curread;
235 	mrp->nml_curwrite = mik.mik_curwrite;
236 	mrp->nml_timeo = mik.mik_timeo;
237 	mrp->nml_retrans = mik.mik_retrans;
238 	mrp->nml_acregmin = mik.mik_acregmin;
239 	mrp->nml_acregmax = mik.mik_acregmax;
240 	mrp->nml_acdirmin = mik.mik_acdirmin;
241 	mrp->nml_acdirmax = mik.mik_acdirmax;
242 	mrp->nml_hard =
243 	    ((mik.mik_flags & MI_HARD) ? B_TRUE : B_FALSE);
244 	mrp->nml_intr =
245 	    ((mik.mik_flags & MI_INT) ? B_TRUE : B_FALSE);
246 	mrp->nml_noac =
247 	    ((mik.mik_flags & MI_NOAC) ? B_TRUE : B_FALSE);
248 	mrp->nml_nocto =
249 	    ((mik.mik_flags & MI_NOCTO) ? B_TRUE : B_FALSE);
250 	mrp->nml_grpid =
251 	    ((mik.mik_flags & MI_GRPID) ? B_TRUE : B_FALSE);
252 	mrp->nml_directio =
253 	    ((mik.mik_flags & MI_DIRECTIO) ? B_TRUE : B_FALSE);
254 	mrp->nml_xattr =
255 	    ((mik.mik_flags & MI_EXTATTR) ? B_TRUE : B_FALSE);
256 	return (0);
257 }
258 
259 nfs_mntlist_t *
260 kstat_mount(nfs_mntlist_t *nfs_mntinfo, kstat_t *ksp) {
261 	nfs_mntlist_t *mrp;
262 	/*
263 	 * MAXMIN is used to retrieve the minor number
264 	 * which is compared to the kstat instance.
265 	 * If they are the same then this is an instance
266 	 * for which mount information is needed.
267 	 * MAXMIN is the maximum minor number and is
268 	 * defined in mkdev.h.
269 	 */
270 	mrp = nfs_mntinfo;
271 	while ((mrp != NULL) &&
272 	    ((mrp->nml_fsid & MAXMIN) != ksp->ks_instance)) {
273 		mrp = mrp->next;
274 	}
275 	return (mrp);
276 }
277 
278 static nfs_mntlist_t *
279 get_nfs_info(fs_mntlist_t *fslist, int *errp) {
280 	nfs_mntlist_t *mrp = NULL;
281 	nfs_mntlist_t *headptr = NULL;
282 	nfs_mntlist_t *tailptr = NULL;
283 	fs_mntlist_t *fsmnt_list;
284 
285 	for (fsmnt_list = fslist; fsmnt_list; fsmnt_list = fsmnt_list->next) {
286 		/* ignore non "nfs" and the "ignore" entries */
287 
288 		if ((strcmp(fsmnt_list->fstype, MNTTYPE_NFS) != 0) ||
289 		    (ignore(fsmnt_list->mntopts))) {
290 			continue;
291 		}
292 
293 		if ((mrp = get_mount_data(fsmnt_list, errp)) == NULL) {
294 			nfs_free_mntinfo_list(headptr);
295 			return (NULL);
296 		}
297 		if (tailptr == NULL) {
298 			headptr = mrp;
299 			tailptr = mrp;
300 			tailptr->next = NULL;
301 		} else {
302 			tailptr->next = mrp;
303 			tailptr = mrp;
304 			tailptr->next = NULL;
305 		}
306 	}
307 
308 	if (get_kstat_info(headptr, errp) == -1) {
309 		nfs_free_mntinfo_list(mrp);
310 		return (NULL);
311 	}
312 	return (headptr);
313 
314 } /* get_nfs_info */
315 
316 
317 static nfs_mntlist_t *
318 get_mount_data(fs_mntlist_t *fsmnt_list, int *errp) {
319 	struct replica *rep_list; /* defined in replica.h */
320 	nfs_mntlist_t *mrp;
321 	int i, server_count = 0;
322 	struct stat	stat_buf;
323 
324 	if ((mrp = malloc(sizeof (nfs_mntlist_t))) == 0) {
325 		*errp = errno;
326 		return (NULL);
327 	}
328 
329 	if ((stat(fsmnt_list->mountp, &stat_buf) == 0)) {
330 		mrp->nml_fsid = stat_buf.st_dev;
331 	} else {
332 		*errp = errno;
333 		nfs_free_mntinfo_list(mrp);
334 		return (NULL);
335 	}
336 
337 	if ((mrp->nml_resource = strdup(fsmnt_list->resource))
338 	    == NULL) {
339 		*errp = errno;
340 		nfs_free_mntinfo_list(mrp);
341 		return (NULL);
342 	}
343 	if ((rep_list =
344 	    parse_replica(mrp->nml_resource, &server_count)) == NULL) {
345 		nfs_free_mntinfo_list(mrp);
346 		return (NULL);
347 	}
348 	if ((mrp->nml_failoverlist =
349 	    calloc(server_count, sizeof (char *))) == NULL) {
350 		nfs_free_mntinfo_list(mrp);
351 		return (NULL);
352 	}
353 	for (i = 0; i < server_count; i++) {
354 		mrp->nml_failoverlist[i] =
355 		    malloc(strlen(rep_list[i].host) + strlen(":") +
356 		    strlen(rep_list[i].path) + 2);
357 		if (!mrp->nml_failoverlist[i]) {
358 			nfs_free_mntinfo_list(mrp);
359 			return (NULL);
360 		}
361 		sprintf(mrp->nml_failoverlist[i], "%s%s%s",
362 		    rep_list[i].host, ":", rep_list[i].path);
363 	}
364 	/*
365 	 * If the number of servers is not 1 then resource is
366 	 * either a failover list or there is an error. In either
367 	 * case the path can't be determined and curpath is set to
368 	 * unknown".
369 	 */
370 	if (server_count == 1) {
371 		if (strcmp(rep_list[0].host, "nfs") == 0) {
372 			char *path;
373 			char *last;
374 			path = strdup(rep_list[0].path);
375 			if ((path = (char *)strtok_r(path, "//",
376 			    &last)) != NULL) {
377 				strcpy(mrp->nml_curpath,
378 				    strcat("/", last));
379 			} else {
380 				/*
381 				 * If NULL is returned this is an
382 				 * invalid path entry. no path can
383 				 * be determined.
384 				 */
385 				strcpy(mrp->nml_curpath, "unknown");
386 			}
387 		} else {
388 			strcpy(mrp->nml_curpath,
389 			    (strchr(mrp->nml_failoverlist[0],
390 			    ':') + 1));
391 		}
392 	} else {
393 		/*
394 		 * more than one server in the failover list
395 		 * path can't be determined.
396 		 */
397 		strcpy(mrp->nml_curpath, "unknown");
398 	}
399 
400 	mrp->nml_failovercount = server_count;
401 
402 	for (i = 0; i < server_count; i++) {
403 		if (rep_list[i].host) {
404 			free(rep_list[i].host);
405 		}
406 		if (rep_list[i].path) {
407 			free(rep_list[i].path);
408 		}
409 	}
410 	free(rep_list);
411 
412 	if ((mrp->nml_mountp = strdup(fsmnt_list->mountp)) == NULL) {
413 		*errp = errno;
414 		nfs_free_mntinfo_list(mrp);
415 		return (NULL);
416 	}
417 	if ((mrp->nml_fstype = strdup(fsmnt_list->fstype)) == NULL) {
418 		*errp = errno;
419 		nfs_free_mntinfo_list(mrp);
420 		return (NULL);
421 	}
422 	if ((mrp->nml_mntopts = strdup(fsmnt_list->mntopts)) == NULL) {
423 		*errp = errno;
424 		nfs_free_mntinfo_list(mrp);
425 		return (NULL);
426 	}
427 	if ((mrp->nml_time = strdup(fsmnt_list->time)) == NULL) {
428 		*errp = errno;
429 		nfs_free_mntinfo_list(mrp);
430 		return (NULL);
431 	}
432 	if (fsmnt_list->overlayed) {
433 		mrp->nml_overlayed = B_TRUE;
434 	} else {
435 		mrp->nml_overlayed = B_FALSE;
436 	}
437 	return (mrp);
438 } /* get_mount_data */
439 
440 kid_t
441 safe_kstat_read(
442 	kstat_ctl_t *libkstat_cookie,
443 	kstat_t *ksp,
444 	void *data,
445 	int *errp)
446 {
447 
448 	kid_t kstat_chain_id = kstat_read(libkstat_cookie, ksp, data);
449 
450 	if (kstat_chain_id == -1) {
451 		*errp = errno;
452 		return (-1);
453 	}
454 	return (kstat_chain_id);
455 } /* safe_kstat_read */
456 
457 
458 /*
459  * ignore - Checks for the ignore mount option in the mount opts string.
460  * Returns 1 if the ignore option is found and 0 if not.
461  */
462 static int
463 ignore(char *opts)
464 {
465 	char *value;
466 	char *s;
467 	char *tmp;
468 
469 	if (opts == NULL)
470 		return (0);
471 	s = strdup(opts);
472 	if (s == NULL)
473 		return (0);
474 
475 	tmp = s;
476 
477 	while (*s != '\0') {
478 		if (getsubopt(&s, mntopts, &value) == IGNORE) {
479 			free(tmp);
480 			return (1);
481 		}
482 	}
483 	free(tmp);
484 	return (0);
485 } /* ignore */
486