1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * rmtab.c 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <stdio.h> 32*0Sstevel@tonic-gate #include <stdlib.h> 33*0Sstevel@tonic-gate #include <ctype.h> 34*0Sstevel@tonic-gate #include <sys/types.h> 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <sys/param.h> 37*0Sstevel@tonic-gate #include <sys/stat.h> 38*0Sstevel@tonic-gate #include <sys/file.h> 39*0Sstevel@tonic-gate #include <sys/time.h> 40*0Sstevel@tonic-gate #include <errno.h> 41*0Sstevel@tonic-gate #include <rpcsvc/mount.h> 42*0Sstevel@tonic-gate #include <sys/pathconf.h> 43*0Sstevel@tonic-gate #include <sys/systeminfo.h> 44*0Sstevel@tonic-gate #include <sys/utsname.h> 45*0Sstevel@tonic-gate #include <signal.h> 46*0Sstevel@tonic-gate #include <locale.h> 47*0Sstevel@tonic-gate #include <unistd.h> 48*0Sstevel@tonic-gate #include <thread.h> 49*0Sstevel@tonic-gate #include <syslog.h> 50*0Sstevel@tonic-gate #include <sys/socket.h> 51*0Sstevel@tonic-gate #include <netinet/in.h> 52*0Sstevel@tonic-gate #include <arpa/inet.h> 53*0Sstevel@tonic-gate #include "../lib/sharetab.h" 54*0Sstevel@tonic-gate #include "hashset.h" 55*0Sstevel@tonic-gate #include "mountd.h" 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate static char RMTAB[] = "/etc/rmtab"; 58*0Sstevel@tonic-gate static FILE *rmtabf = NULL; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* 61*0Sstevel@tonic-gate * There is nothing magic about the value selected here. Too low, 62*0Sstevel@tonic-gate * and mountd might spend too much time rewriting the rmtab file. 63*0Sstevel@tonic-gate * Too high, it won't do it frequently enough. 64*0Sstevel@tonic-gate */ 65*0Sstevel@tonic-gate static int rmtab_del_thresh = 250; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate #define RMTAB_TOOMANY_DELETED() \ 68*0Sstevel@tonic-gate ((rmtab_deleted > rmtab_del_thresh) && (rmtab_deleted > rmtab_inuse)) 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * mountd's version of a "struct mountlist". It is the same except 72*0Sstevel@tonic-gate * for the added ml_pos field. 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate struct mntentry { 75*0Sstevel@tonic-gate char *m_host; 76*0Sstevel@tonic-gate char *m_path; 77*0Sstevel@tonic-gate long m_pos; 78*0Sstevel@tonic-gate }; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate static HASHSET mntlist; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate static int mntentry_equal(const void *, const void *); 83*0Sstevel@tonic-gate static uint32_t mntentry_hash(const void *); 84*0Sstevel@tonic-gate static int mntlist_contains(char *, char *); 85*0Sstevel@tonic-gate static void rmtab_delete(long); 86*0Sstevel@tonic-gate static long rmtab_insert(char *, char *); 87*0Sstevel@tonic-gate static void rmtab_rewrite(void); 88*0Sstevel@tonic-gate static void rmtab_parse(char *buf); 89*0Sstevel@tonic-gate static bool_t xdr_mntlistencode(XDR * xdrs, HASHSET * mntlist); 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate #define exstrdup(s) \ 92*0Sstevel@tonic-gate strcpy(exmalloc(strlen(s)+1), s) 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static int rmtab_inuse; 96*0Sstevel@tonic-gate static int rmtab_deleted; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate static rwlock_t rmtab_lock; /* lock to protect rmtab list */ 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * Check whether the given client/path combination 103*0Sstevel@tonic-gate * already appears in the mount list. 104*0Sstevel@tonic-gate */ 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate static int 107*0Sstevel@tonic-gate mntlist_contains(char *host, char *path) 108*0Sstevel@tonic-gate { 109*0Sstevel@tonic-gate struct mntentry m; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate m.m_host = host; 112*0Sstevel@tonic-gate m.m_path = path; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate return (h_get(mntlist, &m) != NULL); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* 119*0Sstevel@tonic-gate * Add an entry to the mount list. 120*0Sstevel@tonic-gate * First check whether it's there already - the client 121*0Sstevel@tonic-gate * may have crashed and be rebooting. 122*0Sstevel@tonic-gate */ 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate static void 125*0Sstevel@tonic-gate mntlist_insert(char *host, char *path) 126*0Sstevel@tonic-gate { 127*0Sstevel@tonic-gate if (!mntlist_contains(host, path)) { 128*0Sstevel@tonic-gate struct mntentry *m; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate m = exmalloc(sizeof (struct mntentry)); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate m->m_host = exstrdup(host); 133*0Sstevel@tonic-gate m->m_path = exstrdup(path); 134*0Sstevel@tonic-gate m->m_pos = rmtab_insert(host, path); 135*0Sstevel@tonic-gate (void) h_put(mntlist, m); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate void 140*0Sstevel@tonic-gate mntlist_new(char *host, char *path) 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate (void) rw_wrlock(&rmtab_lock); 143*0Sstevel@tonic-gate mntlist_insert(host, path); 144*0Sstevel@tonic-gate (void) rw_unlock(&rmtab_lock); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate /* 148*0Sstevel@tonic-gate * Delete an entry from the mount list. 149*0Sstevel@tonic-gate */ 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate void 152*0Sstevel@tonic-gate mntlist_delete(char *host, char *path) 153*0Sstevel@tonic-gate { 154*0Sstevel@tonic-gate struct mntentry *m, mm; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate mm.m_host = host; 157*0Sstevel@tonic-gate mm.m_path = path; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate (void) rw_wrlock(&rmtab_lock); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (m = (struct mntentry *)h_get(mntlist, &mm)) { 162*0Sstevel@tonic-gate rmtab_delete(m->m_pos); 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate (void) h_delete(mntlist, m); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate free(m->m_path); 167*0Sstevel@tonic-gate free(m->m_host); 168*0Sstevel@tonic-gate free(m); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate if (RMTAB_TOOMANY_DELETED()) 171*0Sstevel@tonic-gate rmtab_rewrite(); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate (void) rw_unlock(&rmtab_lock); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * Delete all entries for a host from the mount list 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate void 181*0Sstevel@tonic-gate mntlist_delete_all(char *host) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate HASHSET_ITERATOR iterator; 184*0Sstevel@tonic-gate struct mntentry *m; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate (void) rw_wrlock(&rmtab_lock); 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate iterator = h_iterator(mntlist); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate while (m = (struct mntentry *)h_next(iterator)) { 191*0Sstevel@tonic-gate if (strcasecmp(m->m_host, host)) 192*0Sstevel@tonic-gate continue; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate rmtab_delete(m->m_pos); 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate (void) h_delete(mntlist, m); 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate free(m->m_path); 199*0Sstevel@tonic-gate free(m->m_host); 200*0Sstevel@tonic-gate free(m); 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (RMTAB_TOOMANY_DELETED()) 204*0Sstevel@tonic-gate rmtab_rewrite(); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate (void) rw_unlock(&rmtab_lock); 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate if (iterator != NULL) 209*0Sstevel@tonic-gate free(iterator); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * Equivalent to xdr_mountlist from librpcsvc but for HASHSET 214*0Sstevel@tonic-gate * rather that for a linked list. It is used only to encode data 215*0Sstevel@tonic-gate * from HASHSET before sending it over the wire. 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate static bool_t 219*0Sstevel@tonic-gate xdr_mntlistencode(XDR *xdrs, HASHSET *mntlist) 220*0Sstevel@tonic-gate { 221*0Sstevel@tonic-gate HASHSET_ITERATOR iterator = h_iterator(*mntlist); 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate for (;;) { 224*0Sstevel@tonic-gate struct mntentry *m = (struct mntentry *)h_next(iterator); 225*0Sstevel@tonic-gate bool_t more_data = (m != NULL); 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate if (!xdr_bool(xdrs, &more_data)) { 228*0Sstevel@tonic-gate if (iterator != NULL) 229*0Sstevel@tonic-gate free(iterator); 230*0Sstevel@tonic-gate return (FALSE); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate if (!more_data) 234*0Sstevel@tonic-gate break; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate if ((!xdr_name(xdrs, &m->m_host)) || 237*0Sstevel@tonic-gate (!xdr_dirpath(xdrs, &m->m_path))) { 238*0Sstevel@tonic-gate if (iterator != NULL) 239*0Sstevel@tonic-gate free(iterator); 240*0Sstevel@tonic-gate return (FALSE); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate if (iterator != NULL) 246*0Sstevel@tonic-gate free(iterator); 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate return (TRUE); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate void 252*0Sstevel@tonic-gate mntlist_send(SVCXPRT *transp) 253*0Sstevel@tonic-gate { 254*0Sstevel@tonic-gate (void) rw_rdlock(&rmtab_lock); 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate errno = 0; 257*0Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_mntlistencode, (char *)&mntlist)) 258*0Sstevel@tonic-gate log_cant_reply(transp); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate (void) rw_unlock(&rmtab_lock); 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate /* 264*0Sstevel@tonic-gate * Compute a hash for an mntlist entry. 265*0Sstevel@tonic-gate */ 266*0Sstevel@tonic-gate #define SPACE (uchar_t)0x20 267*0Sstevel@tonic-gate #define HASH_BITS 3 /* Num. of bits to shift the hash */ 268*0Sstevel@tonic-gate #define HASH_MAXHOST 6 /* Max. number of characters from a hostname */ 269*0Sstevel@tonic-gate #define HASH_MAXPATH 3 /* Max. number of characters from a pathname */ 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * Compute a 32 bit hash value for an mntlist entry. 273*0Sstevel@tonic-gate * We consider only first HASH_MAXHOST characters from the host part. 274*0Sstevel@tonic-gate * We skip the first character in the path part (usually /), and we 275*0Sstevel@tonic-gate * consider at most HASH_MAXPATH following characters. 276*0Sstevel@tonic-gate * We shift the hash value by HASH_BITS after each character. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate static uint32_t 280*0Sstevel@tonic-gate mntentry_hash(const void *p) 281*0Sstevel@tonic-gate { 282*0Sstevel@tonic-gate struct mntentry *m = (struct mntentry *)p; 283*0Sstevel@tonic-gate uchar_t *s; 284*0Sstevel@tonic-gate uint_t i, sum = 0; 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate for (i = 0, s = (uchar_t *)m->m_host; *s && i < HASH_MAXHOST; i++) { 287*0Sstevel@tonic-gate uchar_t ls = tolower(*s); 288*0Sstevel@tonic-gate sum <<= HASH_BITS; 289*0Sstevel@tonic-gate sum += ls - SPACE; 290*0Sstevel@tonic-gate *s++; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate /* 294*0Sstevel@tonic-gate * The first character is usually '/'. 295*0Sstevel@tonic-gate * Start with the next character. 296*0Sstevel@tonic-gate */ 297*0Sstevel@tonic-gate for (i = 0, s = (uchar_t *)m->m_path+1; *s && i < HASH_MAXPATH; i++) { 298*0Sstevel@tonic-gate sum <<= HASH_BITS; 299*0Sstevel@tonic-gate sum += *s++ - SPACE; 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate return (sum); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* 306*0Sstevel@tonic-gate * Compare mntlist entries. 307*0Sstevel@tonic-gate * The comparison ignores a value of m_pos. 308*0Sstevel@tonic-gate */ 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate static int 311*0Sstevel@tonic-gate mntentry_equal(const void *p1, const void *p2) 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate struct mntentry *m1 = (struct mntentry *)p1; 314*0Sstevel@tonic-gate struct mntentry *m2 = (struct mntentry *)p2; 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate return ((strcasecmp(m1->m_host, m2->m_host) || 317*0Sstevel@tonic-gate strcmp(m1->m_path, m2->m_path)) ? 0 : 1); 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * Rewrite /etc/rmtab with a current content of mntlist. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate static void 324*0Sstevel@tonic-gate rmtab_rewrite() 325*0Sstevel@tonic-gate { 326*0Sstevel@tonic-gate if (rmtabf) 327*0Sstevel@tonic-gate (void) fclose(rmtabf); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate /* Rewrite the file. */ 330*0Sstevel@tonic-gate if (rmtabf = fopen(RMTAB, "w+")) { 331*0Sstevel@tonic-gate HASHSET_ITERATOR iterator; 332*0Sstevel@tonic-gate struct mntentry *m; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate (void) fchmod(fileno(rmtabf), 335*0Sstevel@tonic-gate (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)); 336*0Sstevel@tonic-gate rmtab_inuse = rmtab_deleted = 0; 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate iterator = h_iterator(mntlist); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate while (m = (struct mntentry *)h_next(iterator)) 341*0Sstevel@tonic-gate m->m_pos = rmtab_insert(m->m_host, m->m_path); 342*0Sstevel@tonic-gate if (iterator != NULL) 343*0Sstevel@tonic-gate free(iterator); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* 348*0Sstevel@tonic-gate * Parse the content of /etc/rmtab and insert the entries into mntlist. 349*0Sstevel@tonic-gate * The buffer s should be ended with a NUL char. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate static void 353*0Sstevel@tonic-gate rmtab_parse(char *s) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate char *host; 356*0Sstevel@tonic-gate char *path; 357*0Sstevel@tonic-gate char *tmp; 358*0Sstevel@tonic-gate struct in6_addr ipv6addr; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate host_part: 361*0Sstevel@tonic-gate if (*s == '#') 362*0Sstevel@tonic-gate goto skip_rest; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate host = s; 365*0Sstevel@tonic-gate for (;;) { 366*0Sstevel@tonic-gate switch (*s++) { 367*0Sstevel@tonic-gate case '\0': 368*0Sstevel@tonic-gate return; 369*0Sstevel@tonic-gate case '\n': 370*0Sstevel@tonic-gate goto host_part; 371*0Sstevel@tonic-gate case ':': 372*0Sstevel@tonic-gate s[-1] = '\0'; 373*0Sstevel@tonic-gate goto path_part; 374*0Sstevel@tonic-gate case '[': 375*0Sstevel@tonic-gate tmp = strchr(s, ']'); 376*0Sstevel@tonic-gate if (tmp) { 377*0Sstevel@tonic-gate *tmp = '\0'; 378*0Sstevel@tonic-gate if (inet_pton(AF_INET6, s, &ipv6addr) > 0) { 379*0Sstevel@tonic-gate host = s; 380*0Sstevel@tonic-gate s = ++tmp; 381*0Sstevel@tonic-gate } else 382*0Sstevel@tonic-gate *tmp = ']'; 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate default: 385*0Sstevel@tonic-gate continue; 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate path_part: 390*0Sstevel@tonic-gate path = s; 391*0Sstevel@tonic-gate for (;;) { 392*0Sstevel@tonic-gate switch (*s++) { 393*0Sstevel@tonic-gate case '\n': 394*0Sstevel@tonic-gate s[-1] = '\0'; 395*0Sstevel@tonic-gate if (*host && *path) 396*0Sstevel@tonic-gate mntlist_insert(host, path); 397*0Sstevel@tonic-gate goto host_part; 398*0Sstevel@tonic-gate case '\0': 399*0Sstevel@tonic-gate if (*host && *path) 400*0Sstevel@tonic-gate mntlist_insert(host, path); 401*0Sstevel@tonic-gate return; 402*0Sstevel@tonic-gate default: 403*0Sstevel@tonic-gate continue; 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate skip_rest: 408*0Sstevel@tonic-gate for (;;) { 409*0Sstevel@tonic-gate switch (*++s) { 410*0Sstevel@tonic-gate case '\n': 411*0Sstevel@tonic-gate goto host_part; 412*0Sstevel@tonic-gate case '\0': 413*0Sstevel@tonic-gate return; 414*0Sstevel@tonic-gate default: 415*0Sstevel@tonic-gate continue; 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate /* 421*0Sstevel@tonic-gate * Read in contents of rmtab. 422*0Sstevel@tonic-gate * Call rmtab_parse to parse the file and store entries in mntlist. 423*0Sstevel@tonic-gate * Rewrites the file to get rid of unused entries. 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate #define RMTAB_LOADLEN (16*2024) /* Max bytes to read at a time */ 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate void 429*0Sstevel@tonic-gate rmtab_load() 430*0Sstevel@tonic-gate { 431*0Sstevel@tonic-gate FILE *fp; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate (void) rwlock_init(&rmtab_lock, USYNC_THREAD, NULL); 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * Don't need to lock the list at this point 437*0Sstevel@tonic-gate * because there's only a single thread running. 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate mntlist = h_create(mntentry_hash, mntentry_equal, 101, 0.75); 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate if (fp = fopen(RMTAB, "r")) { 442*0Sstevel@tonic-gate char buf[RMTAB_LOADLEN+1]; 443*0Sstevel@tonic-gate size_t len; 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate /* 446*0Sstevel@tonic-gate * Read at most RMTAB_LOADLEN bytes from /etc/rmtab. 447*0Sstevel@tonic-gate * - if fread returns RMTAB_LOADLEN we can be in the middle 448*0Sstevel@tonic-gate * of a line so change the last newline character into NUL 449*0Sstevel@tonic-gate * and seek back to the next character after newline. 450*0Sstevel@tonic-gate * - otherwise set NUL behind the last character read. 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate while ((len = fread(buf, 1, RMTAB_LOADLEN, fp)) > 0) { 453*0Sstevel@tonic-gate if (len == RMTAB_LOADLEN) { 454*0Sstevel@tonic-gate int i; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate for (i = 1; i < len; i++) { 457*0Sstevel@tonic-gate if (buf[len-i] == '\n') { 458*0Sstevel@tonic-gate buf[len-i] = '\0'; 459*0Sstevel@tonic-gate (void) fseek(fp, -i+1, 460*0Sstevel@tonic-gate SEEK_CUR); 461*0Sstevel@tonic-gate goto parse; 462*0Sstevel@tonic-gate } 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate /* Put a NUL character at the end of buffer */ 467*0Sstevel@tonic-gate buf[len] = '\0'; 468*0Sstevel@tonic-gate parse: 469*0Sstevel@tonic-gate rmtab_parse(buf); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate (void) fclose(fp); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate rmtab_rewrite(); 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate /* 477*0Sstevel@tonic-gate * Write an entry at the current location in rmtab 478*0Sstevel@tonic-gate * for the given client and path. 479*0Sstevel@tonic-gate * 480*0Sstevel@tonic-gate * Returns the starting position of the entry 481*0Sstevel@tonic-gate * or -1 if there was an error. 482*0Sstevel@tonic-gate */ 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate long 485*0Sstevel@tonic-gate rmtab_insert(char *host, char *path) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate long pos; 488*0Sstevel@tonic-gate struct in6_addr ipv6addr; 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate if (rmtabf == NULL || fseek(rmtabf, 0L, 2) == -1) { 491*0Sstevel@tonic-gate return (-1); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate pos = ftell(rmtabf); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * Check if host is an IPv6 literal 497*0Sstevel@tonic-gate */ 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if (inet_pton(AF_INET6, host, &ipv6addr) > 0) { 500*0Sstevel@tonic-gate if (fprintf(rmtabf, "[%s]:%s\n", host, path) == EOF) { 501*0Sstevel@tonic-gate return (-1); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate } else { 504*0Sstevel@tonic-gate if (fprintf(rmtabf, "%s:%s\n", host, path) == EOF) { 505*0Sstevel@tonic-gate return (-1); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate if (fflush(rmtabf) == EOF) { 509*0Sstevel@tonic-gate return (-1); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate rmtab_inuse++; 512*0Sstevel@tonic-gate return (pos); 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * Mark as unused the rmtab entry at the given offset in the file. 517*0Sstevel@tonic-gate */ 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate void 520*0Sstevel@tonic-gate rmtab_delete(long pos) 521*0Sstevel@tonic-gate { 522*0Sstevel@tonic-gate if (rmtabf != NULL && pos != -1 && fseek(rmtabf, pos, 0) == 0) { 523*0Sstevel@tonic-gate (void) fprintf(rmtabf, "#"); 524*0Sstevel@tonic-gate (void) fflush(rmtabf); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate rmtab_inuse--; 527*0Sstevel@tonic-gate rmtab_deleted++; 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate } 530