1 /*
2  * atexit.c --- Clean things up when we exit normally.
3  *
4  * Copyright Oracle, 2014
5  * Author Darrick J. Wong <darrick.wong@oracle.com>
6  *
7  * %Begin-Header%
8  * This file may be redistributed under the terms of the GNU Library
9  * General Public License, version 2.
10  * %End-Header%
11  */
12 
13 #ifndef _LARGEFILE_SOURCE
14 #define _LARGEFILE_SOURCE
15 #endif
16 #ifndef _LARGEFILE64_SOURCE
17 #define _LARGEFILE64_SOURCE
18 #endif
19 
20 #include "config.h"
21 #include <stdlib.h>
22 
23 #include "ext2_fs.h"
24 #include "ext2fs.h"
25 #include "ext2fsP.h"
26 
27 struct exit_data {
28 	ext2_exit_fn func;
29 	void *data;
30 };
31 
32 static struct exit_data *items;
33 static size_t nr_items;
34 
handle_exit(void)35 static void handle_exit(void)
36 {
37 	struct exit_data *ed;
38 
39 	for (ed = items + nr_items - 1; ed >= items; ed--) {
40 		if (ed->func == NULL)
41 			continue;
42 		ed->func(ed->data);
43 	}
44 
45 	ext2fs_free_mem(&items);
46 	nr_items = 0;
47 }
48 
49 /*
50  * Schedule a function to be called at (normal) program termination.
51  * If you want this to be called during a signal exit, you must capture
52  * the signal and call exit() yourself!
53  */
ext2fs_add_exit_fn(ext2_exit_fn func,void * data)54 errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data)
55 {
56 	struct exit_data *ed, *free_ed = NULL;
57 	size_t x;
58 	errcode_t ret;
59 
60 	if (func == NULL)
61 		return EXT2_ET_INVALID_ARGUMENT;
62 
63 	for (x = 0, ed = items; x < nr_items; x++, ed++) {
64 		if (ed->func == func && ed->data == data)
65 			return EXT2_ET_FILE_EXISTS;
66 		if (ed->func == NULL)
67 			free_ed = ed;
68 	}
69 
70 	if (free_ed) {
71 		free_ed->func = func;
72 		free_ed->data = data;
73 		return 0;
74 	}
75 
76 	if (nr_items == 0) {
77 		ret = atexit(handle_exit);
78 		if (ret)
79 			return ret;
80 	}
81 
82 	ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data),
83 				&items);
84 	if (ret)
85 		return ret;
86 
87 	items[nr_items].func = func;
88 	items[nr_items].data = data;
89 	nr_items++;
90 
91 	return 0;
92 }
93 
94 /* Remove a function from the exit cleanup list. */
ext2fs_remove_exit_fn(ext2_exit_fn func,void * data)95 errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data)
96 {
97 	struct exit_data *ed;
98 	size_t x;
99 
100 	if (func == NULL)
101 		return EXT2_ET_INVALID_ARGUMENT;
102 
103 	for (x = 0, ed = items; x < nr_items; x++, ed++) {
104 		if (ed->func == NULL)
105 			return 0;
106 		if (ed->func == func && ed->data == data) {
107 			size_t sz = (nr_items - (x + 1)) *
108 				    sizeof(struct exit_data);
109 			memmove(ed, ed + 1, sz);
110 			memset(items + nr_items - 1, 0,
111 			       sizeof(struct exit_data));
112 		}
113 	}
114 
115 	return 0;
116 }
117