Wed Apr 6 11:30:04 2011

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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 403 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 296 of file func_env.c.

00296                  {
00297    FF_UNKNOWN = -1,
00298    FF_UNIX,
00299    FF_DOS,
00300    FF_MAC,
00301 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1239 of file func_env.c.

static void __unreg_module ( void   )  [static]

Definition at line 1239 of file func_env.c.

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

Definition at line 303 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().

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

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

Definition at line 223 of file func_env.c.

References ast_copy_string().

00225 {
00226    char *ret = NULL;
00227 
00228    *buf = '\0';
00229 
00230    if (data)
00231       ret = getenv(data);
00232 
00233    if (ret)
00234       ast_copy_string(buf, ret, len);
00235 
00236    return 0;
00237 }

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

Definition at line 239 of file func_env.c.

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

00241 {
00242    if (!ast_strlen_zero(data) && strncmp(data, "AST_", 4)) {
00243       if (!ast_strlen_zero(value)) {
00244          setenv(data, value, 1);
00245       } else {
00246          unsetenv(data);
00247       }
00248    }
00249 
00250    return 0;
00251 }

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

Definition at line 417 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().

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

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 378 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.

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

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

Definition at line 457 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().

00458 {
00459    enum file_format newline_format = file2format(data);
00460    ast_str_set(buf, len, "%c", newline_format == FF_UNIX ? 'u' : newline_format == FF_DOS ? 'd' : newline_format == FF_MAC ? 'm' : 'x');
00461    return 0;
00462 }

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

Definition at line 464 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.

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

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

Definition at line 714 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(), fwrite, LINE_COUNTER, LLONG_MAX, LOG_ERROR, LOG_WARNING, and S_OR.

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

const char * format2term ( enum file_format  f  ) 

Definition at line 708 of file func_env.c.

Referenced by file_write().

00709 {
00710    const char *term[] = { "", "\n", "\r\n", "\r" };
00711    return term[f + 1];
00712 }

static int load_module ( void   )  [static]

Definition at line 1226 of file func_env.c.

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

01227 {
01228    int res = 0;
01229 
01230    res |= ast_custom_function_register(&env_function);
01231    res |= ast_custom_function_register(&stat_function);
01232    res |= ast_custom_function_register(&file_function);
01233    res |= ast_custom_function_register(&file_count_line_function);
01234    res |= ast_custom_function_register(&file_format_function);
01235 
01236    return res;
01237 }

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

Definition at line 253 of file func_env.c.

References ast_copy_string(), and strsep().

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

static int unload_module ( void   )  [static]

Definition at line 1213 of file func_env.c.

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

01214 {
01215    int res = 0;
01216 
01217    res |= ast_custom_function_unregister(&env_function);
01218    res |= ast_custom_function_unregister(&stat_function);
01219    res |= ast_custom_function_unregister(&file_function);
01220    res |= ast_custom_function_unregister(&file_count_line_function);
01221    res |= ast_custom_function_unregister(&file_format_function);
01222 
01223    return res;
01224 }


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

Definition at line 1239 of file func_env.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1239 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 1183 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 1201 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 1207 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 1195 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 1189 of file func_env.c.

Referenced by load_module(), and unload_module().


Generated on Wed Apr 6 11:30:04 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7