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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 32 /* All Rights Reserved */ 33 34 /* 35 * University Copyright- Copyright (c) 1982, 1986, 1988 36 * The Regents of the University of California 37 * All Rights Reserved 38 * 39 * University Acknowledgment- Portions of this document are derived from 40 * software developed by the University of California, Berkeley, and its 41 * contributors. 42 */ 43 44 /* 45 * Copyright (c) 2012 by Delphix. All rights reserved. 46 */ 47 48 /* 49 * sm_statd.c consists of routines used for the intermediate 50 * statd implementation(3.2 rpc.statd); 51 * it creates an entry in "current" directory for each site that it monitors; 52 * after crash and recovery, it moves all entries in "current" 53 * to "backup" directory, and notifies the corresponding statd of its recovery. 54 */ 55 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <unistd.h> 59 #include <string.h> 60 #include <syslog.h> 61 #include <netdb.h> 62 #include <sys/types.h> 63 #include <sys/stat.h> 64 #include <sys/file.h> 65 #include <sys/param.h> 66 #include <arpa/inet.h> 67 #include <dirent.h> 68 #include <rpc/rpc.h> 69 #include <rpcsvc/sm_inter.h> 70 #include <rpcsvc/nsm_addr.h> 71 #include <errno.h> 72 #include <memory.h> 73 #include <signal.h> 74 #include <synch.h> 75 #include <thread.h> 76 #include <limits.h> 77 #include <strings.h> 78 #include "sm_statd.h" 79 80 81 int LOCAL_STATE; 82 83 sm_hash_t mon_table[MAX_HASHSIZE]; 84 static sm_hash_t record_table[MAX_HASHSIZE]; 85 static sm_hash_t recov_q; 86 87 static name_entry *find_name(name_entry **namepp, char *name); 88 static name_entry *insert_name(name_entry **namepp, char *name, 89 int need_alloc); 90 static void delete_name(name_entry **namepp, char *name); 91 static void remove_name(char *name, int op, int startup); 92 static int statd_call_statd(char *name); 93 static void pr_name(char *name, int flag); 94 static void *thr_statd_init(void *); 95 static void *sm_try(void *); 96 static void *thr_call_statd(void *); 97 static void remove_single_name(char *name, char *dir1, char *dir2); 98 static int move_file(char *fromdir, char *file, char *todir); 99 static int count_symlinks(char *dir, char *name, int *count); 100 static char *family2string(sa_family_t family); 101 102 /* 103 * called when statd first comes up; it searches /etc/sm to gather 104 * all entries to notify its own failure 105 */ 106 void 107 statd_init(void) 108 { 109 struct dirent *dirp; 110 DIR *dp; 111 FILE *fp, *fp_tmp; 112 int i, tmp_state; 113 char state_file[MAXPATHLEN+SM_MAXPATHLEN]; 114 115 if (debug) 116 (void) printf("enter statd_init\n"); 117 118 /* 119 * First try to open the file. If that fails, try to create it. 120 * If that fails, give up. 121 */ 122 if ((fp = fopen(STATE, "r+")) == NULL) { 123 if ((fp = fopen(STATE, "w+")) == NULL) { 124 syslog(LOG_ERR, "can't open %s: %m", STATE); 125 exit(1); 126 } else 127 (void) chmod(STATE, 0644); 128 } 129 if ((fscanf(fp, "%d", &LOCAL_STATE)) == EOF) { 130 if (debug >= 2) 131 (void) printf("empty file\n"); 132 LOCAL_STATE = 0; 133 } 134 135 /* 136 * Scan alternate paths for largest "state" number 137 */ 138 for (i = 0; i < pathix; i++) { 139 (void) sprintf(state_file, "%s/statmon/state", path_name[i]); 140 if ((fp_tmp = fopen(state_file, "r+")) == NULL) { 141 if ((fp_tmp = fopen(state_file, "w+")) == NULL) { 142 if (debug) 143 syslog(LOG_ERR, 144 "can't open %s: %m", 145 state_file); 146 continue; 147 } else 148 (void) chmod(state_file, 0644); 149 } 150 if ((fscanf(fp_tmp, "%d", &tmp_state)) == EOF) { 151 if (debug) 152 syslog(LOG_ERR, 153 "statd: %s: file empty\n", state_file); 154 (void) fclose(fp_tmp); 155 continue; 156 } 157 if (tmp_state > LOCAL_STATE) { 158 LOCAL_STATE = tmp_state; 159 if (debug) 160 (void) printf("Update LOCAL STATE: %d\n", 161 tmp_state); 162 } 163 (void) fclose(fp_tmp); 164 } 165 166 LOCAL_STATE = ((LOCAL_STATE%2) == 0) ? LOCAL_STATE+1 : LOCAL_STATE+2; 167 168 /* IF local state overflows, reset to value 1 */ 169 if (LOCAL_STATE < 0) { 170 LOCAL_STATE = 1; 171 } 172 173 /* Copy the LOCAL_STATE value back to all stat files */ 174 if (fseek(fp, 0, 0) == -1) { 175 syslog(LOG_ERR, "statd: fseek failed\n"); 176 exit(1); 177 } 178 179 (void) fprintf(fp, "%-10d", LOCAL_STATE); 180 (void) fflush(fp); 181 if (fsync(fileno(fp)) == -1) { 182 syslog(LOG_ERR, "statd: fsync failed\n"); 183 exit(1); 184 } 185 (void) fclose(fp); 186 187 for (i = 0; i < pathix; i++) { 188 (void) sprintf(state_file, "%s/statmon/state", path_name[i]); 189 if ((fp_tmp = fopen(state_file, "r+")) == NULL) { 190 if ((fp_tmp = fopen(state_file, "w+")) == NULL) { 191 syslog(LOG_ERR, 192 "can't open %s: %m", state_file); 193 continue; 194 } else 195 (void) chmod(state_file, 0644); 196 } 197 (void) fprintf(fp_tmp, "%-10d", LOCAL_STATE); 198 (void) fflush(fp_tmp); 199 if (fsync(fileno(fp_tmp)) == -1) { 200 syslog(LOG_ERR, 201 "statd: %s: fsync failed\n", state_file); 202 (void) fclose(fp_tmp); 203 exit(1); 204 } 205 (void) fclose(fp_tmp); 206 } 207 208 if (debug) 209 (void) printf("local state = %d\n", LOCAL_STATE); 210 211 if ((mkdir(CURRENT, SM_DIRECTORY_MODE)) == -1) { 212 if (errno != EEXIST) { 213 syslog(LOG_ERR, "statd: mkdir current, error %m\n"); 214 exit(1); 215 } 216 } 217 if ((mkdir(BACKUP, SM_DIRECTORY_MODE)) == -1) { 218 if (errno != EEXIST) { 219 syslog(LOG_ERR, "statd: mkdir backup, error %m\n"); 220 exit(1); 221 } 222 } 223 224 /* get all entries in CURRENT into BACKUP */ 225 if ((dp = opendir(CURRENT)) == NULL) { 226 syslog(LOG_ERR, "statd: open current directory, error %m\n"); 227 exit(1); 228 } 229 230 while ((dirp = readdir(dp)) != NULL) { 231 if (strcmp(dirp->d_name, ".") != 0 && 232 strcmp(dirp->d_name, "..") != 0) { 233 /* rename all entries from CURRENT to BACKUP */ 234 (void) move_file(CURRENT, dirp->d_name, BACKUP); 235 } 236 } 237 238 (void) closedir(dp); 239 240 /* Contact hosts' statd */ 241 if (thr_create(NULL, 0, thr_statd_init, NULL, THR_DETACHED, NULL)) { 242 syslog(LOG_ERR, 243 "statd: unable to create thread for thr_statd_init\n"); 244 exit(1); 245 } 246 } 247 248 /* 249 * Work thread which contacts hosts' statd. 250 */ 251 static void * 252 thr_statd_init(void *arg __unused) 253 { 254 struct dirent *dirp; 255 DIR *dp; 256 int num_threads; 257 int num_join; 258 int i; 259 char *name; 260 char buf[MAXPATHLEN+SM_MAXPATHLEN]; 261 262 /* Go thru backup directory and contact hosts */ 263 if ((dp = opendir(BACKUP)) == NULL) { 264 syslog(LOG_ERR, "statd: open backup directory, error %m\n"); 265 exit(1); 266 } 267 268 /* 269 * Create "UNDETACHED" threads for each symlink and (unlinked) 270 * regular file in backup directory to initiate statd_call_statd. 271 * NOTE: These threads are the only undetached threads in this 272 * program and thus, the thread id is not needed to join the threads. 273 */ 274 num_threads = 0; 275 while ((dirp = readdir(dp)) != NULL) { 276 /* 277 * If host file is not a symlink, don't bother to 278 * spawn a thread for it. If any link(s) refer to 279 * it, the host will be contacted using the link(s). 280 * If not, we'll deal with it during the legacy pass. 281 */ 282 (void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name); 283 if (is_symlink(buf) == 0) { 284 continue; 285 } 286 287 /* 288 * If the num_threads has exceeded, wait until 289 * a certain amount of threads have finished. 290 * Currently, 10% of threads created should be joined. 291 */ 292 if (num_threads > MAX_THR) { 293 num_join = num_threads/PERCENT_MINJOIN; 294 for (i = 0; i < num_join; i++) 295 thr_join(0, 0, 0); 296 num_threads -= num_join; 297 } 298 299 /* 300 * If can't alloc name then print error msg and 301 * continue to next item on list. 302 */ 303 name = strdup(dirp->d_name); 304 if (name == NULL) { 305 syslog(LOG_ERR, 306 "statd: unable to allocate space for name %s\n", 307 dirp->d_name); 308 continue; 309 } 310 311 /* Create a thread to do a statd_call_statd for name */ 312 if (thr_create(NULL, 0, thr_call_statd, name, 0, NULL)) { 313 syslog(LOG_ERR, 314 "statd: unable to create thr_call_statd() " 315 "for name %s.\n", dirp->d_name); 316 free(name); 317 continue; 318 } 319 num_threads++; 320 } 321 322 /* 323 * Join the other threads created above before processing the 324 * legacies. This allows all symlinks and the regular files 325 * to which they correspond to be processed and deleted. 326 */ 327 for (i = 0; i < num_threads; i++) { 328 thr_join(0, 0, 0); 329 } 330 331 /* 332 * The second pass checks for `legacies': regular files which 333 * never had symlinks pointing to them at all, just like in the 334 * good old (pre-1184192 fix) days. Once a machine has cleaned 335 * up its legacies they should only reoccur due to catastrophes 336 * (e.g., severed symlinks). 337 */ 338 rewinddir(dp); 339 num_threads = 0; 340 while ((dirp = readdir(dp)) != NULL) { 341 if (strcmp(dirp->d_name, ".") == 0 || 342 strcmp(dirp->d_name, "..") == 0) { 343 continue; 344 } 345 346 (void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name); 347 if (is_symlink(buf)) { 348 /* 349 * We probably couldn't reach this host and it's 350 * been put on the recovery queue for retry. 351 * Skip it and keep looking for regular files. 352 */ 353 continue; 354 } 355 356 if (debug) { 357 (void) printf("thr_statd_init: legacy %s\n", 358 dirp->d_name); 359 } 360 361 /* 362 * If the number of threads exceeds the maximum, wait 363 * for some fraction of them to finish before 364 * continuing. 365 */ 366 if (num_threads > MAX_THR) { 367 num_join = num_threads/PERCENT_MINJOIN; 368 for (i = 0; i < num_join; i++) 369 thr_join(0, 0, 0); 370 num_threads -= num_join; 371 } 372 373 /* 374 * If can't alloc name then print error msg and 375 * continue to next item on list. 376 */ 377 name = strdup(dirp->d_name); 378 if (name == NULL) { 379 syslog(LOG_ERR, 380 "statd: unable to allocate space for name %s\n", 381 dirp->d_name); 382 continue; 383 } 384 385 /* Create a thread to do a statd_call_statd for name */ 386 if (thr_create(NULL, 0, thr_call_statd, name, 0, NULL)) { 387 syslog(LOG_ERR, 388 "statd: unable to create thr_call_statd() " 389 "for name %s.\n", dirp->d_name); 390 free(name); 391 continue; 392 } 393 num_threads++; 394 } 395 396 (void) closedir(dp); 397 398 /* 399 * Join the other threads created above before creating thread 400 * to process items in recovery table. 401 */ 402 for (i = 0; i < num_threads; i++) { 403 thr_join(0, 0, 0); 404 } 405 406 /* 407 * Need to only copy /var/statmon/sm.bak to alternate paths, since 408 * the only hosts in /var/statmon/sm should be the ones currently 409 * being monitored and already should be in alternate paths as part 410 * of insert_mon(). 411 */ 412 for (i = 0; i < pathix; i++) { 413 (void) sprintf(buf, "%s/statmon/sm.bak", path_name[i]); 414 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 415 if (errno != EEXIST) 416 syslog(LOG_ERR, "statd: mkdir %s error %m\n", 417 buf); 418 else 419 copydir_from_to(BACKUP, buf); 420 } else 421 copydir_from_to(BACKUP, buf); 422 } 423 424 425 /* 426 * Reset the die and in_crash variables. 427 */ 428 mutex_lock(&crash_lock); 429 die = 0; 430 in_crash = 0; 431 mutex_unlock(&crash_lock); 432 433 if (debug) 434 (void) printf("Creating thread for sm_try\n"); 435 436 /* Continue to notify statd on hosts that were unreachable. */ 437 if (thr_create(NULL, 0, sm_try, NULL, THR_DETACHED, NULL)) 438 syslog(LOG_ERR, 439 "statd: unable to create thread for sm_try().\n"); 440 thr_exit(NULL); 441 #ifdef lint 442 return (0); 443 #endif 444 } 445 446 /* 447 * Work thread to make call to statd_call_statd. 448 */ 449 void * 450 thr_call_statd(void *namep) 451 { 452 char *name = (char *)namep; 453 454 /* 455 * If statd of name is unreachable, add name to recovery table 456 * otherwise if statd_call_statd was successful, remove from backup. 457 */ 458 if (statd_call_statd(name) != 0) { 459 int n; 460 char *tail; 461 char path[MAXPATHLEN]; 462 /* 463 * since we are constructing this pathname below we add 464 * another space for the terminating NULL so we don't 465 * overflow our buffer when we do the readlink 466 */ 467 char rname[MAXNAMELEN + 1]; 468 469 if (debug) { 470 (void) printf( 471 "statd call failed, inserting %s in recov_q\n", name); 472 } 473 mutex_lock(&recov_q.lock); 474 (void) insert_name(&recov_q.sm_recovhdp, name, 0); 475 mutex_unlock(&recov_q.lock); 476 477 /* 478 * If we queued a symlink name in the recovery queue, 479 * we now clean up the regular file to which it referred. 480 * This may leave a severed symlink if multiple links 481 * referred to one regular file; this is unaesthetic but 482 * it works. The big benefit is that it prevents us 483 * from recovering the same host twice (as symlink and 484 * as regular file) needlessly, usually on separate reboots. 485 */ 486 (void) strcpy(path, BACKUP); 487 (void) strcat(path, "/"); 488 (void) strcat(path, name); 489 if (is_symlink(path)) { 490 n = readlink(path, rname, MAXNAMELEN); 491 if (n <= 0) { 492 if (debug >= 2) { 493 (void) printf( 494 "thr_call_statd: can't read " 495 "link %s\n", path); 496 } 497 } else { 498 rname[n] = '\0'; 499 500 tail = strrchr(path, '/') + 1; 501 502 if ((strlen(BACKUP) + strlen(rname) + 2) <= 503 MAXPATHLEN) { 504 (void) strcpy(tail, rname); 505 delete_file(path); 506 } else if (debug) { 507 printf("thr_call_statd: path over" 508 "maxpathlen!\n"); 509 } 510 } 511 512 } 513 514 if (debug) 515 pr_name(name, 0); 516 517 } else { 518 /* 519 * If `name' is an IP address symlink to a name file, 520 * remove it now. If it is the last such symlink, 521 * remove the name file as well. Regular files with 522 * no symlinks to them are assumed to be legacies and 523 * are removed as well. 524 */ 525 remove_name(name, 1, 1); 526 free(name); 527 } 528 thr_exit((void *) 0); 529 #ifdef lint 530 return (0); 531 #endif 532 } 533 534 /* 535 * Notifies the statd of host specified by name to indicate that 536 * state has changed for this server. 537 */ 538 static int 539 statd_call_statd(char *name) 540 { 541 enum clnt_stat clnt_stat; 542 struct timeval tottimeout; 543 CLIENT *clnt; 544 char *name_or_addr; 545 stat_chge ntf; 546 int i; 547 int rc; 548 int dummy1, dummy2, dummy3, dummy4; 549 char ascii_addr[MAXNAMELEN]; 550 size_t unq_len; 551 552 ntf.mon_name = hostname; 553 ntf.state = LOCAL_STATE; 554 if (debug) 555 (void) printf("statd_call_statd at %s\n", name); 556 557 /* 558 * If it looks like an ASCII <address family>.<address> specifier, 559 * strip off the family - we just want the address when obtaining 560 * a client handle. 561 * If it's anything else, just pass it on to create_client(). 562 */ 563 unq_len = strcspn(name, "."); 564 565 if ((strncmp(name, SM_ADDR_IPV4, unq_len) == 0) || 566 (strncmp(name, SM_ADDR_IPV6, unq_len) == 0)) { 567 name_or_addr = strchr(name, '.') + 1; 568 } else { 569 name_or_addr = name; 570 } 571 572 /* 573 * NOTE: We depend here upon the fact that the RPC client code 574 * allows us to use ASCII dotted quad `names', i.e. "192.9.200.1". 575 * This may change in a future release. 576 */ 577 if (debug) { 578 (void) printf("statd_call_statd: calling create_client(%s)\n", 579 name_or_addr); 580 } 581 582 tottimeout.tv_sec = SM_RPC_TIMEOUT; 583 tottimeout.tv_usec = 0; 584 585 if ((clnt = create_client(name_or_addr, SM_PROG, SM_VERS, NULL, 586 &tottimeout)) == NULL) { 587 return (-1); 588 } 589 590 /* Perform notification to client */ 591 rc = 0; 592 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge, (char *)&ntf, 593 xdr_void, NULL, tottimeout); 594 if (debug) { 595 (void) printf("clnt_stat=%s(%d)\n", 596 clnt_sperrno(clnt_stat), clnt_stat); 597 } 598 if (clnt_stat != (int)RPC_SUCCESS) { 599 syslog(LOG_WARNING, 600 "statd: cannot talk to statd at %s, %s(%d)\n", 601 name_or_addr, clnt_sperrno(clnt_stat), clnt_stat); 602 rc = -1; 603 } 604 605 /* 606 * Wait until the host_name is populated. 607 */ 608 (void) mutex_lock(&merges_lock); 609 while (in_merges) 610 (void) cond_wait(&merges_cond, &merges_lock); 611 (void) mutex_unlock(&merges_lock); 612 613 /* For HA systems and multi-homed hosts */ 614 ntf.state = LOCAL_STATE; 615 for (i = 0; i < addrix; i++) { 616 ntf.mon_name = host_name[i]; 617 if (debug) 618 (void) printf("statd_call_statd at %s\n", name_or_addr); 619 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge, 620 (char *)&ntf, xdr_void, NULL, tottimeout); 621 if (clnt_stat != (int)RPC_SUCCESS) { 622 syslog(LOG_WARNING, 623 "statd: cannot talk to statd at %s, %s(%d)\n", 624 name_or_addr, clnt_sperrno(clnt_stat), clnt_stat); 625 rc = -1; 626 } 627 } 628 clnt_destroy(clnt); 629 return (rc); 630 } 631 632 /* 633 * Continues to contact hosts in recovery table that were unreachable. 634 * NOTE: There should only be one sm_try thread executing and 635 * thus locks are not needed for recovery table. Die is only cleared 636 * after all the hosts has at least been contacted once. The reader/writer 637 * lock ensures to finish this code before an sm_crash is started. Die 638 * variable will signal it. 639 */ 640 void * 641 sm_try(void *arg __unused) 642 { 643 name_entry *nl, *next; 644 timestruc_t wtime; 645 int delay = 0; 646 647 rw_rdlock(&thr_rwlock); 648 if (mutex_trylock(&sm_trylock)) 649 goto out; 650 mutex_lock(&crash_lock); 651 652 while (!die) { 653 wtime.tv_sec = delay; 654 wtime.tv_nsec = 0; 655 /* 656 * Wait until signalled to wakeup or time expired. 657 * If signalled to be awoken, then a crash has occurred 658 * or otherwise time expired. 659 */ 660 if (cond_reltimedwait(&retrywait, &crash_lock, &wtime) == 0) { 661 break; 662 } 663 664 /* Exit loop if queue is empty */ 665 if ((next = recov_q.sm_recovhdp) == NULL) 666 break; 667 668 mutex_unlock(&crash_lock); 669 670 while (((nl = next) != NULL) && (!die)) { 671 next = next->nxt; 672 if (statd_call_statd(nl->name) == 0) { 673 /* remove name from BACKUP */ 674 remove_name(nl->name, 1, 0); 675 mutex_lock(&recov_q.lock); 676 /* remove entry from recovery_q */ 677 delete_name(&recov_q.sm_recovhdp, nl->name); 678 mutex_unlock(&recov_q.lock); 679 } else { 680 /* 681 * Print message only once since unreachable 682 * host can be contacted forever. 683 */ 684 if (delay == 0) 685 syslog(LOG_WARNING, 686 "statd: host %s is not " 687 "responding\n", nl->name); 688 } 689 } 690 /* 691 * Increment the amount of delay before restarting again. 692 * The amount of delay should not exceed the MAX_DELAYTIME. 693 */ 694 if (delay <= MAX_DELAYTIME) 695 delay += INC_DELAYTIME; 696 mutex_lock(&crash_lock); 697 } 698 699 mutex_unlock(&crash_lock); 700 mutex_unlock(&sm_trylock); 701 out: 702 rw_unlock(&thr_rwlock); 703 if (debug) 704 (void) printf("EXITING sm_try\n"); 705 thr_exit((void *) 0); 706 #ifdef lint 707 return (0); 708 #endif 709 } 710 711 /* 712 * Malloc's space and returns the ptr to malloc'ed space. NULL if unsuccessful. 713 */ 714 char * 715 xmalloc(unsigned len) 716 { 717 char *new; 718 719 if ((new = malloc(len)) == 0) { 720 syslog(LOG_ERR, "statd: malloc, error %m\n"); 721 return (NULL); 722 } else { 723 (void) memset(new, 0, len); 724 return (new); 725 } 726 } 727 728 /* 729 * the following two routines are very similar to 730 * insert_mon and delete_mon in sm_proc.c, except the structture 731 * is different 732 */ 733 static name_entry * 734 insert_name(name_entry **namepp, char *name, int need_alloc) 735 { 736 name_entry *new; 737 738 new = (name_entry *)xmalloc(sizeof (name_entry)); 739 if (new == (name_entry *) NULL) 740 return (NULL); 741 742 /* Allocate name when needed which is only when adding to record_t */ 743 if (need_alloc) { 744 if ((new->name = strdup(name)) == NULL) { 745 syslog(LOG_ERR, "statd: strdup, error %m\n"); 746 free(new); 747 return (NULL); 748 } 749 } else 750 new->name = name; 751 752 new->nxt = *namepp; 753 if (new->nxt != NULL) 754 new->nxt->prev = new; 755 756 new->prev = (name_entry *) NULL; 757 758 *namepp = new; 759 if (debug) { 760 (void) printf("insert_name: inserted %s at %p\n", 761 name, (void *)namepp); 762 } 763 764 return (new); 765 } 766 767 /* 768 * Deletes name from specified list (namepp). 769 */ 770 static void 771 delete_name(name_entry **namepp, char *name) 772 { 773 name_entry *nl; 774 775 nl = *namepp; 776 while (nl != NULL) { 777 if (str_cmp_address_specifier(nl->name, name) == 0 || 778 str_cmp_unqual_hostname(nl->name, name) == 0) { 779 if (nl->prev != NULL) 780 nl->prev->nxt = nl->nxt; 781 else 782 *namepp = nl->nxt; 783 if (nl->nxt != NULL) 784 nl->nxt->prev = nl->prev; 785 free(nl->name); 786 free(nl); 787 return; 788 } 789 nl = nl->nxt; 790 } 791 } 792 793 /* 794 * Finds name from specified list (namep). 795 */ 796 static name_entry * 797 find_name(name_entry **namep, char *name) 798 { 799 name_entry *nl; 800 801 nl = *namep; 802 803 while (nl != NULL) { 804 if (str_cmp_unqual_hostname(nl->name, name) == 0) { 805 return (nl); 806 } 807 nl = nl->nxt; 808 } 809 return (NULL); 810 } 811 812 /* 813 * Creates a file. 814 */ 815 816 int 817 create_file(char *name) 818 { 819 int fd; 820 821 /* 822 * The file might already exist. If it does, we ask for only write 823 * permission, since that's all the file was created with. 824 */ 825 if ((fd = open(name, O_CREAT | O_WRONLY, S_IWUSR)) == -1) { 826 if (errno != EEXIST) { 827 syslog(LOG_ERR, "can't open %s: %m", name); 828 return (1); 829 } 830 } 831 832 if (debug >= 2) 833 (void) printf("%s is created\n", name); 834 if (close(fd)) { 835 syslog(LOG_ERR, "statd: close, error %m\n"); 836 return (1); 837 } 838 839 return (0); 840 } 841 842 /* 843 * Deletes the file specified by name. 844 */ 845 void 846 delete_file(char *name) 847 { 848 if (debug >= 2) 849 (void) printf("Remove monitor entry %s\n", name); 850 if (unlink(name) == -1) { 851 if (errno != ENOENT) 852 syslog(LOG_ERR, "statd: unlink of %s, error %m", name); 853 } 854 } 855 856 /* 857 * Return 1 if file is a symlink, else 0. 858 */ 859 int 860 is_symlink(char *file) 861 { 862 int error; 863 struct stat lbuf; 864 865 do { 866 bzero((caddr_t)&lbuf, sizeof (lbuf)); 867 error = lstat(file, &lbuf); 868 } while (error == EINTR); 869 870 if (error == 0) { 871 return ((lbuf.st_mode & S_IFMT) == S_IFLNK); 872 } 873 874 return (0); 875 } 876 877 /* 878 * Moves the file specified by `from' to `to' only if the 879 * new file is guaranteed to be created (which is presumably 880 * why we don't just do a rename(2)). If `from' is a 881 * symlink, the destination file will be a similar symlink 882 * in the directory of `to'. 883 * 884 * Returns 0 for success, 1 for failure. 885 */ 886 static int 887 move_file(char *fromdir, char *file, char *todir) 888 { 889 int n; 890 char rname[MAXNAMELEN + 1]; /* +1 for the terminating NULL */ 891 char from[MAXPATHLEN]; 892 char to[MAXPATHLEN]; 893 894 (void) strcpy(from, fromdir); 895 (void) strcat(from, "/"); 896 (void) strcat(from, file); 897 if (is_symlink(from)) { 898 /* 899 * Dig out the name of the regular file the link points to. 900 */ 901 n = readlink(from, rname, MAXNAMELEN); 902 if (n <= 0) { 903 if (debug >= 2) { 904 (void) printf("move_file: can't read link %s\n", 905 from); 906 } 907 return (1); 908 } 909 rname[n] = '\0'; 910 911 /* 912 * Create the link. 913 */ 914 if (create_symlink(todir, rname, file) != 0) { 915 return (1); 916 } 917 } else { 918 /* 919 * Do what we've always done to move regular files. 920 */ 921 (void) strcpy(to, todir); 922 (void) strcat(to, "/"); 923 (void) strcat(to, file); 924 if (create_file(to) != 0) { 925 return (1); 926 } 927 } 928 929 /* 930 * Remove the old file if we've created the new one. 931 */ 932 if (unlink(from) < 0) { 933 syslog(LOG_ERR, "move_file: unlink of %s, error %m", from); 934 return (1); 935 } 936 937 return (0); 938 } 939 940 /* 941 * Create a symbolic link named `lname' to regular file `rname'. 942 * Both files should be in directory `todir'. 943 */ 944 int 945 create_symlink(char *todir, char *rname, char *lname) 946 { 947 int error; 948 char lpath[MAXPATHLEN]; 949 950 /* 951 * Form the full pathname of the link. 952 */ 953 (void) strcpy(lpath, todir); 954 (void) strcat(lpath, "/"); 955 (void) strcat(lpath, lname); 956 957 /* 958 * Now make the new symlink ... 959 */ 960 if (symlink(rname, lpath) < 0) { 961 error = errno; 962 if (error != 0 && error != EEXIST) { 963 if (debug >= 2) { 964 (void) printf("create_symlink: can't link " 965 "%s/%s -> %s\n", todir, lname, rname); 966 } 967 return (1); 968 } 969 } 970 971 if (debug) { 972 if (error == EEXIST) { 973 (void) printf("link %s/%s -> %s already exists\n", 974 todir, lname, rname); 975 } else { 976 (void) printf("created link %s/%s -> %s\n", 977 todir, lname, rname); 978 } 979 } 980 981 return (0); 982 } 983 984 /* 985 * remove the name from the specified directory 986 * op = 0: CURRENT 987 * op = 1: BACKUP 988 */ 989 static void 990 remove_name(char *name, int op, int startup) 991 { 992 int i; 993 char *alt_dir; 994 char *queue; 995 996 if (op == 0) { 997 alt_dir = "statmon/sm"; 998 queue = CURRENT; 999 } else { 1000 alt_dir = "statmon/sm.bak"; 1001 queue = BACKUP; 1002 } 1003 1004 remove_single_name(name, queue, NULL); 1005 /* 1006 * At startup, entries have not yet been copied to alternate 1007 * directories and thus do not need to be removed. 1008 */ 1009 if (startup == 0) { 1010 for (i = 0; i < pathix; i++) { 1011 remove_single_name(name, path_name[i], alt_dir); 1012 } 1013 } 1014 } 1015 1016 /* 1017 * Remove the name from the specified directory, which is dir1/dir2 or 1018 * dir1, depending on whether dir2 is NULL. 1019 */ 1020 static void 1021 remove_single_name(char *name, char *dir1, char *dir2) 1022 { 1023 int n, error; 1024 char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN]; /* why > MAXPATHLEN? */ 1025 char dirpath[MAXPATHLEN]; 1026 char rname[MAXNAMELEN + 1]; /* +1 for NULL term */ 1027 1028 if (strlen(name) + strlen(dir1) + (dir2 != NULL ? strlen(dir2) : 0) + 1029 3 > MAXPATHLEN) { 1030 if (dir2 != NULL) 1031 syslog(LOG_ERR, 1032 "statd: pathname too long: %s/%s/%s\n", 1033 dir1, dir2, name); 1034 else 1035 syslog(LOG_ERR, 1036 "statd: pathname too long: %s/%s\n", 1037 dir1, name); 1038 1039 return; 1040 } 1041 1042 (void) strcpy(path, dir1); 1043 (void) strcat(path, "/"); 1044 if (dir2 != NULL) { 1045 (void) strcat(path, dir2); 1046 (void) strcat(path, "/"); 1047 } 1048 (void) strcpy(dirpath, path); /* save here - we may need it shortly */ 1049 (void) strcat(path, name); 1050 1051 /* 1052 * Despite the name of this routine :-@), `path' may be a symlink 1053 * to a regular file. If it is, and if that file has no other 1054 * links to it, we must remove it now as well. 1055 */ 1056 if (is_symlink(path)) { 1057 n = readlink(path, rname, MAXNAMELEN); 1058 if (n > 0) { 1059 rname[n] = '\0'; 1060 1061 if (count_symlinks(dirpath, rname, &n) < 0) { 1062 return; 1063 } 1064 1065 if (n == 1) { 1066 (void) strcat(dirpath, rname); 1067 error = unlink(dirpath); 1068 if (debug >= 2) { 1069 if (error < 0) { 1070 (void) printf( 1071 "remove_name: can't " 1072 "unlink %s\n", 1073 dirpath); 1074 } else { 1075 (void) printf( 1076 "remove_name: unlinked ", 1077 "%s\n", dirpath); 1078 } 1079 } 1080 } 1081 } else { 1082 /* 1083 * Policy: if we can't read the symlink, leave it 1084 * here for analysis by the system administrator. 1085 */ 1086 syslog(LOG_ERR, 1087 "statd: can't read link %s: %m\n", path); 1088 } 1089 } 1090 1091 /* 1092 * If it's a regular file, we can assume all symlinks and the 1093 * files to which they refer have been processed already - just 1094 * fall through to here to remove it. 1095 */ 1096 delete_file(path); 1097 } 1098 1099 /* 1100 * Count the number of symlinks in `dir' which point to `name' (also in dir). 1101 * Passes back symlink count in `count'. 1102 * Returns 0 for success, < 0 for failure. 1103 */ 1104 static int 1105 count_symlinks(char *dir, char *name, int *count) 1106 { 1107 int cnt = 0; 1108 int n; 1109 DIR *dp; 1110 struct dirent *dirp; 1111 char lpath[MAXPATHLEN]; 1112 char rname[MAXNAMELEN + 1]; /* +1 for term NULL */ 1113 1114 if ((dp = opendir(dir)) == NULL) { 1115 syslog(LOG_ERR, "count_symlinks: open %s dir, error %m\n", 1116 dir); 1117 return (-1); 1118 } 1119 1120 while ((dirp = readdir(dp)) != NULL) { 1121 if (strcmp(dirp->d_name, ".") == 0 || 1122 strcmp(dirp->d_name, "..") == 0) { 1123 continue; 1124 } 1125 1126 (void) sprintf(lpath, "%s%s", dir, dirp->d_name); 1127 if (is_symlink(lpath)) { 1128 /* 1129 * Fetch the name of the file the symlink refers to. 1130 */ 1131 n = readlink(lpath, rname, MAXNAMELEN); 1132 if (n <= 0) { 1133 if (debug >= 2) { 1134 (void) printf( 1135 "count_symlinks: can't read link " 1136 "%s\n", lpath); 1137 } 1138 continue; 1139 } 1140 rname[n] = '\0'; 1141 1142 /* 1143 * If `rname' matches `name', bump the count. There 1144 * may well be multiple symlinks to the same name, so 1145 * we must continue to process the entire directory. 1146 */ 1147 if (strcmp(rname, name) == 0) { 1148 cnt++; 1149 } 1150 } 1151 } 1152 1153 (void) closedir(dp); 1154 1155 if (debug) { 1156 (void) printf("count_symlinks: found %d symlinks\n", cnt); 1157 } 1158 *count = cnt; 1159 return (0); 1160 } 1161 1162 /* 1163 * Manage the cache of hostnames. An entry for each host that has recently 1164 * locked a file is kept. There is an in-ram table (record_table) and an empty 1165 * file in the file system name space (/var/statmon/sm/<name>). This 1166 * routine adds (deletes) the name to (from) the in-ram table and the entry 1167 * to (from) the file system name space. 1168 * 1169 * If op == 1 then the name is added to the queue otherwise the name is 1170 * deleted. 1171 */ 1172 void 1173 record_name(char *name, int op) 1174 { 1175 name_entry *nl; 1176 int i; 1177 char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN]; 1178 name_entry **record_q; 1179 unsigned int hash; 1180 1181 /* 1182 * These names are supposed to be just host names, not paths or 1183 * other arbitrary files. 1184 * manipulating the empty pathname unlinks CURRENT, 1185 * manipulating files with '/' would allow you to create and unlink 1186 * files all over the system; LOG_AUTH, it's a security thing. 1187 * Don't remove the directories . and .. 1188 */ 1189 if (name == NULL) 1190 return; 1191 1192 if (name[0] == '\0' || strchr(name, '/') != NULL || 1193 strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 1194 syslog(LOG_ERR|LOG_AUTH, "statd: attempt to %s \"%s/%s\"", 1195 op == 1 ? "create" : "remove", CURRENT, name); 1196 return; 1197 } 1198 1199 SMHASH(name, hash); 1200 if (debug) { 1201 if (op == 1) 1202 (void) printf("inserting %s at hash %d,\n", 1203 name, hash); 1204 else 1205 (void) printf("deleting %s at hash %d\n", name, hash); 1206 pr_name(name, 1); 1207 } 1208 1209 1210 if (op == 1) { /* insert */ 1211 mutex_lock(&record_table[hash].lock); 1212 record_q = &record_table[hash].sm_rechdp; 1213 if ((nl = find_name(record_q, name)) == NULL) { 1214 1215 int path_len; 1216 1217 if ((nl = insert_name(record_q, name, 1)) != 1218 (name_entry *) NULL) 1219 nl->count++; 1220 mutex_unlock(&record_table[hash].lock); 1221 /* make an entry in current directory */ 1222 1223 path_len = strlen(CURRENT) + strlen(name) + 2; 1224 if (path_len > MAXPATHLEN) { 1225 syslog(LOG_ERR, 1226 "statd: pathname too long: %s/%s\n", 1227 CURRENT, name); 1228 return; 1229 } 1230 (void) strcpy(path, CURRENT); 1231 (void) strcat(path, "/"); 1232 (void) strcat(path, name); 1233 (void) create_file(path); 1234 if (debug) { 1235 (void) printf("After insert_name\n"); 1236 pr_name(name, 1); 1237 } 1238 /* make an entry in alternate paths */ 1239 for (i = 0; i < pathix; i++) { 1240 path_len = strlen(path_name[i]) + 1241 strlen("/statmon/sm/") + strlen(name) + 1; 1242 1243 if (path_len > MAXPATHLEN) { 1244 syslog(LOG_ERR, "statd: pathname too " 1245 "long: %s/statmon/sm/%s\n", 1246 path_name[i], name); 1247 continue; 1248 } 1249 (void) strcpy(path, path_name[i]); 1250 (void) strcat(path, "/statmon/sm/"); 1251 (void) strcat(path, name); 1252 (void) create_file(path); 1253 } 1254 return; 1255 } 1256 nl->count++; 1257 mutex_unlock(&record_table[hash].lock); 1258 1259 } else { /* delete */ 1260 mutex_lock(&record_table[hash].lock); 1261 record_q = &record_table[hash].sm_rechdp; 1262 if ((nl = find_name(record_q, name)) == NULL) { 1263 mutex_unlock(&record_table[hash].lock); 1264 return; 1265 } 1266 nl->count--; 1267 if (nl->count == 0) { 1268 delete_name(record_q, name); 1269 mutex_unlock(&record_table[hash].lock); 1270 /* remove this entry from current directory */ 1271 remove_name(name, 0, 0); 1272 } else 1273 mutex_unlock(&record_table[hash].lock); 1274 if (debug) { 1275 (void) printf("After delete_name \n"); 1276 pr_name(name, 1); 1277 } 1278 } 1279 } 1280 1281 /* 1282 * This routine adds a symlink in the form of an ASCII dotted quad 1283 * IP address that is linked to the name already recorded in the 1284 * filesystem name space by record_name(). Enough information is 1285 * (hopefully) provided to support other address types in the future. 1286 * The purpose of this is to cache enough information to contact 1287 * hosts in other domains during server crash recovery (see bugid 1288 * 1184192). 1289 * 1290 * The worst failure mode here is that the symlink is not made, and 1291 * statd falls back to the old buggy behavior. 1292 */ 1293 void 1294 record_addr(char *name, sa_family_t family, struct netobj *ah) 1295 { 1296 int i; 1297 int path_len; 1298 char *famstr; 1299 struct in_addr addr; 1300 char *addr6; 1301 char ascii_addr[MAXNAMELEN]; 1302 char path[MAXPATHLEN]; 1303 1304 if (family == AF_INET) { 1305 if (ah->n_len != sizeof (struct in_addr)) 1306 return; 1307 addr = *(struct in_addr *)ah->n_bytes; 1308 } else if (family == AF_INET6) { 1309 if (ah->n_len != sizeof (struct in6_addr)) 1310 return; 1311 addr6 = (char *)ah->n_bytes; 1312 } else 1313 return; 1314 1315 if (debug) { 1316 if (family == AF_INET) 1317 (void) printf("record_addr: addr= %x\n", addr.s_addr); 1318 else if (family == AF_INET6) 1319 (void) printf("record_addr: addr= %x\n", 1320 ((struct in6_addr *)addr6)->s6_addr); 1321 } 1322 1323 if (family == AF_INET) { 1324 if (addr.s_addr == INADDR_ANY || 1325 ((addr.s_addr && 0xff000000) == 0)) { 1326 syslog(LOG_DEBUG, 1327 "record_addr: illegal IP address %x\n", 1328 addr.s_addr); 1329 return; 1330 } 1331 } 1332 1333 /* convert address to ASCII */ 1334 famstr = family2string(family); 1335 if (famstr == NULL) { 1336 syslog(LOG_DEBUG, 1337 "record_addr: unsupported address family %d\n", 1338 family); 1339 return; 1340 } 1341 1342 switch (family) { 1343 char abuf[INET6_ADDRSTRLEN]; 1344 case AF_INET: 1345 (void) sprintf(ascii_addr, "%s.%s", famstr, inet_ntoa(addr)); 1346 break; 1347 1348 case AF_INET6: 1349 (void) sprintf(ascii_addr, "%s.%s", famstr, 1350 inet_ntop(family, addr6, abuf, sizeof (abuf))); 1351 break; 1352 1353 default: 1354 if (debug) { 1355 (void) printf( 1356 "record_addr: family2string supports unknown " 1357 "family %d (%s)\n", family, famstr); 1358 } 1359 free(famstr); 1360 return; 1361 } 1362 1363 if (debug) { 1364 (void) printf("record_addr: ascii_addr= %s\n", ascii_addr); 1365 } 1366 free(famstr); 1367 1368 /* 1369 * Make the symlink in CURRENT. The `name' file should have 1370 * been created previously by record_name(). 1371 */ 1372 (void) create_symlink(CURRENT, name, ascii_addr); 1373 1374 /* 1375 * Similarly for alternate paths. 1376 */ 1377 for (i = 0; i < pathix; i++) { 1378 path_len = strlen(path_name[i]) + 1379 strlen("/statmon/sm/") + 1380 strlen(name) + 1; 1381 1382 if (path_len > MAXPATHLEN) { 1383 syslog(LOG_ERR, 1384 "statd: pathname too long: %s/statmon/sm/%s\n", 1385 path_name[i], name); 1386 continue; 1387 } 1388 (void) strcpy(path, path_name[i]); 1389 (void) strcat(path, "/statmon/sm"); 1390 (void) create_symlink(path, name, ascii_addr); 1391 } 1392 } 1393 1394 /* 1395 * SM_CRASH - simulate a crash of statd. 1396 */ 1397 void 1398 sm_crash(void) 1399 { 1400 name_entry *nl, *next; 1401 mon_entry *nl_monp, *mon_next; 1402 int k; 1403 my_id *nl_idp; 1404 1405 for (k = 0; k < MAX_HASHSIZE; k++) { 1406 mutex_lock(&mon_table[k].lock); 1407 if ((mon_next = mon_table[k].sm_monhdp) == 1408 (mon_entry *) NULL) { 1409 mutex_unlock(&mon_table[k].lock); 1410 continue; 1411 } else { 1412 while ((nl_monp = mon_next) != NULL) { 1413 mon_next = mon_next->nxt; 1414 nl_idp = &nl_monp->id.mon_id.my_id; 1415 free(nl_monp->id.mon_id.mon_name); 1416 free(nl_idp->my_name); 1417 free(nl_monp); 1418 } 1419 mon_table[k].sm_monhdp = NULL; 1420 } 1421 mutex_unlock(&mon_table[k].lock); 1422 } 1423 1424 /* Clean up entries in record table */ 1425 for (k = 0; k < MAX_HASHSIZE; k++) { 1426 mutex_lock(&record_table[k].lock); 1427 if ((next = record_table[k].sm_rechdp) == 1428 (name_entry *) NULL) { 1429 mutex_unlock(&record_table[k].lock); 1430 continue; 1431 } else { 1432 while ((nl = next) != NULL) { 1433 next = next->nxt; 1434 free(nl->name); 1435 free(nl); 1436 } 1437 record_table[k].sm_rechdp = NULL; 1438 } 1439 mutex_unlock(&record_table[k].lock); 1440 } 1441 1442 /* Clean up entries in recovery table */ 1443 mutex_lock(&recov_q.lock); 1444 if ((next = recov_q.sm_recovhdp) != NULL) { 1445 while ((nl = next) != NULL) { 1446 next = next->nxt; 1447 free(nl->name); 1448 free(nl); 1449 } 1450 recov_q.sm_recovhdp = NULL; 1451 } 1452 mutex_unlock(&recov_q.lock); 1453 statd_init(); 1454 } 1455 1456 /* 1457 * Initialize the hash tables: mon_table, record_table, recov_q and 1458 * locks. 1459 */ 1460 void 1461 sm_inithash(void) 1462 { 1463 int k; 1464 1465 if (debug) 1466 (void) printf("Initializing hash tables\n"); 1467 for (k = 0; k < MAX_HASHSIZE; k++) { 1468 mon_table[k].sm_monhdp = NULL; 1469 record_table[k].sm_rechdp = NULL; 1470 mutex_init(&mon_table[k].lock, USYNC_THREAD, NULL); 1471 mutex_init(&record_table[k].lock, USYNC_THREAD, NULL); 1472 } 1473 mutex_init(&recov_q.lock, USYNC_THREAD, NULL); 1474 recov_q.sm_recovhdp = NULL; 1475 1476 } 1477 1478 /* 1479 * Maps a socket address family to a name string, or NULL if the family 1480 * is not supported by statd. 1481 * Caller is responsible for freeing storage used by result string, if any. 1482 */ 1483 static char * 1484 family2string(sa_family_t family) 1485 { 1486 char *rc; 1487 1488 switch (family) { 1489 case AF_INET: 1490 rc = strdup(SM_ADDR_IPV4); 1491 break; 1492 1493 case AF_INET6: 1494 rc = strdup(SM_ADDR_IPV6); 1495 break; 1496 1497 default: 1498 rc = NULL; 1499 break; 1500 } 1501 1502 return (rc); 1503 } 1504 1505 /* 1506 * Prints out list in record_table if flag is 1 otherwise 1507 * prints out each list in recov_q specified by name. 1508 */ 1509 static void 1510 pr_name(char *name, int flag) 1511 { 1512 name_entry *nl; 1513 unsigned int hash; 1514 1515 if (!debug) 1516 return; 1517 if (flag) { 1518 SMHASH(name, hash); 1519 (void) printf("*****record_q: "); 1520 mutex_lock(&record_table[hash].lock); 1521 nl = record_table[hash].sm_rechdp; 1522 while (nl != NULL) { 1523 (void) printf("(%x), ", (int)nl); 1524 nl = nl->nxt; 1525 } 1526 mutex_unlock(&record_table[hash].lock); 1527 } else { 1528 (void) printf("*****recovery_q: "); 1529 mutex_lock(&recov_q.lock); 1530 nl = recov_q.sm_recovhdp; 1531 while (nl != NULL) { 1532 (void) printf("(%x), ", (int)nl); 1533 nl = nl->nxt; 1534 } 1535 mutex_unlock(&recov_q.lock); 1536 1537 } 1538 (void) printf("\n"); 1539 } 1540