Fix various issues discovered by Coverity
[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         if (!(new = (notify_list *) xmalloc(sizeof(notify_list))))
58                 return NULL;
59         memset(new, 0, sizeof(*new));
60
61         NL_TIMES(new) = MAX_TRIES;
62         NL_STATE(new) = state;
63         if (!(NL_MY_NAME(new) = xstrdup(my_name))
64             || !(NL_MON_NAME(new) = xstrdup(mon_name))) {
65                 if (NL_MY_NAME(new))
66                         free(NL_MY_NAME(new));
67                 free(new);
68                 return NULL;
69         }
70
71         return new;
72 }
73
74 /*
75  * Insert *entry into a notify list at the point specified by
76  * **head.  This can be in the middle.  However, we do not handle
77  * list _append_ in this function; rather, the only place we should
78  * have to worry about this case is in nlist_insert_timer below.
79  * - entry must not be NULL.
80  */
81 void 
82 nlist_insert(notify_list **head, notify_list *entry)
83 {
84         if (*head) {
85                 /* 
86                  * Cases where we're prepending a non-empty list
87                  * or inserting possibly in the middle somewhere (eg,
88                  * nlist_insert_timer...)
89                  */
90                 entry->next = (*head);          /* Forward pointer */
91                 entry->prev = (*head)->prev;    /* Back pointer */
92                 (*head)->prev = entry;          /* head's new back pointer */
93         }
94
95         /* Common to all cases, including new list creation */
96         *head = entry;                  /* New head */
97
98 #ifdef DEBUG
99         nlist_print(head);
100 #endif
101 }
102
103 /* 
104  * (re)insert *entry into notify_list **head.  This requires that
105  * NL_WHEN(entry) has been set (usually, this is time() + 5 seconds).
106  * - entry must not be NULL
107  *
108  * LH - This used to cause (a) a memory leak and (b) dropped notify-list
109  * entries.  The pointer ran off the end of the list, and changed the 
110  * head-end to point to the new, one-entry list.  All other entries became garbage.
111  *
112  * FIXME: Optimize this function. (I'll work on it - LH)
113  */
114 void 
115 nlist_insert_timer(notify_list **head, notify_list *entry)
116 {
117         notify_list     *spot = *head,          /* Insertion location */
118                                                 /* ...Start at head */
119                         *back = NULL;           /* Back pointer */
120
121
122         /* Find first entry with higher timeout value or end of list */
123         while (spot && NL_WHEN(spot) <= NL_WHEN(entry)) {
124                 /* 
125                  * Keep the back pointer in case we 
126                  * run off the end...  (see below)
127                  */
128                 back = spot;
129                 spot = spot->next;
130         }
131
132         if (spot == (*head)) {
133                 /* 
134                  * case where we're prepending an empty or non-empty
135                  * list or inserting in the middle somewhere.  Pass 
136                  * the real head of the list, since we'll be changing 
137                  * during the insert... 
138                  */
139                 nlist_insert(head, entry);
140         } else {
141                 /* all other cases - don't move the real head pointer */
142                 nlist_insert(&spot, entry);
143
144                 /* 
145                  * If spot == entry, then spot was NULL when we called
146                  * nlist_insert.  This happened because we had run off 
147                  * the end of the list.  Append entry to original list.
148                  */
149                 if (spot == entry) {
150                         back->next = entry;
151                         entry->prev = back;
152                 }
153         }
154 }
155
156 /* 
157  * Remove *entry from the list pointed to by **head.
158  * Do not destroy *entry.  This is normally done before
159  * a re-insertion with a timer, but can be done anywhere.
160  * - entry must not be NULL.
161  */
162 void 
163 nlist_remove(notify_list **head, notify_list *entry)
164 {
165         notify_list     *prev = entry->prev,
166                         *next = entry->next;
167
168         if (next) {
169                 next->prev = prev;
170         }
171
172         if (prev) {
173                 /* Case(s) where entry isn't at the front */
174                 prev->next = next; 
175         } else {
176                 /* cases where entry is at the front */
177                 *head = next;
178         }
179
180         entry->next = entry->prev = NULL;
181 #ifdef DEBUG
182         nlist_print(head);
183 #endif
184 }
185
186 /* 
187  * Clone an entry in the notify list -
188  * - entry must not be NULL
189  */
190 notify_list *
191 nlist_clone(notify_list *entry)
192 {
193         notify_list     *new;
194
195         new = nlist_new(NL_MY_NAME(entry), NL_MON_NAME(entry), NL_STATE(entry));
196         NL_MY_PROG(new) = NL_MY_PROG(entry);
197         NL_MY_VERS(new) = NL_MY_VERS(entry);
198         NL_MY_PROC(new) = NL_MY_PROC(entry);
199         NL_ADDR(new)    = NL_ADDR(entry);
200         memcpy(NL_PRIV(new), NL_PRIV(entry), SM_PRIV_SIZE);
201
202         return new;
203 }
204
205 /* 
206  * Destroy an entry in a notify list and free the memory.
207  * If *head is NULL, just free the entry.  This would be
208  * done only when we know entry isn't in any list.
209  * - entry must not be NULL.
210  */
211 void 
212 nlist_free(notify_list **head, notify_list *entry)
213 {
214         if (head && (*head))
215                 nlist_remove(head, entry);
216         if (NL_MY_NAME(entry))
217                 free(NL_MY_NAME(entry));
218         if (NL_MON_NAME(entry))
219                 free(NL_MON_NAME(entry));
220         free(entry);
221 }
222
223 /* 
224  * Destroy an entire notify list 
225  */
226 void 
227 nlist_kill(notify_list **head)
228 {
229         while (*head)
230                 nlist_free(head, *head);
231 }
232
233 /*
234  * Walk a list looking for a matching name in the NL_MON_NAME field.
235  */
236 notify_list *
237 nlist_gethost(notify_list *list, char *host, int myname)
238 {
239         notify_list     *lp;
240
241         for (lp = list; lp; lp = lp->next) {
242                 if (matchhostname(host, myname? NL_MY_NAME(lp) : NL_MON_NAME(lp)))
243                         return lp;
244         }
245
246         return (notify_list *) NULL;
247 }