| /* |
| * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff |
| * Modified by Olaf Kirch, 1996. |
| * Modified by H.J. Lu, 1998. |
| * Modified by Lon Hohberger, Oct. 2000. |
| * - Fixed memory leaks, run-off-end problems, etc. |
| * |
| * NSM for Linux. |
| */ |
| |
| /* |
| * Simple list management for notify list |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <string.h> |
| #include "statd.h" |
| #include "notlist.h" |
| |
| |
| #ifdef DEBUG |
| /* |
| * LH - The linked list code had some bugs. Used this to help debug |
| * new code. |
| */ |
| static void |
| plist(notify_list *head, int en) |
| { |
| /* case where we ran off the end */ |
| if (!head) return; |
| |
| printf("Entry %d: %s\n",en, NL_MON_NAME(head)); |
| plist(head->next, ++en); |
| } |
| |
| static void |
| nlist_print(notify_list **head) |
| { |
| printf("--- Begin notify list dump ---\n"); |
| plist(*head,1); |
| printf("--- End notify list dump ---\n"); |
| } |
| #endif /* DEBUG */ |
| |
| /* |
| * Allocate memory and set up a new notify list entry. |
| */ |
| notify_list * |
| nlist_new(char *my_name, char *mon_name, int state) |
| { |
| notify_list *new; |
| |
| new = (notify_list *) xmalloc(sizeof(notify_list)); |
| memset(new, 0, sizeof(*new)); |
| |
| NL_TIMES(new) = MAX_TRIES; |
| NL_STATE(new) = state; |
| NL_MY_NAME(new) = xstrdup(my_name); |
| NL_MON_NAME(new) = xstrdup(mon_name); |
| |
| return new; |
| } |
| |
| /* |
| * Insert *entry into a notify list at the point specified by |
| * **head. This can be in the middle. However, we do not handle |
| * list _append_ in this function; rather, the only place we should |
| * have to worry about this case is in nlist_insert_timer below. |
| * - entry must not be NULL. |
| */ |
| void |
| nlist_insert(notify_list **head, notify_list *entry) |
| { |
| if (*head) { |
| /* |
| * Cases where we're prepending a non-empty list |
| * or inserting possibly in the middle somewhere (eg, |
| * nlist_insert_timer...) |
| */ |
| entry->next = (*head); /* Forward pointer */ |
| entry->prev = (*head)->prev; /* Back pointer */ |
| (*head)->prev = entry; /* head's new back pointer */ |
| } |
| |
| /* Common to all cases, including new list creation */ |
| *head = entry; /* New head */ |
| |
| #ifdef DEBUG |
| nlist_print(head); |
| #endif |
| } |
| |
| /* |
| * (re)insert *entry into notify_list **head. This requires that |
| * NL_WHEN(entry) has been set (usually, this is time() + 5 seconds). |
| * - entry must not be NULL |
| * |
| * LH - This used to cause (a) a memory leak and (b) dropped notify-list |
| * entries. The pointer ran off the end of the list, and changed the |
| * head-end to point to the new, one-entry list. All other entries became garbage. |
| * |
| * FIXME: Optimize this function. (I'll work on it - LH) |
| */ |
| void |
| nlist_insert_timer(notify_list **head, notify_list *entry) |
| { |
| notify_list *spot = *head, /* Insertion location */ |
| /* ...Start at head */ |
| *back = NULL; /* Back pointer */ |
| |
| |
| /* Find first entry with higher timeout value or end of list */ |
| while (spot && NL_WHEN(spot) <= NL_WHEN(entry)) { |
| /* |
| * Keep the back pointer in case we |
| * run off the end... (see below) |
| */ |
| back = spot; |
| spot = spot->next; |
| } |
| |
| if (spot == (*head)) { |
| /* |
| * case where we're prepending an empty or non-empty |
| * list or inserting in the middle somewhere. Pass |
| * the real head of the list, since we'll be changing |
| * during the insert... |
| */ |
| nlist_insert(head, entry); |
| } else { |
| /* all other cases - don't move the real head pointer */ |
| nlist_insert(&spot, entry); |
| |
| /* |
| * If spot == entry, then spot was NULL when we called |
| * nlist_insert. This happened because we had run off |
| * the end of the list. Append entry to original list. |
| */ |
| if (spot == entry) { |
| back->next = entry; |
| entry->prev = back; |
| } |
| } |
| } |
| |
| /* |
| * Remove *entry from the list pointed to by **head. |
| * Do not destroy *entry. This is normally done before |
| * a re-insertion with a timer, but can be done anywhere. |
| * - entry must not be NULL. |
| */ |
| void |
| nlist_remove(notify_list **head, notify_list *entry) |
| { |
| notify_list *prev = entry->prev, |
| *next = entry->next; |
| |
| if (next) { |
| next->prev = prev; |
| } |
| |
| if (prev) { |
| /* Case(s) where entry isn't at the front */ |
| prev->next = next; |
| } else { |
| /* cases where entry is at the front */ |
| *head = next; |
| } |
| |
| entry->next = entry->prev = NULL; |
| #ifdef DEBUG |
| nlist_print(head); |
| #endif |
| } |
| |
| /* |
| * Clone an entry in the notify list - |
| * - entry must not be NULL |
| */ |
| notify_list * |
| nlist_clone(notify_list *entry) |
| { |
| notify_list *new; |
| |
| new = nlist_new(NL_MY_NAME(entry), NL_MON_NAME(entry), NL_STATE(entry)); |
| NL_MY_PROG(new) = NL_MY_PROG(entry); |
| NL_MY_VERS(new) = NL_MY_VERS(entry); |
| NL_MY_PROC(new) = NL_MY_PROC(entry); |
| memcpy(NL_PRIV(new), NL_PRIV(entry), SM_PRIV_SIZE); |
| |
| return new; |
| } |
| |
| /* |
| * Destroy an entry in a notify list and free the memory. |
| * If *head is NULL, just free the entry. This would be |
| * done only when we know entry isn't in any list. |
| * - entry must not be NULL. |
| */ |
| void |
| nlist_free(notify_list **head, notify_list *entry) |
| { |
| if (head && (*head)) |
| nlist_remove(head, entry); |
| if (NL_MY_NAME(entry)) |
| free(NL_MY_NAME(entry)); |
| if (NL_MON_NAME(entry)) |
| free(NL_MON_NAME(entry)); |
| free(entry->dns_name); |
| } |
| |
| /* |
| * Destroy an entire notify list |
| */ |
| void |
| nlist_kill(notify_list **head) |
| { |
| notify_list *next; |
| |
| while (*head) { |
| next = (*head)->next; |
| nlist_free(head, *head); |
| free(*head); |
| *head = next; |
| } |
| } |
| |
| /* |
| * Walk a list looking for a matching name in the NL_MON_NAME field. |
| */ |
| notify_list * |
| nlist_gethost(notify_list *list, char *host, int myname) |
| { |
| notify_list *lp; |
| |
| for (lp = list; lp; lp = lp->next) { |
| if (statd_matchhostname(host, |
| myname? NL_MY_NAME(lp) : NL_MON_NAME(lp))) |
| return lp; |
| } |
| |
| return (notify_list *) NULL; |
| } |