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, (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 *
thr_statd_init(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 *
thr_call_statd(void * namep)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
statd_call_statd(char * name)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 *
sm_try(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 *
xmalloc(unsigned len)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 *
insert_name(name_entry ** namepp,char * name,int need_alloc)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
delete_name(name_entry ** namepp,char * name)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 *
find_name(name_entry ** namep,char * name)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
create_file(char * name)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
delete_file(char * name)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
is_symlink(char * file)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
move_file(char * fromdir,char * file,char * todir)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
create_symlink(char * todir,char * rname,char * lname)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
remove_name(char * name,int op,int startup)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
remove_single_name(char * name,char * dir1,char * dir2)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
count_symlinks(char * dir,char * name,int * count)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
record_name(char * name,int op)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
record_addr(char * name,sa_family_t family,struct netobj * ah)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
sm_crash(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
sm_inithash(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 *
family2string(sa_family_t family)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
pr_name(char * name,int flag)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