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