diff options
Diffstat (limited to 'apps/plugin.c')
-rw-r--r-- | apps/plugin.c | 264 |
1 files changed, 114 insertions, 150 deletions
diff --git a/apps/plugin.c b/apps/plugin.c index 8edc773239..8a6c577f69 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -18,6 +18,8 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #define DIRFUNCTIONS_DEFINED | ||
22 | #define FILEFUNCTIONS_DEFINED | ||
21 | #include "plugin.h" | 23 | #include "plugin.h" |
22 | #include <ctype.h> | 24 | #include <ctype.h> |
23 | #include <string.h> | 25 | #include <string.h> |
@@ -40,8 +42,9 @@ | |||
40 | #include "pcmbuf.h" | 42 | #include "pcmbuf.h" |
41 | #include "errno.h" | 43 | #include "errno.h" |
42 | #include "diacritic.h" | 44 | #include "diacritic.h" |
43 | #include "filefuncs.h" | 45 | #include "pathfuncs.h" |
44 | #include "load_code.h" | 46 | #include "load_code.h" |
47 | #include "file.h" | ||
45 | 48 | ||
46 | #if CONFIG_CHARGING | 49 | #if CONFIG_CHARGING |
47 | #include "power.h" | 50 | #include "power.h" |
@@ -58,80 +61,119 @@ | |||
58 | #include "usbstack/usb_hid.h" | 61 | #include "usbstack/usb_hid.h" |
59 | #endif | 62 | #endif |
60 | 63 | ||
61 | #if defined (SIMULATOR) | 64 | #define WRAPPER(_x_) _x_ ## _wrapper |
62 | #define PREFIX(_x_) sim_ ## _x_ | 65 | |
63 | #elif defined (APPLICATION) | 66 | #if (CONFIG_PLATFORM & PLATFORM_HOSTED) |
64 | #define PREFIX(_x_) app_ ## _x_ | 67 | static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE]; |
68 | void sim_lcd_ex_init(unsigned long (*getpixel)(int, int)); | ||
69 | void sim_lcd_ex_update_rect(int x, int y, int width, int height); | ||
65 | #else | 70 | #else |
66 | #define PREFIX(_x_) _x_ | 71 | extern unsigned char pluginbuf[]; |
72 | #include "bitswap.h" | ||
67 | #endif | 73 | #endif |
68 | 74 | ||
69 | #if defined (APPLICATION) | 75 | /* for actual plugins only, not for codecs */ |
70 | /* For symmetry reasons (we want app_ and sim_ to behave similarly), some | 76 | static int plugin_size = 0; |
71 | * wrappers are needed */ | 77 | static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */ |
72 | static int app_close(int fd) | 78 | static char current_plugin[MAX_PATH]; |
79 | /* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */ | ||
80 | static void *current_plugin_handle; | ||
81 | |||
82 | char *plugin_get_current_filename(void); | ||
83 | |||
84 | static void* plugin_get_audio_buffer(size_t *buffer_size); | ||
85 | static void plugin_release_audio_buffer(void); | ||
86 | static void plugin_tsr(bool (*exit_callback)(bool)); | ||
87 | |||
88 | |||
89 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | ||
90 | /* File handle leak prophylaxis */ | ||
91 | #include "bitarray.h" | ||
92 | #include "file_internal.h" /* for MAX_OPEN_FILES */ | ||
93 | |||
94 | #define PCOC_WRAPPER(_x_) WRAPPER(_x_) | ||
95 | |||
96 | BITARRAY_TYPE_DECLARE(plugin_check_open_close_bitmap_t, open_files_bitmap, | ||
97 | MAX_OPEN_FILES) | ||
98 | |||
99 | static plugin_check_open_close_bitmap_t open_files_bitmap; | ||
100 | |||
101 | static void plugin_check_open_close__enter(void) | ||
73 | { | 102 | { |
74 | return close(fd); | 103 | if (!current_plugin_handle) |
104 | open_files_bitmap_clear(&open_files_bitmap); | ||
75 | } | 105 | } |
76 | 106 | ||
77 | static ssize_t app_read(int fd, void *buf, size_t count) | 107 | static void plugin_check_open_close__open(int fildes) |
78 | { | 108 | { |
79 | return read(fd,buf,count); | 109 | if (fildes >= 0) |
110 | open_files_bitmap_set_bit(&open_files_bitmap, fildes); | ||
80 | } | 111 | } |
81 | 112 | ||
82 | static off_t app_lseek(int fd, off_t offset, int whence) | 113 | static void plugin_check_open_close__close(int fildes) |
83 | { | 114 | { |
84 | return lseek(fd,offset,whence); | 115 | if (fildes < 0) |
116 | return; | ||
117 | |||
118 | if (!open_files_bitmap_test_bit(&open_files_bitmap, fildes)) | ||
119 | { | ||
120 | logf("double close from plugin"); | ||
121 | } | ||
122 | |||
123 | open_files_bitmap_clear_bit(&open_files_bitmap, fildes); | ||
85 | } | 124 | } |
86 | 125 | ||
87 | static ssize_t app_write(int fd, const void *buf, size_t count) | 126 | static int WRAPPER(open)(const char *path, int oflag, ...) |
88 | { | 127 | { |
89 | return write(fd,buf,count); | 128 | int fildes = FS_PREFIX(open)(path, oflag __OPEN_MODE_ARG); |
129 | plugin_check_open_close__open(fildes); | ||
130 | return fildes; | ||
90 | } | 131 | } |
91 | 132 | ||
92 | static int app_ftruncate(int fd, off_t length) | 133 | static int WRAPPER(creat)(const char *path, mode_t mode) |
93 | { | 134 | { |
94 | return ftruncate(fd,length); | 135 | int fildes = FS_PREFIX(creat)(path __CREAT_MODE_ARG); |
136 | plugin_check_open_close__open(fildes); | ||
137 | return fildes; | ||
138 | (void)mode; | ||
95 | } | 139 | } |
96 | #endif | ||
97 | 140 | ||
98 | #if defined(HAVE_PLUGIN_CHECK_OPEN_CLOSE) && (MAX_OPEN_FILES>32) | 141 | static int WRAPPER(close)(int fildes) |
99 | #warning "MAX_OPEN_FILES>32, disabling plugin file open/close checking" | 142 | { |
100 | #undef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 143 | int rc = FS_PREFIX(close)(fildes); |
101 | #endif | 144 | if (rc >= 0) |
145 | plugin_check_open_close__close(fildes); | ||
102 | 146 | ||
103 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 147 | return rc; |
104 | static unsigned int open_files; | 148 | } |
105 | #endif | ||
106 | 149 | ||
107 | #if (CONFIG_PLATFORM & PLATFORM_HOSTED) | 150 | static void plugin_check_open_close__exit(void) |
108 | static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE]; | 151 | { |
109 | void sim_lcd_ex_init(unsigned long (*getpixel)(int, int)); | 152 | if (current_plugin_handle) |
110 | void sim_lcd_ex_update_rect(int x, int y, int width, int height); | 153 | return; |
111 | #else | ||
112 | extern unsigned char pluginbuf[]; | ||
113 | #include "bitswap.h" | ||
114 | #endif | ||
115 | 154 | ||
116 | /* for actual plugins only, not for codecs */ | 155 | if (open_files_bitmap_is_clear(&open_files_bitmap)) |
117 | static int plugin_size = 0; | 156 | return; |
118 | static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */ | ||
119 | static char current_plugin[MAX_PATH]; | ||
120 | /* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */ | ||
121 | static void *current_plugin_handle; | ||
122 | 157 | ||
123 | char *plugin_get_current_filename(void); | 158 | logf("Plugin '%s' leaks file handles", plugin); |
124 | 159 | ||
125 | /* Some wrappers used to monitor open and close and detect leaks*/ | 160 | static const char *lines[] = |
126 | static int open_wrapper(const char* pathname, int flags, ...); | 161 | { ID2P(LANG_PLUGIN_ERROR), "#leak-file-handles" }; |
127 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 162 | static const struct text_message message = { lines, 2 }; |
128 | static int close_wrapper(int fd); | 163 | button_clear_queue(); /* Empty the keyboard buffer */ |
129 | static int creat_wrapper(const char *pathname, mode_t mode); | 164 | gui_syncyesno_run(&message, NULL, NULL); |
130 | #endif | ||
131 | 165 | ||
132 | static void* plugin_get_audio_buffer(size_t *buffer_size); | 166 | FOR_EACH_BITARRAY_SET_BIT(&open_files_bitmap, fildes) |
133 | static void plugin_release_audio_buffer(void); | 167 | WRAPPER(close)(fildes); |
134 | static void plugin_tsr(bool (*exit_callback)(bool)); | 168 | } |
169 | |||
170 | #else /* !HAVE_PLUGIN_CHECK_OPEN_CLOSE */ | ||
171 | |||
172 | #define PCOC_WRAPPER(_x_) FS_PREFIX(_x_) | ||
173 | #define plugin_check_open_close__enter() | ||
174 | #define plugin_check_open_close__exit() | ||
175 | |||
176 | #endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */ | ||
135 | 177 | ||
136 | static const struct plugin_api rockbox_api = { | 178 | static const struct plugin_api rockbox_api = { |
137 | 179 | ||
@@ -339,24 +381,16 @@ static const struct plugin_api rockbox_api = { | |||
339 | 381 | ||
340 | /* file */ | 382 | /* file */ |
341 | open_utf8, | 383 | open_utf8, |
342 | (open_func)open_wrapper, | 384 | PCOC_WRAPPER(open), |
343 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 385 | PCOC_WRAPPER(creat), |
344 | close_wrapper, | 386 | PCOC_WRAPPER(close), |
345 | #else | 387 | FS_PREFIX(read), |
346 | PREFIX(close), | 388 | FS_PREFIX(lseek), |
347 | #endif | 389 | FS_PREFIX(write), |
348 | (read_func)PREFIX(read), | 390 | FS_PREFIX(remove), |
349 | PREFIX(lseek), | 391 | FS_PREFIX(rename), |
350 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 392 | FS_PREFIX(ftruncate), |
351 | (creat_func)creat_wrapper, | 393 | FS_PREFIX(filesize), |
352 | #else | ||
353 | PREFIX(creat), | ||
354 | #endif | ||
355 | (write_func)PREFIX(write), | ||
356 | PREFIX(remove), | ||
357 | PREFIX(rename), | ||
358 | PREFIX(ftruncate), | ||
359 | filesize, | ||
360 | fdprintf, | 394 | fdprintf, |
361 | read_line, | 395 | read_line, |
362 | settings_parseline, | 396 | settings_parseline, |
@@ -369,18 +403,18 @@ static const struct plugin_api rockbox_api = { | |||
369 | #endif /* USING_STORAGE_CALLBACK */ | 403 | #endif /* USING_STORAGE_CALLBACK */ |
370 | reload_directory, | 404 | reload_directory, |
371 | create_numbered_filename, | 405 | create_numbered_filename, |
372 | file_exists, | 406 | FS_PREFIX(file_exists), |
373 | strip_extension, | 407 | strip_extension, |
374 | crc_32, | 408 | crc_32, |
375 | filetype_get_attr, | 409 | filetype_get_attr, |
376 | 410 | ||
377 | /* dir */ | 411 | /* dir */ |
378 | (opendir_func)opendir, | 412 | FS_PREFIX(opendir), |
379 | (closedir_func)closedir, | 413 | FS_PREFIX(closedir), |
380 | (readdir_func)readdir, | 414 | FS_PREFIX(readdir), |
381 | mkdir, | 415 | FS_PREFIX(mkdir), |
382 | rmdir, | 416 | FS_PREFIX(rmdir), |
383 | dir_exists, | 417 | FS_PREFIX(dir_exists), |
384 | dir_get_info, | 418 | dir_get_info, |
385 | 419 | ||
386 | /* browsing */ | 420 | /* browsing */ |
@@ -688,10 +722,11 @@ static const struct plugin_api rockbox_api = { | |||
688 | #endif | 722 | #endif |
689 | srand, | 723 | srand, |
690 | rand, | 724 | rand, |
691 | (qsort_func)qsort, | 725 | (void *)qsort, |
692 | kbd_input, | 726 | kbd_input, |
693 | get_time, | 727 | get_time, |
694 | set_time, | 728 | set_time, |
729 | gmtime_r, | ||
695 | #if CONFIG_RTC | 730 | #if CONFIG_RTC |
696 | mktime, | 731 | mktime, |
697 | #endif | 732 | #endif |
@@ -891,9 +926,7 @@ int plugin_load(const char* plugin, const void* parameter) | |||
891 | /* allow voice to back off if the plugin needs lots of memory */ | 926 | /* allow voice to back off if the plugin needs lots of memory */ |
892 | talk_buffer_set_policy(TALK_BUFFER_LOOSE); | 927 | talk_buffer_set_policy(TALK_BUFFER_LOOSE); |
893 | 928 | ||
894 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 929 | plugin_check_open_close__enter(); |
895 | open_files = 0; | ||
896 | #endif | ||
897 | 930 | ||
898 | int rc = p_hdr->entry_point(parameter); | 931 | int rc = p_hdr->entry_point(parameter); |
899 | 932 | ||
@@ -947,24 +980,7 @@ int plugin_load(const char* plugin, const void* parameter) | |||
947 | FOR_NB_SCREENS(i) | 980 | FOR_NB_SCREENS(i) |
948 | viewportmanager_theme_undo(i, true); | 981 | viewportmanager_theme_undo(i, true); |
949 | 982 | ||
950 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 983 | plugin_check_open_close__exit(); |
951 | if(open_files != 0 && !current_plugin_handle) | ||
952 | { | ||
953 | int fd; | ||
954 | logf("Plugin '%s' leaks file handles", plugin); | ||
955 | |||
956 | static const char *lines[] = | ||
957 | { ID2P(LANG_PLUGIN_ERROR), | ||
958 | "#leak-file-handles" }; | ||
959 | static const struct text_message message={ lines, 2 }; | ||
960 | button_clear_queue(); /* Empty the keyboard buffer */ | ||
961 | gui_syncyesno_run(&message, NULL, NULL); | ||
962 | |||
963 | for(fd=0; fd < MAX_OPEN_FILES; fd++) | ||
964 | if(open_files & (1<<fd)) | ||
965 | close_wrapper(fd); | ||
966 | } | ||
967 | #endif | ||
968 | 984 | ||
969 | if (rc == PLUGIN_ERROR) | 985 | if (rc == PLUGIN_ERROR) |
970 | splash(HZ*2, str(LANG_PLUGIN_ERROR)); | 986 | splash(HZ*2, str(LANG_PLUGIN_ERROR)); |
@@ -1027,55 +1043,3 @@ char *plugin_get_current_filename(void) | |||
1027 | { | 1043 | { |
1028 | return current_plugin; | 1044 | return current_plugin; |
1029 | } | 1045 | } |
1030 | |||
1031 | static int open_wrapper(const char* pathname, int flags, ...) | ||
1032 | { | ||
1033 | /* we don't have an 'open' function. it's a define. and we need | ||
1034 | * the real file_open, hence PREFIX() doesn't work here */ | ||
1035 | int fd; | ||
1036 | #if (CONFIG_PLATFORM & PLATFORM_HOSTED) | ||
1037 | if (flags & O_CREAT) | ||
1038 | { | ||
1039 | va_list ap; | ||
1040 | va_start(ap, flags); | ||
1041 | fd = open(pathname, flags, va_arg(ap, unsigned int)); | ||
1042 | va_end(ap); | ||
1043 | } | ||
1044 | else | ||
1045 | fd = open(pathname, flags); | ||
1046 | #else | ||
1047 | fd = file_open(pathname,flags); | ||
1048 | #endif | ||
1049 | |||
1050 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | ||
1051 | if(fd >= 0) | ||
1052 | open_files |= 1<<fd; | ||
1053 | #endif | ||
1054 | return fd; | ||
1055 | } | ||
1056 | |||
1057 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | ||
1058 | static int close_wrapper(int fd) | ||
1059 | { | ||
1060 | if((~open_files) & (1<<fd)) | ||
1061 | { | ||
1062 | logf("double close from plugin"); | ||
1063 | } | ||
1064 | if(fd >= 0) | ||
1065 | open_files &= (~(1<<fd)); | ||
1066 | |||
1067 | return PREFIX(close)(fd); | ||
1068 | } | ||
1069 | |||
1070 | static int creat_wrapper(const char *pathname, mode_t mode) | ||
1071 | { | ||
1072 | (void)mode; | ||
1073 | |||
1074 | int fd = PREFIX(creat)(pathname, mode); | ||
1075 | |||
1076 | if(fd >= 0) | ||
1077 | open_files |= (1<<fd); | ||
1078 | |||
1079 | return fd; | ||
1080 | } | ||
1081 | #endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */ | ||