#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/param.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <rpc/rpc.h>
#include <rpcsvc/sm_inter.h>
#include <rpcsvc/nsm_addr.h>
#include <errno.h>
#include <memory.h>
#include <signal.h>
#include <synch.h>
#include <thread.h>
#include <limits.h>
#include <strings.h>
#include "sm_statd.h"
int LOCAL_STATE;
sm_hash_t mon_table[MAX_HASHSIZE];
static sm_hash_t record_table[MAX_HASHSIZE];
static sm_hash_t recov_q;
static name_entry *find_name(name_entry **namepp, char *name);
static name_entry *insert_name(name_entry **namepp, char *name,
int need_alloc);
static void delete_name(name_entry **namepp, char *name);
static void remove_name(char *name, int op, int startup);
static int statd_call_statd(char *name);
static void pr_name(char *name, int flag);
static void *thr_statd_init(void *);
static void *sm_try(void *);
static void *thr_call_statd(void *);
static void remove_single_name(char *name, char *dir1, char *dir2);
static int move_file(char *fromdir, char *file, char *todir);
static int count_symlinks(char *dir, char *name, int *count);
static char *family2string(sa_family_t family);
void
statd_init(void)
{
struct dirent *dirp;
DIR *dp;
FILE *fp, *fp_tmp;
int i, tmp_state;
char state_file[MAXPATHLEN+SM_MAXPATHLEN];
if (debug)
(void) printf("enter statd_init\n");
if ((fp = fopen(STATE, "r+")) == NULL) {
if ((fp = fopen(STATE, "w+")) == NULL) {
syslog(LOG_ERR, "can't open %s: %m", STATE);
exit(1);
} else
(void) chmod(STATE, 0644);
}
if ((fscanf(fp, "%d", &LOCAL_STATE)) == EOF) {
if (debug >= 2)
(void) printf("empty file\n");
LOCAL_STATE = 0;
}
for (i = 0; i < pathix; i++) {
(void) sprintf(state_file, "%s/statmon/state", path_name[i]);
if ((fp_tmp = fopen(state_file, "r+")) == NULL) {
if ((fp_tmp = fopen(state_file, "w+")) == NULL) {
if (debug)
syslog(LOG_ERR,
"can't open %s: %m",
state_file);
continue;
} else
(void) chmod(state_file, 0644);
}
if ((fscanf(fp_tmp, "%d", &tmp_state)) == EOF) {
if (debug)
syslog(LOG_ERR,
"statd: %s: file empty\n", state_file);
(void) fclose(fp_tmp);
continue;
}
if (tmp_state > LOCAL_STATE) {
LOCAL_STATE = tmp_state;
if (debug)
(void) printf("Update LOCAL STATE: %d\n",
tmp_state);
}
(void) fclose(fp_tmp);
}
LOCAL_STATE = ((LOCAL_STATE%2) == 0) ? LOCAL_STATE+1 : LOCAL_STATE+2;
if (LOCAL_STATE < 0) {
LOCAL_STATE = 1;
}
if (fseek(fp, 0, 0) == -1) {
syslog(LOG_ERR, "statd: fseek failed\n");
exit(1);
}
(void) fprintf(fp, "%-10d", LOCAL_STATE);
(void) fflush(fp);
if (fsync(fileno(fp)) == -1) {
syslog(LOG_ERR, "statd: fsync failed\n");
exit(1);
}
(void) fclose(fp);
for (i = 0; i < pathix; i++) {
(void) sprintf(state_file, "%s/statmon/state", path_name[i]);
if ((fp_tmp = fopen(state_file, "r+")) == NULL) {
if ((fp_tmp = fopen(state_file, "w+")) == NULL) {
syslog(LOG_ERR,
"can't open %s: %m", state_file);
continue;
} else
(void) chmod(state_file, 0644);
}
(void) fprintf(fp_tmp, "%-10d", LOCAL_STATE);
(void) fflush(fp_tmp);
if (fsync(fileno(fp_tmp)) == -1) {
syslog(LOG_ERR,
"statd: %s: fsync failed\n", state_file);
(void) fclose(fp_tmp);
exit(1);
}
(void) fclose(fp_tmp);
}
if (debug)
(void) printf("local state = %d\n", LOCAL_STATE);
if ((mkdir(CURRENT, SM_DIRECTORY_MODE)) == -1) {
if (errno != EEXIST) {
syslog(LOG_ERR, "statd: mkdir current, error %m\n");
exit(1);
}
}
if ((mkdir(BACKUP, SM_DIRECTORY_MODE)) == -1) {
if (errno != EEXIST) {
syslog(LOG_ERR, "statd: mkdir backup, error %m\n");
exit(1);
}
}
if ((dp = opendir(CURRENT)) == NULL) {
syslog(LOG_ERR, "statd: open current directory, error %m\n");
exit(1);
}
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp->d_name, ".") != 0 &&
strcmp(dirp->d_name, "..") != 0) {
(void) move_file(CURRENT, dirp->d_name, BACKUP);
}
}
(void) closedir(dp);
if (thr_create(NULL, 0, thr_statd_init, NULL, THR_DETACHED, NULL)) {
syslog(LOG_ERR,
"statd: unable to create thread for thr_statd_init\n");
exit(1);
}
}
static void *
thr_statd_init(void *arg __unused)
{
struct dirent *dirp;
DIR *dp;
int num_threads;
int num_join;
int i;
char *name;
char buf[MAXPATHLEN+SM_MAXPATHLEN];
if ((dp = opendir(BACKUP)) == NULL) {
syslog(LOG_ERR, "statd: open backup directory, error %m\n");
exit(1);
}
num_threads = 0;
while ((dirp = readdir(dp)) != NULL) {
(void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
if (is_symlink(buf) == 0) {
continue;
}
if (num_threads > MAX_THR) {
num_join = num_threads/PERCENT_MINJOIN;
for (i = 0; i < num_join; i++)
thr_join(0, 0, 0);
num_threads -= num_join;
}
name = strdup(dirp->d_name);
if (name == NULL) {
syslog(LOG_ERR,
"statd: unable to allocate space for name %s\n",
dirp->d_name);
continue;
}
if (thr_create(NULL, 0, thr_call_statd, name, 0, NULL)) {
syslog(LOG_ERR,
"statd: unable to create thr_call_statd() "
"for name %s.\n", dirp->d_name);
free(name);
continue;
}
num_threads++;
}
for (i = 0; i < num_threads; i++) {
thr_join(0, 0, 0);
}
rewinddir(dp);
num_threads = 0;
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp->d_name, ".") == 0 ||
strcmp(dirp->d_name, "..") == 0) {
continue;
}
(void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
if (is_symlink(buf)) {
continue;
}
if (debug) {
(void) printf("thr_statd_init: legacy %s\n",
dirp->d_name);
}
if (num_threads > MAX_THR) {
num_join = num_threads/PERCENT_MINJOIN;
for (i = 0; i < num_join; i++)
thr_join(0, 0, 0);
num_threads -= num_join;
}
name = strdup(dirp->d_name);
if (name == NULL) {
syslog(LOG_ERR,
"statd: unable to allocate space for name %s\n",
dirp->d_name);
continue;
}
if (thr_create(NULL, 0, thr_call_statd, name, 0, NULL)) {
syslog(LOG_ERR,
"statd: unable to create thr_call_statd() "
"for name %s.\n", dirp->d_name);
free(name);
continue;
}
num_threads++;
}
(void) closedir(dp);
for (i = 0; i < num_threads; i++) {
thr_join(0, 0, 0);
}
for (i = 0; i < pathix; i++) {
(void) sprintf(buf, "%s/statmon/sm.bak", path_name[i]);
if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
if (errno != EEXIST)
syslog(LOG_ERR, "statd: mkdir %s error %m\n",
buf);
else
copydir_from_to(BACKUP, buf);
} else
copydir_from_to(BACKUP, buf);
}
mutex_lock(&crash_lock);
die = 0;
in_crash = 0;
mutex_unlock(&crash_lock);
if (debug)
(void) printf("Creating thread for sm_try\n");
if (thr_create(NULL, 0, sm_try, NULL, THR_DETACHED, NULL))
syslog(LOG_ERR,
"statd: unable to create thread for sm_try().\n");
thr_exit(NULL);
#ifdef lint
return (0);
#endif
}
void *
thr_call_statd(void *namep)
{
char *name = (char *)namep;
if (statd_call_statd(name) != 0) {
int n;
char *tail;
char path[MAXPATHLEN];
char rname[MAXNAMELEN + 1];
if (debug) {
(void) printf(
"statd call failed, inserting %s in recov_q\n", name);
}
mutex_lock(&recov_q.lock);
(void) insert_name(&recov_q.sm_recovhdp, name, 0);
mutex_unlock(&recov_q.lock);
(void) strcpy(path, BACKUP);
(void) strcat(path, "/");
(void) strcat(path, name);
if (is_symlink(path)) {
n = readlink(path, rname, MAXNAMELEN);
if (n <= 0) {
if (debug >= 2) {
(void) printf(
"thr_call_statd: can't read "
"link %s\n", path);
}
} else {
rname[n] = '\0';
tail = strrchr(path, '/') + 1;
if ((strlen(BACKUP) + strlen(rname) + 2) <=
MAXPATHLEN) {
(void) strcpy(tail, rname);
delete_file(path);
} else if (debug) {
printf("thr_call_statd: path over"
"maxpathlen!\n");
}
}
}
if (debug)
pr_name(name, 0);
} else {
remove_name(name, 1, 1);
free(name);
}
thr_exit((void *) 0);
#ifdef lint
return (0);
#endif
}
static int
statd_call_statd(char *name)
{
enum clnt_stat clnt_stat;
struct timeval tottimeout;
CLIENT *clnt;
char *name_or_addr;
stat_chge ntf;
int i;
int rc;
size_t unq_len;
ntf.mon_name = hostname;
ntf.state = LOCAL_STATE;
if (debug)
(void) printf("statd_call_statd at %s\n", name);
unq_len = strcspn(name, ".");
if ((strncmp(name, SM_ADDR_IPV4, unq_len) == 0) ||
(strncmp(name, SM_ADDR_IPV6, unq_len) == 0)) {
name_or_addr = strchr(name, '.') + 1;
} else {
name_or_addr = name;
}
if (debug) {
(void) printf("statd_call_statd: calling create_client(%s)\n",
name_or_addr);
}
tottimeout.tv_sec = SM_RPC_TIMEOUT;
tottimeout.tv_usec = 0;
if ((clnt = create_client(name_or_addr, SM_PROG, SM_VERS, NULL,
&tottimeout)) == NULL) {
return (-1);
}
rc = 0;
clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge, (char *)&ntf,
xdr_void, NULL, tottimeout);
if (debug) {
(void) printf("clnt_stat=%s(%d)\n",
clnt_sperrno(clnt_stat), clnt_stat);
}
if (clnt_stat != (int)RPC_SUCCESS) {
syslog(LOG_WARNING,
"statd: cannot talk to statd at %s, %s(%d)\n",
name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
rc = -1;
}
(void) mutex_lock(&merges_lock);
while (in_merges)
(void) cond_wait(&merges_cond, &merges_lock);
(void) mutex_unlock(&merges_lock);
ntf.state = LOCAL_STATE;
for (i = 0; i < addrix; i++) {
ntf.mon_name = host_name[i];
if (debug)
(void) printf("statd_call_statd at %s\n", name_or_addr);
clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge,
(char *)&ntf, xdr_void, NULL, tottimeout);
if (clnt_stat != (int)RPC_SUCCESS) {
syslog(LOG_WARNING,
"statd: cannot talk to statd at %s, %s(%d)\n",
name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
rc = -1;
}
}
clnt_destroy(clnt);
return (rc);
}
void *
sm_try(void *arg __unused)
{
name_entry *nl, *next;
timestruc_t wtime;
int delay = 0;
rw_rdlock(&thr_rwlock);
if (mutex_trylock(&sm_trylock))
goto out;
mutex_lock(&crash_lock);
while (!die) {
wtime.tv_sec = delay;
wtime.tv_nsec = 0;
if (cond_reltimedwait(&retrywait, &crash_lock, &wtime) == 0) {
break;
}
if ((next = recov_q.sm_recovhdp) == NULL)
break;
mutex_unlock(&crash_lock);
while (((nl = next) != NULL) && (!die)) {
next = next->nxt;
if (statd_call_statd(nl->name) == 0) {
remove_name(nl->name, 1, 0);
mutex_lock(&recov_q.lock);
delete_name(&recov_q.sm_recovhdp, nl->name);
mutex_unlock(&recov_q.lock);
} else {
if (delay == 0)
syslog(LOG_WARNING,
"statd: host %s is not "
"responding\n", nl->name);
}
}
if (delay <= MAX_DELAYTIME)
delay += INC_DELAYTIME;
mutex_lock(&crash_lock);
}
mutex_unlock(&crash_lock);
mutex_unlock(&sm_trylock);
out:
rw_unlock(&thr_rwlock);
if (debug)
(void) printf("EXITING sm_try\n");
thr_exit((void *) 0);
#ifdef lint
return (0);
#endif
}
char *
xmalloc(unsigned len)
{
char *new;
if ((new = malloc(len)) == 0) {
syslog(LOG_ERR, "statd: malloc, error %m\n");
return (NULL);
} else {
(void) memset(new, 0, len);
return (new);
}
}
static name_entry *
insert_name(name_entry **namepp, char *name, int need_alloc)
{
name_entry *new;
new = (name_entry *)xmalloc(sizeof (name_entry));
if (new == (name_entry *) NULL)
return (NULL);
if (need_alloc) {
if ((new->name = strdup(name)) == NULL) {
syslog(LOG_ERR, "statd: strdup, error %m\n");
free(new);
return (NULL);
}
} else
new->name = name;
new->nxt = *namepp;
if (new->nxt != NULL)
new->nxt->prev = new;
new->prev = (name_entry *) NULL;
*namepp = new;
if (debug) {
(void) printf("insert_name: inserted %s at %p\n",
name, (void *)namepp);
}
return (new);
}
static void
delete_name(name_entry **namepp, char *name)
{
name_entry *nl;
nl = *namepp;
while (nl != NULL) {
if (str_cmp_address_specifier(nl->name, name) == 0 ||
str_cmp_unqual_hostname(nl->name, name) == 0) {
if (nl->prev != NULL)
nl->prev->nxt = nl->nxt;
else
*namepp = nl->nxt;
if (nl->nxt != NULL)
nl->nxt->prev = nl->prev;
free(nl->name);
free(nl);
return;
}
nl = nl->nxt;
}
}
static name_entry *
find_name(name_entry **namep, char *name)
{
name_entry *nl;
nl = *namep;
while (nl != NULL) {
if (str_cmp_unqual_hostname(nl->name, name) == 0) {
return (nl);
}
nl = nl->nxt;
}
return (NULL);
}
int
create_file(char *name)
{
int fd;
if ((fd = open(name, O_CREAT | O_WRONLY, S_IWUSR)) == -1) {
if (errno != EEXIST) {
syslog(LOG_ERR, "can't open %s: %m", name);
return (1);
}
}
if (debug >= 2)
(void) printf("%s is created\n", name);
if (close(fd)) {
syslog(LOG_ERR, "statd: close, error %m\n");
return (1);
}
return (0);
}
void
delete_file(char *name)
{
if (debug >= 2)
(void) printf("Remove monitor entry %s\n", name);
if (unlink(name) == -1) {
if (errno != ENOENT)
syslog(LOG_ERR, "statd: unlink of %s, error %m", name);
}
}
int
is_symlink(char *file)
{
int error;
struct stat lbuf;
do {
bzero((caddr_t)&lbuf, sizeof (lbuf));
error = lstat(file, &lbuf);
} while (error == EINTR);
if (error == 0) {
return ((lbuf.st_mode & S_IFMT) == S_IFLNK);
}
return (0);
}
static int
move_file(char *fromdir, char *file, char *todir)
{
int n;
char rname[MAXNAMELEN + 1];
char from[MAXPATHLEN];
char to[MAXPATHLEN];
(void) strcpy(from, fromdir);
(void) strcat(from, "/");
(void) strcat(from, file);
if (is_symlink(from)) {
n = readlink(from, rname, MAXNAMELEN);
if (n <= 0) {
if (debug >= 2) {
(void) printf("move_file: can't read link %s\n",
from);
}
return (1);
}
rname[n] = '\0';
if (create_symlink(todir, rname, file) != 0) {
return (1);
}
} else {
(void) strcpy(to, todir);
(void) strcat(to, "/");
(void) strcat(to, file);
if (create_file(to) != 0) {
return (1);
}
}
if (unlink(from) < 0) {
syslog(LOG_ERR, "move_file: unlink of %s, error %m", from);
return (1);
}
return (0);
}
int
create_symlink(char *todir, char *rname, char *lname)
{
int error = 0;
char lpath[MAXPATHLEN];
(void) strcpy(lpath, todir);
(void) strcat(lpath, "/");
(void) strcat(lpath, lname);
if (symlink(rname, lpath) < 0) {
error = errno;
if (error != 0 && error != EEXIST) {
if (debug >= 2) {
(void) printf("create_symlink: can't link "
"%s/%s -> %s\n", todir, lname, rname);
}
return (1);
}
}
if (debug) {
if (error == EEXIST) {
(void) printf("link %s/%s -> %s already exists\n",
todir, lname, rname);
} else {
(void) printf("created link %s/%s -> %s\n",
todir, lname, rname);
}
}
return (0);
}
static void
remove_name(char *name, int op, int startup)
{
int i;
char *alt_dir;
char *queue;
if (op == 0) {
alt_dir = "statmon/sm";
queue = CURRENT;
} else {
alt_dir = "statmon/sm.bak";
queue = BACKUP;
}
remove_single_name(name, queue, NULL);
if (startup == 0) {
for (i = 0; i < pathix; i++) {
remove_single_name(name, path_name[i], alt_dir);
}
}
}
static void
remove_single_name(char *name, char *dir1, char *dir2)
{
int n, error;
char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];
char dirpath[MAXPATHLEN];
char rname[MAXNAMELEN + 1];
if (strlen(name) + strlen(dir1) + (dir2 != NULL ? strlen(dir2) : 0) +
3 > MAXPATHLEN) {
if (dir2 != NULL)
syslog(LOG_ERR,
"statd: pathname too long: %s/%s/%s\n",
dir1, dir2, name);
else
syslog(LOG_ERR,
"statd: pathname too long: %s/%s\n",
dir1, name);
return;
}
(void) strcpy(path, dir1);
(void) strcat(path, "/");
if (dir2 != NULL) {
(void) strcat(path, dir2);
(void) strcat(path, "/");
}
(void) strcpy(dirpath, path);
(void) strcat(path, name);
if (is_symlink(path)) {
n = readlink(path, rname, MAXNAMELEN);
if (n > 0) {
rname[n] = '\0';
if (count_symlinks(dirpath, rname, &n) < 0) {
return;
}
if (n == 1) {
(void) strcat(dirpath, rname);
error = unlink(dirpath);
if (debug >= 2) {
if (error < 0) {
(void) printf(
"remove_name: can't "
"unlink %s\n",
dirpath);
} else {
(void) printf(
"remove_name: unlinked ",
"%s\n", dirpath);
}
}
}
} else {
syslog(LOG_ERR,
"statd: can't read link %s: %m\n", path);
}
}
delete_file(path);
}
static int
count_symlinks(char *dir, char *name, int *count)
{
int cnt = 0;
int n;
DIR *dp;
struct dirent *dirp;
char lpath[MAXPATHLEN];
char rname[MAXNAMELEN + 1];
if ((dp = opendir(dir)) == NULL) {
syslog(LOG_ERR, "count_symlinks: open %s dir, error %m\n",
dir);
return (-1);
}
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp->d_name, ".") == 0 ||
strcmp(dirp->d_name, "..") == 0) {
continue;
}
(void) sprintf(lpath, "%s%s", dir, dirp->d_name);
if (is_symlink(lpath)) {
n = readlink(lpath, rname, MAXNAMELEN);
if (n <= 0) {
if (debug >= 2) {
(void) printf(
"count_symlinks: can't read link "
"%s\n", lpath);
}
continue;
}
rname[n] = '\0';
if (strcmp(rname, name) == 0) {
cnt++;
}
}
}
(void) closedir(dp);
if (debug) {
(void) printf("count_symlinks: found %d symlinks\n", cnt);
}
*count = cnt;
return (0);
}
void
record_name(char *name, int op)
{
name_entry *nl;
int i;
char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];
name_entry **record_q;
unsigned int hash;
if (name == NULL)
return;
if (name[0] == '\0' || strchr(name, '/') != NULL ||
strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
syslog(LOG_ERR|LOG_AUTH, "statd: attempt to %s \"%s/%s\"",
op == 1 ? "create" : "remove", CURRENT, name);
return;
}
SMHASH(name, hash);
if (debug) {
if (op == 1)
(void) printf("inserting %s at hash %d,\n",
name, hash);
else
(void) printf("deleting %s at hash %d\n", name, hash);
pr_name(name, 1);
}
if (op == 1) {
mutex_lock(&record_table[hash].lock);
record_q = &record_table[hash].sm_rechdp;
if ((nl = find_name(record_q, name)) == NULL) {
int path_len;
if ((nl = insert_name(record_q, name, 1)) !=
(name_entry *) NULL)
nl->count++;
mutex_unlock(&record_table[hash].lock);
path_len = strlen(CURRENT) + strlen(name) + 2;
if (path_len > MAXPATHLEN) {
syslog(LOG_ERR,
"statd: pathname too long: %s/%s\n",
CURRENT, name);
return;
}
(void) strcpy(path, CURRENT);
(void) strcat(path, "/");
(void) strcat(path, name);
(void) create_file(path);
if (debug) {
(void) printf("After insert_name\n");
pr_name(name, 1);
}
for (i = 0; i < pathix; i++) {
path_len = strlen(path_name[i]) +
strlen("/statmon/sm/") + strlen(name) + 1;
if (path_len > MAXPATHLEN) {
syslog(LOG_ERR, "statd: pathname too "
"long: %s/statmon/sm/%s\n",
path_name[i], name);
continue;
}
(void) strcpy(path, path_name[i]);
(void) strcat(path, "/statmon/sm/");
(void) strcat(path, name);
(void) create_file(path);
}
return;
}
nl->count++;
mutex_unlock(&record_table[hash].lock);
} else {
mutex_lock(&record_table[hash].lock);
record_q = &record_table[hash].sm_rechdp;
if ((nl = find_name(record_q, name)) == NULL) {
mutex_unlock(&record_table[hash].lock);
return;
}
nl->count--;
if (nl->count == 0) {
delete_name(record_q, name);
mutex_unlock(&record_table[hash].lock);
remove_name(name, 0, 0);
} else
mutex_unlock(&record_table[hash].lock);
if (debug) {
(void) printf("After delete_name \n");
pr_name(name, 1);
}
}
}
void
record_addr(char *name, sa_family_t family, struct netobj *ah)
{
int i;
int path_len;
char *famstr;
struct in_addr addr = { 0 };
char *addr6 = NULL;
char ascii_addr[MAXNAMELEN];
char path[MAXPATHLEN];
if (family == AF_INET) {
if (ah->n_len != sizeof (struct in_addr))
return;
addr = *(struct in_addr *)ah->n_bytes;
} else if (family == AF_INET6) {
if (ah->n_len != sizeof (struct in6_addr))
return;
addr6 = (char *)ah->n_bytes;
} else
return;
if (debug) {
if (family == AF_INET)
(void) printf("record_addr: addr= %x\n", addr.s_addr);
else if (family == AF_INET6)
(void) printf("record_addr: addr= %x\n",
((struct in6_addr *)addr6)->s6_addr);
}
if (family == AF_INET) {
if ((ntohl(addr.s_addr) & 0xff000000) == 0) {
syslog(LOG_DEBUG,
"record_addr: illegal IP address %x\n",
addr.s_addr);
return;
}
}
famstr = family2string(family);
if (famstr == NULL) {
syslog(LOG_DEBUG,
"record_addr: unsupported address family %d\n",
family);
return;
}
switch (family) {
char abuf[INET6_ADDRSTRLEN];
case AF_INET:
(void) sprintf(ascii_addr, "%s.%s", famstr, inet_ntoa(addr));
break;
case AF_INET6:
(void) sprintf(ascii_addr, "%s.%s", famstr,
inet_ntop(family, addr6, abuf, sizeof (abuf)));
break;
default:
if (debug) {
(void) printf(
"record_addr: family2string supports unknown "
"family %d (%s)\n", family, famstr);
}
free(famstr);
return;
}
if (debug) {
(void) printf("record_addr: ascii_addr= %s\n", ascii_addr);
}
free(famstr);
(void) create_symlink(CURRENT, name, ascii_addr);
for (i = 0; i < pathix; i++) {
path_len = strlen(path_name[i]) +
strlen("/statmon/sm/") +
strlen(name) + 1;
if (path_len > MAXPATHLEN) {
syslog(LOG_ERR,
"statd: pathname too long: %s/statmon/sm/%s\n",
path_name[i], name);
continue;
}
(void) strcpy(path, path_name[i]);
(void) strcat(path, "/statmon/sm");
(void) create_symlink(path, name, ascii_addr);
}
}
void
sm_crash(void)
{
name_entry *nl, *next;
mon_entry *nl_monp, *mon_next;
int k;
my_id *nl_idp;
for (k = 0; k < MAX_HASHSIZE; k++) {
mutex_lock(&mon_table[k].lock);
if ((mon_next = mon_table[k].sm_monhdp) ==
(mon_entry *) NULL) {
mutex_unlock(&mon_table[k].lock);
continue;
} else {
while ((nl_monp = mon_next) != NULL) {
mon_next = mon_next->nxt;
nl_idp = &nl_monp->id.mon_id.my_id;
free(nl_monp->id.mon_id.mon_name);
free(nl_idp->my_name);
free(nl_monp);
}
mon_table[k].sm_monhdp = NULL;
}
mutex_unlock(&mon_table[k].lock);
}
for (k = 0; k < MAX_HASHSIZE; k++) {
mutex_lock(&record_table[k].lock);
if ((next = record_table[k].sm_rechdp) ==
(name_entry *) NULL) {
mutex_unlock(&record_table[k].lock);
continue;
} else {
while ((nl = next) != NULL) {
next = next->nxt;
free(nl->name);
free(nl);
}
record_table[k].sm_rechdp = NULL;
}
mutex_unlock(&record_table[k].lock);
}
mutex_lock(&recov_q.lock);
if ((next = recov_q.sm_recovhdp) != NULL) {
while ((nl = next) != NULL) {
next = next->nxt;
free(nl->name);
free(nl);
}
recov_q.sm_recovhdp = NULL;
}
mutex_unlock(&recov_q.lock);
statd_init();
}
void
sm_inithash(void)
{
int k;
if (debug)
(void) printf("Initializing hash tables\n");
for (k = 0; k < MAX_HASHSIZE; k++) {
mon_table[k].sm_monhdp = NULL;
record_table[k].sm_rechdp = NULL;
mutex_init(&mon_table[k].lock, USYNC_THREAD, NULL);
mutex_init(&record_table[k].lock, USYNC_THREAD, NULL);
}
mutex_init(&recov_q.lock, USYNC_THREAD, NULL);
recov_q.sm_recovhdp = NULL;
}
static char *
family2string(sa_family_t family)
{
char *rc;
switch (family) {
case AF_INET:
rc = strdup(SM_ADDR_IPV4);
break;
case AF_INET6:
rc = strdup(SM_ADDR_IPV6);
break;
default:
rc = NULL;
break;
}
return (rc);
}
static void
pr_name(char *name, int flag)
{
name_entry *nl;
unsigned int hash;
if (!debug)
return;
if (flag) {
SMHASH(name, hash);
(void) printf("*****record_q: ");
mutex_lock(&record_table[hash].lock);
nl = record_table[hash].sm_rechdp;
while (nl != NULL) {
(void) printf("(%x), ", (int)nl);
nl = nl->nxt;
}
mutex_unlock(&record_table[hash].lock);
} else {
(void) printf("*****recovery_q: ");
mutex_lock(&recov_q.lock);
nl = recov_q.sm_recovhdp;
while (nl != NULL) {
(void) printf("(%x), ", (int)nl);
nl = nl->nxt;
}
mutex_unlock(&recov_q.lock);
}
(void) printf("\n");
}