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