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 2004 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 <unistd.h> 32 #include <signal.h> 33 #include <sys/types.h> 34 #include <memory.h> 35 #include <stropts.h> 36 #include <netconfig.h> 37 #include <stdarg.h> 38 #include <sys/resource.h> 39 #include <sys/systeminfo.h> 40 #include <syslog.h> 41 #include <errno.h> 42 #include <sys/sockio.h> 43 #include <rpc/rpc.h> 44 #include <rpc/xdr.h> 45 #include <rpcsvc/nfs_prot.h> 46 #include <net/if.h> 47 #include <netdir.h> 48 #include <string.h> 49 #include <thread.h> 50 #include <locale.h> 51 #include "automount.h" 52 #include <sys/vfs.h> 53 #include <sys/mnttab.h> 54 #include <arpa/inet.h> 55 #include <rpc/svc.h> /* for private dupcache routines */ 56 #include <rpcsvc/daemon_utils.h> 57 #include <deflt.h> 58 #include <strings.h> 59 60 61 static void autofs_prog(struct svc_req *, SVCXPRT *); 62 static void autofs_mount_1_r(struct autofs_lookupargs *, 63 struct autofs_mountres *, struct authunix_parms *); 64 static void autofs_mount_1_free_r(struct autofs_mountres *); 65 static void autofs_lookup_1_r(struct autofs_lookupargs *, 66 struct autofs_lookupres *, struct authunix_parms *); 67 static void autofs_lookup_1_free_r(struct autofs_lookupres *); 68 static void autofs_unmount_1_r(struct umntrequest *, struct umntres *, 69 struct authunix_parms *); 70 static void autofs_unmount_1_free_r(struct umntres *); 71 static void autofs_readdir_1_r(struct autofs_rddirargs *, 72 struct autofs_rddirres *, struct authunix_parms *); 73 static void autofs_readdir_1_free_r(struct autofs_rddirres *); 74 static void usage(); 75 static void warn_hup(int); 76 static void free_action_list(); 77 78 static int dupreq_nonidemp(struct svc_req *, SVCXPRT *, int, bool_t (*)(), 79 void (*)()); 80 static int dupdonereq_nonidemp(struct svc_req *, caddr_t, bool_t (*)()); 81 static int dupreq_idemp(struct svc_req *, SVCXPRT *, int, bool_t (*)(), 82 void (*)()); 83 static int dupdonereq_idemp(struct svc_req *, caddr_t, bool_t (*)()); 84 85 #define CTIME_BUF_LEN 26 86 87 /* 88 * XXX - this limit was imposed due to resource problems - even though 89 * we can and do try and set the rlimit to be able to handle more threads, 90 * fopen() doesn't allow more than 256 fp's. 91 */ 92 #define MAXTHREADS 64 93 94 #define RESOURCE_FACTOR 8 95 96 static char str_arch[32]; 97 static char str_cpu[32]; 98 99 struct autodir *dir_head; 100 struct autodir *dir_tail; 101 char self[64]; 102 103 time_t timenow; 104 int verbose = 0; 105 int trace = 0; 106 int automountd_nobrowse = 0; 107 108 int 109 main(argc, argv) 110 int argc; 111 char *argv[]; 112 113 { 114 pid_t pid; 115 int c, i, error; 116 struct rlimit rlset; 117 int rpc_svc_mode = RPC_SVC_MT_AUTO; 118 int maxthreads = MAXTHREADS; 119 int prevthreads = 0; 120 char *defval; 121 int defflags; 122 123 if (geteuid() != 0) { 124 (void) fprintf(stderr, "%s must be run as root\n", argv[0]); 125 exit(1); 126 } 127 128 /* 129 * Read in the values from config file first before we check 130 * commandline options so the options override the file. 131 */ 132 if ((defopen(AUTOFSADMIN)) == 0) { 133 if ((defval = defread("AUTOMOUNTD_VERBOSE=")) != NULL) { 134 if (strncasecmp("true", defval, 4) == 0) 135 verbose = TRUE; 136 else 137 verbose = FALSE; 138 } 139 if ((defval = defread("AUTOMOUNTD_NOBROWSE=")) != NULL) { 140 if (strncasecmp("true", defval, 4) == 0) 141 automountd_nobrowse = TRUE; 142 else 143 automountd_nobrowse = FALSE; 144 } 145 if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) { 146 errno = 0; 147 trace = strtol(defval, (char **)NULL, 10); 148 if (errno != 0) 149 trace = 0; 150 } 151 if ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) { 152 (void) putenv(strdup(defval)); 153 defflags = defcntl(DC_GETFLAGS, 0); 154 TURNON(defflags, DC_NOREWIND); 155 defflags = defcntl(DC_SETFLAGS, defflags); 156 while ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) 157 (void) putenv(strdup(defval)); 158 (void) defcntl(DC_SETFLAGS, defflags); 159 } 160 161 /* close defaults file */ 162 defopen(NULL); 163 } 164 165 while ((c = getopt(argc, argv, "vnTD:")) != EOF) { 166 switch (c) { 167 case 'v': 168 verbose++; 169 break; 170 case 'n': 171 automountd_nobrowse++; 172 break; 173 case 'T': 174 trace++; 175 break; 176 case 'D': 177 (void) putenv(optarg); 178 break; 179 default: 180 usage(); 181 } 182 } 183 184 if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) { 185 error = errno; 186 fprintf(stderr, 187 "automountd: can't determine hostname, error: %d\n", 188 error); 189 exit(1); 190 } 191 192 #ifndef DEBUG 193 pid = fork(); 194 if (pid < 0) { 195 perror("cannot fork"); 196 exit(1); 197 } 198 if (pid) 199 exit(0); 200 #endif 201 202 (void) setsid(); 203 openlog("automountd", LOG_PID, LOG_DAEMON); 204 (void) setlocale(LC_ALL, ""); 205 206 /* 207 * Since the "arch" command no longer exists we 208 * have to rely on sysinfo(SI_MACHINE) to return the closest 209 * approximation. For backward compatibility we 210 * need to substitute "sun4" for "sun4m", "sun4c", ... 211 */ 212 if (getenv("ARCH") == NULL) { 213 char buf[16]; 214 215 if (sysinfo(SI_MACHINE, buf, sizeof (buf)) != -1) { 216 if (strncmp(buf, "sun4", 4) == 0) 217 (void) strcpy(buf, "sun4"); 218 (void) sprintf(str_arch, "ARCH=%s", buf); 219 (void) putenv(str_arch); 220 } else { 221 syslog(LOG_ERR, 222 "can't determine machine type, error: %m"); 223 } 224 } 225 if (getenv("CPU") == NULL) { 226 char buf[16]; 227 228 if (sysinfo(SI_ARCHITECTURE, buf, sizeof (buf)) != -1) { 229 (void) sprintf(str_cpu, "CPU=%s", buf); 230 (void) putenv(str_cpu); 231 } else { 232 syslog(LOG_ERR, 233 "can't determine processor type, error: %m"); 234 } 235 } 236 237 (void) rwlock_init(&cache_lock, USYNC_THREAD, NULL); 238 (void) rwlock_init(&rddir_cache_lock, USYNC_THREAD, NULL); 239 240 /* 241 * initialize the name services, use NULL arguments to ensure 242 * we don't initialize the stack of files used in file service 243 */ 244 (void) ns_setup(NULL, NULL); 245 246 /* 247 * set the maximum number of threads to be used. If it succeeds 248 * increase the number of resources the threads need. If the 249 * the resource allocation fails, return the threads value back 250 * to the default value 251 */ 252 if (((rpc_control(RPC_SVC_THRMAX_GET, &prevthreads)) == TRUE) && 253 ((rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) == TRUE)) { 254 rlset.rlim_max = RESOURCE_FACTOR * maxthreads; 255 rlset.rlim_cur = RESOURCE_FACTOR * maxthreads; 256 if ((setrlimit(RLIMIT_NOFILE, &rlset)) != 0) { 257 syslog(LOG_ERR, 258 "unable to increase system resource limit"); 259 260 /* back off changes to threads */ 261 if ((rpc_control(RPC_SVC_THRMAX_SET, &prevthreads)) 262 == FALSE) { 263 /* 264 * Exit if we have more threads than resources. 265 */ 266 syslog(LOG_ERR, 267 "unable to match threads to system resources"); 268 exit(1); 269 } 270 syslog(LOG_ERR, 271 "decreased threads to match low resources"); 272 } else { 273 /* 274 * Both are successful. Note that setrlimit 275 * allows a max setting of 1024 276 */ 277 if (trace > 3) { 278 trace_prt(1, 279 " maxthreads: %d rlim_max: %d rlim_cur: %d\n", 280 maxthreads, rlset.rlim_max, rlset.rlim_cur); 281 } 282 closefrom(3); 283 } 284 } else { 285 syslog(LOG_ERR, 286 "unable to increase threads - continue with default"); 287 } 288 289 /* 290 * establish our lock on the lock file and write our pid to it. 291 * exit if some other process holds the lock, or if there's any 292 * error in writing/locking the file. 293 */ 294 pid = _enter_daemon_lock(AUTOMOUNTD); 295 switch (pid) { 296 case 0: 297 break; 298 case -1: 299 syslog(LOG_ERR, "error locking for %s: %s", AUTOMOUNTD, 300 strerror(errno)); 301 exit(2); 302 default: 303 /* daemon was already running */ 304 exit(0); 305 } 306 307 /* 308 * If we coredump it'll be /core. 309 */ 310 if (chdir("/") < 0) 311 syslog(LOG_ERR, "chdir /: %m"); 312 313 /* 314 * Create cache_cleanup thread 315 */ 316 if (thr_create(NULL, 0, (void *(*)(void *))cache_cleanup, NULL, 317 THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) { 318 syslog(LOG_ERR, "unable to create cache_cleanup thread"); 319 exit(1); 320 } 321 322 /* other initializations */ 323 (void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL); 324 325 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 326 syslog(LOG_ERR, "unable to set automatic MT mode"); 327 exit(1); 328 } 329 if (svc_create_local_service(autofs_prog, 330 AUTOFS_PROG, AUTOFS_VERS, "netpath", "autofs") == 0) { 331 syslog(LOG_ERR, "unable to create service"); 332 exit(1); 333 } 334 335 (void) signal(SIGHUP, warn_hup); 336 337 svc_run(); 338 syslog(LOG_ERR, "svc_run returned"); 339 return (1); 340 } 341 342 /* 343 * The old automounter supported a SIGHUP 344 * to allow it to resynchronize internal 345 * state with the /etc/mnttab. 346 * This is no longer relevant, but we 347 * need to catch the signal and warn 348 * the user. 349 */ 350 /* ARGSUSED */ 351 static void 352 warn_hup(i) 353 int i; 354 { 355 syslog(LOG_ERR, "SIGHUP received: ignored"); 356 (void) signal(SIGHUP, warn_hup); 357 } 358 359 static void 360 usage() 361 { 362 (void) fprintf(stderr, "Usage: automountd\n" 363 "\t[-T]\t\t(trace requests)\n" 364 "\t[-v]\t\t(verbose error msgs)\n" 365 "\t[-D n=s]\t(define env variable)\n"); 366 exit(1); 367 /* NOTREACHED */ 368 } 369 370 /* 371 * dupreq_nonidemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz, 372 * bool_t (*xdr_result)(), void (*local_free)()) 373 * check the status of nonidempotent requests in the duplicate request cache. 374 * Get result of done requests and send a reply to the kernel. Return status. 375 */ 376 static int 377 dupreq_nonidemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz, 378 bool_t (*xdr_result)(), void (*local_free)()) 379 { 380 caddr_t resp_buf; 381 uint_t resp_bufsz; 382 int dupstat; 383 XDR xdrs; 384 caddr_t res; 385 386 dupstat = __svc_vc_dup(rqstp, &resp_buf, &resp_bufsz); 387 switch (dupstat) { 388 case DUP_NEW: 389 break; 390 case DUP_DONE: 391 if (!resp_buf) { 392 if (verbose) { 393 syslog(LOG_ERR, 394 "dupreq_nonidemp: done, no cached result"); 395 } 396 break; 397 } 398 /* buffer contains xdr encoded results - decode and sendreply */ 399 if (verbose) { 400 syslog(LOG_ERR, 401 "dupreq_nonidemp: done, send reply to kernel"); 402 } 403 404 memset((caddr_t)&xdrs, 0, sizeof (XDR)); 405 xdrmem_create(&xdrs, resp_buf, resp_bufsz, XDR_DECODE); 406 407 if ((res = (caddr_t)malloc(res_sz)) == NULL) { 408 syslog(LOG_ERR, "dupreq_nonidemp: out of memory"); 409 xdr_destroy(&xdrs); 410 free(resp_buf); 411 break; 412 } 413 memset(res, 0, res_sz); 414 415 if ((*xdr_result)(&xdrs, res) == FALSE) { 416 if (verbose) 417 syslog(LOG_ERR, 418 "dupreq_nonidemp: cannot xdr decode result"); 419 xdr_destroy(&xdrs); 420 free(resp_buf); 421 free(res); 422 break; 423 } 424 425 if (!svc_sendreply(transp, xdr_result, (caddr_t)res)) { 426 xdr_destroy(&xdrs); 427 free(resp_buf); 428 (void) (*local_free)(res); 429 free(res); 430 svcerr_systemerr(transp); 431 return (DUP_ERROR); 432 } 433 xdr_destroy(&xdrs); 434 free(resp_buf); 435 (void) (*local_free)(res); 436 free(res); 437 break; 438 439 /* all other cases log the case and drop the request */ 440 case DUP_INPROGRESS: 441 if (verbose) { 442 syslog(LOG_ERR, 443 "dupreq_nonidemp: duplicate request in progress\n"); 444 } 445 break; 446 case DUP_DROP: /* should never be called in automountd */ 447 if (verbose) 448 syslog(LOG_ERR, 449 "dupreq_nonidemp: dropped duplicate request error"); 450 break; 451 case DUP_ERROR: /* fall through */ 452 default: 453 if (verbose) 454 syslog(LOG_ERR, 455 "dupreq_nonidemp: duplicate request cache error"); 456 break; 457 } 458 return (dupstat); 459 } 460 461 /* 462 * dupdonereq_nonidemp(struct svc_req *rqstp, caddr_t res, 463 * bool_t (*xdr_result)()) 464 * call the cache to indicate we are done with the nonidempotent request. 465 * xdr_result will write the encoded xdr form of results into the buffer 466 * provided in xdrmem_create. Makes a best effort to update the cache 467 * first with a buffer containing the results, and then with a NULL buffer. 468 * Return status. 469 */ 470 static int 471 dupdonereq_nonidemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)()) 472 { 473 caddr_t resp_buf; 474 ulong_t resp_bufsz; 475 XDR xdrs; 476 int dupstat; 477 478 /* 479 * create a results buffer and write into the cache 480 * continue with a NULL buffer on errors. 481 */ 482 if ((resp_bufsz = xdr_sizeof(xdr_result, (void *)res)) == 0) { 483 if (verbose) 484 syslog(LOG_ERR, "dupdonereq_nonidemp: xdr error"); 485 resp_buf = NULL; 486 resp_bufsz = 0; 487 } else { 488 if ((resp_buf = (caddr_t)malloc(resp_bufsz)) == NULL) { 489 syslog(LOG_ERR, "dupdonereq_nonidemp: out of memory"); 490 resp_bufsz = 0; 491 } else { 492 memset(resp_buf, 0, resp_bufsz); 493 memset((caddr_t)&xdrs, 0, sizeof (XDR)); 494 xdrmem_create(&xdrs, resp_buf, (uint_t)resp_bufsz, 495 XDR_ENCODE); 496 if ((*xdr_result)(&xdrs, res) == FALSE) { 497 if (verbose) 498 syslog(LOG_ERR, 499 "cannot xdr encode results"); 500 xdr_destroy(&xdrs); 501 free(resp_buf); 502 resp_buf = NULL; 503 resp_bufsz = 0; 504 } else 505 xdr_destroy(&xdrs); 506 } 507 } 508 509 dupstat = __svc_vc_dupdone(rqstp, resp_buf, (uint_t)resp_bufsz, 510 DUP_DONE); 511 if (dupstat == DUP_ERROR) { 512 if (verbose) 513 syslog(LOG_ERR, "dupdonereq_nonidemp: cache error"); 514 if (resp_buf != NULL) { 515 if (verbose) 516 syslog(LOG_ERR, "dupdonereq_nonidemp: retry"); 517 dupstat = __svc_vc_dupdone(rqstp, NULL, 0, DUP_DONE); 518 if ((dupstat == DUP_ERROR) && verbose) 519 syslog(LOG_ERR, 520 "dupdonereq_nonidemp: retry failed"); 521 } 522 } 523 if (resp_buf) 524 free(resp_buf); 525 return (dupstat); 526 } 527 528 /* 529 * dupreq_idemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz; 530 * bool_t (*xdr_result)(), void (*local_free)()) 531 * check the status of idempotent requests in the duplicate request cache. 532 * treat a idempotent request like a new one if its done, but do workavoids 533 * if its a request in progress. Return status. 534 */ 535 static int 536 dupreq_idemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz, 537 bool_t (*xdr_result)(), void (*local_free)()) 538 { 539 int dupstat; 540 541 #ifdef lint 542 transp = transp; 543 res_sz = res_sz; 544 local_free = local_free; 545 xdr_result = xdr_result; 546 #endif /* lint */ 547 548 /* 549 * call the cache to check the status of the request. don't care 550 * about results in the cache. 551 */ 552 dupstat = __svc_vc_dup(rqstp, NULL, NULL); 553 switch (dupstat) { 554 case DUP_NEW: 555 break; 556 case DUP_DONE: 557 if (verbose) 558 syslog(LOG_ERR, "dupreq_idemp: done request, redo"); 559 dupstat = DUP_NEW; 560 break; 561 562 /* all other cases log the case and drop the request */ 563 case DUP_INPROGRESS: 564 if (verbose) 565 syslog(LOG_ERR, 566 "dupreq_idemp: duplicate request in progress\n"); 567 break; 568 case DUP_DROP: /* should never be called in automountd */ 569 if (verbose) 570 syslog(LOG_ERR, 571 "dupreq_idemp: dropped duplicate request error"); 572 break; 573 case DUP_ERROR: /* fall through */ 574 default: 575 if (verbose) 576 syslog(LOG_ERR, 577 "dupreq_idemp: duplicate request cache error"); 578 break; 579 } 580 return (dupstat); 581 } 582 583 /* 584 * dupdonereq_idemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)()) 585 * call the cache to indicate we are done with the idempotent request - we do 586 * this to allow work avoids for in progress requests. don't bother to store 587 * any results in the cache. Return status. 588 */ 589 static int 590 dupdonereq_idemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)()) 591 { 592 int dupstat; 593 594 #ifdef lint 595 res = res; 596 xdr_result = xdr_result; 597 #endif /* lint */ 598 599 dupstat = __svc_vc_dupdone(rqstp, NULL, (uint_t)0, DUP_DONE); 600 if ((dupstat == DUP_ERROR) && verbose) 601 syslog(LOG_ERR, "dupdonereq_idemp: cannot cache result"); 602 return (dupstat); 603 } 604 605 /* 606 * Returns the UID of the caller 607 */ 608 static uid_t 609 getowner(transp) 610 SVCXPRT *transp; 611 { 612 uid_t uid; 613 614 if (__rpc_get_local_uid(transp, &uid) < 0) { 615 char *err_msg = "Could not get local uid - request ignored\n"; 616 617 if (trace > 1) 618 trace_prt(1, err_msg); 619 if (verbose) 620 pr_msg(err_msg); 621 return (-1); 622 } 623 if (uid != 0) { 624 char *err_msg = 625 "Illegal access attempt by uid=%ld - request ignored\n"; 626 627 if (trace > 1) 628 trace_prt(1, err_msg, uid); 629 pr_msg(err_msg, uid); 630 } 631 return (uid); 632 } 633 634 /* 635 * Each RPC request will automatically spawn a new thread with this 636 * as its entry point. 637 * XXX - the switch statement should be changed to a table of procedures 638 * similar to that used by rfs_dispatch() in uts/common/fs/nfs/nfs_server.c. 639 * duplicate request handling should also be synced with rfs_dispatch(). 640 */ 641 static void 642 autofs_prog(rqstp, transp) 643 struct svc_req *rqstp; 644 register SVCXPRT *transp; 645 { 646 union { 647 autofs_lookupargs autofs_mount_1_arg; 648 autofs_lookupargs autofs_lookup_1_arg; 649 umntrequest autofs_umount_1_arg; 650 autofs_rddirargs autofs_readdir_1_arg; 651 } argument; 652 653 union { 654 autofs_mountres mount_res; 655 autofs_lookupres lookup_res; 656 umntres umount_res; 657 autofs_rddirres readdir_res; 658 } res; 659 660 bool_t (*xdr_argument)(); 661 bool_t (*xdr_result)(); 662 void (*local)(); 663 void (*local_free)(); 664 int (*dup_request)(); 665 int (*dupdone_request)(); 666 667 timenow = time((time_t *)NULL); 668 669 if (rqstp->rq_proc != NULLPROC && getowner(transp) != 0) { 670 /* 671 * Drop request 672 */ 673 return; 674 } 675 676 switch (rqstp->rq_proc) { 677 case NULLPROC: 678 (void) svc_sendreply(transp, xdr_void, (char *)NULL); 679 return; 680 681 #ifdef MALLOC_DEBUG 682 case AUTOFS_DUMP_DEBUG: 683 (void) svc_sendreply(transp, xdr_void, (char *)NULL); 684 check_leaks("/var/tmp/automountd.leak"); 685 return; 686 #endif 687 688 case AUTOFS_LOOKUP: 689 xdr_argument = xdr_autofs_lookupargs; 690 xdr_result = xdr_autofs_lookupres; 691 local = autofs_lookup_1_r; 692 local_free = autofs_lookup_1_free_r; 693 dup_request = dupreq_nonidemp; 694 dupdone_request = dupdonereq_nonidemp; 695 break; 696 697 case AUTOFS_MOUNT: 698 xdr_argument = xdr_autofs_lookupargs; 699 xdr_result = xdr_autofs_mountres; 700 local = autofs_mount_1_r; 701 local_free = autofs_mount_1_free_r; 702 dup_request = dupreq_nonidemp; 703 dupdone_request = dupdonereq_nonidemp; 704 break; 705 706 case AUTOFS_UNMOUNT: 707 xdr_argument = xdr_umntrequest; 708 xdr_result = xdr_umntres; 709 local = autofs_unmount_1_r; 710 local_free = autofs_unmount_1_free_r; 711 dup_request = dupreq_nonidemp; 712 dupdone_request = dupdonereq_nonidemp; 713 break; 714 715 case AUTOFS_READDIR: 716 xdr_argument = xdr_autofs_rddirargs; 717 xdr_result = xdr_autofs_rddirres; 718 local = autofs_readdir_1_r; 719 local_free = autofs_readdir_1_free_r; 720 dup_request = dupreq_idemp; 721 dupdone_request = dupdonereq_idemp; 722 break; 723 724 default: 725 svcerr_noproc(transp); 726 return; 727 } 728 729 730 if ((*dup_request)(rqstp, transp, sizeof (res), xdr_result, 731 local_free) != DUP_NEW) 732 return; 733 734 (void) memset((char *)&argument, 0, sizeof (argument)); 735 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 736 svcerr_decode(transp); 737 return; 738 } 739 740 (void) memset((char *)&res, 0, sizeof (res)); 741 (*local)(&argument, &res, rqstp->rq_clntcred); 742 743 /* update cache with done request results */ 744 (void) (*dupdone_request)(rqstp, (caddr_t)&res, xdr_result); 745 746 if (!svc_sendreply(transp, xdr_result, (caddr_t)&res)) { 747 svcerr_systemerr(transp); 748 } 749 750 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 751 syslog(LOG_ERR, "unable to free arguments"); 752 } 753 754 (*local_free)(&res); 755 756 } 757 758 static void 759 autofs_readdir_1_r(req, res, cred) 760 struct autofs_rddirargs *req; 761 struct autofs_rddirres *res; 762 struct authunix_parms *cred; 763 { 764 if (trace > 0) 765 trace_prt(1, "READDIR REQUEST : %s @ %ld\n", 766 req->rda_map, req->rda_offset); 767 768 (void) do_readdir(req, res, cred); 769 770 if (trace > 0) 771 trace_prt(1, "READDIR REPLY : status=%d\n", res->rd_status); 772 } 773 774 static void 775 autofs_readdir_1_free_r(res) 776 struct autofs_rddirres *res; 777 { 778 if (res->rd_status == AUTOFS_OK) { 779 if (res->rd_rddir.rddir_entries) 780 free(res->rd_rddir.rddir_entries); 781 } 782 } 783 784 /* ARGSUSED */ 785 static void 786 autofs_unmount_1_r(m, res, cred) 787 struct umntrequest *m; 788 struct umntres *res; 789 struct authunix_parms *cred; 790 { 791 struct umntrequest *ul; 792 793 if (trace > 0) { 794 char ctime_buf[CTIME_BUF_LEN]; 795 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 796 ctime_buf[0] = '\0'; 797 798 trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf); 799 for (ul = m; ul; ul = ul->next) 800 trace_prt(1, " resource=%s fstype=%s mntpnt=%s" 801 " mntopts=%s %s\n", 802 ul->mntresource, 803 ul->fstype, 804 ul->mntpnt, 805 ul->mntopts, 806 ul->isdirect ? "direct" : "indirect"); 807 } 808 809 res->status = do_unmount1(m); 810 811 if (trace > 0) 812 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status); 813 } 814 815 static void 816 autofs_unmount_1_free_r(res) 817 struct umntres *res; 818 { 819 #ifdef lint 820 res = res; 821 #endif /* lint */ 822 } 823 824 static void 825 autofs_lookup_1_r(m, res, cred) 826 struct autofs_lookupargs *m; 827 struct autofs_lookupres *res; 828 struct authunix_parms *cred; 829 { 830 enum autofs_action action; 831 struct linka link; 832 int status; 833 834 if (trace > 0) { 835 char ctime_buf[CTIME_BUF_LEN]; 836 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 837 ctime_buf[0] = '\0'; 838 839 trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf); 840 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 841 m->name, m->subdir, m->map, m->opts, 842 m->path, m->isdirect); 843 } 844 845 status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path, 846 (uint_t)m->isdirect, &action, &link, cred); 847 if (status == 0) { 848 /* 849 * Return action list to kernel. 850 */ 851 res->lu_res = AUTOFS_OK; 852 if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) 853 res->lu_type.lookup_result_type_u.lt_linka = link; 854 } else { 855 /* 856 * Entry not found 857 */ 858 res->lu_res = AUTOFS_NOENT; 859 } 860 res->lu_verbose = verbose; 861 862 if (trace > 0) 863 trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res); 864 } 865 866 static void 867 autofs_lookup_1_free_r(res) 868 struct autofs_lookupres *res; 869 { 870 struct linka link; 871 872 if ((res->lu_res == AUTOFS_OK) && 873 (res->lu_type.action == AUTOFS_LINK_RQ)) { 874 /* 875 * Free link information 876 */ 877 link = res->lu_type.lookup_result_type_u.lt_linka; 878 if (link.dir) 879 free(link.dir); 880 if (link.link) 881 free(link.link); 882 } 883 } 884 885 static void 886 autofs_mount_1_r(m, res, cred) 887 struct autofs_lookupargs *m; 888 struct autofs_mountres *res; 889 struct authunix_parms *cred; 890 { 891 int status; 892 action_list *alp = NULL; 893 894 if (trace > 0) { 895 char ctime_buf[CTIME_BUF_LEN]; 896 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 897 ctime_buf[0] = '\0'; 898 899 trace_prt(1, "MOUNT REQUEST: %s", ctime_buf); 900 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 901 m->name, m->subdir, m->map, m->opts, 902 m->path, m->isdirect); 903 } 904 905 status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path, 906 (uint_t)m->isdirect, &alp, cred); 907 if (status != 0) { 908 /* 909 * An error occurred, free action list if allocated. 910 */ 911 if (alp != NULL) { 912 free_action_list(alp); 913 alp = NULL; 914 } 915 } 916 if (alp != NULL) { 917 /* 918 * Return action list to kernel. 919 */ 920 res->mr_type.status = AUTOFS_ACTION; 921 res->mr_type.mount_result_type_u.list = alp; 922 } else { 923 /* 924 * No work to do left for the kernel 925 */ 926 res->mr_type.status = AUTOFS_DONE; 927 res->mr_type.mount_result_type_u.error = status; 928 } 929 res->mr_verbose = verbose; 930 931 if (trace > 0) { 932 switch (res->mr_type.status) { 933 case AUTOFS_ACTION: 934 trace_prt(1, 935 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n", 936 status); 937 break; 938 case AUTOFS_DONE: 939 trace_prt(1, 940 "MOUNT REPLY : status=%d, AUTOFS_DONE\n", 941 status); 942 break; 943 default: 944 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n", 945 status); 946 } 947 } 948 949 if (status && verbose) { 950 if (m->isdirect) { 951 /* direct mount */ 952 syslog(LOG_ERR, "mount of %s failed", m->path); 953 } else { 954 /* indirect mount */ 955 syslog(LOG_ERR, 956 "mount of %s/%s failed", m->path, m->name); 957 } 958 } 959 } 960 961 static void 962 autofs_mount_1_free_r(res) 963 struct autofs_mountres *res; 964 { 965 if (res->mr_type.status == AUTOFS_ACTION) { 966 if (trace > 2) 967 trace_prt(1, "freeing action list\n"); 968 969 free_action_list(res->mr_type.mount_result_type_u.list); 970 } 971 } 972 973 /* 974 * Used for reporting messages from code 975 * shared with automount command. 976 * Formats message into a buffer and 977 * calls syslog. 978 * 979 * Print an error. 980 * Works like printf (fmt string and variable args) 981 * except that it will subsititute an error message 982 * for a "%m" string (like syslog). 983 */ 984 void 985 pr_msg(const char *fmt, ...) 986 { 987 va_list ap; 988 char fmtbuff[BUFSIZ], buff[BUFSIZ]; 989 const char *p1; 990 char *p2; 991 992 p2 = fmtbuff; 993 fmt = gettext(fmt); 994 995 for (p1 = fmt; *p1; p1++) { 996 if (*p1 == '%' && *(p1+1) == 'm') { 997 if (errno < sys_nerr) { 998 (void) strcpy(p2, sys_errlist[errno]); 999 p2 += strlen(p2); 1000 } 1001 p1++; 1002 } else { 1003 *p2++ = *p1; 1004 } 1005 } 1006 if (p2 > fmtbuff && *(p2-1) != '\n') 1007 *p2++ = '\n'; 1008 *p2 = '\0'; 1009 1010 va_start(ap, fmt); 1011 (void) vsprintf(buff, fmtbuff, ap); 1012 va_end(ap); 1013 syslog(LOG_ERR, buff); 1014 } 1015 1016 static void 1017 free_action_list(action_list *alp) 1018 { 1019 action_list *p, *next = NULL; 1020 struct mounta *mp; 1021 1022 for (p = alp; p != NULL; p = next) { 1023 switch (p->action.action) { 1024 case AUTOFS_MOUNT_RQ: 1025 mp = &(p->action.action_list_entry_u.mounta); 1026 /* LINTED pointer alignment */ 1027 free_autofs_args((autofs_args *)mp->dataptr); 1028 mp->dataptr = NULL; 1029 mp->datalen = 0; 1030 free_mounta(mp); 1031 break; 1032 case AUTOFS_LINK_RQ: 1033 syslog(LOG_ERR, 1034 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 1035 break; 1036 default: 1037 syslog(LOG_ERR, 1038 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 1039 break; 1040 } 1041 next = p->next; 1042 free(p); 1043 } 1044 } 1045