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 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 */ 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. */ 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 }