Wed May 16 06:35:49 2012

Asterisk developer's documentation


func_env.c File Reference

Environment related dialplan functions. More...

#include "asterisk.h"
#include <sys/stat.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/file.h"

Include dependency graph for func_env.c:

Go to the source code of this file.

Defines

#define LINE_COUNTER(cptr, term, counter)

Enumerations

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

Functions

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

Variables

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


Detailed Description

Environment related dialplan functions.

Definition in file func_env.c.


Define Documentation

#define LINE_COUNTER ( cptr,
term,
counter   ) 

Definition at line 407 of file func_env.c.

Referenced by file_read(), and file_write().


Enumeration Type Documentation

Enumerator:
FF_UNKNOWN 
FF_UNIX 
FF_DOS 
FF_MAC 

Definition at line 300 of file func_env.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1270 of file func_env.c.

static void __unreg_module ( void   )  [static]

Definition at line 1270 of file func_env.c.

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

Definition at line 307 of file func_env.c.

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

Referenced by file_count_line().

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

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

Definition at line 227 of file func_env.c.

References ast_copy_string().

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

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

Definition at line 243 of file func_env.c.

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

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

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

Definition at line 421 of file func_env.c.

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

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

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

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

Definition at line 382 of file func_env.c.

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

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

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

Definition at line 461 of file func_env.c.

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

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

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

Definition at line 468 of file func_env.c.

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

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

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

Definition at line 727 of file func_env.c.

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

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

const char * format2term ( enum file_format  f  ) 

Definition at line 721 of file func_env.c.

Referenced by file_write().

00722 {
00723    const char *term[] = { "", "\n", "\r\n", "\r" };
00724    return term[f + 1];
00725 }

static int load_module ( void   )  [static]

Definition at line 1257 of file func_env.c.

References ast_custom_function_register.

01258 {
01259    int res = 0;
01260 
01261    res |= ast_custom_function_register(&env_function);
01262    res |= ast_custom_function_register(&stat_function);
01263    res |= ast_custom_function_register(&file_function);
01264    res |= ast_custom_function_register(&file_count_line_function);
01265    res |= ast_custom_function_register(&file_format_function);
01266 
01267    return res;
01268 }

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

Definition at line 257 of file func_env.c.

References ast_copy_string(), and strsep().

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

static int unload_module ( void   )  [static]

Definition at line 1244 of file func_env.c.

References ast_custom_function_unregister().

01245 {
01246    int res = 0;
01247 
01248    res |= ast_custom_function_unregister(&env_function);
01249    res |= ast_custom_function_unregister(&stat_function);
01250    res |= ast_custom_function_unregister(&file_function);
01251    res |= ast_custom_function_unregister(&file_count_line_function);
01252    res |= ast_custom_function_unregister(&file_format_function);
01253 
01254    return res;
01255 }


Variable Documentation

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

Definition at line 1270 of file func_env.c.

Definition at line 1270 of file func_env.c.

Initial value:

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

Definition at line 1214 of file func_env.c.

Initial value:

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

Definition at line 1232 of file func_env.c.

Initial value:

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

Definition at line 1238 of file func_env.c.

Initial value:

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

Definition at line 1226 of file func_env.c.

Initial value:

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

Definition at line 1220 of file func_env.c.


Generated on Wed May 16 06:35:49 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6