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