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
statd_init(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 *
thr_statd_init(void * arg __unused)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 *
thr_call_statd(void * namep)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
statd_call_statd(char * name)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 size_t unq_len;
549
550 ntf.mon_name = hostname;
551 ntf.state = LOCAL_STATE;
552 if (debug)
553 (void) printf("statd_call_statd at %s\n", name);
554
555 /*
556 * If it looks like an ASCII <address family>.<address> specifier,
557 * strip off the family - we just want the address when obtaining
558 * a client handle.
559 * If it's anything else, just pass it on to create_client().
560 */
561 unq_len = strcspn(name, ".");
562
563 if ((strncmp(name, SM_ADDR_IPV4, unq_len) == 0) ||
564 (strncmp(name, SM_ADDR_IPV6, unq_len) == 0)) {
565 name_or_addr = strchr(name, '.') + 1;
566 } else {
567 name_or_addr = name;
568 }
569
570 /*
571 * NOTE: We depend here upon the fact that the RPC client code
572 * allows us to use ASCII dotted quad `names', i.e. "192.9.200.1".
573 * This may change in a future release.
574 */
575 if (debug) {
576 (void) printf("statd_call_statd: calling create_client(%s)\n",
577 name_or_addr);
578 }
579
580 tottimeout.tv_sec = SM_RPC_TIMEOUT;
581 tottimeout.tv_usec = 0;
582
583 if ((clnt = create_client(name_or_addr, SM_PROG, SM_VERS, NULL,
584 &tottimeout)) == NULL) {
585 return (-1);
586 }
587
588 /* Perform notification to client */
589 rc = 0;
590 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge, (char *)&ntf,
591 xdr_void, NULL, tottimeout);
592 if (debug) {
593 (void) printf("clnt_stat=%s(%d)\n",
594 clnt_sperrno(clnt_stat), clnt_stat);
595 }
596 if (clnt_stat != (int)RPC_SUCCESS) {
597 syslog(LOG_WARNING,
598 "statd: cannot talk to statd at %s, %s(%d)\n",
599 name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
600 rc = -1;
601 }
602
603 /*
604 * Wait until the host_name is populated.
605 */
606 (void) mutex_lock(&merges_lock);
607 while (in_merges)
608 (void) cond_wait(&merges_cond, &merges_lock);
609 (void) mutex_unlock(&merges_lock);
610
611 /* For HA systems and multi-homed hosts */
612 ntf.state = LOCAL_STATE;
613 for (i = 0; i < addrix; i++) {
614 ntf.mon_name = host_name[i];
615 if (debug)
616 (void) printf("statd_call_statd at %s\n", name_or_addr);
617 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge,
618 (char *)&ntf, xdr_void, NULL, tottimeout);
619 if (clnt_stat != (int)RPC_SUCCESS) {
620 syslog(LOG_WARNING,
621 "statd: cannot talk to statd at %s, %s(%d)\n",
622 name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
623 rc = -1;
624 }
625 }
626 clnt_destroy(clnt);
627 return (rc);
628 }
629
630 /*
631 * Continues to contact hosts in recovery table that were unreachable.
632 * NOTE: There should only be one sm_try thread executing and
633 * thus locks are not needed for recovery table. Die is only cleared
634 * after all the hosts has at least been contacted once. The reader/writer
635 * lock ensures to finish this code before an sm_crash is started. Die
636 * variable will signal it.
637 */
638 void *
sm_try(void * arg __unused)639 sm_try(void *arg __unused)
640 {
641 name_entry *nl, *next;
642 timestruc_t wtime;
643 int delay = 0;
644
645 rw_rdlock(&thr_rwlock);
646 if (mutex_trylock(&sm_trylock))
647 goto out;
648 mutex_lock(&crash_lock);
649
650 while (!die) {
651 wtime.tv_sec = delay;
652 wtime.tv_nsec = 0;
653 /*
654 * Wait until signalled to wakeup or time expired.
655 * If signalled to be awoken, then a crash has occurred
656 * or otherwise time expired.
657 */
658 if (cond_reltimedwait(&retrywait, &crash_lock, &wtime) == 0) {
659 break;
660 }
661
662 /* Exit loop if queue is empty */
663 if ((next = recov_q.sm_recovhdp) == NULL)
664 break;
665
666 mutex_unlock(&crash_lock);
667
668 while (((nl = next) != NULL) && (!die)) {
669 next = next->nxt;
670 if (statd_call_statd(nl->name) == 0) {
671 /* remove name from BACKUP */
672 remove_name(nl->name, 1, 0);
673 mutex_lock(&recov_q.lock);
674 /* remove entry from recovery_q */
675 delete_name(&recov_q.sm_recovhdp, nl->name);
676 mutex_unlock(&recov_q.lock);
677 } else {
678 /*
679 * Print message only once since unreachable
680 * host can be contacted forever.
681 */
682 if (delay == 0)
683 syslog(LOG_WARNING,
684 "statd: host %s is not "
685 "responding\n", nl->name);
686 }
687 }
688 /*
689 * Increment the amount of delay before restarting again.
690 * The amount of delay should not exceed the MAX_DELAYTIME.
691 */
692 if (delay <= MAX_DELAYTIME)
693 delay += INC_DELAYTIME;
694 mutex_lock(&crash_lock);
695 }
696
697 mutex_unlock(&crash_lock);
698 mutex_unlock(&sm_trylock);
699 out:
700 rw_unlock(&thr_rwlock);
701 if (debug)
702 (void) printf("EXITING sm_try\n");
703 thr_exit((void *) 0);
704 #ifdef lint
705 return (0);
706 #endif
707 }
708
709 /*
710 * Malloc's space and returns the ptr to malloc'ed space. NULL if unsuccessful.
711 */
712 char *
xmalloc(unsigned len)713 xmalloc(unsigned len)
714 {
715 char *new;
716
717 if ((new = malloc(len)) == 0) {
718 syslog(LOG_ERR, "statd: malloc, error %m\n");
719 return (NULL);
720 } else {
721 (void) memset(new, 0, len);
722 return (new);
723 }
724 }
725
726 /*
727 * the following two routines are very similar to
728 * insert_mon and delete_mon in sm_proc.c, except the structture
729 * is different
730 */
731 static name_entry *
insert_name(name_entry ** namepp,char * name,int need_alloc)732 insert_name(name_entry **namepp, char *name, int need_alloc)
733 {
734 name_entry *new;
735
736 new = (name_entry *)xmalloc(sizeof (name_entry));
737 if (new == (name_entry *) NULL)
738 return (NULL);
739
740 /* Allocate name when needed which is only when adding to record_t */
741 if (need_alloc) {
742 if ((new->name = strdup(name)) == NULL) {
743 syslog(LOG_ERR, "statd: strdup, error %m\n");
744 free(new);
745 return (NULL);
746 }
747 } else
748 new->name = name;
749
750 new->nxt = *namepp;
751 if (new->nxt != NULL)
752 new->nxt->prev = new;
753
754 new->prev = (name_entry *) NULL;
755
756 *namepp = new;
757 if (debug) {
758 (void) printf("insert_name: inserted %s at %p\n",
759 name, (void *)namepp);
760 }
761
762 return (new);
763 }
764
765 /*
766 * Deletes name from specified list (namepp).
767 */
768 static void
delete_name(name_entry ** namepp,char * name)769 delete_name(name_entry **namepp, char *name)
770 {
771 name_entry *nl;
772
773 nl = *namepp;
774 while (nl != NULL) {
775 if (str_cmp_address_specifier(nl->name, name) == 0 ||
776 str_cmp_unqual_hostname(nl->name, name) == 0) {
777 if (nl->prev != NULL)
778 nl->prev->nxt = nl->nxt;
779 else
780 *namepp = nl->nxt;
781 if (nl->nxt != NULL)
782 nl->nxt->prev = nl->prev;
783 free(nl->name);
784 free(nl);
785 return;
786 }
787 nl = nl->nxt;
788 }
789 }
790
791 /*
792 * Finds name from specified list (namep).
793 */
794 static name_entry *
find_name(name_entry ** namep,char * name)795 find_name(name_entry **namep, char *name)
796 {
797 name_entry *nl;
798
799 nl = *namep;
800
801 while (nl != NULL) {
802 if (str_cmp_unqual_hostname(nl->name, name) == 0) {
803 return (nl);
804 }
805 nl = nl->nxt;
806 }
807 return (NULL);
808 }
809
810 /*
811 * Creates a file.
812 */
813
814 int
create_file(char * name)815 create_file(char *name)
816 {
817 int fd;
818
819 /*
820 * The file might already exist. If it does, we ask for only write
821 * permission, since that's all the file was created with.
822 */
823 if ((fd = open(name, O_CREAT | O_WRONLY, S_IWUSR)) == -1) {
824 if (errno != EEXIST) {
825 syslog(LOG_ERR, "can't open %s: %m", name);
826 return (1);
827 }
828 }
829
830 if (debug >= 2)
831 (void) printf("%s is created\n", name);
832 if (close(fd)) {
833 syslog(LOG_ERR, "statd: close, error %m\n");
834 return (1);
835 }
836
837 return (0);
838 }
839
840 /*
841 * Deletes the file specified by name.
842 */
843 void
delete_file(char * name)844 delete_file(char *name)
845 {
846 if (debug >= 2)
847 (void) printf("Remove monitor entry %s\n", name);
848 if (unlink(name) == -1) {
849 if (errno != ENOENT)
850 syslog(LOG_ERR, "statd: unlink of %s, error %m", name);
851 }
852 }
853
854 /*
855 * Return 1 if file is a symlink, else 0.
856 */
857 int
is_symlink(char * file)858 is_symlink(char *file)
859 {
860 int error;
861 struct stat lbuf;
862
863 do {
864 bzero((caddr_t)&lbuf, sizeof (lbuf));
865 error = lstat(file, &lbuf);
866 } while (error == EINTR);
867
868 if (error == 0) {
869 return ((lbuf.st_mode & S_IFMT) == S_IFLNK);
870 }
871
872 return (0);
873 }
874
875 /*
876 * Moves the file specified by `from' to `to' only if the
877 * new file is guaranteed to be created (which is presumably
878 * why we don't just do a rename(2)). If `from' is a
879 * symlink, the destination file will be a similar symlink
880 * in the directory of `to'.
881 *
882 * Returns 0 for success, 1 for failure.
883 */
884 static int
move_file(char * fromdir,char * file,char * todir)885 move_file(char *fromdir, char *file, char *todir)
886 {
887 int n;
888 char rname[MAXNAMELEN + 1]; /* +1 for the terminating NULL */
889 char from[MAXPATHLEN];
890 char to[MAXPATHLEN];
891
892 (void) strcpy(from, fromdir);
893 (void) strcat(from, "/");
894 (void) strcat(from, file);
895 if (is_symlink(from)) {
896 /*
897 * Dig out the name of the regular file the link points to.
898 */
899 n = readlink(from, rname, MAXNAMELEN);
900 if (n <= 0) {
901 if (debug >= 2) {
902 (void) printf("move_file: can't read link %s\n",
903 from);
904 }
905 return (1);
906 }
907 rname[n] = '\0';
908
909 /*
910 * Create the link.
911 */
912 if (create_symlink(todir, rname, file) != 0) {
913 return (1);
914 }
915 } else {
916 /*
917 * Do what we've always done to move regular files.
918 */
919 (void) strcpy(to, todir);
920 (void) strcat(to, "/");
921 (void) strcat(to, file);
922 if (create_file(to) != 0) {
923 return (1);
924 }
925 }
926
927 /*
928 * Remove the old file if we've created the new one.
929 */
930 if (unlink(from) < 0) {
931 syslog(LOG_ERR, "move_file: unlink of %s, error %m", from);
932 return (1);
933 }
934
935 return (0);
936 }
937
938 /*
939 * Create a symbolic link named `lname' to regular file `rname'.
940 * Both files should be in directory `todir'.
941 */
942 int
create_symlink(char * todir,char * rname,char * lname)943 create_symlink(char *todir, char *rname, char *lname)
944 {
945 int error = 0;
946 char lpath[MAXPATHLEN];
947
948 /*
949 * Form the full pathname of the link.
950 */
951 (void) strcpy(lpath, todir);
952 (void) strcat(lpath, "/");
953 (void) strcat(lpath, lname);
954
955 /*
956 * Now make the new symlink ...
957 */
958 if (symlink(rname, lpath) < 0) {
959 error = errno;
960 if (error != 0 && error != EEXIST) {
961 if (debug >= 2) {
962 (void) printf("create_symlink: can't link "
963 "%s/%s -> %s\n", todir, lname, rname);
964 }
965 return (1);
966 }
967 }
968
969 if (debug) {
970 if (error == EEXIST) {
971 (void) printf("link %s/%s -> %s already exists\n",
972 todir, lname, rname);
973 } else {
974 (void) printf("created link %s/%s -> %s\n",
975 todir, lname, rname);
976 }
977 }
978
979 return (0);
980 }
981
982 /*
983 * remove the name from the specified directory
984 * op = 0: CURRENT
985 * op = 1: BACKUP
986 */
987 static void
remove_name(char * name,int op,int startup)988 remove_name(char *name, int op, int startup)
989 {
990 int i;
991 char *alt_dir;
992 char *queue;
993
994 if (op == 0) {
995 alt_dir = "statmon/sm";
996 queue = CURRENT;
997 } else {
998 alt_dir = "statmon/sm.bak";
999 queue = BACKUP;
1000 }
1001
1002 remove_single_name(name, queue, NULL);
1003 /*
1004 * At startup, entries have not yet been copied to alternate
1005 * directories and thus do not need to be removed.
1006 */
1007 if (startup == 0) {
1008 for (i = 0; i < pathix; i++) {
1009 remove_single_name(name, path_name[i], alt_dir);
1010 }
1011 }
1012 }
1013
1014 /*
1015 * Remove the name from the specified directory, which is dir1/dir2 or
1016 * dir1, depending on whether dir2 is NULL.
1017 */
1018 static void
remove_single_name(char * name,char * dir1,char * dir2)1019 remove_single_name(char *name, char *dir1, char *dir2)
1020 {
1021 int n, error;
1022 char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN]; /* why > MAXPATHLEN? */
1023 char dirpath[MAXPATHLEN];
1024 char rname[MAXNAMELEN + 1]; /* +1 for NULL term */
1025
1026 if (strlen(name) + strlen(dir1) + (dir2 != NULL ? strlen(dir2) : 0) +
1027 3 > MAXPATHLEN) {
1028 if (dir2 != NULL)
1029 syslog(LOG_ERR,
1030 "statd: pathname too long: %s/%s/%s\n",
1031 dir1, dir2, name);
1032 else
1033 syslog(LOG_ERR,
1034 "statd: pathname too long: %s/%s\n",
1035 dir1, name);
1036
1037 return;
1038 }
1039
1040 (void) strcpy(path, dir1);
1041 (void) strcat(path, "/");
1042 if (dir2 != NULL) {
1043 (void) strcat(path, dir2);
1044 (void) strcat(path, "/");
1045 }
1046 (void) strcpy(dirpath, path); /* save here - we may need it shortly */
1047 (void) strcat(path, name);
1048
1049 /*
1050 * Despite the name of this routine :-@), `path' may be a symlink
1051 * to a regular file. If it is, and if that file has no other
1052 * links to it, we must remove it now as well.
1053 */
1054 if (is_symlink(path)) {
1055 n = readlink(path, rname, MAXNAMELEN);
1056 if (n > 0) {
1057 rname[n] = '\0';
1058
1059 if (count_symlinks(dirpath, rname, &n) < 0) {
1060 return;
1061 }
1062
1063 if (n == 1) {
1064 (void) strcat(dirpath, rname);
1065 error = unlink(dirpath);
1066 if (debug >= 2) {
1067 if (error < 0) {
1068 (void) printf(
1069 "remove_name: can't "
1070 "unlink %s\n",
1071 dirpath);
1072 } else {
1073 (void) printf(
1074 "remove_name: unlinked ",
1075 "%s\n", dirpath);
1076 }
1077 }
1078 }
1079 } else {
1080 /*
1081 * Policy: if we can't read the symlink, leave it
1082 * here for analysis by the system administrator.
1083 */
1084 syslog(LOG_ERR,
1085 "statd: can't read link %s: %m\n", path);
1086 }
1087 }
1088
1089 /*
1090 * If it's a regular file, we can assume all symlinks and the
1091 * files to which they refer have been processed already - just
1092 * fall through to here to remove it.
1093 */
1094 delete_file(path);
1095 }
1096
1097 /*
1098 * Count the number of symlinks in `dir' which point to `name' (also in dir).
1099 * Passes back symlink count in `count'.
1100 * Returns 0 for success, < 0 for failure.
1101 */
1102 static int
count_symlinks(char * dir,char * name,int * count)1103 count_symlinks(char *dir, char *name, int *count)
1104 {
1105 int cnt = 0;
1106 int n;
1107 DIR *dp;
1108 struct dirent *dirp;
1109 char lpath[MAXPATHLEN];
1110 char rname[MAXNAMELEN + 1]; /* +1 for term NULL */
1111
1112 if ((dp = opendir(dir)) == NULL) {
1113 syslog(LOG_ERR, "count_symlinks: open %s dir, error %m\n",
1114 dir);
1115 return (-1);
1116 }
1117
1118 while ((dirp = readdir(dp)) != NULL) {
1119 if (strcmp(dirp->d_name, ".") == 0 ||
1120 strcmp(dirp->d_name, "..") == 0) {
1121 continue;
1122 }
1123
1124 (void) sprintf(lpath, "%s%s", dir, dirp->d_name);
1125 if (is_symlink(lpath)) {
1126 /*
1127 * Fetch the name of the file the symlink refers to.
1128 */
1129 n = readlink(lpath, rname, MAXNAMELEN);
1130 if (n <= 0) {
1131 if (debug >= 2) {
1132 (void) printf(
1133 "count_symlinks: can't read link "
1134 "%s\n", lpath);
1135 }
1136 continue;
1137 }
1138 rname[n] = '\0';
1139
1140 /*
1141 * If `rname' matches `name', bump the count. There
1142 * may well be multiple symlinks to the same name, so
1143 * we must continue to process the entire directory.
1144 */
1145 if (strcmp(rname, name) == 0) {
1146 cnt++;
1147 }
1148 }
1149 }
1150
1151 (void) closedir(dp);
1152
1153 if (debug) {
1154 (void) printf("count_symlinks: found %d symlinks\n", cnt);
1155 }
1156 *count = cnt;
1157 return (0);
1158 }
1159
1160 /*
1161 * Manage the cache of hostnames. An entry for each host that has recently
1162 * locked a file is kept. There is an in-ram table (record_table) and an empty
1163 * file in the file system name space (/var/statmon/sm/<name>). This
1164 * routine adds (deletes) the name to (from) the in-ram table and the entry
1165 * to (from) the file system name space.
1166 *
1167 * If op == 1 then the name is added to the queue otherwise the name is
1168 * deleted.
1169 */
1170 void
record_name(char * name,int op)1171 record_name(char *name, int op)
1172 {
1173 name_entry *nl;
1174 int i;
1175 char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];
1176 name_entry **record_q;
1177 unsigned int hash;
1178
1179 /*
1180 * These names are supposed to be just host names, not paths or
1181 * other arbitrary files.
1182 * manipulating the empty pathname unlinks CURRENT,
1183 * manipulating files with '/' would allow you to create and unlink
1184 * files all over the system; LOG_AUTH, it's a security thing.
1185 * Don't remove the directories . and ..
1186 */
1187 if (name == NULL)
1188 return;
1189
1190 if (name[0] == '\0' || strchr(name, '/') != NULL ||
1191 strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
1192 syslog(LOG_ERR|LOG_AUTH, "statd: attempt to %s \"%s/%s\"",
1193 op == 1 ? "create" : "remove", CURRENT, name);
1194 return;
1195 }
1196
1197 SMHASH(name, hash);
1198 if (debug) {
1199 if (op == 1)
1200 (void) printf("inserting %s at hash %d,\n",
1201 name, hash);
1202 else
1203 (void) printf("deleting %s at hash %d\n", name, hash);
1204 pr_name(name, 1);
1205 }
1206
1207
1208 if (op == 1) { /* insert */
1209 mutex_lock(&record_table[hash].lock);
1210 record_q = &record_table[hash].sm_rechdp;
1211 if ((nl = find_name(record_q, name)) == NULL) {
1212
1213 int path_len;
1214
1215 if ((nl = insert_name(record_q, name, 1)) !=
1216 (name_entry *) NULL)
1217 nl->count++;
1218 mutex_unlock(&record_table[hash].lock);
1219 /* make an entry in current directory */
1220
1221 path_len = strlen(CURRENT) + strlen(name) + 2;
1222 if (path_len > MAXPATHLEN) {
1223 syslog(LOG_ERR,
1224 "statd: pathname too long: %s/%s\n",
1225 CURRENT, name);
1226 return;
1227 }
1228 (void) strcpy(path, CURRENT);
1229 (void) strcat(path, "/");
1230 (void) strcat(path, name);
1231 (void) create_file(path);
1232 if (debug) {
1233 (void) printf("After insert_name\n");
1234 pr_name(name, 1);
1235 }
1236 /* make an entry in alternate paths */
1237 for (i = 0; i < pathix; i++) {
1238 path_len = strlen(path_name[i]) +
1239 strlen("/statmon/sm/") + strlen(name) + 1;
1240
1241 if (path_len > MAXPATHLEN) {
1242 syslog(LOG_ERR, "statd: pathname too "
1243 "long: %s/statmon/sm/%s\n",
1244 path_name[i], name);
1245 continue;
1246 }
1247 (void) strcpy(path, path_name[i]);
1248 (void) strcat(path, "/statmon/sm/");
1249 (void) strcat(path, name);
1250 (void) create_file(path);
1251 }
1252 return;
1253 }
1254 nl->count++;
1255 mutex_unlock(&record_table[hash].lock);
1256
1257 } else { /* delete */
1258 mutex_lock(&record_table[hash].lock);
1259 record_q = &record_table[hash].sm_rechdp;
1260 if ((nl = find_name(record_q, name)) == NULL) {
1261 mutex_unlock(&record_table[hash].lock);
1262 return;
1263 }
1264 nl->count--;
1265 if (nl->count == 0) {
1266 delete_name(record_q, name);
1267 mutex_unlock(&record_table[hash].lock);
1268 /* remove this entry from current directory */
1269 remove_name(name, 0, 0);
1270 } else
1271 mutex_unlock(&record_table[hash].lock);
1272 if (debug) {
1273 (void) printf("After delete_name \n");
1274 pr_name(name, 1);
1275 }
1276 }
1277 }
1278
1279 /*
1280 * This routine adds a symlink in the form of an IP address in
1281 * text string format that is linked to the name already recorded in the
1282 * filesystem name space by record_name(). Enough information is
1283 * (hopefully) provided to support other address types in the future.
1284 * The purpose of this is to cache enough information to contact
1285 * hosts in other domains during server crash recovery (see bugid
1286 * 1184192).
1287 *
1288 * The worst failure mode here is that the symlink is not made, and
1289 * statd falls back to the old buggy behavior.
1290 */
1291 void
record_addr(char * name,sa_family_t family,struct netobj * ah)1292 record_addr(char *name, sa_family_t family, struct netobj *ah)
1293 {
1294 int i;
1295 int path_len;
1296 char *famstr;
1297 struct in_addr addr = { 0 };
1298 char *addr6 = NULL;
1299 char ascii_addr[MAXNAMELEN];
1300 char path[MAXPATHLEN];
1301
1302 if (family == AF_INET) {
1303 if (ah->n_len != sizeof (struct in_addr))
1304 return;
1305 addr = *(struct in_addr *)ah->n_bytes;
1306 } else if (family == AF_INET6) {
1307 if (ah->n_len != sizeof (struct in6_addr))
1308 return;
1309 addr6 = (char *)ah->n_bytes;
1310 } else
1311 return;
1312
1313 if (debug) {
1314 if (family == AF_INET)
1315 (void) printf("record_addr: addr= %x\n", addr.s_addr);
1316 else if (family == AF_INET6)
1317 (void) printf("record_addr: addr= %x\n",
1318 ((struct in6_addr *)addr6)->s6_addr);
1319 }
1320
1321 if (family == AF_INET) {
1322 if ((ntohl(addr.s_addr) & 0xff000000) == 0) {
1323 syslog(LOG_DEBUG,
1324 "record_addr: illegal IP address %x\n",
1325 addr.s_addr);
1326 return;
1327 }
1328 }
1329
1330 /* convert address to ASCII */
1331 famstr = family2string(family);
1332 if (famstr == NULL) {
1333 syslog(LOG_DEBUG,
1334 "record_addr: unsupported address family %d\n",
1335 family);
1336 return;
1337 }
1338
1339 switch (family) {
1340 char abuf[INET6_ADDRSTRLEN];
1341 case AF_INET:
1342 (void) sprintf(ascii_addr, "%s.%s", famstr, inet_ntoa(addr));
1343 break;
1344
1345 case AF_INET6:
1346 (void) sprintf(ascii_addr, "%s.%s", famstr,
1347 inet_ntop(family, addr6, abuf, sizeof (abuf)));
1348 break;
1349
1350 default:
1351 if (debug) {
1352 (void) printf(
1353 "record_addr: family2string supports unknown "
1354 "family %d (%s)\n", family, famstr);
1355 }
1356 free(famstr);
1357 return;
1358 }
1359
1360 if (debug) {
1361 (void) printf("record_addr: ascii_addr= %s\n", ascii_addr);
1362 }
1363 free(famstr);
1364
1365 /*
1366 * Make the symlink in CURRENT. The `name' file should have
1367 * been created previously by record_name().
1368 */
1369 (void) create_symlink(CURRENT, name, ascii_addr);
1370
1371 /*
1372 * Similarly for alternate paths.
1373 */
1374 for (i = 0; i < pathix; i++) {
1375 path_len = strlen(path_name[i]) +
1376 strlen("/statmon/sm/") +
1377 strlen(name) + 1;
1378
1379 if (path_len > MAXPATHLEN) {
1380 syslog(LOG_ERR,
1381 "statd: pathname too long: %s/statmon/sm/%s\n",
1382 path_name[i], name);
1383 continue;
1384 }
1385 (void) strcpy(path, path_name[i]);
1386 (void) strcat(path, "/statmon/sm");
1387 (void) create_symlink(path, name, ascii_addr);
1388 }
1389 }
1390
1391 /*
1392 * SM_CRASH - simulate a crash of statd.
1393 */
1394 void
sm_crash(void)1395 sm_crash(void)
1396 {
1397 name_entry *nl, *next;
1398 mon_entry *nl_monp, *mon_next;
1399 int k;
1400 my_id *nl_idp;
1401
1402 for (k = 0; k < MAX_HASHSIZE; k++) {
1403 mutex_lock(&mon_table[k].lock);
1404 if ((mon_next = mon_table[k].sm_monhdp) ==
1405 (mon_entry *) NULL) {
1406 mutex_unlock(&mon_table[k].lock);
1407 continue;
1408 } else {
1409 while ((nl_monp = mon_next) != NULL) {
1410 mon_next = mon_next->nxt;
1411 nl_idp = &nl_monp->id.mon_id.my_id;
1412 free(nl_monp->id.mon_id.mon_name);
1413 free(nl_idp->my_name);
1414 free(nl_monp);
1415 }
1416 mon_table[k].sm_monhdp = NULL;
1417 }
1418 mutex_unlock(&mon_table[k].lock);
1419 }
1420
1421 /* Clean up entries in record table */
1422 for (k = 0; k < MAX_HASHSIZE; k++) {
1423 mutex_lock(&record_table[k].lock);
1424 if ((next = record_table[k].sm_rechdp) ==
1425 (name_entry *) NULL) {
1426 mutex_unlock(&record_table[k].lock);
1427 continue;
1428 } else {
1429 while ((nl = next) != NULL) {
1430 next = next->nxt;
1431 free(nl->name);
1432 free(nl);
1433 }
1434 record_table[k].sm_rechdp = NULL;
1435 }
1436 mutex_unlock(&record_table[k].lock);
1437 }
1438
1439 /* Clean up entries in recovery table */
1440 mutex_lock(&recov_q.lock);
1441 if ((next = recov_q.sm_recovhdp) != NULL) {
1442 while ((nl = next) != NULL) {
1443 next = next->nxt;
1444 free(nl->name);
1445 free(nl);
1446 }
1447 recov_q.sm_recovhdp = NULL;
1448 }
1449 mutex_unlock(&recov_q.lock);
1450 statd_init();
1451 }
1452
1453 /*
1454 * Initialize the hash tables: mon_table, record_table, recov_q and
1455 * locks.
1456 */
1457 void
sm_inithash(void)1458 sm_inithash(void)
1459 {
1460 int k;
1461
1462 if (debug)
1463 (void) printf("Initializing hash tables\n");
1464 for (k = 0; k < MAX_HASHSIZE; k++) {
1465 mon_table[k].sm_monhdp = NULL;
1466 record_table[k].sm_rechdp = NULL;
1467 mutex_init(&mon_table[k].lock, USYNC_THREAD, NULL);
1468 mutex_init(&record_table[k].lock, USYNC_THREAD, NULL);
1469 }
1470 mutex_init(&recov_q.lock, USYNC_THREAD, NULL);
1471 recov_q.sm_recovhdp = NULL;
1472
1473 }
1474
1475 /*
1476 * Maps a socket address family to a name string, or NULL if the family
1477 * is not supported by statd.
1478 * Caller is responsible for freeing storage used by result string, if any.
1479 */
1480 static char *
family2string(sa_family_t family)1481 family2string(sa_family_t family)
1482 {
1483 char *rc;
1484
1485 switch (family) {
1486 case AF_INET:
1487 rc = strdup(SM_ADDR_IPV4);
1488 break;
1489
1490 case AF_INET6:
1491 rc = strdup(SM_ADDR_IPV6);
1492 break;
1493
1494 default:
1495 rc = NULL;
1496 break;
1497 }
1498
1499 return (rc);
1500 }
1501
1502 /*
1503 * Prints out list in record_table if flag is 1 otherwise
1504 * prints out each list in recov_q specified by name.
1505 */
1506 static void
pr_name(char * name,int flag)1507 pr_name(char *name, int flag)
1508 {
1509 name_entry *nl;
1510 unsigned int hash;
1511
1512 if (!debug)
1513 return;
1514 if (flag) {
1515 SMHASH(name, hash);
1516 (void) printf("*****record_q: ");
1517 mutex_lock(&record_table[hash].lock);
1518 nl = record_table[hash].sm_rechdp;
1519 while (nl != NULL) {
1520 (void) printf("(%x), ", (int)nl);
1521 nl = nl->nxt;
1522 }
1523 mutex_unlock(&record_table[hash].lock);
1524 } else {
1525 (void) printf("*****recovery_q: ");
1526 mutex_lock(&recov_q.lock);
1527 nl = recov_q.sm_recovhdp;
1528 while (nl != NULL) {
1529 (void) printf("(%x), ", (int)nl);
1530 nl = nl->nxt;
1531 }
1532 mutex_unlock(&recov_q.lock);
1533
1534 }
1535 (void) printf("\n");
1536 }
1537