#include "asterisk.h"
#include <sys/stat.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/file.h"
Go to the source code of this file.
Defines | |
#define | LINE_COUNTER(cptr, term, counter) |
Enumerations | |
enum | file_format { FF_UNKNOWN = -1, FF_UNIX, FF_DOS, FF_MAC } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int64_t | count_lines (const char *filename, enum file_format newline_format) |
static int | env_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | env_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
static enum file_format | file2format (const char *filename) |
static int | file_count_line (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | file_format (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | file_read (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | file_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
const char * | format2term (enum file_format f) |
static int | load_module (void) |
static int | stat_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Environment/filesystem dialplan functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_custom_function | env_function |
static struct ast_custom_function | file_count_line_function |
static struct ast_custom_function | file_format_function |
static struct ast_custom_function | file_function |
static struct ast_custom_function | stat_function |
Definition in file func_env.c.
#define LINE_COUNTER | ( | cptr, | |||
term, | |||||
counter | ) |
enum file_format |
Definition at line 300 of file func_env.c.
00300 { 00301 FF_UNKNOWN = -1, 00302 FF_UNIX, 00303 FF_DOS, 00304 FF_MAC, 00305 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1269 of file func_env.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1269 of file func_env.c.
static int64_t count_lines | ( | const char * | filename, | |
enum file_format | newline_format | |||
) | [static] |
Definition at line 307 of file func_env.c.
References ast_log(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, and LOG_ERROR.
Referenced by file_count_line().
00308 { 00309 int count = 0; 00310 char fbuf[4096]; 00311 FILE *ff; 00312 00313 if (!(ff = fopen(filename, "r"))) { 00314 ast_log(LOG_ERROR, "Unable to open '%s': %s\n", filename, strerror(errno)); 00315 return -1; 00316 } 00317 00318 while (fgets(fbuf, sizeof(fbuf), ff)) { 00319 char *next = fbuf, *first_cr = NULL, *first_nl = NULL; 00320 00321 /* Must do it this way, because if the fileformat is FF_MAC, then Unix 00322 * assumptions about line-format will not come into play. */ 00323 while (next) { 00324 if (newline_format == FF_DOS || newline_format == FF_MAC || newline_format == FF_UNKNOWN) { 00325 first_cr = strchr(next, '\r'); 00326 } 00327 if (newline_format == FF_UNIX || newline_format == FF_UNKNOWN) { 00328 first_nl = strchr(next, '\n'); 00329 } 00330 00331 /* No terminators found in buffer */ 00332 if (!first_cr && !first_nl) { 00333 break; 00334 } 00335 00336 if (newline_format == FF_UNKNOWN) { 00337 if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) { 00338 if (first_nl && first_nl == first_cr + 1) { 00339 newline_format = FF_DOS; 00340 } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) { 00341 /* Get it on the next pass */ 00342 fseek(ff, -1, SEEK_CUR); 00343 break; 00344 } else { 00345 newline_format = FF_MAC; 00346 first_nl = NULL; 00347 } 00348 } else { 00349 newline_format = FF_UNIX; 00350 first_cr = NULL; 00351 } 00352 /* Jump down into next section */ 00353 } 00354 00355 if (newline_format == FF_DOS) { 00356 if (first_nl && first_cr && first_nl == first_cr + 1) { 00357 next = first_nl + 1; 00358 count++; 00359 } else if (first_cr == &fbuf[sizeof(fbuf) - 2]) { 00360 /* Get it on the next pass */ 00361 fseek(ff, -1, SEEK_CUR); 00362 break; 00363 } 00364 } else if (newline_format == FF_MAC) { 00365 if (first_cr) { 00366 next = first_cr + 1; 00367 count++; 00368 } 00369 } else if (newline_format == FF_UNIX) { 00370 if (first_nl) { 00371 next = first_nl + 1; 00372 count++; 00373 } 00374 } 00375 } 00376 } 00377 fclose(ff); 00378 00379 return count; 00380 }
static int env_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 227 of file func_env.c.
References ast_copy_string().
00229 { 00230 char *ret = NULL; 00231 00232 *buf = '\0'; 00233 00234 if (data) 00235 ret = getenv(data); 00236 00237 if (ret) 00238 ast_copy_string(buf, ret, len); 00239 00240 return 0; 00241 }
static int env_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 243 of file func_env.c.
References ast_strlen_zero(), setenv(), and unsetenv().
00245 { 00246 if (!ast_strlen_zero(data) && strncmp(data, "AST_", 4)) { 00247 if (!ast_strlen_zero(value)) { 00248 setenv(data, value, 1); 00249 } else { 00250 unsetenv(data); 00251 } 00252 } 00253 00254 return 0; 00255 }
static enum file_format file2format | ( | const char * | filename | ) | [static] |
Definition at line 421 of file func_env.c.
References ast_log(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file_format(), and LOG_ERROR.
Referenced by file_format(), file_read(), and file_write().
00422 { 00423 FILE *ff; 00424 char fbuf[4096]; 00425 char *first_cr, *first_nl; 00426 enum file_format newline_format = FF_UNKNOWN; 00427 00428 if (!(ff = fopen(filename, "r"))) { 00429 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", filename, strerror(errno)); 00430 return -1; 00431 } 00432 00433 while (fgets(fbuf, sizeof(fbuf), ff)) { 00434 first_cr = strchr(fbuf, '\r'); 00435 first_nl = strchr(fbuf, '\n'); 00436 00437 if (!first_cr && !first_nl) { 00438 continue; 00439 } 00440 00441 if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) { 00442 00443 if (first_nl && first_nl == first_cr + 1) { 00444 newline_format = FF_DOS; 00445 } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) { 00446 /* Edge case: get it on the next pass */ 00447 fseek(ff, -1, SEEK_CUR); 00448 continue; 00449 } else { 00450 newline_format = FF_MAC; 00451 } 00452 } else { 00453 newline_format = FF_UNIX; 00454 } 00455 break; 00456 } 00457 fclose(ff); 00458 return newline_format; 00459 }
static int file_count_line | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 382 of file func_env.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_str_set(), count_lines(), FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file_format(), and format.
00383 { 00384 enum file_format newline_format = FF_UNKNOWN; 00385 int64_t count; 00386 AST_DECLARE_APP_ARGS(args, 00387 AST_APP_ARG(filename); 00388 AST_APP_ARG(format); 00389 ); 00390 00391 AST_STANDARD_APP_ARGS(args, data); 00392 if (args.argc > 1) { 00393 if (tolower(args.format[0]) == 'd') { 00394 newline_format = FF_DOS; 00395 } else if (tolower(args.format[0]) == 'm') { 00396 newline_format = FF_MAC; 00397 } else if (tolower(args.format[0]) == 'u') { 00398 newline_format = FF_UNIX; 00399 } 00400 } 00401 00402 count = count_lines(args.filename, newline_format); 00403 ast_str_set(buf, len, "%" PRId64, count); 00404 return 0; 00405 }
static int file_format | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 461 of file func_env.c.
References ast_str_set(), FF_DOS, FF_MAC, FF_UNIX, and file2format().
Referenced by file2format(), file_count_line(), file_read(), and file_write().
00462 { 00463 enum file_format newline_format = file2format(data); 00464 ast_str_set(buf, len, "%c", newline_format == FF_UNIX ? 'u' : newline_format == FF_DOS ? 'd' : newline_format == FF_MAC ? 'm' : 'x'); 00465 return 0; 00466 }
static int file_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 468 of file func_env.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_LOG_ERROR, AST_STANDARD_APP_ARGS, ast_str_append_substr(), ast_str_reset(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), file_format(), format, LINE_COUNTER, LLONG_MAX, LOG_ERROR, and LOG_WARNING.
00469 { 00470 FILE *ff; 00471 int64_t offset = 0, length = LLONG_MAX; 00472 enum file_format format = FF_UNKNOWN; 00473 char fbuf[4096]; 00474 int64_t flength, i; /* iterator needs to be signed, so it can go negative and terminate the loop */ 00475 int64_t offset_offset = -1, length_offset = -1; 00476 char dos_state = 0; 00477 size_t readlen; 00478 AST_DECLARE_APP_ARGS(args, 00479 AST_APP_ARG(filename); 00480 AST_APP_ARG(offset); 00481 AST_APP_ARG(length); 00482 AST_APP_ARG(options); 00483 AST_APP_ARG(fileformat); 00484 ); 00485 00486 AST_STANDARD_APP_ARGS(args, data); 00487 00488 if (args.argc > 1) { 00489 sscanf(args.offset, "%" SCNd64, &offset); 00490 } 00491 if (args.argc > 2) { 00492 sscanf(args.length, "%" SCNd64, &length); 00493 } 00494 00495 if (args.argc < 4 || !strchr(args.options, 'l')) { 00496 /* Character-based mode */ 00497 off_t off_i; 00498 00499 if (!(ff = fopen(args.filename, "r"))) { 00500 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", args.filename, strerror(errno)); 00501 return 0; 00502 } 00503 00504 if (fseeko(ff, 0, SEEK_END) < 0) { 00505 ast_log(LOG_ERROR, "Cannot seek to end of '%s': %s\n", args.filename, strerror(errno)); 00506 fclose(ff); 00507 return -1; 00508 } 00509 flength = ftello(ff); 00510 00511 if (offset < 0) { 00512 fseeko(ff, offset, SEEK_END); 00513 if ((offset = ftello(ff)) < 0) { 00514 ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno)); 00515 fclose(ff); 00516 return -1; 00517 } 00518 } 00519 if (length < 0) { 00520 fseeko(ff, length, SEEK_END); 00521 if ((length = ftello(ff)) - offset < 0) { 00522 /* Eliminates all results */ 00523 fclose(ff); 00524 return -1; 00525 } 00526 } else if (length == LLONG_MAX) { 00527 fseeko(ff, 0, SEEK_END); 00528 length = ftello(ff); 00529 } 00530 00531 ast_str_reset(*buf); 00532 00533 fseeko(ff, offset, SEEK_SET); 00534 for (off_i = ftello(ff); off_i < flength && off_i < offset + length; off_i += sizeof(fbuf)) { 00535 /* Calculate if we need to retrieve just a portion of the file in memory */ 00536 size_t toappend = sizeof(fbuf); 00537 00538 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00539 ast_log(LOG_ERROR, "Short read?!!\n"); 00540 break; 00541 } 00542 00543 /* Don't go past the length requested */ 00544 if (off_i + toappend > offset + length) { 00545 toappend = length - off_i; 00546 } 00547 00548 ast_str_append_substr(buf, len, fbuf, toappend); 00549 } 00550 fclose(ff); 00551 return 0; 00552 } 00553 00554 /* Line-based read */ 00555 if (args.argc == 5) { 00556 if (tolower(args.fileformat[0]) == 'd') { 00557 format = FF_DOS; 00558 } else if (tolower(args.fileformat[0]) == 'm') { 00559 format = FF_MAC; 00560 } else if (tolower(args.fileformat[0]) == 'u') { 00561 format = FF_UNIX; 00562 } 00563 } 00564 00565 if (format == FF_UNKNOWN) { 00566 if ((format = file2format(args.filename)) == FF_UNKNOWN) { 00567 ast_log(LOG_WARNING, "'%s' is not a line-based file\n", args.filename); 00568 return -1; 00569 } 00570 } 00571 00572 if (offset < 0 && length <= offset) { 00573 /* Length eliminates all content */ 00574 return -1; 00575 } else if (offset == 0) { 00576 offset_offset = 0; 00577 } 00578 00579 if (!(ff = fopen(args.filename, "r"))) { 00580 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", args.filename, strerror(errno)); 00581 return -1; 00582 } 00583 00584 if (fseek(ff, 0, SEEK_END)) { 00585 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno)); 00586 fclose(ff); 00587 return -1; 00588 } 00589 00590 flength = ftello(ff); 00591 00592 if (length == LLONG_MAX) { 00593 length_offset = flength; 00594 } 00595 00596 /* For negative offset and/or negative length */ 00597 if (offset < 0 || length < 0) { 00598 int64_t count = 0; 00599 /* Start with an even multiple of fbuf, so at the end of reading with a 00600 * 0 offset, we don't try to go past the beginning of the file. */ 00601 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) { 00602 size_t end; 00603 char *pos; 00604 if (fseeko(ff, i, SEEK_SET)) { 00605 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno)); 00606 } 00607 end = fread(fbuf, 1, sizeof(fbuf), ff); 00608 for (pos = end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) { 00609 LINE_COUNTER(pos, format, count); 00610 00611 if (length < 0 && count * -1 == length) { 00612 length_offset = i + (pos - fbuf); 00613 } else if (offset < 0 && count * -1 == (offset - 1)) { 00614 /* Found our initial offset. We're done with reverse motion! */ 00615 if (format == FF_DOS) { 00616 offset_offset = i + (pos - fbuf) + 2; 00617 } else { 00618 offset_offset = i + (pos - fbuf) + 1; 00619 } 00620 break; 00621 } 00622 } 00623 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) { 00624 break; 00625 } 00626 } 00627 /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */ 00628 if (offset < 0 && offset_offset < 0 && offset == count * -1) { 00629 offset_offset = 0; 00630 } 00631 } 00632 00633 /* Positve line offset */ 00634 if (offset > 0) { 00635 int64_t count = 0; 00636 fseek(ff, 0, SEEK_SET); 00637 for (i = 0; i < flength; i += sizeof(fbuf)) { 00638 char *pos; 00639 if (i + sizeof(fbuf) <= flength) { 00640 /* Don't let previous values influence current counts, due to short reads */ 00641 memset(fbuf, 0, sizeof(fbuf)); 00642 } 00643 if (fread(fbuf, 1, sizeof(fbuf), ff) && !feof(ff)) { 00644 ast_log(LOG_ERROR, "Short read?!!\n"); 00645 fclose(ff); 00646 return -1; 00647 } 00648 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 00649 LINE_COUNTER(pos, format, count); 00650 00651 if (count == offset) { 00652 offset_offset = i + (pos - fbuf) + 1; 00653 break; 00654 } 00655 } 00656 if (offset_offset >= 0) { 00657 break; 00658 } 00659 } 00660 } 00661 00662 if (offset_offset < 0) { 00663 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset); 00664 fclose(ff); 00665 return -1; 00666 } 00667 00668 ast_str_reset(*buf); 00669 if (fseeko(ff, offset_offset, SEEK_SET)) { 00670 ast_log(LOG_ERROR, "fseeko failed: %s\n", strerror(errno)); 00671 } 00672 00673 /* If we have both offset_offset and length_offset, then grabbing the 00674 * buffer is simply a matter of just retrieving the file and adding it 00675 * to buf. Otherwise, we need to run byte-by-byte forward until the 00676 * length is complete. */ 00677 if (length_offset >= 0) { 00678 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset); 00679 for (i = offset_offset; i < length_offset; i += sizeof(fbuf)) { 00680 if (fread(fbuf, 1, i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf), ff) < (i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf))) { 00681 ast_log(LOG_ERROR, "Short read?!!\n"); 00682 } 00683 ast_debug(3, "Appending first %" PRId64" bytes of fbuf=%s\n", i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf), fbuf); 00684 ast_str_append_substr(buf, len, fbuf, i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf)); 00685 } 00686 } else if (length == 0) { 00687 /* Nothing to do */ 00688 } else { 00689 /* Positive line offset */ 00690 int64_t current_length = 0; 00691 char dos_state = 0; 00692 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset); 00693 for (i = offset_offset; i < flength; i += sizeof(fbuf)) { 00694 char *pos; 00695 if ((readlen = fread(fbuf, 1, sizeof(fbuf), ff)) < sizeof(fbuf) && !feof(ff)) { 00696 ast_log(LOG_ERROR, "Short read?!!\n"); 00697 } 00698 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 00699 LINE_COUNTER(pos, format, current_length); 00700 00701 if (current_length == length) { 00702 length_offset = i + (pos - fbuf) + 1; 00703 break; 00704 } 00705 } 00706 ast_debug(3, "length_offset=%" PRId64 ", length_offset - i=%" PRId64 "\n", length_offset, length_offset - i); 00707 ast_str_append_substr(buf, len, fbuf, length_offset >= 0 ? length_offset - i : flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i; 00708 00709 if (length_offset >= 0) { 00710 break; 00711 } 00712 } 00713 } 00714 00715 fclose(ff); 00716 return 0; 00717 }
static int file_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 726 of file func_env.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_LOG_ERROR, AST_STANDARD_APP_ARGS, errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), file_format(), format, format2term(), LINE_COUNTER, LLONG_MAX, LOG_ERROR, LOG_WARNING, and S_OR.
00727 { 00728 AST_DECLARE_APP_ARGS(args, 00729 AST_APP_ARG(filename); 00730 AST_APP_ARG(offset); 00731 AST_APP_ARG(length); 00732 AST_APP_ARG(options); 00733 AST_APP_ARG(format); 00734 ); 00735 int64_t offset = 0, length = LLONG_MAX; 00736 off_t flength, vlength; 00737 size_t foplen = 0; 00738 FILE *ff; 00739 00740 AST_STANDARD_APP_ARGS(args, data); 00741 00742 if (args.argc > 1) { 00743 sscanf(args.offset, "%" SCNd64, &offset); 00744 } 00745 if (args.argc > 2) { 00746 sscanf(args.length, "%" SCNd64, &length); 00747 } 00748 00749 vlength = strlen(value); 00750 00751 if (args.argc < 4 || !strchr(args.options, 'l')) { 00752 /* Character-based mode */ 00753 00754 if (args.argc > 3 && strchr(args.options, 'a')) { 00755 /* Append mode */ 00756 if (!(ff = fopen(args.filename, "a"))) { 00757 ast_log(LOG_WARNING, "Cannot open file '%s' for appending: %s\n", args.filename, strerror(errno)); 00758 return 0; 00759 } 00760 if (fwrite(value, 1, vlength, ff) < vlength) { 00761 ast_log(LOG_ERROR, "Short write?!!\n"); 00762 } 00763 fclose(ff); 00764 return 0; 00765 } else if (offset == 0 && length == LLONG_MAX) { 00766 if (!(ff = fopen(args.filename, "w"))) { 00767 ast_log(LOG_WARNING, "Cannot open file '%s' for writing: %s\n", args.filename, strerror(errno)); 00768 return 0; 00769 } 00770 if (fwrite(value, 1, vlength, ff) < vlength) { 00771 ast_log(LOG_ERROR, "Short write?!!\n"); 00772 } 00773 fclose(ff); 00774 return 0; 00775 } 00776 00777 if (!(ff = fopen(args.filename, "r+"))) { 00778 ast_log(LOG_WARNING, "Cannot open file '%s' for modification: %s\n", args.filename, strerror(errno)); 00779 return 0; 00780 } 00781 fseeko(ff, 0, SEEK_END); 00782 flength = ftello(ff); 00783 00784 if (offset < 0) { 00785 if (fseeko(ff, offset, SEEK_END)) { 00786 ast_log(LOG_ERROR, "Cannot seek to offset of '%s': %s\n", args.filename, strerror(errno)); 00787 fclose(ff); 00788 return -1; 00789 } 00790 if ((offset = ftello(ff)) < 0) { 00791 ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno)); 00792 fclose(ff); 00793 return -1; 00794 } 00795 } 00796 00797 if (length < 0) { 00798 length = flength - offset + length; 00799 if (length < 0) { 00800 ast_log(LOG_ERROR, "Length '%s' exceeds the file length. No data will be written.\n", args.length); 00801 fclose(ff); 00802 return -1; 00803 } 00804 } 00805 00806 fseeko(ff, offset, SEEK_SET); 00807 00808 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n", 00809 S_OR(args.offset, "(null)"), offset, S_OR(args.length, "(null)"), length, vlength, flength); 00810 00811 if (length == vlength) { 00812 /* Simplest case, a straight replace */ 00813 if (fwrite(value, 1, vlength, ff) < vlength) { 00814 ast_log(LOG_ERROR, "Short write?!!\n"); 00815 } 00816 fclose(ff); 00817 } else if (length == LLONG_MAX) { 00818 /* Simple truncation */ 00819 if (fwrite(value, 1, vlength, ff) < vlength) { 00820 ast_log(LOG_ERROR, "Short write?!!\n"); 00821 } 00822 fclose(ff); 00823 if (truncate(args.filename, offset + vlength)) { 00824 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno)); 00825 } 00826 } else if (length > vlength) { 00827 /* More complex -- need to close a gap */ 00828 char fbuf[4096]; 00829 off_t cur; 00830 if (fwrite(value, 1, vlength, ff) < vlength) { 00831 ast_log(LOG_ERROR, "Short write?!!\n"); 00832 } 00833 fseeko(ff, length - vlength, SEEK_CUR); 00834 while ((cur = ftello(ff)) < flength) { 00835 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00836 ast_log(LOG_ERROR, "Short read?!!\n"); 00837 } 00838 fseeko(ff, cur + vlength - length, SEEK_SET); 00839 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 00840 ast_log(LOG_ERROR, "Short write?!!\n"); 00841 } 00842 /* Seek to where we stopped reading */ 00843 if (fseeko(ff, cur + sizeof(fbuf), SEEK_SET) < 0) { 00844 /* Only reason for seek to fail is EOF */ 00845 break; 00846 } 00847 } 00848 fclose(ff); 00849 if (truncate(args.filename, flength - (length - vlength))) { 00850 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno)); 00851 } 00852 } else { 00853 /* Most complex -- need to open a gap */ 00854 char fbuf[4096]; 00855 off_t lastwritten = flength + vlength - length; 00856 00857 /* Start reading exactly the buffer size back from the end. */ 00858 fseeko(ff, flength - sizeof(fbuf), SEEK_SET); 00859 while (offset < ftello(ff)) { 00860 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 00861 ast_log(LOG_ERROR, "Short read?!!\n"); 00862 fclose(ff); 00863 return -1; 00864 } 00865 /* Since the read moved our file ptr forward, we reverse, but 00866 * seek an offset equal to the amount we want to extend the 00867 * file by */ 00868 fseeko(ff, vlength - length - sizeof(fbuf), SEEK_CUR); 00869 00870 /* Note the location of this buffer -- we must not overwrite this position. */ 00871 lastwritten = ftello(ff); 00872 00873 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 00874 ast_log(LOG_ERROR, "Short write?!!\n"); 00875 fclose(ff); 00876 return -1; 00877 } 00878 00879 if (lastwritten < offset + sizeof(fbuf)) { 00880 break; 00881 } 00882 /* Our file pointer is now either pointing to the end of the 00883 * file (new position) or a multiple of the fbuf size back from 00884 * that point. Move back to where we want to start reading 00885 * again. We never actually try to read beyond the end of the 00886 * file, so we don't have do deal with short reads, as we would 00887 * when we're shortening the file. */ 00888 fseeko(ff, 2 * sizeof(fbuf) + vlength - length, SEEK_CUR); 00889 } 00890 00891 /* Last part of the file that we need to preserve */ 00892 if (fseeko(ff, offset + length, SEEK_SET)) { 00893 ast_log(LOG_WARNING, "Unable to seek to %" PRId64 " + %" PRId64 " != %" PRId64 "?)\n", offset, length, ftello(ff)); 00894 } 00895 00896 /* Doesn't matter how much we read -- just need to restrict the write */ 00897 ast_debug(1, "Reading at %" PRId64 "\n", ftello(ff)); 00898 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 00899 ast_log(LOG_ERROR, "Short read?!!\n"); 00900 } 00901 fseek(ff, offset, SEEK_SET); 00902 /* Write out the value, then write just up until where we last moved some data */ 00903 if (fwrite(value, 1, vlength, ff) < vlength) { 00904 ast_log(LOG_ERROR, "Short write?!!\n"); 00905 } else { 00906 off_t curpos = ftello(ff); 00907 foplen = lastwritten - curpos; 00908 if (fwrite(fbuf, 1, foplen, ff) < foplen) { 00909 ast_log(LOG_ERROR, "Short write?!!\n"); 00910 } 00911 } 00912 fclose(ff); 00913 } 00914 } else { 00915 enum file_format newline_format = FF_UNKNOWN; 00916 00917 /* Line mode */ 00918 if (args.argc == 5) { 00919 if (tolower(args.format[0]) == 'u') { 00920 newline_format = FF_UNIX; 00921 } else if (tolower(args.format[0]) == 'm') { 00922 newline_format = FF_MAC; 00923 } else if (tolower(args.format[0]) == 'd') { 00924 newline_format = FF_DOS; 00925 } 00926 } 00927 if (newline_format == FF_UNKNOWN && (newline_format = file2format(args.filename)) == FF_UNKNOWN) { 00928 ast_log(LOG_ERROR, "File '%s' not in line format\n", args.filename); 00929 return -1; 00930 } 00931 00932 if (strchr(args.options, 'a')) { 00933 /* Append to file */ 00934 if (!(ff = fopen(args.filename, "a"))) { 00935 ast_log(LOG_ERROR, "Unable to open '%s' for appending: %s\n", args.filename, strerror(errno)); 00936 return -1; 00937 } 00938 if (fwrite(value, 1, vlength, ff) < vlength) { 00939 ast_log(LOG_ERROR, "Short write?!!\n"); 00940 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 00941 ast_log(LOG_ERROR, "Short write?!!\n"); 00942 } 00943 fclose(ff); 00944 } else if (offset == 0 && length == LLONG_MAX) { 00945 /* Overwrite file */ 00946 off_t truncsize; 00947 if (!(ff = fopen(args.filename, "w"))) { 00948 ast_log(LOG_ERROR, "Unable to open '%s' for writing: %s\n", args.filename, strerror(errno)); 00949 return -1; 00950 } 00951 if (fwrite(value, 1, vlength, ff) < vlength) { 00952 ast_log(LOG_ERROR, "Short write?!!\n"); 00953 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 00954 ast_log(LOG_ERROR, "Short write?!!\n"); 00955 } 00956 if ((truncsize = ftello(ff)) < 0) { 00957 ast_log(AST_LOG_ERROR, "Unable to determine truncate position of '%s': %s\n", args.filename, strerror(errno)); 00958 } 00959 fclose(ff); 00960 if (truncsize >= 0 && truncate(args.filename, truncsize)) { 00961 ast_log(LOG_ERROR, "Unable to truncate file '%s': %s\n", args.filename, strerror(errno)); 00962 return -1; 00963 } 00964 } else { 00965 int64_t offset_offset = (offset == 0 ? 0 : -1), length_offset = -1, flength, i, current_length = 0; 00966 char dos_state = 0, fbuf[4096]; 00967 00968 if (offset < 0 && length < offset) { 00969 /* Nonsense! */ 00970 ast_log(LOG_ERROR, "Length cannot specify a position prior to the offset\n"); 00971 return -1; 00972 } 00973 00974 if (!(ff = fopen(args.filename, "r+"))) { 00975 ast_log(LOG_ERROR, "Cannot open '%s' for modification: %s\n", args.filename, strerror(errno)); 00976 return -1; 00977 } 00978 00979 if (fseek(ff, 0, SEEK_END)) { 00980 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno)); 00981 fclose(ff); 00982 return -1; 00983 } 00984 if ((flength = ftello(ff)) < 0) { 00985 ast_log(AST_LOG_ERROR, "Cannot determine end position of file '%s': %s\n", args.filename, strerror(errno)); 00986 fclose(ff); 00987 return -1; 00988 } 00989 00990 /* For negative offset and/or negative length */ 00991 if (offset < 0 || length < 0) { 00992 int64_t count = 0; 00993 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) { 00994 char *pos; 00995 if (fseeko(ff, i, SEEK_SET)) { 00996 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno)); 00997 } 00998 if (i + sizeof(fbuf) >= flength) { 00999 memset(fbuf, 0, sizeof(fbuf)); 01000 } 01001 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01002 ast_log(LOG_ERROR, "Short read: %s\n", strerror(errno)); 01003 fclose(ff); 01004 return -1; 01005 } 01006 for (pos = fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) { 01007 LINE_COUNTER(pos, newline_format, count); 01008 01009 if (length < 0 && count * -1 == length) { 01010 length_offset = i + (pos - fbuf); 01011 } else if (offset < 0 && count * -1 == (offset - 1)) { 01012 /* Found our initial offset. We're done with reverse motion! */ 01013 if (newline_format == FF_DOS) { 01014 offset_offset = i + (pos - fbuf) + 2; 01015 } else { 01016 offset_offset = i + (pos - fbuf) + 1; 01017 } 01018 break; 01019 } 01020 } 01021 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) { 01022 break; 01023 } 01024 } 01025 /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */ 01026 if (offset < 0 && offset_offset < 0 && offset == count * -1) { 01027 offset_offset = 0; 01028 } 01029 } 01030 01031 /* Positve line offset */ 01032 if (offset > 0) { 01033 int64_t count = 0; 01034 fseek(ff, 0, SEEK_SET); 01035 for (i = 0; i < flength; i += sizeof(fbuf)) { 01036 char *pos; 01037 if (i + sizeof(fbuf) >= flength) { 01038 memset(fbuf, 0, sizeof(fbuf)); 01039 } 01040 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01041 ast_log(LOG_ERROR, "Short read?!!\n"); 01042 fclose(ff); 01043 return -1; 01044 } 01045 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 01046 LINE_COUNTER(pos, newline_format, count); 01047 01048 if (count == offset) { 01049 offset_offset = i + (pos - fbuf) + 1; 01050 break; 01051 } 01052 } 01053 if (offset_offset >= 0) { 01054 break; 01055 } 01056 } 01057 } 01058 01059 if (offset_offset < 0) { 01060 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset); 01061 fclose(ff); 01062 return -1; 01063 } 01064 01065 if (length == 0) { 01066 length_offset = offset_offset; 01067 } else if (length == LLONG_MAX) { 01068 length_offset = flength; 01069 } 01070 01071 /* Positive line length */ 01072 if (length_offset < 0) { 01073 fseeko(ff, offset_offset, SEEK_SET); 01074 for (i = offset_offset; i < flength; i += sizeof(fbuf)) { 01075 char *pos; 01076 if (i + sizeof(fbuf) >= flength) { 01077 memset(fbuf, 0, sizeof(fbuf)); 01078 } 01079 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01080 ast_log(LOG_ERROR, "Short read?!!\n"); 01081 fclose(ff); 01082 return -1; 01083 } 01084 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) { 01085 LINE_COUNTER(pos, newline_format, current_length); 01086 01087 if (current_length == length) { 01088 length_offset = i + (pos - fbuf) + 1; 01089 break; 01090 } 01091 } 01092 if (length_offset >= 0) { 01093 break; 01094 } 01095 } 01096 if (length_offset < 0) { 01097 /* Exceeds length of file */ 01098 ast_debug(3, "Exceeds length of file? length=%" PRId64 ", count=%" PRId64 ", flength=%" PRId64 "\n", length, current_length, flength); 01099 length_offset = flength; 01100 } 01101 } 01102 01103 /* Have offset_offset and length_offset now */ 01104 if (length_offset - offset_offset == vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) { 01105 /* Simple case - replacement of text inline */ 01106 fseeko(ff, offset_offset, SEEK_SET); 01107 if (fwrite(value, 1, vlength, ff) < vlength) { 01108 ast_log(LOG_ERROR, "Short write?!!\n"); 01109 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 01110 ast_log(LOG_ERROR, "Short write?!!\n"); 01111 } 01112 fclose(ff); 01113 } else if (length_offset - offset_offset > vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) { 01114 /* More complex case - need to shorten file */ 01115 off_t cur; 01116 int64_t length_length = length_offset - offset_offset; 01117 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format))); 01118 01119 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 " (%" PRId64 "), vlength=%" PRId64 ", flength=%" PRId64 "\n", 01120 args.offset, offset_offset, args.length, length_offset, length_length, vlength, flength); 01121 01122 fseeko(ff, offset_offset, SEEK_SET); 01123 if (fwrite(value, 1, vlength, ff) < vlength) { 01124 ast_log(LOG_ERROR, "Short write?!!\n"); 01125 fclose(ff); 01126 return -1; 01127 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, vlen - vlength, ff) < vlen - vlength) { 01128 ast_log(LOG_ERROR, "Short write?!!\n"); 01129 fclose(ff); 01130 return -1; 01131 } 01132 while ((cur = ftello(ff)) < flength) { 01133 if (cur < 0) { 01134 ast_log(AST_LOG_ERROR, "Unable to determine last write position for '%s': %s\n", args.filename, strerror(errno)); 01135 fclose(ff); 01136 return -1; 01137 } 01138 fseeko(ff, length_length - vlen, SEEK_CUR); 01139 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01140 ast_log(LOG_ERROR, "Short read?!!\n"); 01141 fclose(ff); 01142 return -1; 01143 } 01144 /* Seek to where we last stopped writing */ 01145 fseeko(ff, cur, SEEK_SET); 01146 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 01147 ast_log(LOG_ERROR, "Short write?!!\n"); 01148 fclose(ff); 01149 return -1; 01150 } 01151 } 01152 fclose(ff); 01153 if (truncate(args.filename, flength - (length_length - vlen))) { 01154 ast_log(LOG_ERROR, "Truncation of file failed: %s\n", strerror(errno)); 01155 } 01156 } else { 01157 /* Most complex case - need to lengthen file */ 01158 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format))); 01159 int64_t origlen = length_offset - offset_offset; 01160 off_t lastwritten = flength + vlen - origlen; 01161 01162 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n", 01163 args.offset, offset_offset, args.length, length_offset, vlength, flength); 01164 01165 fseeko(ff, flength - sizeof(fbuf), SEEK_SET); 01166 while (offset_offset + sizeof(fbuf) < ftello(ff)) { 01167 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 01168 ast_log(LOG_ERROR, "Short read?!!\n"); 01169 fclose(ff); 01170 return -1; 01171 } 01172 fseeko(ff, sizeof(fbuf) - vlen - origlen, SEEK_CUR); 01173 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) { 01174 ast_log(LOG_ERROR, "Short write?!!\n"); 01175 fclose(ff); 01176 return -1; 01177 } 01178 if ((lastwritten = ftello(ff) - sizeof(fbuf)) < offset_offset + sizeof(fbuf)) { 01179 break; 01180 } 01181 fseeko(ff, 2 * sizeof(fbuf) + vlen - origlen, SEEK_CUR); 01182 } 01183 fseek(ff, length_offset, SEEK_SET); 01184 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) { 01185 ast_log(LOG_ERROR, "Short read?!!\n"); 01186 fclose(ff); 01187 return -1; 01188 } 01189 fseek(ff, offset_offset, SEEK_SET); 01190 if (fwrite(value, 1, vlength, ff) < vlength) { 01191 ast_log(LOG_ERROR, "Short write?!!\n"); 01192 fclose(ff); 01193 return -1; 01194 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) { 01195 ast_log(LOG_ERROR, "Short write?!!\n"); 01196 fclose(ff); 01197 return -1; 01198 } else { 01199 off_t curpos = ftello(ff); 01200 foplen = lastwritten - curpos; 01201 if (fwrite(fbuf, 1, foplen, ff) < foplen) { 01202 ast_log(LOG_ERROR, "Short write?!!\n"); 01203 } 01204 } 01205 fclose(ff); 01206 } 01207 } 01208 } 01209 01210 return 0; 01211 }
const char * format2term | ( | enum file_format | f | ) |
Definition at line 720 of file func_env.c.
Referenced by file_write().
00721 { 00722 const char *term[] = { "", "\n", "\r\n", "\r" }; 00723 return term[f + 1]; 00724 }
static int load_module | ( | void | ) | [static] |
Definition at line 1256 of file func_env.c.
References ast_custom_function_register, env_function, file_count_line_function, file_format_function, file_function, and stat_function.
01257 { 01258 int res = 0; 01259 01260 res |= ast_custom_function_register(&env_function); 01261 res |= ast_custom_function_register(&stat_function); 01262 res |= ast_custom_function_register(&file_function); 01263 res |= ast_custom_function_register(&file_count_line_function); 01264 res |= ast_custom_function_register(&file_format_function); 01265 01266 return res; 01267 }
static int stat_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 257 of file func_env.c.
References ast_copy_string(), and strsep().
00259 { 00260 char *action; 00261 struct stat s; 00262 00263 ast_copy_string(buf, "0", len); 00264 00265 action = strsep(&data, ","); 00266 if (stat(data, &s)) { 00267 return 0; 00268 } else { 00269 switch (*action) { 00270 case 'e': 00271 strcpy(buf, "1"); 00272 break; 00273 case 's': 00274 snprintf(buf, len, "%d", (unsigned int) s.st_size); 00275 break; 00276 case 'f': 00277 snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0); 00278 break; 00279 case 'd': 00280 snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0); 00281 break; 00282 case 'M': 00283 snprintf(buf, len, "%d", (int) s.st_mtime); 00284 break; 00285 case 'A': 00286 snprintf(buf, len, "%d", (int) s.st_mtime); 00287 break; 00288 case 'C': 00289 snprintf(buf, len, "%d", (int) s.st_ctime); 00290 break; 00291 case 'm': 00292 snprintf(buf, len, "%o", (int) s.st_mode); 00293 break; 00294 } 00295 } 00296 00297 return 0; 00298 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1243 of file func_env.c.
References ast_custom_function_unregister(), env_function, file_count_line_function, file_format_function, file_function, and stat_function.
01244 { 01245 int res = 0; 01246 01247 res |= ast_custom_function_unregister(&env_function); 01248 res |= ast_custom_function_unregister(&stat_function); 01249 res |= ast_custom_function_unregister(&file_function); 01250 res |= ast_custom_function_unregister(&file_count_line_function); 01251 res |= ast_custom_function_unregister(&file_format_function); 01252 01253 return res; 01254 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Environment/filesystem dialplan functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 1269 of file func_env.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1269 of file func_env.c.
struct ast_custom_function env_function [static] |
Initial value:
Definition at line 1213 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function file_count_line_function [static] |
Initial value:
{ .name = "FILE_COUNT_LINE", .read2 = file_count_line, .read_max = 12, }
Definition at line 1231 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function file_format_function [static] |
Initial value:
{ .name = "FILE_FORMAT", .read2 = file_format, .read_max = 2, }
Definition at line 1237 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function file_function [static] |
Initial value:
{ .name = "FILE", .read2 = file_read, .write = file_write, }
Definition at line 1225 of file func_env.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function stat_function [static] |
Initial value:
{ .name = "STAT", .read = stat_read, .read_max = 12, }
Definition at line 1219 of file func_env.c.
Referenced by load_module(), and unload_module().