Mon Mar 19 11:30:48 2012

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

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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
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 407 of file func_env.c.

Referenced by file_read(), and file_write().


Enumeration Type Documentation

enum file_format

Enumerator:
FF_UNKNOWN 
FF_UNIX 
FF_DOS 
FF_MAC 

Definition at line 300 of file func_env.c.

00300                  {
00301    FF_UNKNOWN = -1,
00302    FF_UNIX,
00303    FF_DOS,
00304    FF_MAC,
00305 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1249 of file func_env.c.

static void __unreg_module ( void   )  [static]

Definition at line 1249 of file func_env.c.

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

Definition at line 307 of file func_env.c.

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

Referenced by file_count_line().

00308 {
00309    int count = 0;
00310    char fbuf[4096];
00311    FILE *ff;
00312 
00313    if (!(ff = fopen(filename, "r"))) {
00314       ast_log(LOG_ERROR, "Unable to open '%s': %s\n", filename, strerror(errno));
00315       return -1;
00316    }
00317 
00318    while (fgets(fbuf, sizeof(fbuf), ff)) {
00319       char *next = fbuf, *first_cr = NULL, *first_nl = NULL;
00320 
00321       /* Must do it this way, because if the fileformat is FF_MAC, then Unix
00322        * assumptions about line-format will not come into play. */
00323       while (next) {
00324          if (newline_format == FF_DOS || newline_format == FF_MAC || newline_format == FF_UNKNOWN) {
00325             first_cr = strchr(next, '\r');
00326          }
00327          if (newline_format == FF_UNIX || newline_format == FF_UNKNOWN) {
00328             first_nl = strchr(next, '\n');
00329          }
00330 
00331          /* No terminators found in buffer */
00332          if (!first_cr && !first_nl) {
00333             break;
00334          }
00335 
00336          if (newline_format == FF_UNKNOWN) {
00337             if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) {
00338                if (first_nl && first_nl == first_cr + 1) {
00339                   newline_format = FF_DOS;
00340                } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) {
00341                   /* Get it on the next pass */
00342                   fseek(ff, -1, SEEK_CUR);
00343                   break;
00344                } else {
00345                   newline_format = FF_MAC;
00346                   first_nl = NULL;
00347                }
00348             } else {
00349                newline_format = FF_UNIX;
00350                first_cr = NULL;
00351             }
00352             /* Jump down into next section */
00353          }
00354 
00355          if (newline_format == FF_DOS) {
00356             if (first_nl && first_cr && first_nl == first_cr + 1) {
00357                next = first_nl + 1;
00358                count++;
00359             } else if (first_cr == &fbuf[sizeof(fbuf) - 2]) {
00360                /* Get it on the next pass */
00361                fseek(ff, -1, SEEK_CUR);
00362                break;
00363             }
00364          } else if (newline_format == FF_MAC) {
00365             if (first_cr) {
00366                next = first_cr + 1;
00367                count++;
00368             }
00369          } else if (newline_format == FF_UNIX) {
00370             if (first_nl) {
00371                next = first_nl + 1;
00372                count++;
00373             }
00374          }
00375       }
00376    }
00377    fclose(ff);
00378 
00379    return count;
00380 }

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

Definition at line 227 of file func_env.c.

References ast_copy_string().

00229 {
00230    char *ret = NULL;
00231 
00232    *buf = '\0';
00233 
00234    if (data)
00235       ret = getenv(data);
00236 
00237    if (ret)
00238       ast_copy_string(buf, ret, len);
00239 
00240    return 0;
00241 }

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

Definition at line 243 of file func_env.c.

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

00245 {
00246    if (!ast_strlen_zero(data) && strncmp(data, "AST_", 4)) {
00247       if (!ast_strlen_zero(value)) {
00248          setenv(data, value, 1);
00249       } else {
00250          unsetenv(data);
00251       }
00252    }
00253 
00254    return 0;
00255 }

static enum file_format file2format ( const char *  filename  )  [static]

Definition at line 421 of file func_env.c.

References ast_log(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file_format(), and LOG_ERROR.

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

00422 {
00423    FILE *ff;
00424    char fbuf[4096];
00425    char *first_cr, *first_nl;
00426    enum file_format newline_format = FF_UNKNOWN;
00427 
00428    if (!(ff = fopen(filename, "r"))) {
00429       ast_log(LOG_ERROR, "Cannot open '%s': %s\n", filename, strerror(errno));
00430       return -1;
00431    }
00432 
00433    while (fgets(fbuf, sizeof(fbuf), ff)) {
00434       first_cr = strchr(fbuf, '\r');
00435       first_nl = strchr(fbuf, '\n');
00436 
00437       if (!first_cr && !first_nl) {
00438          continue;
00439       }
00440 
00441       if ((first_cr && !first_nl) || (first_cr && first_cr < first_nl)) {
00442 
00443          if (first_nl && first_nl == first_cr + 1) {
00444             newline_format = FF_DOS;
00445          } else if (first_cr && first_cr == &fbuf[sizeof(fbuf) - 2]) {
00446             /* Edge case: get it on the next pass */
00447             fseek(ff, -1, SEEK_CUR);
00448             continue;
00449          } else {
00450             newline_format = FF_MAC;
00451          }
00452       } else {
00453          newline_format = FF_UNIX;
00454       }
00455       break;
00456    }
00457    fclose(ff);
00458    return newline_format;
00459 }

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

Definition at line 382 of file func_env.c.

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

00383 {
00384    enum file_format newline_format = FF_UNKNOWN;
00385    int64_t count;
00386    AST_DECLARE_APP_ARGS(args,
00387       AST_APP_ARG(filename);
00388       AST_APP_ARG(format);
00389    );
00390 
00391    AST_STANDARD_APP_ARGS(args, data);
00392    if (args.argc > 1) {
00393       if (tolower(args.format[0]) == 'd') {
00394          newline_format = FF_DOS;
00395       } else if (tolower(args.format[0]) == 'm') {
00396          newline_format = FF_MAC;
00397       } else if (tolower(args.format[0]) == 'u') {
00398          newline_format = FF_UNIX;
00399       }
00400    }
00401 
00402    count = count_lines(args.filename, newline_format);
00403    ast_str_set(buf, len, "%" PRId64, count);
00404    return 0;
00405 }

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

Definition at line 461 of file func_env.c.

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

Referenced by file2format(), file_count_line(), file_read(), and file_write().

00462 {
00463    enum file_format newline_format = file2format(data);
00464    ast_str_set(buf, len, "%c", newline_format == FF_UNIX ? 'u' : newline_format == FF_DOS ? 'd' : newline_format == FF_MAC ? 'm' : 'x');
00465    return 0;
00466 }

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

Definition at line 468 of file func_env.c.

References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_str_append_substr(), ast_str_reset(), errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), file_format(), format, LINE_COUNTER, LLONG_MAX, LOG_ERROR, and LOG_WARNING.

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

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

Definition at line 722 of file func_env.c.

References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, errno, FF_DOS, FF_MAC, FF_UNIX, FF_UNKNOWN, file2format(), file_format(), format, format2term(), LINE_COUNTER, LLONG_MAX, LOG_ERROR, LOG_WARNING, and S_OR.

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

const char * format2term ( enum file_format  f  ) 

Definition at line 716 of file func_env.c.

Referenced by file_write().

00717 {
00718    const char *term[] = { "", "\n", "\r\n", "\r" };
00719    return term[f + 1];
00720 }

static int load_module ( void   )  [static]

Definition at line 1236 of file func_env.c.

References ast_custom_function_register, env_function, file_count_line_function, file_format_function, file_function, and stat_function.

01237 {
01238    int res = 0;
01239 
01240    res |= ast_custom_function_register(&env_function);
01241    res |= ast_custom_function_register(&stat_function);
01242    res |= ast_custom_function_register(&file_function);
01243    res |= ast_custom_function_register(&file_count_line_function);
01244    res |= ast_custom_function_register(&file_format_function);
01245 
01246    return res;
01247 }

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

Definition at line 257 of file func_env.c.

References ast_copy_string(), and strsep().

00259 {
00260    char *action;
00261    struct stat s;
00262 
00263    ast_copy_string(buf, "0", len);
00264 
00265    action = strsep(&data, ",");
00266    if (stat(data, &s)) {
00267       return 0;
00268    } else {
00269       switch (*action) {
00270       case 'e':
00271          strcpy(buf, "1");
00272          break;
00273       case 's':
00274          snprintf(buf, len, "%d", (unsigned int) s.st_size);
00275          break;
00276       case 'f':
00277          snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0);
00278          break;
00279       case 'd':
00280          snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0);
00281          break;
00282       case 'M':
00283          snprintf(buf, len, "%d", (int) s.st_mtime);
00284          break;
00285       case 'A':
00286          snprintf(buf, len, "%d", (int) s.st_mtime);
00287          break;
00288       case 'C':
00289          snprintf(buf, len, "%d", (int) s.st_ctime);
00290          break;
00291       case 'm':
00292          snprintf(buf, len, "%o", (int) s.st_mode);
00293          break;
00294       }
00295    }
00296 
00297    return 0;
00298 }

static int unload_module ( void   )  [static]

Definition at line 1223 of file func_env.c.

References ast_custom_function_unregister(), env_function, file_count_line_function, file_format_function, file_function, and stat_function.

01224 {
01225    int res = 0;
01226 
01227    res |= ast_custom_function_unregister(&env_function);
01228    res |= ast_custom_function_unregister(&stat_function);
01229    res |= ast_custom_function_unregister(&file_function);
01230    res |= ast_custom_function_unregister(&file_count_line_function);
01231    res |= ast_custom_function_unregister(&file_format_function);
01232 
01233    return res;
01234 }


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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 1249 of file func_env.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1249 of file func_env.c.

struct ast_custom_function env_function [static]

Initial value:

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

Definition at line 1193 of file func_env.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function file_count_line_function [static]

Initial value:

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

Definition at line 1211 of file func_env.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function file_format_function [static]

Initial value:

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

Definition at line 1217 of file func_env.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function file_function [static]

Initial value:

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

Definition at line 1205 of file func_env.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function stat_function [static]

Initial value:

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

Definition at line 1199 of file func_env.c.

Referenced by load_module(), and unload_module().


Generated on Mon Mar 19 11:30:48 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7