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 407 of file func_env.c.
Referenced by file_read(), and file_write().
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 };
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 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().
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, 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, 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().
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(), format, LINE_COUNTER, 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(), format, format2term(), LINE_COUNTER, 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.
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().
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().
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_custom_function env_function [static] |
Definition at line 1213 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 1231 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 1237 of file func_env.c.
struct ast_custom_function file_function [static] |
{ .name = "FILE", .read2 = file_read, .write = file_write, }
Definition at line 1225 of file func_env.c.
struct ast_custom_function stat_function [static] |
{ .name = "STAT", .read = stat_read, .read_max = 12, }
Definition at line 1219 of file func_env.c.