/* * Configuration program for DAHDI Telephony Interface * * Written by Mark Spencer * Based on previous works, designs, and architectures conceived and * written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001-2008 Digium, Inc. * * All rights reserved. * * Primary Author: Mark Spencer * Radio Support by Jim Dixon */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tonezone.h" #include "dahdi_tools_version.h" #define CONFIG_FILENAME "/etc/dahdi/system.conf" #define MASTER_DEVICE "/dev/dahdi/ctl" #define NUM_SPANS DAHDI_MAX_SPANS #define NUM_TONES 15 /*! A sanity check for the timing parameter of the span. * * Note that each driver using it is still responsible for validating * that value. */ #define MAX_TIMING 255 /* Assume no more than 1024 dynamics */ #define NUM_DYNAMIC 1024 static int lineno=0; static FILE *cf; static char *filename=CONFIG_FILENAME; int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1]; int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0; int txgain = 0, rxgain = 0, deemp = 0, preemp = 0; int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ; static int toneindex = 1; #define DEBUG_READER (1 << 0) #define DEBUG_PARSER (1 << 1) #define DEBUG_APPLY (1 << 2) static int debug = 0; static int errcnt = 0; static int deftonezone = -1; static struct dahdi_lineconfig lc[DAHDI_MAX_SPANS]; static struct dahdi_chanconfig cc[DAHDI_MAX_CHANNELS]; static int only_span = 0; static int restrict_channels = 0; static int selected_channels[DAHDI_MAX_CHANNELS]; static int declared_spans[DAHDI_MAX_SPANS]; static struct dahdi_attach_echocan ae[DAHDI_MAX_CHANNELS]; static struct dahdi_dynamic_span zds[NUM_DYNAMIC]; static const char *sig[DAHDI_MAX_CHANNELS]; /* Signalling */ static int slineno[DAHDI_MAX_CHANNELS]; /* Line number where signalling specified */ static int fiftysixkhdlc[DAHDI_MAX_CHANNELS]; static int spans=0; static int dry_run = 0; static int verbose = 0; static int force = 0; static int stopmode = 0; static int numdynamic = 0; static char zonestoload[DAHDI_TONE_ZONE_MAX][10]; static int numzones = 0; static int fd = -1; static const char *lbostr[] = { "0 db (CSU)/0-133 feet (DSX-1)", "133-266 feet (DSX-1)", "266-399 feet (DSX-1)", "399-533 feet (DSX-1)", "533-655 feet (DSX-1)", "-7.5db (CSU)", "-15db (CSU)", "-22.5db (CSU)" }; static const char *laws[] = { "Default", "Mu-law", "A-law" }; static bool _are_all_spans_assigned(const char *device_path) { char attribute[1024]; int res; FILE *fp; int span_count; DIR *dirp; struct dirent *dirent; snprintf(attribute, sizeof(attribute) - 1, "%s/span_count", device_path); fp = fopen(attribute, "r"); if (NULL == fp) { fprintf(stderr, "Failed to open '%s'.\n", attribute); return false; } res = fscanf(fp, "%d", &span_count); fclose(fp); if (EOF == res) { fprintf(stderr, "Failed to read '%s'.\n", attribute); return false; } dirp = opendir(device_path); while (span_count) { dirent = readdir(dirp); if (NULL == dirent) break; if (!strncmp("span-", dirent->d_name, 5)) { --span_count; } } closedir(dirp); return (span_count > 0) ? false : true; } /** * are_all_spans_assigned - Look in sysfs to see if all spans for a device are assigned. * * Returns true if there are $span_count child spans of all devices, or false * otherwise. */ static bool are_all_spans_assigned(void) { DIR *dirp; struct dirent *dirent; bool res = true; char device_path[1024]; dirp = opendir("/sys/bus/dahdi_devices/devices"); if (!dirp) { /* If we cannot open dahdi_devices, either dahdi isn't loaded, * or we're using an older version of DAHDI that doesn't use * sysfs. */ return true; } while (true && res) { dirent = readdir(dirp); if (NULL == dirent) break; if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) continue; snprintf(device_path, sizeof(device_path)-1, "/sys/bus/dahdi_devices/devices/%s", dirent->d_name); res = _are_all_spans_assigned(device_path); } closedir(dirp); errno = 0; return res; } static bool wait_for_all_spans_assigned(unsigned long timeout_sec) { bool all_assigned = are_all_spans_assigned(); unsigned int timeout = 10*timeout_sec; while (!all_assigned && --timeout) { usleep(100000); all_assigned = are_all_spans_assigned(); } return all_assigned; } static const char *sigtype_to_str(const int sig) { switch (sig) { case 0: return "Unused"; case DAHDI_SIG_EM: return "E & M"; case DAHDI_SIG_EM_E1: return "E & M E1"; case DAHDI_SIG_FXSLS: return "FXS Loopstart"; case DAHDI_SIG_FXSGS: return "FXS Groundstart"; case DAHDI_SIG_FXSKS: return "FXS Kewlstart"; case DAHDI_SIG_FXOLS: return "FXO Loopstart"; case DAHDI_SIG_FXOGS: return "FXO Groundstart"; case DAHDI_SIG_FXOKS: return "FXO Kewlstart"; case DAHDI_SIG_CAS: return "CAS / User"; case DAHDI_SIG_DACS: return "DACS"; case DAHDI_SIG_DACS_RBS: return "DACS w/RBS"; case DAHDI_SIG_CLEAR: return "Clear channel"; case DAHDI_SIG_SLAVE: return "Slave channel"; case DAHDI_SIG_HDLCRAW: return "Raw HDLC"; case DAHDI_SIG_HDLCNET: return "Network HDLC"; case DAHDI_SIG_HDLCFCS: return "HDLC with FCS check"; case DAHDI_SIG_HARDHDLC: return "Hardware assisted D-channel"; case DAHDI_SIG_MTP2: return "MTP2"; default: return "Unknown"; } } static void clear_fields() { memset(rxtones,0,sizeof(rxtones)); memset(rxtags,0,sizeof(rxtags)); memset(txtones,0,sizeof(txtones)); bursttime = 0; debouncetime = 0; invertcor = 0; exttone = 0; txgain = 0; rxgain = 0; deemp = 0; preemp = 0; } static int error(char *fmt, ...) __attribute__ ((format(printf, 1, 2))); static int error(char *fmt, ...) { int res; static int shown=0; va_list ap; if (!shown) { fprintf(stderr, "Notice: Configuration file is %s\n", filename); shown++; } res = fprintf(stderr, "line %d: ", lineno); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); errcnt++; return res; } static char *trim(char *buf) { size_t len; while (*buf && (*buf < 33)) { buf++; } len = strlen(buf); while (len && buf[len-1] < 33) { buf[--len] = '\0'; } return buf; } static int skip_channel(int x) { if (restrict_channels) { if (!selected_channels[x]) return 1; } else { if (only_span && !declared_spans[only_span]) { fprintf(stderr, "Error: analog span %d given to '-S', without '-C' restriction.\n", only_span); exit(1); } } return 0; } static int parseargs(char *input, char *output[], int maxargs, char sep) { char *c; int pos=0; c = input; output[pos++] = c; while(*c) { while(*c && (*c != sep)) c++; if (*c) { *c = '\0'; c++; while(*c && (*c < 33)) c++; if (*c) { if (pos >= maxargs) return -1; output[pos] = c; trim(output[pos]); pos++; output[pos] = NULL; /* Return error if we have too many */ } else return pos; } } return pos; } int dspanconfig(char *keyword, char *args) { static char *realargs[10]; int res; int chans; int timing; res = parseargs(args, realargs, 4, ','); if (res != 4) { error("Incorrect number of arguments to 'dynamic' (should be ,
,, )\n"); return -1; } res = sscanf(realargs[2], "%d", &chans); if ((res == 1) && (chans < 1)) res = -1; if (res != 1) { error("Invalid number of channels '%s', should be a number > 0.\n", realargs[2]); return -1; } res = sscanf(realargs[3], "%d", &timing); if ((res == 1) && (timing < 0)) res = -1; if (res != 1) { error("Invalid timing '%s', should be a number > 0.\n", realargs[3]); return -1; } dahdi_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver)); dahdi_copy_string(zds[numdynamic].addr, realargs[1], sizeof(zds[numdynamic].addr)); zds[numdynamic].numchans = chans; zds[numdynamic].timing = timing; numdynamic++; return 0; } int spanconfig(char *keyword, char *args) { static char *realargs[10]; int res; int argc; int span; int timing; int i; argc = res = parseargs(args, realargs, 9, ','); if ((res < 5) || (res > 9)) { error("Incorrect number of arguments to 'span' (should be ,,,,[, crc4 | yellow [, yellow]])\n"); return -1; } res = sscanf(realargs[0], "%d", &span); if (res != 1) { error("Span number should be a valid span number, not '%s'\n", realargs[0]); return -1; } declared_spans[span] = 1; res = sscanf(realargs[1], "%d", &timing); if ((res != 1) || (timing < 0) || (timing > MAX_TIMING)) { error("Timing should be a number from 0 to %d, not '%s'\n", MAX_TIMING, realargs[1]); return -1; } res = sscanf(realargs[2], "%d", &lc[spans].lbo); if (res != 1) { error("Line build-out (LBO) should be a number from 0 to 7 (usually 0) not '%s'\n", realargs[2]); return -1; } if ((lc[spans].lbo < 0) || (lc[spans].lbo > 7)) { error("Line build-out should be in the range 0 to 7, not %d\n", lc[spans].lbo); return -1; } if (!strcasecmp(realargs[3], "d4")) { lc[spans].lineconfig |= DAHDI_CONFIG_D4; lc[spans].lineconfig &= ~DAHDI_CONFIG_ESF; lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS; } else if (!strcasecmp(realargs[3], "esf")) { lc[spans].lineconfig |= DAHDI_CONFIG_ESF; lc[spans].lineconfig &= ~DAHDI_CONFIG_D4; lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS; } else if (!strcasecmp(realargs[3], "ccs")) { lc[spans].lineconfig |= DAHDI_CONFIG_CCS; lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4); } else if (!strcasecmp(realargs[3], "cas")) { lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS; lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4); } else { error("Framing(T1)/Signalling(E1) must be one of 'd4', 'esf', 'cas' or 'ccs', not '%s'\n", realargs[3]); return -1; } if (!strcasecmp(realargs[4], "ami")) { lc[spans].lineconfig &= ~(DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_HDB3); lc[spans].lineconfig |= DAHDI_CONFIG_AMI; } else if (!strcasecmp(realargs[4], "b8zs")) { lc[spans].lineconfig |= DAHDI_CONFIG_B8ZS; lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3); } else if (!strcasecmp(realargs[4], "hdb3")) { lc[spans].lineconfig |= DAHDI_CONFIG_HDB3; lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS); } else { error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]); return -1; } for (i = 5; i < argc; i++) { if (!strcasecmp(realargs[i], "yellow")) lc[spans].lineconfig |= DAHDI_CONFIG_NOTOPEN; else if (!strcasecmp(realargs[i], "crc4")) lc[spans].lineconfig |= DAHDI_CONFIG_CRC4; else if (!strcasecmp(realargs[i], "nt")) lc[spans].lineconfig |= DAHDI_CONFIG_NTTE; else if (!strcasecmp(realargs[i], "te")) lc[spans].lineconfig &= ~DAHDI_CONFIG_NTTE; else if (!strcasecmp(realargs[i], "term")) lc[spans].lineconfig |= DAHDI_CONFIG_TERM; else { error("Remaining arguments may be any of: 'yellow', 'crc4', 'nt', 'te', 'term', not '%s'\n", realargs[i]); return -1; } } lc[spans].span = span; lc[spans].sync = timing; /* Valid span */ spans++; return 0; } int apply_channels(int chans[], char *argstr) { char *args[DAHDI_MAX_CHANNELS+1]; char *range[3]; int res,x, res2,y; int chan; int start, finish; char argcopy[256]; res = parseargs(argstr, args, DAHDI_MAX_CHANNELS, ','); if (res < 0) { error("Too many arguments... Max is %d\n", DAHDI_MAX_CHANNELS); return -1; } for (x=0;x-.\n", args[x]); return -1; } res2 =sscanf(range[0], "%d", &start); if (res2 != 1) { error("Syntax error. Start of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1); return -1; } else if ((start < 1) || (start >= DAHDI_MAX_CHANNELS)) { error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, start); return -1; } res2 =sscanf(range[1], "%d", &finish); if (res2 != 1) { error("Syntax error. End of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1); return -1; } else if ((finish < 1) || (finish >= DAHDI_MAX_CHANNELS)) { error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, finish); return -1; } if (start > finish) { error("Range '%s' should start before it ends\n", args[x]); return -1; } for (y=start;y<=finish;y++) chans[y]=1; } else { /* It's a single channel */ res2 =sscanf(args[x], "%d", &chan); if (res2 != 1) { error("Syntax error. Channel should be a number from 1 to %d, not '%s'\n", DAHDI_MAX_CHANNELS - 1, args[x]); return -1; } else if ((chan < 1) || (chan >= DAHDI_MAX_CHANNELS)) { error("Channel must be between 1 and %d (not '%d')\n", DAHDI_MAX_CHANNELS - 1, chan); return -1; } chans[chan]=1; } } return res; } int parse_idle(int *i, char *s) { char a,b,c,d; if (s) { if (sscanf(s, "%c%c%c%c", &a,&b,&c,&d) == 4) { if (((a == '0') || (a == '1')) && ((b == '0') || (b == '1')) && ((c == '0') || (c == '1')) && ((d == '0') || (d == '1'))) { *i = 0; if (a == '1') *i |= DAHDI_ABIT; if (b == '1') *i |= DAHDI_BBIT; if (c == '1') *i |= DAHDI_CBIT; if (d == '1') *i |= DAHDI_DBIT; return 0; } } } error("CAS Signalling requires idle definition in the form ':xxxx' at the end of the channel definition, where xxxx represent the a, b, c, and d bits\n"); return -1; } static int parse_channel(char *channel, int *startchan) { if (!channel || (sscanf(channel, "%d", startchan) != 1) || (*startchan < 1)) { error("DACS requires a starting channel in the form ':x' where x is the channel\n"); return -1; } return 0; } static int chanconfig(char *keyword, char *args) { int chans[DAHDI_MAX_CHANNELS]; int res = 0; int x; int master=0; int dacschan = 0; char *idle; bzero(chans, sizeof(chans)); strtok(args, ":"); idle = strtok(NULL, ":"); if (!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) { res = parse_channel(idle, &dacschan); } if (!res) res = apply_channels(chans, args); if (res <= 0) return -1; for (x=1;x= DAHDI_TONE_ZONE_MAX) { error("Too many tone zones specified\n"); return 0; } dahdi_copy_string(zonestoload[numzones++], args, sizeof(zonestoload[0])); return 0; } static int defaultzone(char *keyword, char *args) { struct tone_zone *z; if (!(z = tone_zone_find(args))) { error("No such tone zone known: %s\n", args); return 0; } deftonezone = z->zone; return 0; } #if 0 static int unimplemented(char *keyword, char *args) { fprintf(stderr, "Warning: '%s' is not yet implemented\n", keyword); return 0; } #endif /* Radio functions */ int ctcss(char *keyword, char *args) { static char *realargs[10]; int res; int rxtone; int rxtag; int txtone; int isdcs = 0; res = parseargs(args, realargs, 3, ','); if (res != 3) { error("Incorrect number of arguments to 'ctcss' (should be ,,)\n"); return -1; } res = sscanf(realargs[0], "%d", &rxtone); if ((res == 1) && (rxtone < 1)) res = -1; if (res != 1) { error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]); return -1; } res = sscanf(realargs[1], "%d", &rxtag); if ((res == 1) && (rxtag < 0)) res = -1; if (res != 1) { error("Invalid rxtag '%s', should be a number > 0.\n", realargs[1]); return -1; } if ((*realargs[2] == 'D') || (*realargs[2] == 'd')) { realargs[2]++; isdcs = 0x8000; } res = sscanf(realargs[2], "%d", &txtone); if ((res == 1) && (rxtag < 0)) res = -1; if (res != 1) { error("Invalid txtone '%s', should be a number > 0.\n", realargs[2]); return -1; } if (toneindex >= NUM_TONES) { error("Cannot specify more then %d CTCSS tones\n",NUM_TONES); return -1; } rxtones[toneindex] = rxtone; rxtags[toneindex] = rxtag; txtones[toneindex] = txtone | isdcs; toneindex++; return 0; } int dcsrx(char *keyword, char *args) { static char *realargs[10]; int res; int rxtone; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'dcsrx' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &rxtone); if ((res == 1) && (rxtone < 1)) res = -1; if (res != 1) { error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]); return -1; } rxtones[0] = rxtone; return 0; } int tx(char *keyword, char *args) { static char *realargs[10]; int res; int txtone; int isdcs = 0; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'tx' (should be )\n"); return -1; } if ((*realargs[0] == 'D') || (*realargs[0] == 'd')) { realargs[0]++; isdcs = 0x8000; } res = sscanf(realargs[0], "%d", &txtone); if ((res == 1) && (txtone < 1)) res = -1; if (res != 1) { error("Invalid tx (tone) '%s', should be a number > 0.\n", realargs[0]); return -1; } txtones[0] = txtone | isdcs; return 0; } int debounce_time(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'debouncetime' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 1)) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } debouncetime = val; return 0; } int burst_time(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'bursttime' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 1)) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } bursttime = val; return 0; } int tx_gain(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'txgain' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } txgain = val; return 0; } int rx_gain(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'rxgain' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } rxgain = val; return 0; } int de_emp(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'de-emp' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 1)) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } deemp = val; return 0; } int pre_emp(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'pre_emp' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 1)) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } preemp = val; return 0; } int invert_cor(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'invertcor' (should be )\n"); return -1; } if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1; else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0; else { res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 0)) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } } invertcor = (val > 0); return 0; } int ext_tone(char *keyword, char *args) { static char *realargs[10]; int res; int val; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'exttone' (should be )\n"); return -1; } if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1; else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0; else if ((*realargs[0] == 'i') || (*realargs[0] == 'I')) val = 2; else { res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 0)) res = -1; if (val > 2) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } } exttone = val; return 0; } int cor_thresh(char *keyword, char *args) { static char *realargs[10]; int res; int val; int x = 0; res = parseargs(args, realargs, 1, ','); if (res != 1) { error("Incorrect number of arguments to 'corthresh' (should be )\n"); return -1; } res = sscanf(realargs[0], "%d", &val); if ((res == 1) && (val < 1)) res = -1; for(x = 0; corthreshes[x]; x++) { if (corthreshes[x] == val) break; } if (!corthreshes[x]) res = -1; if (res != 1) { error("Invalid value '%s', should be a number > 0.\n", realargs[0]); return -1; } corthresh = x + 1; return 0; } static int rad_chanconfig(char *keyword, char *args) { int chans[DAHDI_MAX_CHANNELS]; int res = 0; int x,i,n; struct dahdi_radio_param p; int chanfd; toneindex = 1; bzero(chans, sizeof(chans)); res = apply_channels(chans, args); if (res <= 0) return -1; for (x=1;x 1) { printf("\nChannel map:\n\n"); for (x=1;x -- Use instead of " CONFIG_FILENAME "\n" " -d [level] -- Generate debugging output. (Default level is 1.)\n" " -f -- Always reconfigure every channel\n" " -h -- Generate this help statement\n" " -s -- Shutdown spans only\n" " -t -- Test mode only, do not apply\n" " -C -- Only configure specified channels\n" " -S -- Only configure specified span\n" " -v -- Verbose (more -v's means more verbose)\n" ,c); exit(exitcode); } static int chan_restrict(char *str) { if (apply_channels(selected_channels, str) < 0) return 0; restrict_channels = 1; return 1; } static int span_restrict(char *str) { long spanno; char *endptr; spanno = strtol(str, &endptr, 10); if (endptr == str) { fprintf(stderr, "Missing valid span number after '-S'\n"); return 0; } if (*endptr != '\0') { fprintf(stderr, "Extra garbage after span number in '-S'\n"); return 0; } only_span = spanno; return 1; } static const char *SEM_NAME = "dahdi_cfg"; static sem_t *lock = SEM_FAILED; static void signal_handler(int signal) { if (SEM_FAILED != lock) { sem_unlink(SEM_NAME); } /* The default handler should have been restored before this handler was * called, so we can let the "normal" processing finish the cleanup. */ raise(signal); } int main(int argc, char *argv[]) { int c; char *buf; char *key, *value; int x,found; int exit_code = 0; struct sigaction act; while((c = getopt(argc, argv, "fthc:vsd::C:S:")) != -1) { switch(c) { case 'c': filename=optarg; break; case 'h': usage(argv[0], 0); break; case '?': usage(argv[0], 1); break; case 'v': verbose++; break; case 'f': force++; break; case 't': dry_run = 1; break; case 's': stopmode = 1; break; case 'C': if (!chan_restrict(optarg)) usage(argv[0], 1); break; case 'S': if (!span_restrict(optarg)) usage(argv[0], 1); break; case 'd': if (optarg) debug = atoi(optarg); else debug = 1; break; } } if (verbose) { fprintf(stderr, "%s\n", dahdi_tools_version); } if (!restrict_channels && only_span) { error("-S requires -C\n"); goto finish; } if (!restrict_channels && !only_span) { bool all_assigned = wait_for_all_spans_assigned(5); if (!all_assigned) { fprintf(stderr, "Timeout waiting for all spans to be assigned.\n"); } } if (fd == -1) fd = open(MASTER_DEVICE, O_RDWR); if (fd < 0) { error("Unable to open master device '%s'\n", MASTER_DEVICE); goto finish; } if (strcmp(filename, "-") == 0) cf = fdopen(STDIN_FILENO, "r"); else cf = fopen(filename, "r"); if (cf) { while((buf = readline())) { if (*buf == 10) /* skip new line */ continue; if (debug & DEBUG_READER) fprintf(stderr, "Line %d: %s\n", lineno, buf); if ((value = strchr(buf, '='))) { *value++ = '\0'; value = trim(value); key = trim(buf); } if (!value || !*value || !*key) { error("Syntax error. Should be =\n"); continue; } if (debug & DEBUG_PARSER) fprintf(stderr, "Keyword: [%s], Value: [%s]\n", key, value); found = 0; for (x = 0; x < sizeof(handlers) / sizeof(handlers[0]); x++) { if (!strcasecmp(key, handlers[x].keyword)) { found++; handlers[x].func(key, value); break; } } if (!found) error("Unknown keyword '%s'\n", key); } if (debug & DEBUG_READER) fprintf(stderr, "\n"); /* fclose(cf); // causes seg fault (double free) */ } else { error("Unable to open configuration file '%s'\n", filename); } finish: if (errcnt) { fprintf(stderr, "\n%d error(s) detected\n\n", errcnt); exit(1); } if (verbose) { printconfig(fd); } if (dry_run) exit(0); if (debug & DEBUG_APPLY) { printf("About to open Master device\n"); fflush(stdout); } sigemptyset(&act.sa_mask); act.sa_handler = signal_handler; act.sa_flags = SA_RESETHAND; if (sigaction(SIGTERM, &act, NULL) == -1) { perror("Failed to install SIGTERM handler."); exit(1); } if (sigaction(SIGINT, &act, NULL) == -1) { perror("Failed to install SIGINT handler."); exit(1); } lock = sem_open(SEM_NAME, O_CREAT, O_RDWR, 1); if (SEM_FAILED == lock) { perror("Unable to create 'dahdi_cfg' mutex"); exit_code = 1; goto release_sem; } if (-1 == sem_wait(lock)) { perror("Failed to wait for 'dahdi_cfg' mutex"); exit_code = 1; goto unlink_sem; } if (!restrict_channels && !only_span) { for (x=0;x> 16; if (cc[x].sigtype != current_state.sigtype) { needupdate++; if (verbose > 1) printf("Changing signalling on channel %d from %s to %s\n", cc[x].chan, sigtype_to_str(current_state.sigtype), sigtype_to_str(cc[x].sigtype)); } if ((cc[x].deflaw != DAHDI_LAW_DEFAULT) && (cc[x].deflaw != current_state.curlaw)) { needupdate++; if (verbose > 1) printf("Changing law on channel %d from %s to %s\n", cc[x].chan, laws[current_state.curlaw], laws[cc[x].deflaw]); } if (cc[x].master != master) { needupdate++; if (verbose > 1) printf("Changing master of channel %d from %d to %d\n", cc[x].chan, master, cc[x].master); } if (cc[x].idlebits != current_state.idlebits) { needupdate++; if (verbose > 1) printf("Changing idle bits of channel %d from %d to %d\n", cc[x].chan, current_state.idlebits, cc[x].idlebits); } } if (needupdate && ioctl(fd, DAHDI_CHANCONFIG, &cc[x])) { fprintf(stderr, "DAHDI_CHANCONFIG failed on channel %d: %s (%d)\n", x, strerror(errno), errno); if (errno == EINVAL) { /* give helpful suggestions on signaling errors */ fprintf(stderr, "Selected signaling not " "supported\n"); fprintf(stderr, "Possible causes:\n"); switch(cc[x].sigtype) { case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: case DAHDI_SIG_FXOGS: fprintf(stderr, "\tFXO signaling is " "being used on a FXO interface" " (use a FXS signaling variant" ")\n"); fprintf(stderr, "\tRBS signaling is " "being used on a E1 CCS span" "\n"); break; case DAHDI_SIG_FXSKS: case DAHDI_SIG_FXSLS: case DAHDI_SIG_FXSGS: fprintf(stderr, "\tFXS signaling is " "being used on a FXS interface" " (use a FXO signaling variant" ")\n"); fprintf(stderr, "\tRBS signaling is " "being used on a E1 CCS span" "\n"); break; case DAHDI_SIG_EM: fprintf(stderr, "\te&m signaling is " "being used on a E1 line (use" " e&me1)\n"); break; case DAHDI_SIG_EM_E1: fprintf(stderr, "\te&me1 signaling is " "being used on a T1 line (use " "e&m)\n"); fprintf(stderr, "\tRBS signaling is " "being used on a E1 CCS span" "\n"); break; case DAHDI_SIG_HARDHDLC: fprintf(stderr, "\thardhdlc is being " "used on a TE12x (use dchan)\n" ); break; case DAHDI_SIG_HDLCFCS: fprintf(stderr, "\tdchan is being used" " on a BRI span (use hardhdlc)" "\n"); break; default: break; } fprintf(stderr, "\tSignaling is being assigned" " to channel 16 of an E1 CAS span\n"); } close(fd); exit_code = 1; goto release_sem; } ae[x].chan = x; if (verbose) { printf("Setting echocan for channel %d to %s\n", ae[x].chan, ae[x].echocan[0] ? ae[x].echocan : "none"); } if (ioctl(fd, DAHDI_ATTACH_ECHOCAN, &ae[x])) { fprintf(stderr, "DAHDI_ATTACH_ECHOCAN failed on channel %d: %s (%d)\n", x, strerror(errno), errno); close(fd); exit_code = 1; goto release_sem; } } if (0 == numzones) { /* Default to the us zone if one wasn't specified. */ dahdi_copy_string(zonestoload[numzones++], "us", sizeof(zonestoload[0])); deftonezone = 0; } for (x=0;x -1) { if (ioctl(fd, DAHDI_DEFAULTZONE, &deftonezone)) { fprintf(stderr, "DAHDI_DEFAULTZONE failed: %s (%d)\n", strerror(errno), errno); close(fd); exit_code = 1; goto release_sem; } } for (x=0;x