Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * atexit.c --- Clean things up when we exit normally.
      3  *
      4  * Copyright Oracle, 2014
      5  * Author Darrick J. Wong <darrick.wong (at) 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 }
    117