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
nfs_free_mntinfo_list(nfs_mntlist_t * list)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 *
nfs_get_filtered_mount_list(char * resource,char * mountp,char * mntopts,char * time,boolean_t find_overlays,int * errp)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 *
nfs_get_mounts_by_mntopt(char * mntopt,boolean_t find_overlays,int * errp)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 *
nfs_get_mount_list(int * errp)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
get_kstat_info(nfs_mntlist_t * nfs_mntinfo,int * errp)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
load_kstat_data(kstat_ctl_t * libkstat_cookie,nfs_mntlist_t * mrp,kstat_t * ksp,int * errp)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 *
kstat_mount(nfs_mntlist_t * nfs_mntinfo,kstat_t * ksp)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 *
get_nfs_info(fs_mntlist_t * fslist,int * errp)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 *
get_mount_data(fs_mntlist_t * fsmnt_list,int * errp)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
safe_kstat_read(kstat_ctl_t * libkstat_cookie,kstat_t * ksp,void * data,int * errp)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
ignore(char * opts)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