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