Wed Aug 7 17:16:05 2019

Asterisk developer's documentation


func_env.c File Reference

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

Detailed Description

Environment related dialplan functions.

Definition in file func_env.c.


Define Documentation

#define LINE_COUNTER ( cptr,
term,
counter   ) 

Definition at line 427 of file func_env.c.

Referenced by file_read(), and file_write().


Enumeration Type Documentation

Enumerator:
FF_UNKNOWN 
FF_UNIX 
FF_DOS 
FF_MAC 

Definition at line 320 of file func_env.c.

00320                  {
00321    FF_UNKNOWN = -1,
00322    FF_UNIX,
00323    FF_DOS,
00324    FF_MAC,
00325 };


Function Documentation

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]
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 }


Variable Documentation

Initial value:
 {
   .name = "ENV",
   .read = env_read,
   .write = env_write
}

Definition at line 1233 of file func_env.c.

Initial value:
 {
   .name = "FILE_COUNT_LINE",
   .read2 = file_count_line,
   .read_max = 12,
}

Definition at line 1251 of file func_env.c.

Initial value:
 {
   .name = "FILE_FORMAT",
   .read2 = file_format,
   .read_max = 2,
}

Definition at line 1257 of file func_env.c.

Initial value:
 {
   .name = "FILE",
   .read2 = file_read,
   .write = file_write,
}

Definition at line 1245 of file func_env.c.

Initial value:
 {
   .name = "STAT",
   .read = stat_read,
   .read_max = 12,
}

Definition at line 1239 of file func_env.c.


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1