Mon Jun 27 16:51:14 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 1245 of file func_env.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

const char * format2term ( enum file_format  f  ) 

Definition at line 712 of file func_env.c.

Referenced by file_write().

00713 {
00714    const char *term[] = { "", "\n", "\r\n", "\r" };
00715    return term[f + 1];
00716 }

static int load_module ( void   )  [static]

Definition at line 1232 of file func_env.c.

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

01233 {
01234    int res = 0;
01235 
01236    res |= ast_custom_function_register(&env_function);
01237    res |= ast_custom_function_register(&stat_function);
01238    res |= ast_custom_function_register(&file_function);
01239    res |= ast_custom_function_register(&file_count_line_function);
01240    res |= ast_custom_function_register(&file_format_function);
01241 
01242    return res;
01243 }

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

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

01220 {
01221    int res = 0;
01222 
01223    res |= ast_custom_function_unregister(&env_function);
01224    res |= ast_custom_function_unregister(&stat_function);
01225    res |= ast_custom_function_unregister(&file_function);
01226    res |= ast_custom_function_unregister(&file_count_line_function);
01227    res |= ast_custom_function_unregister(&file_format_function);
01228 
01229    return res;
01230 }


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

struct ast_module_info* ast_module_info = &__mod_info [static]

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

Referenced by load_module(), and unload_module().


Generated on Mon Jun 27 16:51:14 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7