]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/statd/notlist.c
1698c26abef92166941dc39eba066b879422957c
[nfs-utils.git] / utils / statd / notlist.c
1 /*
2  * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
3  * Modified by Olaf Kirch, 1996.
4  * Modified by H.J. Lu, 1998.
5  * Modified by Lon Hohberger, Oct. 2000.
6  *   - Fixed memory leaks, run-off-end problems, etc.
7  *
8  * NSM for Linux.
9  */
10
11 /*
12  * Simple list management for notify list
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #include <string.h>
20 #include "misc.h"
21 #include "statd.h"
22 #include "notlist.h"
23
24
25 #ifdef DEBUG
26 /* 
27  * LH - The linked list code had some bugs.  Used this to help debug
28  * new code. 
29  */
30 static void 
31 plist(notify_list *head, int en)
32 {
33         /* case where we ran off the end */
34         if (!head) return;
35
36         printf("Entry %d: %s\n",en, NL_MON_NAME(head));
37         plist(head->next, ++en);
38 }
39
40 static void 
41 nlist_print(notify_list **head)
42 {
43         printf("--- Begin notify list dump ---\n");
44         plist(*head,1);
45         printf("--- End notify list dump ---\n");
46 }
47 #endif /* DEBUG */
48
49 /* 
50  * Allocate memory and set up a new notify list entry.
51  */
52 notify_list * 
53 nlist_new(char *my_name, char *mon_name, int state)
54 {
55         notify_list     *new;
56
57         new = (notify_list *) xmalloc(sizeof(notify_list));
58         memset(new, 0, sizeof(*new));
59
60         NL_TIMES(new) = MAX_TRIES;
61         NL_STATE(new) = state;
62         NL_MY_NAME(new) = xstrdup(my_name);
63         NL_MON_NAME(new) = xstrdup(mon_name);
64
65         return new;
66 }
67
68 /*
69  * Insert *entry into a notify list at the point specified by
70  * **head.  This can be in the middle.  However, we do not handle
71  * list _append_ in this function; rather, the only place we should
72  * have to worry about this case is in nlist_insert_timer below.
73  * - entry must not be NULL.
74  */
75 void 
76 nlist_insert(notify_list **head, notify_list *entry)
77 {
78         if (*head) {
79                 /* 
80                  * Cases where we're prepending a non-empty list
81                  * or inserting possibly in the middle somewhere (eg,
82                  * nlist_insert_timer...)
83                  */
84                 entry->next = (*head);          /* Forward pointer */
85                 entry->prev = (*head)->prev;    /* Back pointer */
86                 (*head)->prev = entry;          /* head's new back pointer */
87         }
88
89         /* Common to all cases, including new list creation */
90         *head = entry;                  /* New head */
91
92 #ifdef DEBUG
93         nlist_print(head);
94 #endif
95 }
96
97 /* 
98  * (re)insert *entry into notify_list **head.  This requires that
99  * NL_WHEN(entry) has been set (usually, this is time() + 5 seconds).
100  * - entry must not be NULL
101  *
102  * LH - This used to cause (a) a memory leak and (b) dropped notify-list
103  * entries.  The pointer ran off the end of the list, and changed the 
104  * head-end to point to the new, one-entry list.  All other entries became garbage.
105  *
106  * FIXME: Optimize this function. (I'll work on it - LH)
107  */
108 void 
109 nlist_insert_timer(notify_list **head, notify_list *entry)
110 {
111         notify_list     *spot = *head,          /* Insertion location */
112                                                 /* ...Start at head */
113                         *back = NULL;           /* Back pointer */
114
115
116         /* Find first entry with higher timeout value or end of list */
117         while (spot && NL_WHEN(spot) <= NL_WHEN(entry)) {
118                 /* 
119                  * Keep the back pointer in case we 
120                  * run off the end...  (see below)
121                  */
122                 back = spot;
123                 spot = spot->next;
124         }
125
126         if (spot == (*head)) {
127                 /* 
128                  * case where we're prepending an empty or non-empty
129                  * list or inserting in the middle somewhere.  Pass 
130                  * the real head of the list, since we'll be changing 
131                  * during the insert... 
132                  */
133                 nlist_insert(head, entry);
134         } else {
135                 /* all other cases - don't move the real head pointer */
136                 nlist_insert(&spot, entry);
137
138                 /* 
139                  * If spot == entry, then spot was NULL when we called
140                  * nlist_insert.  This happened because we had run off 
141                  * the end of the list.  Append entry to original list.
142                  */
143                 if (spot == entry) {
144                         back->next = entry;
145                         entry->prev = back;
146                 }
147         }
148 }
149
150 /* 
151  * Remove *entry from the list pointed to by **head.
152  * Do not destroy *entry.  This is normally done before
153  * a re-insertion with a timer, but can be done anywhere.
154  * - entry must not be NULL.
155  */
156 void 
157 nlist_remove(notify_list **head, notify_list *entry)
158 {
159         notify_list     *prev = entry->prev,
160                         *next = entry->next;
161
162         if (next) {
163                 next->prev = prev;
164         }
165
166         if (prev) {
167                 /* Case(s) where entry isn't at the front */
168                 prev->next = next; 
169         } else {
170                 /* cases where entry is at the front */
171                 *head = next;
172         }
173
174         entry->next = entry->prev = NULL;
175 #ifdef DEBUG
176         nlist_print(head);
177 #endif
178 }
179
180 /* 
181  * Clone an entry in the notify list -
182  * - entry must not be NULL
183  */
184 notify_list *
185 nlist_clone(notify_list *entry)
186 {
187         notify_list     *new;
188
189         new = nlist_new(NL_MY_NAME(entry), NL_MON_NAME(entry), NL_STATE(entry));
190         NL_MY_PROG(new) = NL_MY_PROG(entry);
191         NL_MY_VERS(new) = NL_MY_VERS(entry);
192         NL_MY_PROC(new) = NL_MY_PROC(entry);
193         NL_ADDR(new)    = NL_ADDR(entry);
194         memcpy(NL_PRIV(new), NL_PRIV(entry), SM_PRIV_SIZE);
195
196         return new;
197 }
198
199 /* 
200  * Destroy an entry in a notify list and free the memory.
201  * If *head is NULL, just free the entry.  This would be
202  * done only when we know entry isn't in any list.
203  * - entry must not be NULL.
204  */
205 void 
206 nlist_free(notify_list **head, notify_list *entry)
207 {
208         if (head && (*head))
209                 nlist_remove(head, entry);
210         if (NL_MY_NAME(entry))
211                 free(NL_MY_NAME(entry));
212         if (NL_MON_NAME(entry))
213                 free(NL_MON_NAME(entry));
214         free(entry->dns_name);
215         free(entry);
216 }
217
218 /* 
219  * Destroy an entire notify list 
220  */
221 void 
222 nlist_kill(notify_list **head)
223 {
224         while (*head)
225                 nlist_free(head, *head);
226 }
227
228 /*
229  * Walk a list looking for a matching name in the NL_MON_NAME field.
230  */
231 notify_list *
232 nlist_gethost(notify_list *list, char *host, int myname)
233 {
234         notify_list     *lp;
235
236         for (lp = list; lp; lp = lp->next) {
237                 if (matchhostname(host, myname? NL_MY_NAME(lp) : NL_MON_NAME(lp)))
238                         return lp;
239         }
240
241         return (notify_list *) NULL;
242 }