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