Asterisk - The Open Source Telephony Project GIT-master-0bf3178
Macros | Enumerations | Functions | Variables
func_env.c File Reference

Environment related dialplan functions. More...

#include "asterisk.h"
#include <sys/stat.h>
#include <libgen.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"
Include dependency graph for func_env.c:

Go to the source code of this file.

Macros

#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)
 
struct ast_moduleAST_MODULE_SELF_SYM (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_basename (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int file_count_line (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
 
static int file_dirname (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_custom_function env_function
 
static struct ast_custom_function file_basename_function
 
static struct ast_custom_function file_count_line_function
 
static struct ast_custom_function file_dirname_function
 
static struct ast_custom_function file_format_function
 
static struct ast_custom_function file_function
 
static struct ast_custom_function stat_function
 

Detailed Description

Environment related dialplan functions.

Definition in file func_env.c.

Macro Definition Documentation

◆ LINE_COUNTER

#define LINE_COUNTER (   cptr,
  term,
  counter 
)

Definition at line 534 of file func_env.c.

Enumeration Type Documentation

◆ file_format

Enumerator
FF_UNKNOWN 
FF_UNIX 
FF_DOS 
FF_MAC 

Definition at line 427 of file func_env.c.

427 {
428 FF_UNKNOWN = -1,
429 FF_UNIX,
430 FF_DOS,
431 FF_MAC,
432};
@ FF_UNKNOWN
Definition: func_env.c:428
@ FF_UNIX
Definition: func_env.c:429
@ FF_DOS
Definition: func_env.c:430
@ FF_MAC
Definition: func_env.c:431

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1448 of file func_env.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1448 of file func_env.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1448 of file func_env.c.

◆ count_lines()

static int64_t count_lines ( const char *  filename,
enum file_format  newline_format 
)
static

Definition at line 434 of file func_env.c.

435{
436 int count = 0;
437 char fbuf[4096];
438 FILE *ff;
439
440 if (!(ff = fopen(filename, "r"))) {
441 ast_log(LOG_ERROR, "Unable to open '%s': %s\n", filename, strerror(errno));
442 return -1;
443 }
444
445 while (fgets(fbuf, sizeof(fbuf), ff)) {
446 char *next = fbuf, *first_cr = NULL, *first_nl = NULL;
447
448 /* Must do it this way, because if the fileformat is FF_MAC, then Unix
449 * assumptions about line-format will not come into play. */
450 while (next) {
451 if (newline_format == FF_DOS || newline_format == FF_MAC || newline_format == FF_UNKNOWN) {
452 first_cr = strchr(next, '\r');
453 }
454 if (newline_format == FF_UNIX || newline_format == FF_UNKNOWN) {
455 first_nl = strchr(next, '\n');
456 }
457
458 /* No terminators found in buffer */
459 if (!first_cr && !first_nl) {
460 break;
461 }
462
463 if (newline_format == FF_UNKNOWN) {
464 if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) {
465 if (first_nl && first_nl == first_cr + 1) {
466 newline_format = FF_DOS;
467 } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) {
468 /* Get it on the next pass */
469 fseek(ff, -1, SEEK_CUR);
470 break;
471 } else {
472 newline_format = FF_MAC;
473 first_nl = NULL;
474 }
475 } else {
476 newline_format = FF_UNIX;
477 first_cr = NULL;
478 }
479 /* Jump down into next section */
480 }
481
482 if (newline_format == FF_DOS) {
483 if (first_nl && first_cr && first_nl == first_cr + 1) {
484 next = first_nl + 1;
485 count++;
486 } else if (first_cr == &fbuf[sizeof(fbuf) - 2]) {
487 /* Get it on the next pass */
488 fseek(ff, -1, SEEK_CUR);
489 break;
490 }
491 } else if (newline_format == FF_MAC) {
492 if (first_cr) {
493 next = first_cr + 1;
494 count++;
495 }
496 } else if (newline_format == FF_UNIX) {
497 if (first_nl) {
498 next = first_nl + 1;
499 count++;
500 }
501 }
502 }
503 }
504 fclose(ff);
505
506 return count;
507}
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
int errno
#define NULL
Definition: resample.c:96

References ast_log, errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, LOG_ERROR, and NULL.

Referenced by file_count_line().

◆ env_read()

static int env_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 354 of file func_env.c.

356{
357 char *ret = NULL;
358
359 *buf = '\0';
360
361 if (data)
362 ret = getenv(data);
363
364 if (ret)
365 ast_copy_string(buf, ret, len);
366
367 return 0;
368}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425

References ast_copy_string(), buf, len(), and NULL.

◆ env_write()

static int env_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
)
static

Definition at line 370 of file func_env.c.

372{
373 if (!ast_strlen_zero(data) && strncmp(data, "AST_", 4)) {
374 if (!ast_strlen_zero(value)) {
375 setenv(data, value, 1);
376 } else {
377 unsetenv(data);
378 }
379 }
380
381 return 0;
382}
int unsetenv(const char *name)
int setenv(const char *name, const char *value, int overwrite)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int value
Definition: syslog.c:37

References ast_strlen_zero(), setenv(), unsetenv(), and value.

◆ file2format()

static enum file_format file2format ( const char *  filename)
static

Definition at line 548 of file func_env.c.

549{
550 FILE *ff;
551 char fbuf[4096];
552 char *first_cr, *first_nl;
553 enum file_format newline_format = FF_UNKNOWN;
554
555 if (!(ff = fopen(filename, "r"))) {
556 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", filename, strerror(errno));
557 return -1;
558 }
559
560 while (fgets(fbuf, sizeof(fbuf), ff)) {
561 first_cr = strchr(fbuf, '\r');
562 first_nl = strchr(fbuf, '\n');
563
564 if (!first_cr && !first_nl) {
565 continue;
566 }
567
568 if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) {
569
570 if (first_nl && first_nl == first_cr + 1) {
571 newline_format = FF_DOS;
572 } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) {
573 /* Edge case: get it on the next pass */
574 fseek(ff, -1, SEEK_CUR);
575 continue;
576 } else {
577 newline_format = FF_MAC;
578 }
579 } else {
580 newline_format = FF_UNIX;
581 }
582 break;
583 }
584 fclose(ff);
585 return newline_format;
586}
file_format
Definition: func_env.c:427

References ast_log, errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, and LOG_ERROR.

Referenced by file_format(), file_read(), and file_write().

◆ file_basename()

static int file_basename ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 612 of file func_env.c.

613{
614 char *ret = NULL;
615
616 *buf = '\0';
617
618 if (data) {
619 ret = basename(data);
620 }
621
622 if (ret) {
623 ast_copy_string(buf, ret, len);
624 }
625
626 return 0;
627}

References ast_copy_string(), buf, len(), and NULL.

◆ file_count_line()

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 509 of file func_env.c.

510{
511 enum file_format newline_format = FF_UNKNOWN;
512 int64_t count;
514 AST_APP_ARG(filename);
515 AST_APP_ARG(format);
516 );
517
519 if (args.argc > 1) {
520 if (tolower(args.format[0]) == 'd') {
521 newline_format = FF_DOS;
522 } else if (tolower(args.format[0]) == 'm') {
523 newline_format = FF_MAC;
524 } else if (tolower(args.format[0]) == 'u') {
525 newline_format = FF_UNIX;
526 }
527 }
528
529 count = count_lines(args.filename, newline_format);
530 ast_str_set(buf, len, "%" PRId64, count);
531 return 0;
532}
static int64_t count_lines(const char *filename, enum file_format newline_format)
Definition: func_env.c:434
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
const char * args

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_str_set(), buf, count_lines(), FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, and len().

◆ file_dirname()

static int file_dirname ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 595 of file func_env.c.

596{
597 char *ret = NULL;
598
599 *buf = '\0';
600
601 if (data) {
602 ret = dirname(data);
603 }
604
605 if (ret) {
606 ast_copy_string(buf, ret, len);
607 }
608
609 return 0;
610}

References ast_copy_string(), buf, len(), and NULL.

◆ file_format()

static int file_format ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 588 of file func_env.c.

589{
590 enum file_format newline_format = file2format(data);
591 ast_str_set(buf, len, "%c", newline_format == FF_UNIX ? 'u' : newline_format == FF_DOS ? 'd' : newline_format == FF_MAC ? 'm' : 'x');
592 return 0;
593}
static enum file_format file2format(const char *filename)
Definition: func_env.c:548

References ast_str_set(), buf, FF_DOS, FF_MAC, FF_UNIX, file2format(), and len().

◆ file_read()

static int file_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 629 of file func_env.c.

630{
631 FILE *ff;
632 int64_t offset = 0, length = LLONG_MAX;
633 enum file_format format = FF_UNKNOWN;
634 char fbuf[4096];
635 int64_t flength, i; /* iterator needs to be signed, so it can go negative and terminate the loop */
636 int64_t offset_offset = -1, length_offset = -1;
637 char dos_state = 0;
639 AST_APP_ARG(filename);
640 AST_APP_ARG(offset);
641 AST_APP_ARG(length);
643 AST_APP_ARG(fileformat);
644 );
645
647
648 if (args.argc > 1) {
649 sscanf(args.offset, "%" SCNd64, &offset);
650 }
651 if (args.argc > 2) {
652 sscanf(args.length, "%" SCNd64, &length);
653 }
654
655 if (args.argc < 4 || !strchr(args.options, 'l')) {
656 /* Character-based mode */
657 off_t off_i;
658
659 if (!(ff = fopen(args.filename, "r"))) {
660 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", args.filename, strerror(errno));
661 return 0;
662 }
663
664 if (fseeko(ff, 0, SEEK_END) < 0) {
665 ast_log(LOG_ERROR, "Cannot seek to end of '%s': %s\n", args.filename, strerror(errno));
666 fclose(ff);
667 return -1;
668 }
669 flength = ftello(ff);
670
671 if (offset < 0) {
672 fseeko(ff, offset, SEEK_END);
673 if ((offset = ftello(ff)) < 0) {
674 ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno));
675 fclose(ff);
676 return -1;
677 }
678 }
679 if (length < 0) {
680 fseeko(ff, length, SEEK_END);
681 if ((length = ftello(ff)) - offset < 0) {
682 /* Eliminates all results */
683 fclose(ff);
684 return -1;
685 }
686 } else if (length == LLONG_MAX) {
687 fseeko(ff, 0, SEEK_END);
688 length = ftello(ff);
689 }
690
692
693 fseeko(ff, offset, SEEK_SET);
694 for (off_i = ftello(ff); off_i < flength && off_i < offset + length; off_i += sizeof(fbuf)) {
695 /* Calculate if we need to retrieve just a portion of the file in memory */
696 size_t toappend = sizeof(fbuf);
697
698 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
699 ast_log(LOG_ERROR, "Short read?!!\n");
700 break;
701 }
702
703 /* Don't go past the length requested */
704 if (off_i + toappend > offset + length) {
705 toappend = MIN(offset + length - off_i, flength - off_i);
706 }
707
708 ast_str_append_substr(buf, len, fbuf, toappend);
709 }
710 fclose(ff);
711 return 0;
712 }
713
714 /* Line-based read */
715 if (args.argc == 5) {
716 if (tolower(args.fileformat[0]) == 'd') {
717 format = FF_DOS;
718 } else if (tolower(args.fileformat[0]) == 'm') {
719 format = FF_MAC;
720 } else if (tolower(args.fileformat[0]) == 'u') {
721 format = FF_UNIX;
722 }
723 }
724
725 if (format == FF_UNKNOWN) {
726 if ((format = file2format(args.filename)) == FF_UNKNOWN) {
727 ast_log(LOG_WARNING, "'%s' is not a line-based file\n", args.filename);
728 return -1;
729 }
730 }
731
732 if (offset < 0 && length <= offset) {
733 /* Length eliminates all content */
734 return -1;
735 } else if (offset == 0) {
736 offset_offset = 0;
737 }
738
739 if (!(ff = fopen(args.filename, "r"))) {
740 ast_log(LOG_ERROR, "Cannot open '%s': %s\n", args.filename, strerror(errno));
741 return -1;
742 }
743
744 if (fseek(ff, 0, SEEK_END)) {
745 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno));
746 fclose(ff);
747 return -1;
748 }
749
750 flength = ftello(ff);
751
752 if (length == LLONG_MAX) {
753 length_offset = flength;
754 }
755
756 /* For negative offset and/or negative length */
757 if (offset < 0 || length < 0) {
758 int64_t count = 0;
759 /* Start with an even multiple of fbuf, so at the end of reading with a
760 * 0 offset, we don't try to go past the beginning of the file. */
761 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) {
762 size_t end;
763 char *pos;
764 if (fseeko(ff, i, SEEK_SET)) {
765 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno));
766 }
767 end = fread(fbuf, 1, sizeof(fbuf), ff);
768 for (pos = (end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1); pos >= fbuf; pos--) {
769 LINE_COUNTER(pos, format, count);
770
771 if (length < 0 && count * -1 == length) {
772 length_offset = i + (pos - fbuf);
773 } else if (offset < 0 && count * -1 == (offset - 1)) {
774 /* Found our initial offset. We're done with reverse motion! */
775 if (format == FF_DOS) {
776 offset_offset = i + (pos - fbuf) + 2;
777 } else {
778 offset_offset = i + (pos - fbuf) + 1;
779 }
780 break;
781 }
782 }
783 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) {
784 break;
785 }
786 }
787 /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */
788 if (offset < 0 && offset_offset < 0 && offset == count * -1) {
789 offset_offset = 0;
790 }
791 }
792
793 /* Positve line offset */
794 if (offset > 0) {
795 int64_t count = 0;
796 fseek(ff, 0, SEEK_SET);
797 for (i = 0; i < flength; i += sizeof(fbuf)) {
798 char *pos;
799 if (i + sizeof(fbuf) <= flength) {
800 /* Don't let previous values influence current counts, due to short reads */
801 memset(fbuf, 0, sizeof(fbuf));
802 }
803 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
804 ast_log(LOG_ERROR, "Short read?!!\n");
805 fclose(ff);
806 return -1;
807 }
808 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
809 LINE_COUNTER(pos, format, count);
810
811 if (count == offset) {
812 offset_offset = i + (pos - fbuf) + 1;
813 break;
814 }
815 }
816 if (offset_offset >= 0) {
817 break;
818 }
819 }
820 }
821
822 if (offset_offset < 0) {
823 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset);
824 fclose(ff);
825 return -1;
826 }
827
829 if (fseeko(ff, offset_offset, SEEK_SET)) {
830 ast_log(LOG_ERROR, "fseeko failed: %s\n", strerror(errno));
831 }
832
833 /* If we have both offset_offset and length_offset, then grabbing the
834 * buffer is simply a matter of just retrieving the file and adding it
835 * to buf. Otherwise, we need to run byte-by-byte forward until the
836 * length is complete. */
837 if (length_offset >= 0) {
838 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset);
839 for (i = offset_offset; i < length_offset; i += sizeof(fbuf)) {
840 if (fread(fbuf, 1, i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf), ff) < (i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf))) {
841 ast_log(LOG_ERROR, "Short read?!!\n");
842 }
843 ast_debug(3, "Appending first %" PRId64" bytes of fbuf=%s\n", (int64_t)(i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf)), fbuf);
844 ast_str_append_substr(buf, len, fbuf, i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf));
845 }
846 } else if (length == 0) {
847 /* Nothing to do */
848 } else {
849 /* Positive line offset */
850 int64_t current_length = 0;
851 char dos_state = 0;
852 ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset);
853 for (i = offset_offset; i < flength; i += sizeof(fbuf)) {
854 char *pos;
855 size_t bytes_read;
856 if ((bytes_read = fread(fbuf, 1, sizeof(fbuf), ff)) < sizeof(fbuf) && !feof(ff)) {
857 ast_log(LOG_ERROR, "Short read?!!\n");
858 fclose(ff);
859 return -1;
860 }
861 for (pos = fbuf; pos < fbuf + bytes_read; pos++) {
862 LINE_COUNTER(pos, format, current_length);
863
864 if (current_length == length) {
865 length_offset = i + (pos - fbuf) + 1;
866 break;
867 }
868 }
869 ast_debug(3, "length_offset=%" PRId64 ", length_offset - i=%" PRId64 "\n", length_offset, length_offset - i);
870 ast_str_append_substr(buf, len, fbuf, (length_offset >= 0) ? length_offset - i : (flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i);
871
872 if (length_offset >= 0) {
873 break;
874 }
875 }
876 }
877
878 fclose(ff);
879 return 0;
880}
char * end
Definition: eagi_proxy.c:73
#define LINE_COUNTER(cptr, term, counter)
Definition: func_env.c:534
#define LLONG_MAX
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition: strings.h:1062
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
static struct test_options options
#define MIN(a, b)
Definition: utils.h:231

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(), buf, end, errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), len(), LINE_COUNTER, LLONG_MAX, LOG_ERROR, LOG_WARNING, MIN, and options.

◆ file_write()

static int file_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
)
static

Definition at line 889 of file func_env.c.

890{
892 AST_APP_ARG(filename);
893 AST_APP_ARG(offset);
894 AST_APP_ARG(length);
896 AST_APP_ARG(format);
897 );
898 int64_t offset = 0, length = LLONG_MAX;
899 off_t flength, vlength;
900 size_t foplen = 0;
901 FILE *ff;
902
904
905 if (args.argc > 1) {
906 sscanf(args.offset, "%" SCNd64, &offset);
907 }
908 if (args.argc > 2) {
909 sscanf(args.length, "%" SCNd64, &length);
910 }
911
912 vlength = strlen(value);
913
914 if (args.argc < 4 || !strchr(args.options, 'l')) {
915 /* Character-based mode */
916
917 if (args.argc > 3 && strchr(args.options, 'a')) {
918 /* Append mode */
919 if (!(ff = fopen(args.filename, "a"))) {
920 ast_log(LOG_WARNING, "Cannot open file '%s' for appending: %s\n", args.filename, strerror(errno));
921 return 0;
922 }
923 if (fwrite(value, 1, vlength, ff) < vlength) {
924 ast_log(LOG_ERROR, "Short write?!!\n");
925 }
926 fclose(ff);
927 return 0;
928 } else if (offset == 0 && length == LLONG_MAX) {
929 if (!(ff = fopen(args.filename, "w"))) {
930 ast_log(LOG_WARNING, "Cannot open file '%s' for writing: %s\n", args.filename, strerror(errno));
931 return 0;
932 }
933 if (fwrite(value, 1, vlength, ff) < vlength) {
934 ast_log(LOG_ERROR, "Short write?!!\n");
935 }
936 fclose(ff);
937 return 0;
938 }
939
940 if (!(ff = fopen(args.filename, "r+"))) {
941 ast_log(LOG_WARNING, "Cannot open file '%s' for modification: %s\n", args.filename, strerror(errno));
942 return 0;
943 }
944 fseeko(ff, 0, SEEK_END);
945 flength = ftello(ff);
946
947 if (offset < 0) {
948 if (fseeko(ff, offset, SEEK_END)) {
949 ast_log(LOG_ERROR, "Cannot seek to offset of '%s': %s\n", args.filename, strerror(errno));
950 fclose(ff);
951 return -1;
952 }
953 if ((offset = ftello(ff)) < 0) {
954 ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno));
955 fclose(ff);
956 return -1;
957 }
958 }
959
960 if (length < 0) {
961 length = flength - offset + length;
962 if (length < 0) {
963 ast_log(LOG_ERROR, "Length '%s' exceeds the file length. No data will be written.\n", args.length);
964 fclose(ff);
965 return -1;
966 }
967 }
968
969 fseeko(ff, offset, SEEK_SET);
970
971 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n",
972 S_OR(args.offset, "(null)"), offset, S_OR(args.length, "(null)"), length, vlength, flength);
973
974 if (length == vlength) {
975 /* Simplest case, a straight replace */
976 if (fwrite(value, 1, vlength, ff) < vlength) {
977 ast_log(LOG_ERROR, "Short write?!!\n");
978 }
979 fclose(ff);
980 } else if (length == LLONG_MAX) {
981 /* Simple truncation */
982 if (fwrite(value, 1, vlength, ff) < vlength) {
983 ast_log(LOG_ERROR, "Short write?!!\n");
984 }
985 fclose(ff);
986 if (truncate(args.filename, offset + vlength)) {
987 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno));
988 }
989 } else if (length > vlength) {
990 /* More complex -- need to close a gap */
991 char fbuf[4096];
992 off_t cur;
993 if (fwrite(value, 1, vlength, ff) < vlength) {
994 ast_log(LOG_ERROR, "Short write?!!\n");
995 }
996 fseeko(ff, length - vlength, SEEK_CUR);
997 while ((cur = ftello(ff)) < flength) {
998 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
999 ast_log(LOG_ERROR, "Short read?!!\n");
1000 }
1001 fseeko(ff, cur + vlength - length, SEEK_SET);
1002 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
1003 ast_log(LOG_ERROR, "Short write?!!\n");
1004 }
1005 /* Seek to where we stopped reading */
1006 if (fseeko(ff, cur + sizeof(fbuf), SEEK_SET) < 0) {
1007 /* Only reason for seek to fail is EOF */
1008 break;
1009 }
1010 }
1011 fclose(ff);
1012 if (truncate(args.filename, flength - (length - vlength))) {
1013 ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno));
1014 }
1015 } else {
1016 /* Most complex -- need to open a gap */
1017 char fbuf[4096];
1018 off_t lastwritten = flength + vlength - length;
1019
1020 /* Start reading exactly the buffer size back from the end. */
1021 fseeko(ff, flength - sizeof(fbuf), SEEK_SET);
1022 while (offset < ftello(ff)) {
1023 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
1024 ast_log(LOG_ERROR, "Short read?!!\n");
1025 fclose(ff);
1026 return -1;
1027 }
1028 /* Since the read moved our file ptr forward, we reverse, but
1029 * seek an offset equal to the amount we want to extend the
1030 * file by */
1031 fseeko(ff, vlength - length - sizeof(fbuf), SEEK_CUR);
1032
1033 /* Note the location of this buffer -- we must not overwrite this position. */
1034 lastwritten = ftello(ff);
1035
1036 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
1037 ast_log(LOG_ERROR, "Short write?!!\n");
1038 fclose(ff);
1039 return -1;
1040 }
1041
1042 if (lastwritten < offset + sizeof(fbuf)) {
1043 break;
1044 }
1045 /* Our file pointer is now either pointing to the end of the
1046 * file (new position) or a multiple of the fbuf size back from
1047 * that point. Move back to where we want to start reading
1048 * again. We never actually try to read beyond the end of the
1049 * file, so we don't have do deal with short reads, as we would
1050 * when we're shortening the file. */
1051 fseeko(ff, 2 * sizeof(fbuf) + vlength - length, SEEK_CUR);
1052 }
1053
1054 /* Last part of the file that we need to preserve */
1055 if (fseeko(ff, offset + length, SEEK_SET)) {
1056 ast_log(LOG_WARNING, "Unable to seek to %" PRId64 " + %" PRId64 " != %" PRId64 "?)\n", offset, length, ftello(ff));
1057 }
1058
1059 /* Doesn't matter how much we read -- just need to restrict the write */
1060 ast_debug(1, "Reading at %" PRId64 "\n", ftello(ff));
1061 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
1062 ast_log(LOG_ERROR, "Short read?!!\n");
1063 }
1064 fseek(ff, offset, SEEK_SET);
1065 /* Write out the value, then write just up until where we last moved some data */
1066 if (fwrite(value, 1, vlength, ff) < vlength) {
1067 ast_log(LOG_ERROR, "Short write?!!\n");
1068 } else {
1069 off_t curpos = ftello(ff);
1070 foplen = lastwritten - curpos;
1071 if (fwrite(fbuf, 1, foplen, ff) < foplen) {
1072 ast_log(LOG_ERROR, "Short write?!!\n");
1073 }
1074 }
1075 fclose(ff);
1076 }
1077 } else {
1078 enum file_format newline_format = FF_UNKNOWN;
1079
1080 /* Line mode */
1081 if (args.argc == 5) {
1082 if (tolower(args.format[0]) == 'u') {
1083 newline_format = FF_UNIX;
1084 } else if (tolower(args.format[0]) == 'm') {
1085 newline_format = FF_MAC;
1086 } else if (tolower(args.format[0]) == 'd') {
1087 newline_format = FF_DOS;
1088 }
1089 }
1090 if (newline_format == FF_UNKNOWN && (newline_format = file2format(args.filename)) == FF_UNKNOWN) {
1091 ast_log(LOG_ERROR, "File '%s' not in line format\n", args.filename);
1092 return -1;
1093 }
1094
1095 if (strchr(args.options, 'a')) {
1096 /* Append to file */
1097 if (!(ff = fopen(args.filename, "a"))) {
1098 ast_log(LOG_ERROR, "Unable to open '%s' for appending: %s\n", args.filename, strerror(errno));
1099 return -1;
1100 }
1101 if (fwrite(value, 1, vlength, ff) < vlength) {
1102 ast_log(LOG_ERROR, "Short write?!!\n");
1103 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
1104 ast_log(LOG_ERROR, "Short write?!!\n");
1105 }
1106 fclose(ff);
1107 } else if (offset == 0 && length == LLONG_MAX) {
1108 /* Overwrite file */
1109 off_t truncsize;
1110 if (!(ff = fopen(args.filename, "w"))) {
1111 ast_log(LOG_ERROR, "Unable to open '%s' for writing: %s\n", args.filename, strerror(errno));
1112 return -1;
1113 }
1114 if (fwrite(value, 1, vlength, ff) < vlength) {
1115 ast_log(LOG_ERROR, "Short write?!!\n");
1116 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
1117 ast_log(LOG_ERROR, "Short write?!!\n");
1118 }
1119 if ((truncsize = ftello(ff)) < 0) {
1120 ast_log(AST_LOG_ERROR, "Unable to determine truncate position of '%s': %s\n", args.filename, strerror(errno));
1121 }
1122 fclose(ff);
1123 if (truncsize >= 0 && truncate(args.filename, truncsize)) {
1124 ast_log(LOG_ERROR, "Unable to truncate file '%s': %s\n", args.filename, strerror(errno));
1125 return -1;
1126 }
1127 } else {
1128 int64_t offset_offset = (offset == 0 ? 0 : -1), length_offset = -1, flength, i, current_length = 0;
1129 char dos_state = 0, fbuf[4096];
1130
1131 if (offset < 0 && length < offset) {
1132 /* Nonsense! */
1133 ast_log(LOG_ERROR, "Length cannot specify a position prior to the offset\n");
1134 return -1;
1135 }
1136
1137 if (!(ff = fopen(args.filename, "r+"))) {
1138 ast_log(LOG_ERROR, "Cannot open '%s' for modification: %s\n", args.filename, strerror(errno));
1139 return -1;
1140 }
1141
1142 if (fseek(ff, 0, SEEK_END)) {
1143 ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno));
1144 fclose(ff);
1145 return -1;
1146 }
1147 if ((flength = ftello(ff)) < 0) {
1148 ast_log(AST_LOG_ERROR, "Cannot determine end position of file '%s': %s\n", args.filename, strerror(errno));
1149 fclose(ff);
1150 return -1;
1151 }
1152
1153 /* For negative offset and/or negative length */
1154 if (offset < 0 || length < 0) {
1155 int64_t count = 0;
1156 for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) {
1157 char *pos;
1158 if (fseeko(ff, i, SEEK_SET)) {
1159 ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno));
1160 }
1161 if (i + sizeof(fbuf) >= flength) {
1162 memset(fbuf, 0, sizeof(fbuf));
1163 }
1164 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
1165 ast_log(LOG_ERROR, "Short read: %s\n", strerror(errno));
1166 fclose(ff);
1167 return -1;
1168 }
1169 for (pos = fbuf + sizeof(fbuf) - 1; pos >= fbuf; pos--) {
1170 LINE_COUNTER(pos, newline_format, count);
1171
1172 if (length < 0 && count * -1 == length) {
1173 length_offset = i + (pos - fbuf);
1174 } else if (offset < 0 && count * -1 == (offset - 1)) {
1175 /* Found our initial offset. We're done with reverse motion! */
1176 if (newline_format == FF_DOS) {
1177 offset_offset = i + (pos - fbuf) + 2;
1178 } else {
1179 offset_offset = i + (pos - fbuf) + 1;
1180 }
1181 break;
1182 }
1183 }
1184 if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) {
1185 break;
1186 }
1187 }
1188 /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */
1189 if (offset < 0 && offset_offset < 0 && offset == count * -1) {
1190 offset_offset = 0;
1191 }
1192 }
1193
1194 /* Positve line offset */
1195 if (offset > 0) {
1196 int64_t count = 0;
1197 fseek(ff, 0, SEEK_SET);
1198 for (i = 0; i < flength; i += sizeof(fbuf)) {
1199 char *pos;
1200 if (i + sizeof(fbuf) >= flength) {
1201 memset(fbuf, 0, sizeof(fbuf));
1202 }
1203 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
1204 ast_log(LOG_ERROR, "Short read?!!\n");
1205 fclose(ff);
1206 return -1;
1207 }
1208 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
1209 LINE_COUNTER(pos, newline_format, count);
1210
1211 if (count == offset) {
1212 offset_offset = i + (pos - fbuf) + 1;
1213 break;
1214 }
1215 }
1216 if (offset_offset >= 0) {
1217 break;
1218 }
1219 }
1220 }
1221
1222 if (offset_offset < 0) {
1223 ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset);
1224 fclose(ff);
1225 return -1;
1226 }
1227
1228 if (length == 0) {
1229 length_offset = offset_offset;
1230 } else if (length == LLONG_MAX) {
1231 length_offset = flength;
1232 }
1233
1234 /* Positive line length */
1235 if (length_offset < 0) {
1236 fseeko(ff, offset_offset, SEEK_SET);
1237 for (i = offset_offset; i < flength; i += sizeof(fbuf)) {
1238 char *pos;
1239 if (i + sizeof(fbuf) >= flength) {
1240 memset(fbuf, 0, sizeof(fbuf));
1241 }
1242 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
1243 ast_log(LOG_ERROR, "Short read?!!\n");
1244 fclose(ff);
1245 return -1;
1246 }
1247 for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
1248 LINE_COUNTER(pos, newline_format, current_length);
1249
1250 if (current_length == length) {
1251 length_offset = i + (pos - fbuf) + 1;
1252 break;
1253 }
1254 }
1255 if (length_offset >= 0) {
1256 break;
1257 }
1258 }
1259 if (length_offset < 0) {
1260 /* Exceeds length of file */
1261 ast_debug(3, "Exceeds length of file? length=%" PRId64 ", count=%" PRId64 ", flength=%" PRId64 "\n", length, current_length, flength);
1262 length_offset = flength;
1263 }
1264 }
1265
1266 /* Have offset_offset and length_offset now */
1267 if (length_offset - offset_offset == vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) {
1268 /* Simple case - replacement of text inline */
1269 fseeko(ff, offset_offset, SEEK_SET);
1270 if (fwrite(value, 1, vlength, ff) < vlength) {
1271 ast_log(LOG_ERROR, "Short write?!!\n");
1272 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
1273 ast_log(LOG_ERROR, "Short write?!!\n");
1274 }
1275 fclose(ff);
1276 } else if (length_offset - offset_offset > vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) {
1277 /* More complex case - need to shorten file */
1278 off_t cur;
1279 int64_t length_length = length_offset - offset_offset;
1280 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)));
1281
1282 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 " (%" PRId64 "), vlength=%" PRId64 ", flength=%" PRId64 "\n",
1283 args.offset, offset_offset, args.length, length_offset, length_length, vlength, flength);
1284
1285 fseeko(ff, offset_offset, SEEK_SET);
1286 if (fwrite(value, 1, vlength, ff) < vlength) {
1287 ast_log(LOG_ERROR, "Short write?!!\n");
1288 fclose(ff);
1289 return -1;
1290 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, vlen - vlength, ff) < vlen - vlength) {
1291 ast_log(LOG_ERROR, "Short write?!!\n");
1292 fclose(ff);
1293 return -1;
1294 }
1295 while ((cur = ftello(ff)) < flength) {
1296 if (cur < 0) {
1297 ast_log(AST_LOG_ERROR, "Unable to determine last write position for '%s': %s\n", args.filename, strerror(errno));
1298 fclose(ff);
1299 return -1;
1300 }
1301 fseeko(ff, length_length - vlen, SEEK_CUR);
1302 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
1303 ast_log(LOG_ERROR, "Short read?!!\n");
1304 fclose(ff);
1305 return -1;
1306 }
1307 /* Seek to where we last stopped writing */
1308 fseeko(ff, cur, SEEK_SET);
1309 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
1310 ast_log(LOG_ERROR, "Short write?!!\n");
1311 fclose(ff);
1312 return -1;
1313 }
1314 }
1315 fclose(ff);
1316 if (truncate(args.filename, flength - (length_length - vlen))) {
1317 ast_log(LOG_ERROR, "Truncation of file failed: %s\n", strerror(errno));
1318 }
1319 } else {
1320 /* Most complex case - need to lengthen file */
1321 size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)));
1322 int64_t origlen = length_offset - offset_offset;
1323 off_t lastwritten = flength + vlen - origlen;
1324
1325 ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n",
1326 args.offset, offset_offset, args.length, length_offset, vlength, flength);
1327
1328 fseeko(ff, flength - sizeof(fbuf), SEEK_SET);
1329 while (offset_offset + sizeof(fbuf) < ftello(ff)) {
1330 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
1331 ast_log(LOG_ERROR, "Short read?!!\n");
1332 fclose(ff);
1333 return -1;
1334 }
1335 fseeko(ff, sizeof(fbuf) - vlen - origlen, SEEK_CUR);
1336 if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
1337 ast_log(LOG_ERROR, "Short write?!!\n");
1338 fclose(ff);
1339 return -1;
1340 }
1341 if ((lastwritten = ftello(ff) - sizeof(fbuf)) < offset_offset + sizeof(fbuf)) {
1342 break;
1343 }
1344 fseeko(ff, 2 * sizeof(fbuf) + vlen - origlen, SEEK_CUR);
1345 }
1346 fseek(ff, length_offset, SEEK_SET);
1347 if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
1348 ast_log(LOG_ERROR, "Short read?!!\n");
1349 fclose(ff);
1350 return -1;
1351 }
1352 fseek(ff, offset_offset, SEEK_SET);
1353 if (fwrite(value, 1, vlength, ff) < vlength) {
1354 ast_log(LOG_ERROR, "Short write?!!\n");
1355 fclose(ff);
1356 return -1;
1357 } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
1358 ast_log(LOG_ERROR, "Short write?!!\n");
1359 fclose(ff);
1360 return -1;
1361 } else {
1362 off_t curpos = ftello(ff);
1363 foplen = lastwritten - curpos;
1364 if (fwrite(fbuf, 1, foplen, ff) < foplen) {
1365 ast_log(LOG_ERROR, "Short write?!!\n");
1366 }
1367 }
1368 fclose(ff);
1369 }
1370 }
1371 }
1372
1373 return 0;
1374}
const char * format2term(enum file_format f)
Definition: func_env.c:883
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80

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(), format2term(), LINE_COUNTER, LLONG_MAX, LOG_ERROR, LOG_WARNING, options, S_OR, and value.

◆ format2term()

const char * format2term ( enum file_format  f)

Definition at line 883 of file func_env.c.

884{
885 const char *term[] = { "", "\n", "\r\n", "\r" };
886 return term[f + 1];
887}

Referenced by file_write().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1433 of file func_env.c.

1434{
1435 int res = 0;
1436
1444
1445 return res;
1446}
static struct ast_custom_function file_format_function
Definition: func_env.c:1400
static struct ast_custom_function file_count_line_function
Definition: func_env.c:1394
static struct ast_custom_function env_function
Definition: func_env.c:1376
static struct ast_custom_function file_function
Definition: func_env.c:1388
static struct ast_custom_function file_basename_function
Definition: func_env.c:1412
static struct ast_custom_function stat_function
Definition: func_env.c:1382
static struct ast_custom_function file_dirname_function
Definition: func_env.c:1406
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
Definition: pbx.h:1567
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
@ AST_CFE_READ
Definition: pbx.h:1550
@ AST_CFE_BOTH
Definition: pbx.h:1552

References AST_CFE_BOTH, AST_CFE_READ, ast_custom_function_register, ast_custom_function_register_escalating, env_function, file_basename_function, file_count_line_function, file_dirname_function, file_format_function, file_function, and stat_function.

◆ stat_read()

static int stat_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 384 of file func_env.c.

386{
387 char *action;
388 struct stat s;
389
390 ast_copy_string(buf, "0", len);
391
392 action = strsep(&data, ",");
393 if (stat(data, &s)) {
394 return 0;
395 } else {
396 switch (*action) {
397 case 'e':
398 strcpy(buf, "1");
399 break;
400 case 's':
401 snprintf(buf, len, "%u", (unsigned int) s.st_size);
402 break;
403 case 'f':
404 snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0);
405 break;
406 case 'd':
407 snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0);
408 break;
409 case 'M':
410 snprintf(buf, len, "%d", (int) s.st_mtime);
411 break;
412 case 'A':
413 snprintf(buf, len, "%d", (int) s.st_mtime);
414 break;
415 case 'C':
416 snprintf(buf, len, "%d", (int) s.st_ctime);
417 break;
418 case 'm':
419 snprintf(buf, len, "%o", (unsigned int) s.st_mode);
420 break;
421 }
422 }
423
424 return 0;
425}
char * strsep(char **str, const char *delims)

References ast_copy_string(), buf, len(), and strsep().

◆ unload_module()

static int unload_module ( void  )
static

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 1448 of file func_env.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1448 of file func_env.c.

◆ env_function

struct ast_custom_function env_function
static
Initial value:
= {
.name = "ENV",
.read = env_read,
.write = env_write
}
static int env_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: func_env.c:370
static int env_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_env.c:354

Definition at line 1376 of file func_env.c.

Referenced by load_module(), and unload_module().

◆ file_basename_function

struct ast_custom_function file_basename_function
static
Initial value:
= {
.name = "BASENAME",
.read = file_basename,
.read_max = 12,
}
static int file_basename(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_env.c:612

Definition at line 1412 of file func_env.c.

Referenced by load_module(), and unload_module().

◆ file_count_line_function

struct ast_custom_function file_count_line_function
static
Initial value:
= {
.name = "FILE_COUNT_LINE",
.read2 = file_count_line,
.read_max = 12,
}
static int file_count_line(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_env.c:509

Definition at line 1394 of file func_env.c.

Referenced by load_module(), and unload_module().

◆ file_dirname_function

struct ast_custom_function file_dirname_function
static
Initial value:
= {
.name = "DIRNAME",
.read = file_dirname,
.read_max = 12,
}
static int file_dirname(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_env.c:595

Definition at line 1406 of file func_env.c.

Referenced by load_module(), and unload_module().

◆ file_format_function

struct ast_custom_function file_format_function
static
Initial value:
= {
.name = "FILE_FORMAT",
.read2 = file_format,
.read_max = 2,
}

Definition at line 1400 of file func_env.c.

Referenced by load_module(), and unload_module().

◆ file_function

struct ast_custom_function file_function
static
Initial value:
= {
.name = "FILE",
.read2 = file_read,
.write = file_write,
}
static int file_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: func_env.c:889
static int file_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_env.c:629

Definition at line 1388 of file func_env.c.

Referenced by load_module(), and unload_module().

◆ stat_function

struct ast_custom_function stat_function
static
Initial value:
= {
.name = "STAT",
.read = stat_read,
.read_max = 12,
}
static int stat_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_env.c:384

Definition at line 1382 of file func_env.c.

Referenced by load_module(), and unload_module().