D-Modem/slmodemd/modem_cmdline.c

297 lines
7.5 KiB
C

/*
*
* Copyright (c) 2002, Smart Link Ltd.
* Copyright (c) 2021, Aon plc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* 3. Neither the name of the Smart Link Ltd. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
*
* modem_cmdline.c -- simple command line processor,
* define config parameters.
*
* Author: Sasha K (sashak@smlink.com)
*
*
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <modem.h>
#include <modem_homolog.h>
#include <modem_debug.h>
#define PR_INFO(fmt...) fprintf(stderr, fmt )
/* global config data */
/* modem.c */
extern const char *modem_default_country;
/* modem_debug.c */
extern unsigned int modem_debug_level;
extern unsigned int modem_debug_logging;
/* config parameters */
const char *modem_dev_name = NULL;
const char *modem_default_dev_name = "/tmp/ttySL0";
const char *modem_alsa_dev_name = "modem:1";
const char *modem_exec = NULL;
unsigned int need_realtime = 0;
#ifdef MODEM_CONFIG_RING_DETECTOR
unsigned int ring_detector = 0;
#endif
unsigned int use_alsa = 0;
const char *modem_group = "dialout";
unsigned int use_short_buffer = 0;
mode_t modem_perm = 0660;
enum {
OPT_HELP = 0,
OPT_USAGE,
OPT_VERSION,
OPT_COUNTRY,
OPT_COUNTRYLIST,
OPT_ALSA,
OPT_GROUP,
OPT_PERM,
#ifdef MODEM_CONFIG_RING_DETECTOR
OPT_RINGDET,
#endif
OPT_USER,
OPT_SHORTBUF,
OPT_DEBUG,
OPT_LOG,
OPT_EXEC,
OPT_LAST
};
static struct opt {
int ch;
const char *name;
const char *desc;
enum {NONE=0,MANDATORY,OPTIONAL} arg;
enum {INTEGER,STRING} arg_type;
const char *arg_val;
unsigned found;
} opt_list[] = {
{'h',"help","this usage"},
{'u',"usage","this usage"},
{'v',"version","show version and exit"},
{'c',"country","default modem country name",MANDATORY,STRING,"USA"},
{ 0 ,"countrylist","show list of supported countries"},
{'a',"alsa","ALSA mode (see README for howto)"},
{'g',"group","Modem TTY group",MANDATORY,STRING,"dialout"},
{'p',"perm","Modem TTY permission",MANDATORY,INTEGER,"0660"},
#ifdef MODEM_CONFIG_RING_DETECTOR
{'r',"ringdetector","with internal ring detector (software)"},
#endif
{'n',"nortpriority","run with regular priority"},
{'s',"shortbuffer","use short buffer (4 periods length)"},
{'d',"debug","debug level (developers only, for ./sl...)",OPTIONAL,INTEGER,"0"},
{'l',"log","logging mode",OPTIONAL,INTEGER,"5"},
{'e',"exec","path to external application that transmits audio over the socket (required)",MANDATORY,STRING,"./d-modem"},
{}
};
static void usage(const char *prog_name)
{
struct opt *opt;
PR_INFO("Usage: %s [option...] <device>\n"
"Where 'device' is name of modem device (default `%s')\n"
" and 'option' may be:\n", prog_name, modem_default_dev_name);
for (opt = opt_list ; opt->name ; opt++ ) {
int n = 0;
if(opt->ch)
n = PR_INFO(" -%c, ",opt->ch);
else
n = PR_INFO(" ");
n += PR_INFO("--%s%s ",opt->name,opt->arg?"=VAL":"");
n += PR_INFO("%*s%s",24-n,"",opt->desc);
if(opt->arg) {
n+= PR_INFO(" (default `%s')",opt->arg_val);
}
PR_INFO("\n");
}
exit(1);
}
static void opt_parse(int argc, char *argv[])
{
const char *prog_name;
const char *dev_name = NULL;
struct opt *opt;
char *p, *arg;
int found, i;
prog_name = argv[0];
for( i = 1 ; i < argc ; i++ ) {
p = argv[i];
if(*p != '-') {
if(dev_name)
usage(prog_name);
dev_name = p;
continue;
}
found = 0;
arg = NULL;
do { p++; } while( *p == '-' );
for (opt = opt_list ; opt->name ; opt++ ) {
if(!strncmp(p,opt->name,strlen(opt->name)) ||
(opt->ch && *p == opt->ch) ) {
char *q;
if(!strncmp(p,opt->name,strlen(opt->name)))
q = p + strlen(opt->name);
else
q = p + 1;
if( *q == '\0' )
found = 1;
else if (*q == '=' && opt->arg ) {
arg = q + 1;
found = 1;
}
else if(isdigit(*q) && opt->arg ) {
arg = q;
found = 1;
}
}
if ( !found )
continue;
if ( arg && !opt->arg )
usage(prog_name);
if (!arg && opt->arg &&
(i < argc - 1 && *argv[i+1] != '-') &&
(!opt->arg_type == INTEGER || isdigit(*argv[i+1])))
arg = argv[++i];
if(!arg && opt->arg == MANDATORY)
usage(prog_name);
opt->found++;
if(opt->arg && arg)
opt->arg_val = arg;
break;
}
if(!found)
usage(prog_name);
}
if(dev_name)
modem_dev_name = dev_name;
}
void modem_cmdline(int argc, char *argv[])
{
const char *prog_name = argv[0];
int val;
opt_parse(argc,argv);
if(opt_list[OPT_HELP].found ||
opt_list[OPT_USAGE].found )
usage(prog_name);
if(opt_list[OPT_VERSION].found) {
extern void modem_print_version();
modem_print_version();
exit(0);
}
if(opt_list[OPT_COUNTRYLIST].found) {
const struct homolog_set *s ;
for( s = homolog_set; s->name ; s++ ) {
PR_INFO("%02x: %s\n",s->id,s->name);
}
exit(0);
}
if(opt_list[OPT_COUNTRY].found)
modem_default_country = opt_list[OPT_COUNTRY].arg_val;
if(opt_list[OPT_ALSA].found) {
#ifndef SUPPORT_ALSA
PR_INFO("ALSA support is not compiled in (see README for howto).\n");
exit(1);
#endif
use_alsa = 1;
}
if(opt_list[OPT_GROUP].found)
modem_group = opt_list[OPT_GROUP].arg_val;
if(opt_list[OPT_PERM].found) {
val = strtol(opt_list[OPT_PERM].arg_val,NULL,8);
if (val <= 0)
usage(prog_name);
modem_perm = val;
}
#ifdef MODEM_CONFIG_RING_DETECTOR
if(opt_list[OPT_RINGDET].found)
ring_detector = 1;
#endif
if(opt_list[OPT_USER].found)
need_realtime = 0;
if(opt_list[OPT_SHORTBUF].found)
use_short_buffer = 1;
if(opt_list[OPT_DEBUG].found) {
modem_debug_level = 1 ;
if(opt_list[OPT_DEBUG].arg_val &&
(val= strtol(opt_list[OPT_DEBUG].arg_val,NULL,0)) > 0 )
modem_debug_level = val;
}
if(opt_list[OPT_LOG].found) {
modem_debug_logging = 5;
if(opt_list[OPT_LOG].arg_val &&
(val= strtol(opt_list[OPT_LOG].arg_val,NULL,0)) > 0 )
modem_debug_logging = val;
}
if(opt_list[OPT_EXEC].found) {
modem_exec = opt_list[OPT_EXEC].arg_val;
} else {
usage(prog_name);
}
if(!modem_dev_name) {
modem_dev_name = use_alsa ? modem_alsa_dev_name : modem_default_dev_name;
}
}