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 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 * 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 * 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 * 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 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 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 * 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 * 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 * 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 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 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