1 /*
2  * Copyright 2011 Tresys Technology, LLC. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *    1. Redistributions of source code must retain the above copyright notice,
8  *       this list of conditions and the following disclaimer.
9  *
10  *    2. Redistributions in binary form must reproduce the above copyright notice,
11  *       this list of conditions and the following disclaimer in the documentation
12  *       and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17  * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * The views and conclusions contained in the software and documentation are those
26  * of the authors and should not be interpreted as representing official policies,
27  * either expressed or implied, of Tresys Technology, LLC.
28  */
29 
30 #include <stdlib.h>
31 #include <stdarg.h>
32 
33 #include "cil_internal.h"
34 #include "cil_flavor.h"
35 #include "cil_log.h"
36 #include "cil_mem.h"
37 
cil_list_error(const char * msg,...)38 __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_list_error(const char* msg, ...)
39 {
40 	va_list ap;
41 	va_start(ap, msg);
42 	cil_vlog(CIL_ERR, msg, ap);
43 	va_end(ap);
44 	exit(1);
45 }
46 
cil_list_init(struct cil_list ** list,enum cil_flavor flavor)47 void cil_list_init(struct cil_list **list, enum cil_flavor flavor)
48 {
49 	struct cil_list *new_list = cil_malloc(sizeof(*new_list));
50 	new_list->head = NULL;
51 	new_list->tail = NULL;
52 	new_list->flavor = flavor;
53 	*list = new_list;
54 }
55 
cil_list_destroy(struct cil_list ** list,unsigned destroy_data)56 void cil_list_destroy(struct cil_list **list, unsigned destroy_data)
57 {
58 	if (*list == NULL) {
59 		return;
60 	}
61 
62 	struct cil_list_item *item = (*list)->head;
63 	struct cil_list_item *next = NULL;
64 	while (item != NULL)
65 	{
66 		next = item->next;
67 		if (item->flavor == CIL_LIST) {
68 			cil_list_destroy((struct cil_list**)&(item->data), destroy_data);
69 			free(item);
70 		} else {
71 			cil_list_item_destroy(&item, destroy_data);
72 		}
73 		item = next;
74 	}
75 	free(*list);
76 	*list = NULL;
77 }
78 
cil_list_item_init(struct cil_list_item ** item)79 void cil_list_item_init(struct cil_list_item **item)
80 {
81 	struct cil_list_item *new_item = cil_malloc(sizeof(*new_item));
82 	new_item->next = NULL;
83 	new_item->flavor = CIL_NONE;
84 	new_item->data = NULL;
85 
86 	*item = new_item;
87 }
88 
cil_list_item_destroy(struct cil_list_item ** item,unsigned destroy_data)89 void cil_list_item_destroy(struct cil_list_item **item, unsigned destroy_data)
90 {
91 	if (destroy_data) {
92 		cil_destroy_data(&(*item)->data, (*item)->flavor);
93 	}
94 	free(*item);
95 	*item = NULL;
96 }
97 
cil_list_append(struct cil_list * list,enum cil_flavor flavor,void * data)98 void cil_list_append(struct cil_list *list, enum cil_flavor flavor, void *data)
99 {
100 	struct cil_list_item *item;
101 
102 	if (list == NULL) {
103 		cil_list_error("Attempt to append data to a NULL list");
104 	}
105 
106 	cil_list_item_init(&item);
107 	item->flavor = flavor;
108 	item->data = data;
109 
110 	if (list->tail == NULL) {
111 		list->head = item;
112 		list->tail = item;
113 		return;
114 	}
115 
116 	list->tail->next = item;
117 	list->tail = item;
118 }
119 
cil_list_prepend(struct cil_list * list,enum cil_flavor flavor,void * data)120 void cil_list_prepend(struct cil_list *list, enum cil_flavor flavor, void *data)
121 {
122 	struct cil_list_item *item;
123 
124 	if (list == NULL) {
125 		cil_list_error("Attempt to prepend data to a NULL list");
126 	}
127 
128 	cil_list_item_init(&item);
129 	item->flavor = flavor;
130 	item->data = data;
131 
132 	if (list->tail == NULL) {
133 		list->head = item;
134 		list->tail = item;
135 		return;
136 	}
137 
138 	item->next = list->head;
139 	list->head = item;
140 }
141 
cil_list_insert(struct cil_list * list,struct cil_list_item * curr,enum cil_flavor flavor,void * data)142 struct cil_list_item *cil_list_insert(struct cil_list *list, struct cil_list_item *curr, enum cil_flavor flavor, void *data)
143 {
144 	struct cil_list_item *item;
145 
146 	if (list == NULL) {
147 		cil_list_error("Attempt to append data to a NULL list");
148 	}
149 
150 	if (curr == NULL) {
151 		/* Insert at the front of the list */
152 		cil_list_prepend(list, flavor, data);
153 		return list->head;
154 	}
155 
156 	if (curr == list->tail) {
157 		cil_list_append(list, flavor, data);
158 		return list->tail;
159 	}
160 
161 	cil_list_item_init(&item);
162 	item->flavor = flavor;
163 	item->data = data;
164 	item->next = curr->next;
165 
166 	curr->next = item;
167 
168 	return item;
169 }
170 
cil_list_append_item(struct cil_list * list,struct cil_list_item * item)171 void cil_list_append_item(struct cil_list *list, struct cil_list_item *item)
172 {
173 	struct cil_list_item *last = item;
174 
175 	if (list == NULL) {
176 		cil_list_error("Attempt to append an item to a NULL list");
177 	}
178 
179 	if (item == NULL) {
180 		cil_list_error("Attempt to append a NULL item to a list");
181 	}
182 
183 	while (last->next != NULL) {
184 		last = last->next;
185 	}
186 
187 	if (list->tail == NULL) {
188 		list->head = item;
189 		list->tail = last;
190 		return;
191 	}
192 
193 	list->tail->next = item;
194 	list->tail = last;
195 
196 }
197 
cil_list_prepend_item(struct cil_list * list,struct cil_list_item * item)198 void cil_list_prepend_item(struct cil_list *list, struct cil_list_item *item)
199 {
200 	struct cil_list_item *last = item;
201 
202 	if (list == NULL) {
203 		cil_list_error("Attempt to prepend an item to a NULL list");
204 	}
205 
206 	if (item == NULL) {
207 		cil_list_error("Attempt to prepend a NULL item to a list");
208 	}
209 
210 	while (last->next != NULL) {
211 		last = last->next;
212 	}
213 
214 	if (list->tail == NULL) {
215 		list->head = item;
216 		list->tail = last;
217 		return;
218 	}
219 
220 	last->next = list->head;
221 	list->head = item;
222 }
223 
cil_list_remove(struct cil_list * list,enum cil_flavor flavor,void * data,unsigned destroy_data)224 void cil_list_remove(struct cil_list *list, enum cil_flavor flavor, void *data, unsigned destroy_data)
225 {
226 	struct cil_list_item *item;
227 	struct cil_list_item *previous = NULL;
228 
229 	if (list == NULL) {
230 		cil_list_error("Attempt to remove data from a NULL list");
231 	}
232 
233 	cil_list_for_each(item, list) {
234 		if (item->data == data && item->flavor == flavor) {
235 			if (previous == NULL) {
236 				list->head = item->next;
237 			} else {
238 				previous->next = item->next;
239 			}
240 			if (item->next == NULL) {
241 				list->tail = previous;
242 			}
243 			cil_list_item_destroy(&item, destroy_data);
244 			break;
245 		}
246 		previous = item;
247 	}
248 }
249 
cil_list_contains(struct cil_list * list,void * data)250 int cil_list_contains(struct cil_list *list, void *data)
251 {
252 	struct cil_list_item *curr = NULL;
253 
254 	cil_list_for_each(curr, list) {
255 		if (curr->data == data) {
256 			return CIL_TRUE;
257 		}
258 	}
259 
260 	return CIL_FALSE;
261 }
262 
cil_list_match_any(struct cil_list * l1,struct cil_list * l2)263 int cil_list_match_any(struct cil_list *l1, struct cil_list *l2)
264 {
265 	struct cil_list_item *i1;
266 	struct cil_list_item *i2;
267 
268 	cil_list_for_each(i1, l1) {
269 		cil_list_for_each(i2, l2) {
270 			if (i1->data == i2->data && i1->flavor == i2->flavor) {
271 				return CIL_TRUE;
272 			}
273 		}
274 	}
275 
276 	return CIL_FALSE;
277 }
278