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