ali: executable file inclusion.
The "< file" construct tests if file is executable and begins with the shell interpreter magic (#!/ or #! /). If so, this file is executed and its output is collected. This provides a way for building aliases on the fly. * mh/mh_alias.l (buffer_ctx) <exec_p>: New member. (exec_p): New static variable. (push_source): If the file is executable and begins with the "#!/" magic, run it and collect its output. (pop_source): Use exec_p to decide how to close the file. * mh/tests/ali.at: Test executable file inclusion. * NEWS: Update.
Showing
3 changed files
with
48 additions
and
8 deletions
1 | GNU mailutils NEWS -- history of user-visible changes. 2012-11-12 | 1 | GNU mailutils NEWS -- history of user-visible changes. 2013-02-16 |
2 | Copyright (C) 2002-2012 Free Software Foundation, Inc. | 2 | Copyright (C) 2002-2012 Free Software Foundation, Inc. |
3 | See the end of file for copying conditions. | 3 | See the end of file for copying conditions. |
4 | 4 | ||
... | @@ -203,6 +203,14 @@ option: | ... | @@ -203,6 +203,14 @@ option: |
203 | "yes", the mailbox will be truncated after successful processing. | 203 | "yes", the mailbox will be truncated after successful processing. |
204 | If BOOL is "no", the source mailbox will not be truncated. | 204 | If BOOL is "no", the source mailbox will not be truncated. |
205 | 205 | ||
206 | ** MH aliases | ||
207 | |||
208 | The "< FILE" construct has been extended to allow for building the | ||
209 | list of aliases on the fly. If FILE is an executable file and its | ||
210 | first line begins with a shell interpreter magic (#!/ or #! /), then | ||
211 | instead of being included, such file is run using "/bin/sh -c", its | ||
212 | output is collected and included in the aliases. | ||
213 | |||
206 | ** mailutils-config is deprecated. | 214 | ** mailutils-config is deprecated. |
207 | 215 | ||
208 | Use `mu cflags' and `mu ldflags' instead. The mailutils-config is | 216 | Use `mu cflags' and `mu ldflags' instead. The mailutils-config is | ... | ... |
... | @@ -219,10 +219,12 @@ struct buffer_ctx { | ... | @@ -219,10 +219,12 @@ struct buffer_ctx { |
219 | int line; | 219 | int line; |
220 | ino_t i_node; | 220 | ino_t i_node; |
221 | FILE *yyin; | 221 | FILE *yyin; |
222 | int exec_p; | ||
222 | LEX_BUFFER_STATE state; | 223 | LEX_BUFFER_STATE state; |
223 | }; | 224 | }; |
224 | 225 | ||
225 | static struct buffer_ctx *context_stack; | 226 | static struct buffer_ctx *context_stack; |
227 | static int exec_p; | ||
226 | 228 | ||
227 | static struct buffer_ctx * | 229 | static struct buffer_ctx * |
228 | ctx_lookup (ino_t ino) | 230 | ctx_lookup (ino_t ino) |
... | @@ -242,7 +244,8 @@ push_source (const char *name, int fail) | ... | @@ -242,7 +244,8 @@ push_source (const char *name, int fail) |
242 | struct buffer_ctx *ctx; | 244 | struct buffer_ctx *ctx; |
243 | struct stat st; | 245 | struct stat st; |
244 | char *filename; | 246 | char *filename; |
245 | 247 | int ex = 0; | |
248 | |||
246 | filename = mh_expand_name (NULL, name, 0); | 249 | filename = mh_expand_name (NULL, name, 0); |
247 | if (stat (filename, &st)) | 250 | if (stat (filename, &st)) |
248 | { | 251 | { |
... | @@ -251,7 +254,7 @@ push_source (const char *name, int fail) | ... | @@ -251,7 +254,7 @@ push_source (const char *name, int fail) |
251 | free (filename); | 254 | free (filename); |
252 | return 1; | 255 | return 1; |
253 | } | 256 | } |
254 | 257 | ||
255 | if (ali_filename && st.st_ino == ali_source_inode) | 258 | if (ali_filename && st.st_ino == ali_source_inode) |
256 | { | 259 | { |
257 | ali_parse_error (_("recursive inclusion")); | 260 | ali_parse_error (_("recursive inclusion")); |
... | @@ -279,12 +282,35 @@ push_source (const char *name, int fail) | ... | @@ -279,12 +282,35 @@ push_source (const char *name, int fail) |
279 | free (filename); | 282 | free (filename); |
280 | return 1; | 283 | return 1; |
281 | } | 284 | } |
285 | if (access (filename, X_OK) == 0) | ||
286 | { | ||
287 | char sig[4]; | ||
288 | |||
289 | if (fread (sig, sizeof(sig), 1, fp) == 1 && | ||
290 | (memcmp(sig, "#!/", 3) == 0 || | ||
291 | memcmp(sig, "#! /", 4) == 0)) | ||
292 | { | ||
293 | ex = 1; | ||
294 | fclose (fp); | ||
295 | fp = popen (filename, "r"); | ||
296 | if (!fp) | ||
297 | { | ||
298 | ali_parse_error (_("can't execute `%s': %s"), | ||
299 | filename, strerror (errno)); | ||
300 | free (filename); | ||
301 | return 1; | ||
302 | } | ||
303 | } | ||
304 | else | ||
305 | rewind (fp); | ||
306 | } | ||
282 | 307 | ||
283 | /* Push current context */ | 308 | /* Push current context */ |
284 | if (ali_filename) | 309 | if (ali_filename) |
285 | { | 310 | { |
286 | ctx = mu_alloc (sizeof (*ctx)); | 311 | ctx = mu_alloc (sizeof (*ctx)); |
287 | ctx->filename = ali_filename; | 312 | ctx->filename = ali_filename; |
313 | ctx->exec_p = exec_p; | ||
288 | ctx->line = ali_line_num; | 314 | ctx->line = ali_line_num; |
289 | ctx->i_node = ali_source_inode; | 315 | ctx->i_node = ali_source_inode; |
290 | ctx->yyin = yyin; | 316 | ctx->yyin = yyin; |
... | @@ -307,6 +333,7 @@ push_source (const char *name, int fail) | ... | @@ -307,6 +333,7 @@ push_source (const char *name, int fail) |
307 | ali_filename = filename; | 333 | ali_filename = filename; |
308 | ali_line_num = 1; | 334 | ali_line_num = 1; |
309 | ali_source_inode = st.st_ino; | 335 | ali_source_inode = st.st_ino; |
336 | exec_p = ex; | ||
310 | return 0; | 337 | return 0; |
311 | } | 338 | } |
312 | 339 | ||
... | @@ -316,7 +343,7 @@ pop_source () | ... | @@ -316,7 +343,7 @@ pop_source () |
316 | struct buffer_ctx *ctx; | 343 | struct buffer_ctx *ctx; |
317 | 344 | ||
318 | if (yyin) | 345 | if (yyin) |
319 | fclose (yyin); | 346 | (exec_p ? pclose : fclose) (yyin); |
320 | #ifndef FLEX_SCANNER | 347 | #ifndef FLEX_SCANNER |
321 | lex_delete_buffer (current_buffer); | 348 | lex_delete_buffer (current_buffer); |
322 | #endif | 349 | #endif |
... | @@ -332,6 +359,7 @@ pop_source () | ... | @@ -332,6 +359,7 @@ pop_source () |
332 | ali_filename = context_stack->filename; | 359 | ali_filename = context_stack->filename; |
333 | ali_line_num = context_stack->line + 1; /* < line did not increment it */ | 360 | ali_line_num = context_stack->line + 1; /* < line did not increment it */ |
334 | ali_source_inode = context_stack->i_node; | 361 | ali_source_inode = context_stack->i_node; |
362 | exec_p = context_stack->exec_p; | ||
335 | RESTORE_BUFFER_STATE (context_stack->state); | 363 | RESTORE_BUFFER_STATE (context_stack->state); |
336 | ctx = context_stack->prev; | 364 | ctx = context_stack->prev; |
337 | free (context_stack); | 365 | free (context_stack); | ... | ... |
... | @@ -108,15 +108,19 @@ ali -list -a ./mh_aliases everybody | ... | @@ -108,15 +108,19 @@ ali -list -a ./mh_aliases everybody |
108 | [0], | 108 | [0], |
109 | [expout]) | 109 | [expout]) |
110 | 110 | ||
111 | MH_CHECK([ali: simple aliases],[ali00],[ | 111 | MH_CHECK([ali: executable file inlcusion],[ali02 ali-xinclude],[ |
112 | AT_DATA([Mail/ali.sh],[#! /bin/sh | ||
113 | echo "admin: gray, jeff" | ||
114 | ]) | ||
115 | chmod +x Mail/ali.sh | ||
112 | AT_DATA([mh_aliases],[ | 116 | AT_DATA([mh_aliases],[ |
113 | devel: gray, polak | 117 | devel: gray, polak, admin |
114 | admin: gray, jeff | 118 | <ali.sh |
115 | ]) | 119 | ]) |
116 | ali -a ./mh_aliases devel | 120 | ali -a ./mh_aliases devel |
117 | ], | 121 | ], |
118 | [0], | 122 | [0], |
119 | [gray, polak | 123 | [gray, polak, gray, jeff |
120 | ]) | 124 | ]) |
121 | 125 | ||
122 | m4_popdef[MH_KEYWORDS]) | 126 | m4_popdef[MH_KEYWORDS]) | ... | ... |
-
Please register or sign in to post a comment