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.
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.
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]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
35 * University Copyright- Copyright (c) 1982, 1986, 1988
36 * The Regents of the University of California
39 * University Acknowledgment- Portions of this document are derived from
40 * software developed by the University of California, Berkeley, and its
45 * Copyright (c) 2012 by Delphix. All rights reserved.
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.
62 #include <sys/types.h>
65 #include <sys/param.h>
66 #include <arpa/inet.h>
69 #include <rpcsvc/sm_inter.h>
70 #include <rpcsvc/nsm_addr.h>
83 sm_hash_t mon_table
[MAX_HASHSIZE
];
84 static sm_hash_t record_table
[MAX_HASHSIZE
];
85 static sm_hash_t recov_q
;
87 static name_entry
*find_name(name_entry
**namepp
, char *name
);
88 static name_entry
*insert_name(name_entry
**namepp
, char *name
,
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
);
103 * called when statd first comes up; it searches /etc/sm to gather
104 * all entries to notify its own failure
113 char state_file
[MAXPATHLEN
+SM_MAXPATHLEN
];
116 (void) printf("enter statd_init\n");
119 * First try to open the file. If that fails, try to create it.
120 * If that fails, give up.
122 if ((fp
= fopen(STATE
, "r+")) == NULL
) {
123 if ((fp
= fopen(STATE
, "w+")) == NULL
) {
124 syslog(LOG_ERR
, "can't open %s: %m", STATE
);
127 (void) chmod(STATE
, 0644);
129 if ((fscanf(fp
, "%d", &LOCAL_STATE
)) == EOF
) {
131 (void) printf("empty file\n");
136 * Scan alternate paths for largest "state" number
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
) {
148 (void) chmod(state_file
, 0644);
150 if ((fscanf(fp_tmp
, "%d", &tmp_state
)) == EOF
) {
153 "statd: %s: file empty\n", state_file
);
154 (void) fclose(fp_tmp
);
157 if (tmp_state
> LOCAL_STATE
) {
158 LOCAL_STATE
= tmp_state
;
160 (void) printf("Update LOCAL STATE: %d\n",
163 (void) fclose(fp_tmp
);
166 LOCAL_STATE
= ((LOCAL_STATE
%2) == 0) ? LOCAL_STATE
+1 : LOCAL_STATE
+2;
168 /* IF local state overflows, reset to value 1 */
169 if (LOCAL_STATE
< 0) {
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");
179 (void) fprintf(fp
, "%-10d", LOCAL_STATE
);
181 if (fsync(fileno(fp
)) == -1) {
182 syslog(LOG_ERR
, "statd: fsync failed\n");
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
) {
192 "can't open %s: %m", state_file
);
195 (void) chmod(state_file
, 0644);
197 (void) fprintf(fp_tmp
, "%-10d", LOCAL_STATE
);
198 (void) fflush(fp_tmp
);
199 if (fsync(fileno(fp_tmp
)) == -1) {
201 "statd: %s: fsync failed\n", state_file
);
202 (void) fclose(fp_tmp
);
205 (void) fclose(fp_tmp
);
209 (void) printf("local state = %d\n", LOCAL_STATE
);
211 if ((mkdir(CURRENT
, SM_DIRECTORY_MODE
)) == -1) {
212 if (errno
!= EEXIST
) {
213 syslog(LOG_ERR
, "statd: mkdir current, error %m\n");
217 if ((mkdir(BACKUP
, SM_DIRECTORY_MODE
)) == -1) {
218 if (errno
!= EEXIST
) {
219 syslog(LOG_ERR
, "statd: mkdir backup, error %m\n");
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");
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
);
240 /* Contact hosts' statd */
241 if (thr_create(NULL
, 0, (void *(*)(void *))thr_statd_init
, NULL
,
242 THR_DETACHED
, NULL
)) {
244 "statd: unable to create thread for thr_statd_init\n");
250 * Work thread which contacts hosts' statd.
261 char buf
[MAXPATHLEN
+SM_MAXPATHLEN
];
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");
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.
276 while ((dirp
= readdir(dp
)) != NULL
) {
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.
283 (void) sprintf(buf
, "%s/%s", BACKUP
, dirp
->d_name
);
284 if (is_symlink(buf
) == 0) {
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.
293 if (num_threads
> MAX_THR
) {
294 num_join
= num_threads
/PERCENT_MINJOIN
;
295 for (i
= 0; i
< num_join
; i
++)
297 num_threads
-= num_join
;
301 * If can't alloc name then print error msg and
302 * continue to next item on list.
304 name
= strdup(dirp
->d_name
);
307 "statd: unable to allocate space for name %s\n",
312 /* Create a thread to do a statd_call_statd for name */
313 if (thr_create(NULL
, 0, thr_call_statd
, name
, 0, NULL
)) {
315 "statd: unable to create thr_call_statd() "
316 "for name %s.\n", dirp
->d_name
);
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.
328 for (i
= 0; i
< num_threads
; i
++) {
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).
341 while ((dirp
= readdir(dp
)) != NULL
) {
342 if (strcmp(dirp
->d_name
, ".") == 0 ||
343 strcmp(dirp
->d_name
, "..") == 0) {
347 (void) sprintf(buf
, "%s/%s", BACKUP
, dirp
->d_name
);
348 if (is_symlink(buf
)) {
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.
358 (void) printf("thr_statd_init: legacy %s\n",
363 * If the number of threads exceeds the maximum, wait
364 * for some fraction of them to finish before
367 if (num_threads
> MAX_THR
) {
368 num_join
= num_threads
/PERCENT_MINJOIN
;
369 for (i
= 0; i
< num_join
; i
++)
371 num_threads
-= num_join
;
375 * If can't alloc name then print error msg and
376 * continue to next item on list.
378 name
= strdup(dirp
->d_name
);
381 "statd: unable to allocate space for name %s\n",
386 /* Create a thread to do a statd_call_statd for name */
387 if (thr_create(NULL
, 0, thr_call_statd
, name
, 0, NULL
)) {
389 "statd: unable to create thr_call_statd() "
390 "for name %s.\n", dirp
->d_name
);
400 * Join the other threads created above before creating thread
401 * to process items in recovery table.
403 for (i
= 0; i
< num_threads
; i
++) {
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
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) {
417 syslog(LOG_ERR
, "statd: mkdir %s error %m\n",
420 copydir_from_to(BACKUP
, buf
);
422 copydir_from_to(BACKUP
, buf
);
427 * Reset the die and in_crash variables.
429 mutex_lock(&crash_lock
);
432 mutex_unlock(&crash_lock
);
435 (void) printf("Creating thread for sm_try\n");
437 /* Continue to notify statd on hosts that were unreachable. */
438 if (thr_create(NULL
, 0, (void *(*)(void *))sm_try
, NULL
, THR_DETACHED
,
441 "statd: unable to create thread for sm_try().\n");
442 thr_exit((void *) 0);
449 * Work thread to make call to statd_call_statd.
452 thr_call_statd(void *namep
)
454 char *name
= (char *)namep
;
457 * If statd of name is unreachable, add name to recovery table
458 * otherwise if statd_call_statd was successful, remove from backup.
460 if (statd_call_statd(name
) != 0) {
463 char path
[MAXPATHLEN
];
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
469 char rname
[MAXNAMELEN
+ 1];
473 "statd call failed, inserting %s in recov_q\n", name
);
475 mutex_lock(&recov_q
.lock
);
476 (void) insert_name(&recov_q
.sm_recovhdp
, name
, 0);
477 mutex_unlock(&recov_q
.lock
);
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.
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
);
496 "thr_call_statd: can't read "
502 tail
= strrchr(path
, '/') + 1;
504 if ((strlen(BACKUP
) + strlen(rname
) + 2) <=
506 (void) strcpy(tail
, rname
);
509 printf("thr_call_statd: path over"
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.
527 remove_name(name
, 1, 1);
530 thr_exit((void *) 0);
537 * Notifies the statd of host specified by name to indicate that
538 * state has changed for this server.
541 statd_call_statd(char *name
)
543 enum clnt_stat clnt_stat
;
544 struct timeval tottimeout
;
550 int dummy1
, dummy2
, dummy3
, dummy4
;
551 char ascii_addr
[MAXNAMELEN
];
554 ntf
.mon_name
= hostname
;
555 ntf
.state
= LOCAL_STATE
;
557 (void) printf("statd_call_statd at %s\n", name
);
560 * If it looks like an ASCII <address family>.<address> specifier,
561 * strip off the family - we just want the address when obtaining
563 * If it's anything else, just pass it on to create_client().
565 unq_len
= strcspn(name
, ".");
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;
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.
580 (void) printf("statd_call_statd: calling create_client(%s)\n",
584 tottimeout
.tv_sec
= SM_RPC_TIMEOUT
;
585 tottimeout
.tv_usec
= 0;
587 if ((clnt
= create_client(name_or_addr
, SM_PROG
, SM_VERS
, NULL
,
588 &tottimeout
)) == NULL
) {
592 /* Perform notification to client */
594 clnt_stat
= clnt_call(clnt
, SM_NOTIFY
, xdr_stat_chge
, (char *)&ntf
,
595 xdr_void
, NULL
, tottimeout
);
597 (void) printf("clnt_stat=%s(%d)\n",
598 clnt_sperrno(clnt_stat
), clnt_stat
);
600 if (clnt_stat
!= (int)RPC_SUCCESS
) {
602 "statd: cannot talk to statd at %s, %s(%d)\n",
603 name_or_addr
, clnt_sperrno(clnt_stat
), clnt_stat
);
608 * Wait until the host_name is populated.
610 (void) mutex_lock(&merges_lock
);
612 (void) cond_wait(&merges_cond
, &merges_lock
);
613 (void) mutex_unlock(&merges_lock
);
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
];
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
) {
625 "statd: cannot talk to statd at %s, %s(%d)\n",
626 name_or_addr
, clnt_sperrno(clnt_stat
), clnt_stat
);
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.
645 name_entry
*nl
, *next
;
649 rw_rdlock(&thr_rwlock
);
650 if (mutex_trylock(&sm_trylock
))
652 mutex_lock(&crash_lock
);
655 wtime
.tv_sec
= delay
;
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.
662 if (cond_reltimedwait(&retrywait
, &crash_lock
, &wtime
) == 0) {
666 /* Exit loop if queue is empty */
667 if ((next
= recov_q
.sm_recovhdp
) == NULL
)
670 mutex_unlock(&crash_lock
);
672 while (((nl
= next
) != NULL
) && (!die
)) {
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
);
683 * Print message only once since unreachable
684 * host can be contacted forever.
688 "statd: host %s is not "
689 "responding\n", nl
->name
);
693 * Increment the amount of delay before restarting again.
694 * The amount of delay should not exceed the MAX_DELAYTIME.
696 if (delay
<= MAX_DELAYTIME
)
697 delay
+= INC_DELAYTIME
;
698 mutex_lock(&crash_lock
);
701 mutex_unlock(&crash_lock
);
702 mutex_unlock(&sm_trylock
);
704 rw_unlock(&thr_rwlock
);
706 (void) printf("EXITING sm_try\n");
707 thr_exit((void *) 0);
714 * Malloc's space and returns the ptr to malloc'ed space. NULL if unsuccessful.
717 xmalloc(unsigned len
)
721 if ((new = malloc(len
)) == 0) {
722 syslog(LOG_ERR
, "statd: malloc, error %m\n");
725 (void) memset(new, 0, len
);
731 * the following two routines are very similar to
732 * insert_mon and delete_mon in sm_proc.c, except the structture
736 insert_name(name_entry
**namepp
, char *name
, int need_alloc
)
740 new = (name_entry
*)xmalloc(sizeof (name_entry
));
741 if (new == (name_entry
*) NULL
)
744 /* Allocate name when needed which is only when adding to record_t */
746 if ((new->name
= strdup(name
)) == NULL
) {
747 syslog(LOG_ERR
, "statd: strdup, error %m\n");
755 if (new->nxt
!= NULL
)
756 new->nxt
->prev
= new;
758 new->prev
= (name_entry
*) NULL
;
762 (void) printf("insert_name: inserted %s at %p\n",
763 name
, (void *)namepp
);
770 * Deletes name from specified list (namepp).
773 delete_name(name_entry
**namepp
, char *name
)
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
;
786 nl
->nxt
->prev
= nl
->prev
;
796 * Finds name from specified list (namep).
799 find_name(name_entry
**namep
, char *name
)
806 if (str_cmp_unqual_hostname(nl
->name
, name
) == 0) {
819 create_file(char *name
)
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.
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
);
835 (void) printf("%s is created\n", name
);
837 syslog(LOG_ERR
, "statd: close, error %m\n");
845 * Deletes the file specified by name.
848 delete_file(char *name
)
851 (void) printf("Remove monitor entry %s\n", name
);
852 if (unlink(name
) == -1) {
854 syslog(LOG_ERR
, "statd: unlink of %s, error %m", name
);
859 * Return 1 if file is a symlink, else 0.
862 is_symlink(char *file
)
868 bzero((caddr_t
)&lbuf
, sizeof (lbuf
));
869 error
= lstat(file
, &lbuf
);
870 } while (error
== EINTR
);
873 return ((lbuf
.st_mode
& S_IFMT
) == S_IFLNK
);
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'.
886 * Returns 0 for success, 1 for failure.
889 move_file(char *fromdir
, char *file
, char *todir
)
892 char rname
[MAXNAMELEN
+ 1]; /* +1 for the terminating NULL */
893 char from
[MAXPATHLEN
];
896 (void) strcpy(from
, fromdir
);
897 (void) strcat(from
, "/");
898 (void) strcat(from
, file
);
899 if (is_symlink(from
)) {
901 * Dig out the name of the regular file the link points to.
903 n
= readlink(from
, rname
, MAXNAMELEN
);
906 (void) printf("move_file: can't read link %s\n",
916 if (create_symlink(todir
, rname
, file
) != 0) {
921 * Do what we've always done to move regular files.
923 (void) strcpy(to
, todir
);
924 (void) strcat(to
, "/");
925 (void) strcat(to
, file
);
926 if (create_file(to
) != 0) {
932 * Remove the old file if we've created the new one.
934 if (unlink(from
) < 0) {
935 syslog(LOG_ERR
, "move_file: unlink of %s, error %m", from
);
943 * Create a symbolic link named `lname' to regular file `rname'.
944 * Both files should be in directory `todir'.
947 create_symlink(char *todir
, char *rname
, char *lname
)
950 char lpath
[MAXPATHLEN
];
953 * Form the full pathname of the link.
955 (void) strcpy(lpath
, todir
);
956 (void) strcat(lpath
, "/");
957 (void) strcat(lpath
, lname
);
960 * Now make the new symlink ...
962 if (symlink(rname
, lpath
) < 0) {
964 if (error
!= 0 && error
!= EEXIST
) {
966 (void) printf("create_symlink: can't link "
967 "%s/%s -> %s\n", todir
, lname
, rname
);
974 if (error
== EEXIST
) {
975 (void) printf("link %s/%s -> %s already exists\n",
976 todir
, lname
, rname
);
978 (void) printf("created link %s/%s -> %s\n",
979 todir
, lname
, rname
);
987 * remove the name from the specified directory
992 remove_name(char *name
, int op
, int startup
)
999 alt_dir
= "statmon/sm";
1002 alt_dir
= "statmon/sm.bak";
1006 remove_single_name(name
, queue
, NULL
);
1008 * At startup, entries have not yet been copied to alternate
1009 * directories and thus do not need to be removed.
1012 for (i
= 0; i
< pathix
; i
++) {
1013 remove_single_name(name
, path_name
[i
], alt_dir
);
1019 * Remove the name from the specified directory, which is dir1/dir2 or
1020 * dir1, depending on whether dir2 is NULL.
1023 remove_single_name(char *name
, char *dir1
, char *dir2
)
1026 char path
[MAXPATHLEN
+MAXNAMELEN
+SM_MAXPATHLEN
]; /* why > MAXPATHLEN? */
1027 char dirpath
[MAXPATHLEN
];
1028 char rname
[MAXNAMELEN
+ 1]; /* +1 for NULL term */
1030 if (strlen(name
) + strlen(dir1
) + (dir2
!= NULL
? strlen(dir2
) : 0) +
1034 "statd: pathname too long: %s/%s/%s\n",
1038 "statd: pathname too long: %s/%s\n",
1044 (void) strcpy(path
, dir1
);
1045 (void) strcat(path
, "/");
1047 (void) strcat(path
, dir2
);
1048 (void) strcat(path
, "/");
1050 (void) strcpy(dirpath
, path
); /* save here - we may need it shortly */
1051 (void) strcat(path
, name
);
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.
1058 if (is_symlink(path
)) {
1059 n
= readlink(path
, rname
, MAXNAMELEN
);
1063 if (count_symlinks(dirpath
, rname
, &n
) < 0) {
1068 (void) strcat(dirpath
, rname
);
1069 error
= unlink(dirpath
);
1073 "remove_name: can't "
1078 "remove_name: unlinked ",
1085 * Policy: if we can't read the symlink, leave it
1086 * here for analysis by the system administrator.
1089 "statd: can't read link %s: %m\n", path
);
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.
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.
1107 count_symlinks(char *dir
, char *name
, int *count
)
1112 struct dirent
*dirp
;
1113 char lpath
[MAXPATHLEN
];
1114 char rname
[MAXNAMELEN
+ 1]; /* +1 for term NULL */
1116 if ((dp
= opendir(dir
)) == NULL
) {
1117 syslog(LOG_ERR
, "count_symlinks: open %s dir, error %m\n",
1122 while ((dirp
= readdir(dp
)) != NULL
) {
1123 if (strcmp(dirp
->d_name
, ".") == 0 ||
1124 strcmp(dirp
->d_name
, "..") == 0) {
1128 (void) sprintf(lpath
, "%s%s", dir
, dirp
->d_name
);
1129 if (is_symlink(lpath
)) {
1131 * Fetch the name of the file the symlink refers to.
1133 n
= readlink(lpath
, rname
, MAXNAMELEN
);
1137 "count_symlinks: can't read link "
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.
1149 if (strcmp(rname
, name
) == 0) {
1155 (void) closedir(dp
);
1158 (void) printf("count_symlinks: found %d symlinks\n", cnt
);
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.
1171 * If op == 1 then the name is added to the queue otherwise the name is
1175 record_name(char *name
, int op
)
1179 char path
[MAXPATHLEN
+MAXNAMELEN
+SM_MAXPATHLEN
];
1180 name_entry
**record_q
;
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 ..
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
);
1204 (void) printf("inserting %s at hash %d,\n",
1207 (void) printf("deleting %s at hash %d\n", name
, hash
);
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
) {
1219 if ((nl
= insert_name(record_q
, name
, 1)) !=
1220 (name_entry
*) NULL
)
1222 mutex_unlock(&record_table
[hash
].lock
);
1223 /* make an entry in current directory */
1225 path_len
= strlen(CURRENT
) + strlen(name
) + 2;
1226 if (path_len
> MAXPATHLEN
) {
1228 "statd: pathname too long: %s/%s\n",
1232 (void) strcpy(path
, CURRENT
);
1233 (void) strcat(path
, "/");
1234 (void) strcat(path
, name
);
1235 (void) create_file(path
);
1237 (void) printf("After insert_name\n");
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;
1245 if (path_len
> MAXPATHLEN
) {
1246 syslog(LOG_ERR
, "statd: pathname too "
1247 "long: %s/statmon/sm/%s\n",
1248 path_name
[i
], name
);
1251 (void) strcpy(path
, path_name
[i
]);
1252 (void) strcat(path
, "/statmon/sm/");
1253 (void) strcat(path
, name
);
1254 (void) create_file(path
);
1259 mutex_unlock(&record_table
[hash
].lock
);
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
);
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);
1275 mutex_unlock(&record_table
[hash
].lock
);
1277 (void) printf("After delete_name \n");
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
1292 * The worst failure mode here is that the symlink is not made, and
1293 * statd falls back to the old buggy behavior.
1296 record_addr(char *name
, sa_family_t family
, struct netobj
*ah
)
1301 struct in_addr addr
;
1303 char ascii_addr
[MAXNAMELEN
];
1304 char path
[MAXPATHLEN
];
1306 if (family
== AF_INET
) {
1307 if (ah
->n_len
!= sizeof (struct in_addr
))
1309 addr
= *(struct in_addr
*)ah
->n_bytes
;
1310 } else if (family
== AF_INET6
) {
1311 if (ah
->n_len
!= sizeof (struct in6_addr
))
1313 addr6
= (char *)ah
->n_bytes
;
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
);
1325 if (family
== AF_INET
) {
1326 if (addr
.s_addr
== INADDR_ANY
||
1327 ((addr
.s_addr
&& 0xff000000) == 0)) {
1329 "record_addr: illegal IP address %x\n",
1335 /* convert address to ASCII */
1336 famstr
= family2string(family
);
1337 if (famstr
== NULL
) {
1339 "record_addr: unsupported address family %d\n",
1345 char abuf
[INET6_ADDRSTRLEN
];
1347 (void) sprintf(ascii_addr
, "%s.%s", famstr
, inet_ntoa(addr
));
1351 (void) sprintf(ascii_addr
, "%s.%s", famstr
,
1352 inet_ntop(family
, addr6
, abuf
, sizeof (abuf
)));
1358 "record_addr: family2string supports unknown "
1359 "family %d (%s)\n", family
, famstr
);
1366 (void) printf("record_addr: ascii_addr= %s\n", ascii_addr
);
1371 * Make the symlink in CURRENT. The `name' file should have
1372 * been created previously by record_name().
1374 (void) create_symlink(CURRENT
, name
, ascii_addr
);
1377 * Similarly for alternate paths.
1379 for (i
= 0; i
< pathix
; i
++) {
1380 path_len
= strlen(path_name
[i
]) +
1381 strlen("/statmon/sm/") +
1384 if (path_len
> MAXPATHLEN
) {
1386 "statd: pathname too long: %s/statmon/sm/%s\n",
1387 path_name
[i
], name
);
1390 (void) strcpy(path
, path_name
[i
]);
1391 (void) strcat(path
, "/statmon/sm");
1392 (void) create_symlink(path
, name
, ascii_addr
);
1397 * SM_CRASH - simulate a crash of statd.
1402 name_entry
*nl
, *next
;
1403 mon_entry
*nl_monp
, *mon_next
;
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
);
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
);
1421 mon_table
[k
].sm_monhdp
= NULL
;
1423 mutex_unlock(&mon_table
[k
].lock
);
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
);
1434 while ((nl
= next
) != NULL
) {
1439 record_table
[k
].sm_rechdp
= NULL
;
1441 mutex_unlock(&record_table
[k
].lock
);
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
) {
1452 recov_q
.sm_recovhdp
= NULL
;
1454 mutex_unlock(&recov_q
.lock
);
1459 * Initialize the hash tables: mon_table, record_table, recov_q and
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
);
1475 mutex_init(&recov_q
.lock
, USYNC_THREAD
, NULL
);
1476 recov_q
.sm_recovhdp
= NULL
;
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.
1486 family2string(sa_family_t family
)
1492 rc
= strdup(SM_ADDR_IPV4
);
1496 rc
= strdup(SM_ADDR_IPV6
);
1508 * Prints out list in record_table if flag is 1 otherwise
1509 * prints out each list in recov_q specified by name.
1512 pr_name(char *name
, int flag
)
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
);
1528 mutex_unlock(&record_table
[hash
].lock
);
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
);
1537 mutex_unlock(&recov_q
.lock
);
1540 (void) printf("\n");