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"

Include dependency graph for func_env.c:

Go to the source code of this file.

Defines

#define LINE_COUNTER(cptr, term, counter)

Enumerations

enum  file_format { FF_UNKNOWN = -1, FF_UNIX, FF_DOS, FF_MAC }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int64_t count_lines (const char *filename, enum file_format newline_format)
static int env_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int env_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static enum file_format file2format (const char *filename)
static int file_count_line (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
static int file_format (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
static int file_read (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
static int file_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
const char * format2term (enum file_format f)
static int load_module (void)
static int stat_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Environment/filesystem dialplan functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_custom_function env_function
static struct ast_custom_function file_count_line_function
static struct ast_custom_function file_format_function
static struct ast_custom_function file_function
static struct ast_custom_function stat_function


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

static void __reg_module ( void   )  [static]

Definition at line 1290 of file func_env.c.

static void __unreg_module ( void   )  [static]

Definition at line 1290 of file func_env.c.

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, LOG_ERROR, and NULL.

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(), and NULL.

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, setenv(), and unsetenv().

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

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    AST_DECLARE_APP_ARGS(args,
00498       AST_APP_ARG(filename);
00499       AST_APP_ARG(offset);
00500       AST_APP_ARG(length);
00501       AST_APP_ARG(options);
00502       AST_APP_ARG(fileformat);
00503    );
00504 
00505    AST_STANDARD_APP_ARGS(args, data);
00506 
00507    if (args.argc > 1) {
00508       sscanf(args.offset, "%" SCNd64, &offset);
00509    }
00510    if (args.argc > 2) {
00511       sscanf(args.length, "%" SCNd64, &length);
00512    }
00513 
00514    if (args.argc < 4 || !strchr(args.options, 'l')) {
00515       /* Character-based mode */
00516       off_t off_i;
00517 
00518       if (!(ff = fopen(args.filename, "r"))) {
00519          ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", args.filename, strerror(errno));
00520          return 0;
00521       }
00522 
00523       if (fseeko(ff, 0, SEEK_END) < 0) {
00524          ast_log(LOG_ERROR, "Cannot seek to end of '%s': %s\n", args.filename, strerror(errno));
00525          fclose(ff);
00526          return -1;
00527       }
00528       flength = ftello(ff);
00529 
00530       if (offset < 0) {
00531          fseeko(ff, offset, SEEK_END);
00532          if ((offset = ftello(ff)) < 0) {
00533             ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno));
00534             fclose(ff);
00535             return -1;
00536          }
00537       }
00538       if (length < 0) {
00539          fseeko(ff, length, SEEK_END);
00540          if ((length = ftello(ff)) - offset < 0) {
00541             /* Eliminates all results */
00542             fclose(ff);
00543             return -1;
00544          }
00545       } else if (length == LLONG_MAX) {
00546          fseeko(ff, 0, SEEK_END);
00547          length = ftello(ff);
00548       }
00549 
00550       ast_str_reset(*buf);
00551 
00552       fseeko(ff, offset, SEEK_SET);
00553       for (off_i = ftello(ff); off_i < flength && off_i < offset + length; off_i += sizeof(fbuf)) {
00554          /* Calculate if we need to retrieve just a portion of the file in memory */
00555          size_t toappend = sizeof(fbuf);
00556 
00557          if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00558             ast_log(LOG_ERROR, "Short read?!!\n");
00559             break;
00560          }
00561 
00562          /* Don't go past the length requested */
00563          if (off_i + toappend > offset + length) {
00564             toappend = MIN(offset + length - off_i, flength - off_i);
00565          }
00566 
00567          ast_str_append_substr(buf, len, fbuf, toappend);
00568       }
00569       fclose(ff);
00570       return 0;
00571    }
00572 
00573    /* Line-based read */
00574    if (args.argc == 5) {
00575       if (tolower(args.fileformat[0]) == 'd') {
00576          format = FF_DOS;
00577       } else if (tolower(args.fileformat[0]) == 'm') {
00578          format = FF_MAC;
00579       } else if (tolower(args.fileformat[0]) == 'u') {
00580          format = FF_UNIX;
00581       }
00582    }
00583 
00584    if (format == FF_UNKNOWN) {
00585       if ((format = file2format(args.filename)) == FF_UNKNOWN) {
00586          ast_log(LOG_WARNING, "'%s' is not a line-based file\n", args.filename);
00587          return -1;
00588       }
00589    }
00590 
00591    if (offset < 0 && length <= offset) {
00592       /* Length eliminates all content */
00593       return -1;
00594    } else if (offset == 0) {
00595       offset_offset = 0;
00596    }
00597 
00598    if (!(ff = fopen(args.filename, "r"))) {
00599       ast_log(LOG_ERROR, "Cannot open '%s': %s\n", args.filename, strerror(errno));
00600       return -1;
00601    }
00602 
00603    if (fseek(ff, 0, SEEK_END)) {
00604       ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno));
00605       fclose(ff);
00606       return -1;
00607    }
00608 
00609    flength = ftello(ff);
00610 
00611    if (length == LLONG_MAX) {
00612       length_offset = flength;
00613    }
00614 
00615    /* For negative offset and/or negative length */
00616    if (offset < 0 || length < 0) {
00617       int64_t count = 0;
00618       /* Start with an even multiple of fbuf, so at the end of reading with a
00619        * 0 offset, we don't try to go past the beginning of the file. */
00620       for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) {
00621          size_t end;
00622          char *pos;
00623          if (fseeko(ff, i, SEEK_SET)) {
00624             ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno));
00625          }
00626          end = fread(fbuf, 1, sizeof(fbuf), ff);
00627          for (pos = (end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1); pos > fbuf - 1; pos--) {
00628             LINE_COUNTER(pos, format, count);
00629 
00630             if (length < 0 && count * -1 == length) {
00631                length_offset = i + (pos - fbuf);
00632             } else if (offset < 0 && count * -1 == (offset - 1)) {
00633                /* Found our initial offset.  We're done with reverse motion! */
00634                if (format == FF_DOS) {
00635                   offset_offset = i + (pos - fbuf) + 2;
00636                } else {
00637                   offset_offset = i + (pos - fbuf) + 1;
00638                }
00639                break;
00640             }
00641          }
00642          if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) {
00643             break;
00644          }
00645       }
00646       /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */
00647       if (offset < 0 && offset_offset < 0 && offset == count * -1) {
00648          offset_offset = 0;
00649       }
00650    }
00651 
00652    /* Positve line offset */
00653    if (offset > 0) {
00654       int64_t count = 0;
00655       fseek(ff, 0, SEEK_SET);
00656       for (i = 0; i < flength; i += sizeof(fbuf)) {
00657          char *pos;
00658          if (i + sizeof(fbuf) <= flength) {
00659             /* Don't let previous values influence current counts, due to short reads */
00660             memset(fbuf, 0, sizeof(fbuf));
00661          }
00662          if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00663             ast_log(LOG_ERROR, "Short read?!!\n");
00664             fclose(ff);
00665             return -1;
00666          }
00667          for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
00668             LINE_COUNTER(pos, format, count);
00669 
00670             if (count == offset) {
00671                offset_offset = i + (pos - fbuf) + 1;
00672                break;
00673             }
00674          }
00675          if (offset_offset >= 0) {
00676             break;
00677          }
00678       }
00679    }
00680 
00681    if (offset_offset < 0) {
00682       ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset);
00683       fclose(ff);
00684       return -1;
00685    }
00686 
00687    ast_str_reset(*buf);
00688    if (fseeko(ff, offset_offset, SEEK_SET)) {
00689       ast_log(LOG_ERROR, "fseeko failed: %s\n", strerror(errno));
00690    }
00691 
00692    /* If we have both offset_offset and length_offset, then grabbing the
00693     * buffer is simply a matter of just retrieving the file and adding it
00694     * to buf.  Otherwise, we need to run byte-by-byte forward until the
00695     * length is complete. */
00696    if (length_offset >= 0) {
00697       ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset);
00698       for (i = offset_offset; i < length_offset; i += sizeof(fbuf)) {
00699          if (fread(fbuf, 1, i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf), ff) < (i + sizeof(fbuf) > flength ? flength - i : sizeof(fbuf))) {
00700             ast_log(LOG_ERROR, "Short read?!!\n");
00701          }
00702          ast_debug(3, "Appending first %" PRId64" bytes of fbuf=%s\n", (int64_t)(i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf)), fbuf);
00703          ast_str_append_substr(buf, len, fbuf, i + sizeof(fbuf) > length_offset ? length_offset - i : sizeof(fbuf));
00704       }
00705    } else if (length == 0) {
00706       /* Nothing to do */
00707    } else {
00708       /* Positive line offset */
00709       int64_t current_length = 0;
00710       char dos_state = 0;
00711       ast_debug(3, "offset=%" PRId64 ", length=%" PRId64 ", offset_offset=%" PRId64 ", length_offset=%" PRId64 "\n", offset, length, offset_offset, length_offset);
00712       for (i = offset_offset; i < flength; i += sizeof(fbuf)) {
00713          char *pos;
00714          if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00715             ast_log(LOG_ERROR, "Short read?!!\n");
00716             fclose(ff);
00717             return -1;
00718          }
00719          for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
00720             LINE_COUNTER(pos, format, current_length);
00721 
00722             if (current_length == length) {
00723                length_offset = i + (pos - fbuf) + 1;
00724                break;
00725             }
00726          }
00727          ast_debug(3, "length_offset=%" PRId64 ", length_offset - i=%" PRId64 "\n", length_offset, length_offset - i);
00728          ast_str_append_substr(buf, len, fbuf, (length_offset >= 0) ? length_offset - i : (flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i);
00729 
00730          if (length_offset >= 0) {
00731             break;
00732          }
00733       }
00734    }
00735 
00736    fclose(ff);
00737    return 0;
00738 }

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

Definition at line 747 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, LLONG_MAX, LOG_ERROR, LOG_WARNING, and S_OR.

00748 {
00749    AST_DECLARE_APP_ARGS(args,
00750       AST_APP_ARG(filename);
00751       AST_APP_ARG(offset);
00752       AST_APP_ARG(length);
00753       AST_APP_ARG(options);
00754       AST_APP_ARG(format);
00755    );
00756    int64_t offset = 0, length = LLONG_MAX;
00757    off_t flength, vlength;
00758    size_t foplen = 0;
00759    FILE *ff;
00760 
00761    AST_STANDARD_APP_ARGS(args, data);
00762 
00763    if (args.argc > 1) {
00764       sscanf(args.offset, "%" SCNd64, &offset);
00765    }
00766    if (args.argc > 2) {
00767       sscanf(args.length, "%" SCNd64, &length);
00768    }
00769 
00770    vlength = strlen(value);
00771 
00772    if (args.argc < 4 || !strchr(args.options, 'l')) {
00773       /* Character-based mode */
00774 
00775       if (args.argc > 3 && strchr(args.options, 'a')) {
00776          /* Append mode */
00777          if (!(ff = fopen(args.filename, "a"))) {
00778             ast_log(LOG_WARNING, "Cannot open file '%s' for appending: %s\n", args.filename, strerror(errno));
00779             return 0;
00780          }
00781          if (fwrite(value, 1, vlength, ff) < vlength) {
00782             ast_log(LOG_ERROR, "Short write?!!\n");
00783          }
00784          fclose(ff);
00785          return 0;
00786       } else if (offset == 0 && length == LLONG_MAX) {
00787          if (!(ff = fopen(args.filename, "w"))) {
00788             ast_log(LOG_WARNING, "Cannot open file '%s' for writing: %s\n", args.filename, strerror(errno));
00789             return 0;
00790          }
00791          if (fwrite(value, 1, vlength, ff) < vlength) {
00792             ast_log(LOG_ERROR, "Short write?!!\n");
00793          }
00794          fclose(ff);
00795          return 0;
00796       }
00797 
00798       if (!(ff = fopen(args.filename, "r+"))) {
00799          ast_log(LOG_WARNING, "Cannot open file '%s' for modification: %s\n", args.filename, strerror(errno));
00800          return 0;
00801       }
00802       fseeko(ff, 0, SEEK_END);
00803       flength = ftello(ff);
00804 
00805       if (offset < 0) {
00806          if (fseeko(ff, offset, SEEK_END)) {
00807             ast_log(LOG_ERROR, "Cannot seek to offset of '%s': %s\n", args.filename, strerror(errno));
00808             fclose(ff);
00809             return -1;
00810          }
00811          if ((offset = ftello(ff)) < 0) {
00812             ast_log(AST_LOG_ERROR, "Cannot determine offset position of '%s': %s\n", args.filename, strerror(errno));
00813             fclose(ff);
00814             return -1;
00815          }
00816       }
00817 
00818       if (length < 0) {
00819          length = flength - offset + length;
00820          if (length < 0) {
00821             ast_log(LOG_ERROR, "Length '%s' exceeds the file length.  No data will be written.\n", args.length);
00822             fclose(ff);
00823             return -1;
00824          }
00825       }
00826 
00827       fseeko(ff, offset, SEEK_SET);
00828 
00829       ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n",
00830          S_OR(args.offset, "(null)"), offset, S_OR(args.length, "(null)"), length, vlength, flength);
00831 
00832       if (length == vlength) {
00833          /* Simplest case, a straight replace */
00834          if (fwrite(value, 1, vlength, ff) < vlength) {
00835             ast_log(LOG_ERROR, "Short write?!!\n");
00836          }
00837          fclose(ff);
00838       } else if (length == LLONG_MAX) {
00839          /* Simple truncation */
00840          if (fwrite(value, 1, vlength, ff) < vlength) {
00841             ast_log(LOG_ERROR, "Short write?!!\n");
00842          }
00843          fclose(ff);
00844          if (truncate(args.filename, offset + vlength)) {
00845             ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno));
00846          }
00847       } else if (length > vlength) {
00848          /* More complex -- need to close a gap */
00849          char fbuf[4096];
00850          off_t cur;
00851          if (fwrite(value, 1, vlength, ff) < vlength) {
00852             ast_log(LOG_ERROR, "Short write?!!\n");
00853          }
00854          fseeko(ff, length - vlength, SEEK_CUR);
00855          while ((cur = ftello(ff)) < flength) {
00856             if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00857                ast_log(LOG_ERROR, "Short read?!!\n");
00858             }
00859             fseeko(ff, cur + vlength - length, SEEK_SET);
00860             if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
00861                ast_log(LOG_ERROR, "Short write?!!\n");
00862             }
00863             /* Seek to where we stopped reading */
00864             if (fseeko(ff, cur + sizeof(fbuf), SEEK_SET) < 0) {
00865                /* Only reason for seek to fail is EOF */
00866                break;
00867             }
00868          }
00869          fclose(ff);
00870          if (truncate(args.filename, flength - (length - vlength))) {
00871             ast_log(LOG_ERROR, "Unable to truncate the file: %s\n", strerror(errno));
00872          }
00873       } else {
00874          /* Most complex -- need to open a gap */
00875          char fbuf[4096];
00876          off_t lastwritten = flength + vlength - length;
00877 
00878          /* Start reading exactly the buffer size back from the end. */
00879          fseeko(ff, flength - sizeof(fbuf), SEEK_SET);
00880          while (offset < ftello(ff)) {
00881             if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
00882                ast_log(LOG_ERROR, "Short read?!!\n");
00883                fclose(ff);
00884                return -1;
00885             }
00886             /* Since the read moved our file ptr forward, we reverse, but
00887              * seek an offset equal to the amount we want to extend the
00888              * file by */
00889             fseeko(ff, vlength - length - sizeof(fbuf), SEEK_CUR);
00890 
00891             /* Note the location of this buffer -- we must not overwrite this position. */
00892             lastwritten = ftello(ff);
00893 
00894             if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
00895                ast_log(LOG_ERROR, "Short write?!!\n");
00896                fclose(ff);
00897                return -1;
00898             }
00899 
00900             if (lastwritten < offset + sizeof(fbuf)) {
00901                break;
00902             }
00903             /* Our file pointer is now either pointing to the end of the
00904              * file (new position) or a multiple of the fbuf size back from
00905              * that point.  Move back to where we want to start reading
00906              * again.  We never actually try to read beyond the end of the
00907              * file, so we don't have do deal with short reads, as we would
00908              * when we're shortening the file. */
00909             fseeko(ff, 2 * sizeof(fbuf) + vlength - length, SEEK_CUR);
00910          }
00911 
00912          /* Last part of the file that we need to preserve */
00913          if (fseeko(ff, offset + length, SEEK_SET)) {
00914             ast_log(LOG_WARNING, "Unable to seek to %" PRId64 " + %" PRId64 " != %" PRId64 "?)\n", offset, length, ftello(ff));
00915          }
00916 
00917          /* Doesn't matter how much we read -- just need to restrict the write */
00918          ast_debug(1, "Reading at %" PRId64 "\n", ftello(ff));
00919          if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
00920             ast_log(LOG_ERROR, "Short read?!!\n");
00921          }
00922          fseek(ff, offset, SEEK_SET);
00923          /* Write out the value, then write just up until where we last moved some data */
00924          if (fwrite(value, 1, vlength, ff) < vlength) {
00925             ast_log(LOG_ERROR, "Short write?!!\n");
00926          } else {
00927             off_t curpos = ftello(ff);
00928             foplen = lastwritten - curpos;
00929             if (fwrite(fbuf, 1, foplen, ff) < foplen) {
00930                ast_log(LOG_ERROR, "Short write?!!\n");
00931             }
00932          }
00933          fclose(ff);
00934       }
00935    } else {
00936       enum file_format newline_format = FF_UNKNOWN;
00937 
00938       /* Line mode */
00939       if (args.argc == 5) {
00940          if (tolower(args.format[0]) == 'u') {
00941             newline_format = FF_UNIX;
00942          } else if (tolower(args.format[0]) == 'm') {
00943             newline_format = FF_MAC;
00944          } else if (tolower(args.format[0]) == 'd') {
00945             newline_format = FF_DOS;
00946          }
00947       }
00948       if (newline_format == FF_UNKNOWN && (newline_format = file2format(args.filename)) == FF_UNKNOWN) {
00949          ast_log(LOG_ERROR, "File '%s' not in line format\n", args.filename);
00950          return -1;
00951       }
00952 
00953       if (strchr(args.options, 'a')) {
00954          /* Append to file */
00955          if (!(ff = fopen(args.filename, "a"))) {
00956             ast_log(LOG_ERROR, "Unable to open '%s' for appending: %s\n", args.filename, strerror(errno));
00957             return -1;
00958          }
00959          if (fwrite(value, 1, vlength, ff) < vlength) {
00960             ast_log(LOG_ERROR, "Short write?!!\n");
00961          } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
00962             ast_log(LOG_ERROR, "Short write?!!\n");
00963          }
00964          fclose(ff);
00965       } else if (offset == 0 && length == LLONG_MAX) {
00966          /* Overwrite file */
00967          off_t truncsize;
00968          if (!(ff = fopen(args.filename, "w"))) {
00969             ast_log(LOG_ERROR, "Unable to open '%s' for writing: %s\n", args.filename, strerror(errno));
00970             return -1;
00971          }
00972          if (fwrite(value, 1, vlength, ff) < vlength) {
00973             ast_log(LOG_ERROR, "Short write?!!\n");
00974          } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
00975             ast_log(LOG_ERROR, "Short write?!!\n");
00976          }
00977          if ((truncsize = ftello(ff)) < 0) {
00978             ast_log(AST_LOG_ERROR, "Unable to determine truncate position of '%s': %s\n", args.filename, strerror(errno));
00979          }
00980          fclose(ff);
00981          if (truncsize >= 0 && truncate(args.filename, truncsize)) {
00982             ast_log(LOG_ERROR, "Unable to truncate file '%s': %s\n", args.filename, strerror(errno));
00983             return -1;
00984          }
00985       } else {
00986          int64_t offset_offset = (offset == 0 ? 0 : -1), length_offset = -1, flength, i, current_length = 0;
00987          char dos_state = 0, fbuf[4096];
00988 
00989          if (offset < 0 && length < offset) {
00990             /* Nonsense! */
00991             ast_log(LOG_ERROR, "Length cannot specify a position prior to the offset\n");
00992             return -1;
00993          }
00994 
00995          if (!(ff = fopen(args.filename, "r+"))) {
00996             ast_log(LOG_ERROR, "Cannot open '%s' for modification: %s\n", args.filename, strerror(errno));
00997             return -1;
00998          }
00999 
01000          if (fseek(ff, 0, SEEK_END)) {
01001             ast_log(LOG_ERROR, "Cannot seek to end of file '%s': %s\n", args.filename, strerror(errno));
01002             fclose(ff);
01003             return -1;
01004          }
01005          if ((flength = ftello(ff)) < 0) {
01006             ast_log(AST_LOG_ERROR, "Cannot determine end position of file '%s': %s\n", args.filename, strerror(errno));
01007             fclose(ff);
01008             return -1;
01009          }
01010 
01011          /* For negative offset and/or negative length */
01012          if (offset < 0 || length < 0) {
01013             int64_t count = 0;
01014             for (i = (flength / sizeof(fbuf)) * sizeof(fbuf); i >= 0; i -= sizeof(fbuf)) {
01015                char *pos;
01016                if (fseeko(ff, i, SEEK_SET)) {
01017                   ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno));
01018                }
01019                if (i + sizeof(fbuf) >= flength) {
01020                   memset(fbuf, 0, sizeof(fbuf));
01021                }
01022                if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01023                   ast_log(LOG_ERROR, "Short read: %s\n", strerror(errno));
01024                   fclose(ff);
01025                   return -1;
01026                }
01027                for (pos = fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) {
01028                   LINE_COUNTER(pos, newline_format, count);
01029 
01030                   if (length < 0 && count * -1 == length) {
01031                      length_offset = i + (pos - fbuf);
01032                   } else if (offset < 0 && count * -1 == (offset - 1)) {
01033                      /* Found our initial offset.  We're done with reverse motion! */
01034                      if (newline_format == FF_DOS) {
01035                         offset_offset = i + (pos - fbuf) + 2;
01036                      } else {
01037                         offset_offset = i + (pos - fbuf) + 1;
01038                      }
01039                      break;
01040                   }
01041                }
01042                if ((offset < 0 && offset_offset >= 0) || (offset >= 0 && length_offset >= 0)) {
01043                   break;
01044                }
01045             }
01046             /* We're at the beginning, and the negative offset indicates the exact number of lines in the file */
01047             if (offset < 0 && offset_offset < 0 && offset == count * -1) {
01048                offset_offset = 0;
01049             }
01050          }
01051 
01052          /* Positve line offset */
01053          if (offset > 0) {
01054             int64_t count = 0;
01055             fseek(ff, 0, SEEK_SET);
01056             for (i = 0; i < flength; i += sizeof(fbuf)) {
01057                char *pos;
01058                if (i + sizeof(fbuf) >= flength) {
01059                   memset(fbuf, 0, sizeof(fbuf));
01060                }
01061                if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01062                   ast_log(LOG_ERROR, "Short read?!!\n");
01063                   fclose(ff);
01064                   return -1;
01065                }
01066                for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
01067                   LINE_COUNTER(pos, newline_format, count);
01068 
01069                   if (count == offset) {
01070                      offset_offset = i + (pos - fbuf) + 1;
01071                      break;
01072                   }
01073                }
01074                if (offset_offset >= 0) {
01075                   break;
01076                }
01077             }
01078          }
01079 
01080          if (offset_offset < 0) {
01081             ast_log(LOG_ERROR, "Offset '%s' refers to before the beginning of the file!\n", args.offset);
01082             fclose(ff);
01083             return -1;
01084          }
01085 
01086          if (length == 0) {
01087             length_offset = offset_offset;
01088          } else if (length == LLONG_MAX) {
01089             length_offset = flength;
01090          }
01091 
01092          /* Positive line length */
01093          if (length_offset < 0) {
01094             fseeko(ff, offset_offset, SEEK_SET);
01095             for (i = offset_offset; i < flength; i += sizeof(fbuf)) {
01096                char *pos;
01097                if (i + sizeof(fbuf) >= flength) {
01098                   memset(fbuf, 0, sizeof(fbuf));
01099                }
01100                if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01101                   ast_log(LOG_ERROR, "Short read?!!\n");
01102                   fclose(ff);
01103                   return -1;
01104                }
01105                for (pos = fbuf; pos < fbuf + sizeof(fbuf); pos++) {
01106                   LINE_COUNTER(pos, newline_format, current_length);
01107 
01108                   if (current_length == length) {
01109                      length_offset = i + (pos - fbuf) + 1;
01110                      break;
01111                   }
01112                }
01113                if (length_offset >= 0) {
01114                   break;
01115                }
01116             }
01117             if (length_offset < 0) {
01118                /* Exceeds length of file */
01119                ast_debug(3, "Exceeds length of file? length=%" PRId64 ", count=%" PRId64 ", flength=%" PRId64 "\n", length, current_length, flength);
01120                length_offset = flength;
01121             }
01122          }
01123 
01124          /* Have offset_offset and length_offset now */
01125          if (length_offset - offset_offset == vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) {
01126             /* Simple case - replacement of text inline */
01127             fseeko(ff, offset_offset, SEEK_SET);
01128             if (fwrite(value, 1, vlength, ff) < vlength) {
01129                ast_log(LOG_ERROR, "Short write?!!\n");
01130             } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
01131                ast_log(LOG_ERROR, "Short write?!!\n");
01132             }
01133             fclose(ff);
01134          } else if (length_offset - offset_offset > vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)))) {
01135             /* More complex case - need to shorten file */
01136             off_t cur;
01137             int64_t length_length = length_offset - offset_offset;
01138             size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)));
01139 
01140             ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 " (%" PRId64 "), vlength=%" PRId64 ", flength=%" PRId64 "\n",
01141                args.offset, offset_offset, args.length, length_offset, length_length, vlength, flength);
01142 
01143             fseeko(ff, offset_offset, SEEK_SET);
01144             if (fwrite(value, 1, vlength, ff) < vlength) {
01145                ast_log(LOG_ERROR, "Short write?!!\n");
01146                fclose(ff);
01147                return -1;
01148             } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, vlen - vlength, ff) < vlen - vlength) {
01149                ast_log(LOG_ERROR, "Short write?!!\n");
01150                fclose(ff);
01151                return -1;
01152             }
01153             while ((cur = ftello(ff)) < flength) {
01154                if (cur < 0) {
01155                   ast_log(AST_LOG_ERROR, "Unable to determine last write position for '%s': %s\n", args.filename, strerror(errno));
01156                   fclose(ff);
01157                   return -1;
01158                }
01159                fseeko(ff, length_length - vlen, SEEK_CUR);
01160                if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01161                   ast_log(LOG_ERROR, "Short read?!!\n");
01162                   fclose(ff);
01163                   return -1;
01164                }
01165                /* Seek to where we last stopped writing */
01166                fseeko(ff, cur, SEEK_SET);
01167                if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
01168                   ast_log(LOG_ERROR, "Short write?!!\n");
01169                   fclose(ff);
01170                   return -1;
01171                }
01172             }
01173             fclose(ff);
01174             if (truncate(args.filename, flength - (length_length - vlen))) {
01175                ast_log(LOG_ERROR, "Truncation of file failed: %s\n", strerror(errno));
01176             }
01177          } else {
01178             /* Most complex case - need to lengthen file */
01179             size_t vlen = vlength + (strchr(args.options, 'd') ? 0 : strlen(format2term(newline_format)));
01180             int64_t origlen = length_offset - offset_offset;
01181             off_t lastwritten = flength + vlen - origlen;
01182 
01183             ast_debug(3, "offset=%s/%" PRId64 ", length=%s/%" PRId64 ", vlength=%" PRId64 ", flength=%" PRId64 "\n",
01184                args.offset, offset_offset, args.length, length_offset, vlength, flength);
01185 
01186             fseeko(ff, flength - sizeof(fbuf), SEEK_SET);
01187             while (offset_offset + sizeof(fbuf) < ftello(ff)) {
01188                if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
01189                   ast_log(LOG_ERROR, "Short read?!!\n");
01190                   fclose(ff);
01191                   return -1;
01192                }
01193                fseeko(ff, sizeof(fbuf) - vlen - origlen, SEEK_CUR);
01194                if (fwrite(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf)) {
01195                   ast_log(LOG_ERROR, "Short write?!!\n");
01196                   fclose(ff);
01197                   return -1;
01198                }
01199                if ((lastwritten = ftello(ff) - sizeof(fbuf)) < offset_offset + sizeof(fbuf)) {
01200                   break;
01201                }
01202                fseeko(ff, 2 * sizeof(fbuf) + vlen - origlen, SEEK_CUR);
01203             }
01204             fseek(ff, length_offset, SEEK_SET);
01205             if (fread(fbuf, 1, sizeof(fbuf), ff) < sizeof(fbuf) && !feof(ff)) {
01206                ast_log(LOG_ERROR, "Short read?!!\n");
01207                fclose(ff);
01208                return -1;
01209             }
01210             fseek(ff, offset_offset, SEEK_SET);
01211             if (fwrite(value, 1, vlength, ff) < vlength) {
01212                ast_log(LOG_ERROR, "Short write?!!\n");
01213                fclose(ff);
01214                return -1;
01215             } else if (!strchr(args.options, 'd') && fwrite(format2term(newline_format), 1, strlen(format2term(newline_format)), ff) < strlen(format2term(newline_format))) {
01216                ast_log(LOG_ERROR, "Short write?!!\n");
01217                fclose(ff);
01218                return -1;
01219             } else {
01220                off_t curpos = ftello(ff);
01221                foplen = lastwritten - curpos;
01222                if (fwrite(fbuf, 1, foplen, ff) < foplen) {
01223                   ast_log(LOG_ERROR, "Short write?!!\n");
01224                }
01225             }
01226             fclose(ff);
01227          }
01228       }
01229    }
01230 
01231    return 0;
01232 }

const char * format2term ( enum file_format  f  ) 

Definition at line 741 of file func_env.c.

Referenced by file_write().

00742 {
00743    const char *term[] = { "", "\n", "\r\n", "\r" };
00744    return term[f + 1];
00745 }

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(), and strsep().

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

References ast_custom_function_unregister().

01265 {
01266    int res = 0;
01267 
01268    res |= ast_custom_function_unregister(&env_function);
01269    res |= ast_custom_function_unregister(&stat_function);
01270    res |= ast_custom_function_unregister(&file_function);
01271    res |= ast_custom_function_unregister(&file_count_line_function);
01272    res |= ast_custom_function_unregister(&file_format_function);
01273 
01274    return res;
01275 }


Variable Documentation

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

Definition at line 1290 of file func_env.c.

Initial value:

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

Definition at line 1234 of file func_env.c.

Initial value:

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

Definition at line 1252 of file func_env.c.

Initial value:

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

Definition at line 1258 of file func_env.c.

Initial value:

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

Definition at line 1246 of file func_env.c.

Initial value:

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

Definition at line 1240 of file func_env.c.


Generated on Thu Apr 16 06:31:16 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6