sercmd.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License 
00024  * along with this program; if not, write to the Free Software 
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  */
00027 /*
00028  * send commands using binrpc
00029  *
00030  * History:
00031  * --------
00032  *  2006-02-14  created by andrei
00033  *  2009-06-29  command line completion for cfg groups and vars (andrei)
00034  *  2009-06-30  command line completion for mi cmds (andrei)
00035  *  2010-08-08  command line completion for counters/statistic (andrei)
00036  */
00037 
00038 
00039 #include <stdlib.h> /* exit, abort */
00040 #include <stdio.h>
00041 #include <string.h>
00042 #include <unistd.h>
00043 #include <errno.h>
00044 #include <ctype.h> /* isprint */
00045 #include <sys/socket.h>
00046 #include <sys/un.h> /* unix sock*/
00047 #include <netinet/in.h> /* udp sock */
00048 #include <sys/uio.h> /* writev */
00049 #include <netdb.h> /* gethostbyname */
00050 #include <time.h> /* time */
00051 
00052 #ifdef USE_READLINE
00053 #include <readline/readline.h>
00054 #include <readline/history.h>
00055 
00056 #define USE_CFG_VARS /* cfg group and vars completion */
00057 #define USE_MI  /* mi completion */
00058 #define USE_COUNTERS /* counters/statistics completion */
00059 #endif
00060 
00061 #include "parse_listen_id.h"
00062 #include "license.h"
00063 
00064 #include "../../modules/ctl/ctl_defaults.h" /* default socket & port */
00065 #include "../../modules/ctl/binrpc.h"
00066 #include "../../modules/ctl/binrpc.c" /* ugly hack */
00067 
00068 
00069 #ifndef NAME
00070 #define NAME    "sercmd"
00071 #endif
00072 #ifndef VERSION
00073 #define VERSION "0.2"
00074 #endif
00075 
00076 #define IOVEC_CNT 20
00077 #define MAX_LINE_SIZE 16384 /* for non readline mode */
00078 #define MAX_REPLY_SIZE 65536
00079 #define MAX_BODY_SIZE  65536
00080 #define MAX_BINRPC_ARGS 256
00081 
00082 
00083 #ifndef UNIX_PATH_MAX
00084 #define UNIX_PATH_MAX 108
00085 #endif
00086 
00087 static char id[]="$Id$";
00088 static char version[]= NAME " " VERSION;
00089 static char compiled[]= __TIME__ " " __DATE__;
00090 static char help_msg[]="\
00091 Usage: " NAME " [options][-s address] [ cmd ]\n\
00092 Options:\n\
00093     -s address  unix socket name or host name to send the commands on\n\
00094     -R name     force reply socket name, for the unix datagram socket mode\n\
00095     -D dir      create the reply socket in the directory <dir> if no reply \n\
00096                 socket is forced (-R) and a unix datagram socket is selected\n\
00097                 as the transport\n\
00098     -f format   print the result using format. Format is a string containing\n\
00099                 %v at the places where values read from the reply should be\n\
00100                 substituted. To print '%v', escape it using '%': %%v.\n\
00101     -v          Verbose       \n\
00102     -V          Version number\n\
00103     -h          This help message\n\
00104 address:\n\
00105     [proto:]name[:port]   where proto is one of tcp, udp, unixs or unixd\n\
00106                           e.g.:  tcp:localhost:2048 , unixs:/tmp/ser_ctl\n\
00107 cmd:\n\
00108     method  [arg1 [arg2...]]\n\
00109 arg:\n\
00110      string or number; to force a number to be interpreted as string \n\
00111      prefix it by \"s:\", e.g. s:1\n\
00112 Examples:\n\
00113         " NAME " -s unixs:/tmp/ser_unix system.listMethods\n\
00114         " NAME " -f \"pid: %v  desc: %v\\n\" -s udp:localhost:2047 core.ps \n\
00115         " NAME " ps  # uses default ctl socket \n\
00116         " NAME "     # enters interactive mode on the default socket \n\
00117         " NAME " -s tcp:localhost # interactive mode, default port \n\
00118 ";
00119 
00120 
00121 int verbose=0;
00122 char* reply_socket=0; /* unix datagram reply socket name */
00123 char* sock_dir=0;     /* same as above, but only the directory */
00124 char* unix_socket=0;
00125 struct sockaddr_un mysun;
00126 int quit; /* used only in interactive mode */
00127 
00128 struct binrpc_val* rpc_array;
00129 int rpc_no=0;
00130 
00131 #ifdef USE_CFG_VARS
00132 
00133 struct binrpc_val* cfg_vars_array;
00134 int cfg_vars_no;
00135 
00136 struct cfg_var_grp{
00137         struct cfg_var_grp* next;
00138         str grp_name; 
00139         str* var_names; 
00140         int var_no;
00141 };
00142 
00143 struct cfg_var_grp* cfg_grp_lst; 
00144 struct cfg_var_grp* crt_cfg_grp;
00145 #endif /* USE_CFG_VARS */
00146 
00147 #ifdef USE_MI
00148 struct binrpc_val* mi_which_array;
00149 int mi_which_no;
00150 
00151 str* mi_cmds;
00152 int mi_cmds_no;
00153 #endif /* USE_MI */
00154 
00155 #ifdef USE_COUNTERS
00156 struct binrpc_val* cnt_grps_array; /* response array */
00157 int cnt_grps_no; /* number of response records */
00158 
00159 struct cnt_var_grp {
00160         struct cnt_var_grp * next;
00161         str grp_name;
00162         str* var_names; 
00163         int var_no;
00164         struct binrpc_val* cnt_vars_array; /* var_name will point here */
00165         int cnt_vars_no; /* cnt_vars_array size (no. of response records) */
00166 };
00167 
00168 struct cnt_var_grp* cnt_grp_lst; /* counters groups list, allong with vars */
00169 struct cnt_var_grp* crt_cnt_grp;
00170 #endif /* USE_COUNTERS */
00171 
00172 
00173 
00174 #define IOV_SET(vect, str) \
00175         do{\
00176                 (vect).iov_base=(str); \
00177                 (vect).iov_len=strlen((str)); \
00178         }while(0)
00179 
00180 
00181 #define INT2STR_MAX_LEN  (19+1+1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */
00182 
00183 /* returns a pointer to a static buffer containing l in asciiz & sets len */
00184 static inline char* int2str(unsigned int l, int* len)
00185 {
00186         static char r[INT2STR_MAX_LEN];
00187         int i;
00188         
00189         i=INT2STR_MAX_LEN-2;
00190         r[INT2STR_MAX_LEN-1]=0; /* null terminate */
00191         do{
00192                 r[i]=l%10+'0';
00193                 i--;
00194                 l/=10;
00195         }while(l && (i>=0));
00196         if (l && (i<0)){
00197                 fprintf(stderr, "BUG: int2str: overflow\n");
00198         }
00199         if (len) *len=(INT2STR_MAX_LEN-2)-i;
00200         return &r[i+1];
00201 }
00202 
00203 
00204 
00205 static char* trim_ws(char* l)
00206 {
00207         char* ret;
00208         
00209         for(;*l && ((*l==' ')||(*l=='\t')||(*l=='\n')||(*l=='\r')); l++);
00210         ret=l;
00211         if (*ret==0) return ret;
00212         for(l=l+strlen(l)-1; (l>ret) && 
00213                         ((*l==' ')||(*l=='\t')||(*l=='\n')||(*l=='\r')); l--);
00214         *(l+1)=0;
00215         return ret;
00216 }
00217 
00218 
00219 
00220 int gen_cookie()
00221 {
00222         return rand();
00223 }
00224 
00225 
00226 
00227 struct binrpc_cmd{
00228         char* method;
00229         int argc;
00230         struct binrpc_val argv[MAX_BINRPC_ARGS];
00231 };
00232 
00233 
00234 struct cmd_alias{
00235         char* name;
00236         char* method;
00237         char* format; /* reply print format */
00238 };
00239 
00240 
00241 struct sercmd_builtin{
00242         char* name;
00243         int (*f)(int, struct binrpc_cmd*);
00244         char* doc;
00245 };
00246 
00247 
00248 static int sercmd_help(int s, struct binrpc_cmd* cmd);
00249 static int sercmd_ver(int s, struct binrpc_cmd* cmd);
00250 static int sercmd_quit(int s, struct binrpc_cmd* cmd);
00251 static int sercmd_warranty(int s, struct binrpc_cmd* cmd);
00252 
00253 
00254 static struct cmd_alias cmd_aliases[]={
00255         {       "ps",                   "core.ps",                              "%v\t%v\n"      },
00256         {       "list",                 "system.listMethods",   0                       },
00257         {       "ls",                   "system.listMethods",   0                       },
00258         {       "server",               "core.version",                 0                       },
00259         {       "serversion",   "core.version",                 0                       },
00260         {       "who",                  "ctl.who",                              "[%v] %v: %v %v -> %v %v\n"},
00261         {       "listen",               "ctl.listen",                   "[%v] %v: %v %v\n"},
00262         {       "dns_mem_info",         "dns.mem_info",                 "%v / %v\n"},
00263         {       "dns_debug",    "dns.debug",                    
00264                                         "%v (%v): size=%v ref=%v expire=%vs last=%vs ago f=%v\n"},
00265         {       "dns_debug_all",        "dns.debug_all",                        
00266                         "%v (%v) [%v]: size=%v ref=%v expire=%vs last=%vs ago f=%v\n"
00267                         "\t\t%v:%v expire=%vs f=%v\n"},
00268         {       "dst_blacklist_mem_info",       "dst_blacklist.mem_info",       "%v / %v\n"},
00269         {       "dst_blacklist_debug",          "dst_blacklist.debug",  
00270                 "%v:%v:%v expire:%v flags: %v\n"},
00271         {0,0,0}
00272 };
00273 
00274 
00275 static struct sercmd_builtin builtins[]={
00276         {       "?",            sercmd_help, "help"},
00277         {       "help",         sercmd_help, "displays help for a command"},
00278         {       "version",      sercmd_ver,  "displays " NAME "version"},
00279         {       "quit",         sercmd_quit, "exits " NAME },
00280         {       "exit",         sercmd_quit, "exits " NAME },
00281         {       "warranty",             sercmd_warranty, "displays " NAME "'s warranty info"},
00282         {       "license",              sercmd_warranty, "displays " NAME "'s license"},
00283         {0,0}
00284 };
00285 
00286 
00287 
00288 #ifdef USE_READLINE
00289 
00290 enum complete_states {
00291         COMPLETE_INIT,
00292         COMPLETE_CMD_NAME,
00293 #ifdef USE_CFG_VARS
00294         COMPLETE_CFG_GRP,
00295         COMPLETE_CFG_VAR,
00296 #endif /* USE_CFG_VARS */
00297 #ifdef USE_MI
00298         COMPLETE_MI,
00299 #endif /* USE_Mi */
00300 #ifdef USE_COUNTERS
00301         COMPLETE_CNT_GRP,
00302         COMPLETE_CNT_VAR,
00303 #endif /* USE_COUNTERS */
00304         COMPLETE_NOTHING
00305 };
00306 
00307 /* instead of rl_attempted_completion_over which is not present in
00308    some readline emulations, use attempted_completion_state */
00309 static enum complete_states attempted_completion_state;
00310 static int crt_param_no;
00311 
00312 /* commands for which we complete the params to other method names */
00313 char* complete_params_methods[]={
00314         "?",
00315         "h",
00316         "help",
00317         "system.methodSignature",
00318         "system.methodHelp",
00319         0
00320 };
00321 
00322 #ifdef USE_CFG_VARS
00323 /* commands for which we complete the first param with a cfg var grp*/
00324 char* complete_params_cfg_var[]={
00325         "cfg.get",
00326         "cfg.help",
00327         "cfg.set_delayed_int",
00328         "cfg.set_delayed_string",
00329         "cfg.set_now_int",
00330         "cfg.set_now_string",
00331         0
00332 };
00333 #endif /* USE_CFG_VARS */
00334 
00335 #ifdef USE_MI
00336 /* commands for which we complete the first param with an mi command*/
00337 char* complete_params_mi[]={
00338         "mi",
00339         "mi_fifo",
00340         "mi_dg",
00341         "mi_xmlrpc",
00342         0
00343 };
00344 #endif /* USE_MI */
00345 
00346 #ifdef USE_COUNTERS
00347 /* commands for which we complete the first param with a counter group */
00348 char* complete_param1_counter_grp[] = {
00349         "cnt.get",
00350         "cnt.get_raw",
00351         "cnt.grp_get_all",
00352         "cnt.reset",
00353         "cnt.var_list",
00354         "cnt.help",
00355         0
00356 };
00357 
00358 /* commands for which we completed the 2nd param with a counter name */
00359 char* complete_param2_counter_name[] = {
00360         "cnt.get",
00361         "cnt.get_raw",
00362         "cnt.reset",
00363         "cnt.help",
00364         0
00365 };
00366 #endif /* USE_COUNTERS */
00367 
00368 #endif /* USE_READLINE */
00369 
00370 
00371 
00372 static int parse_arg(struct binrpc_val* v, char* arg)
00373 {
00374         int i;
00375         double f;
00376         char* tmp;
00377         int len;
00378         
00379         i=strtol(arg, &tmp, 10);
00380         if ((tmp==0) || (*tmp)){
00381                 f=strtod(arg, &tmp);
00382                 if ((tmp==0) || (*tmp)){
00383                         /* not an int or a float => string */
00384                         len=strlen(arg);
00385                         if ((len>=2) && (arg[0]=='s') && (arg[1]==':')){
00386                                 tmp=&arg[2];
00387                                 len-=2;
00388                         }else{
00389                                 tmp=arg;
00390                         }
00391                         v->type=BINRPC_T_STR;
00392                         v->u.strval.s=tmp;
00393                         v->u.strval.len=len;
00394                 }else{ /* float */
00395                         v->type=BINRPC_T_DOUBLE;
00396                         v->u.fval=f;
00397                 }
00398         }else{ /* int */
00399                 v->type=BINRPC_T_INT;
00400                 v->u.intval=i;
00401         }
00402         return 0;
00403 }
00404 
00405 
00406 
00407 static int parse_cmd(struct binrpc_cmd* cmd, char** argv, int count)
00408 {
00409         int r;
00410         
00411         cmd->method=argv[0];
00412         if ((count-1)>MAX_BINRPC_ARGS){
00413                 fprintf(stderr,  "ERROR: too many args %d, only %d allowed\n",
00414                                         count-1, MAX_BINRPC_ARGS);
00415                 return -1;
00416         }
00417         for (r=1; r<count; r++){
00418                 if (parse_arg(&cmd->argv[r-1], argv[r])<0)
00419                         return -1;
00420         }
00421         cmd->argc=r-1;
00422         return 0;
00423 }
00424 
00425 
00426 void print_binrpc_val(struct binrpc_val* v, int ident)
00427 {
00428         int r;
00429 
00430         if ((v->type==BINRPC_T_STRUCT) && !v->u.end)
00431                 ident--; /* fix to have strut beg. idented differently */
00432         for (r=0; r<ident; r++) putchar('       ');
00433         if (v->name.s){
00434                 printf("%.*s: ", v->name.len, v->name.s);
00435         }
00436         switch(v->type){
00437                 case BINRPC_T_INT:
00438                         printf("%d", v->u.intval);
00439                         break;
00440                 case BINRPC_T_STR:
00441                 case BINRPC_T_BYTES:
00442                         printf("%.*s", v->u.strval.len, v->u.strval.s);
00443                         break;
00444                 case BINRPC_T_ARRAY:
00445                         printf("%c", (v->u.end)?']':'[');
00446                         break;
00447                 case BINRPC_T_STRUCT:
00448                         printf("%c", (v->u.end)?'}':'{');
00449                         break;
00450                 case BINRPC_T_DOUBLE:
00451                         printf("%f", v->u.fval);
00452                         break;
00453                 default:
00454                         printf("ERROR: unknown type %d\n", v->type);
00455         };
00456 }
00457 
00458 
00459 
00460 /* opens,  and  connects on a STREAM unix socket
00461  * returns socket fd or -1 on error */
00462 int connect_unix_sock(char* name, int type)
00463 {
00464         struct sockaddr_un ifsun;
00465         int s;
00466         int len;
00467         int ret;
00468         int retries;
00469         
00470         retries=0;
00471         s=-1;
00472         memset(&ifsun, 0, sizeof (struct sockaddr_un));
00473         len=strlen(name);
00474         if (len>UNIX_PATH_MAX){
00475                 fprintf(stderr, "ERROR: connect_unix_sock: name too long "
00476                                 "(%d > %d): %s\n", len, UNIX_PATH_MAX, name);
00477                 goto error;
00478         }
00479         ifsun.sun_family=AF_UNIX;
00480         memcpy(ifsun.sun_path, name, len);
00481 #ifdef HAVE_SOCKADDR_SA_LEN
00482         ifsun.sun_len=len;
00483 #endif
00484         s=socket(PF_UNIX, type, 0);
00485         if (s==-1){
00486                 fprintf(stderr, "ERROR: connect_unix_sock: cannot create unix socket"
00487                                 " %s: %s [%d]\n", name, strerror(errno), errno);
00488                 goto error;
00489         }
00490         if (type==SOCK_DGRAM){
00491                 /* we must bind so that we can receive replies */
00492                 if (reply_socket==0){
00493                         if (sock_dir==0)
00494                                 sock_dir="/tmp";
00495 retry:
00496                         ret=snprintf(mysun.sun_path, UNIX_PATH_MAX, "%s/" NAME "_%d",
00497                                                         sock_dir, rand()); 
00498                         if ((ret<0) ||(ret>=UNIX_PATH_MAX)){
00499                                 fprintf(stderr, "ERROR: buffer overflow while trying to"
00500                                                         "generate unix datagram socket name");
00501                                 goto error;
00502                         }
00503                 }else{
00504                         if (strlen(reply_socket)>UNIX_PATH_MAX){
00505                                 fprintf(stderr, "ERROR: buffer overflow while trying to"
00506                                                         "use the provided unix datagram socket name (%s)",
00507                                                         reply_socket);
00508                                 goto error;
00509                         }
00510                         strcpy(mysun.sun_path, reply_socket);
00511                 }
00512                 mysun.sun_family=AF_UNIX;
00513                 if (bind(s, (struct sockaddr*)&mysun, sizeof(mysun))==-1){
00514                         if (errno==EADDRINUSE && (reply_socket==0) && (retries < 10)){
00515                                 retries++;
00516                                 /* try another one */
00517                                 goto retry;
00518                         }
00519                         fprintf(stderr, "ERROR: could not bind the unix socket to"
00520                                         " %s: %s (%d)\n",
00521                                         mysun.sun_path, strerror(errno), errno);
00522                         goto error;
00523                 }
00524                 unix_socket=mysun.sun_path;
00525         }
00526         if (connect(s, (struct sockaddr *)&ifsun, sizeof(ifsun))==-1){
00527                 fprintf(stderr, "ERROR: connect_unix_sock: connect(%s): %s [%d]\n",
00528                                 name, strerror(errno), errno);
00529                 goto error;
00530         }
00531         return s;
00532 error:
00533         if (s!=-1) close(s);
00534         return -1;
00535 }
00536 
00537 
00538 
00539 int connect_tcpudp_socket(char* address, int port, int type)
00540 {
00541         struct sockaddr_in addr;
00542         struct hostent* he;
00543         int sock;
00544         
00545         sock=-1;
00546         /* resolve destination */
00547         he=gethostbyname(address);
00548         if (he==0){
00549                 fprintf(stderr, "ERROR: could not resolve %s\n", address);
00550                 goto error;
00551         }
00552         /* open socket*/
00553         addr.sin_family=he->h_addrtype;
00554         addr.sin_port=htons(port);
00555         memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
00556         
00557         sock = socket(he->h_addrtype, type, 0);
00558         if (sock==-1){
00559                 fprintf(stderr, "ERROR: socket: %s\n", strerror(errno));
00560                 goto error;
00561         }
00562         if (connect(sock, (struct sockaddr*) &addr, sizeof(struct sockaddr))!=0){
00563                 fprintf(stderr, "ERROR: connect: %s\n", strerror(errno));
00564                 goto error;
00565         }
00566         return sock;
00567 error:
00568         if (sock!=-1) close(sock);
00569         return -1;
00570 }
00571 
00572 
00573 
00574 static void hexdump(unsigned char* buf, int len, int ascii)
00575 {
00576         int r, i;
00577         
00578         /* dump it in hex */
00579         for (r=0; r<len; r++){
00580                 if ((r) && ((r%16)==0)){
00581                         if (ascii){
00582                                 putchar(' ');
00583                                 for (i=r-16; i<r; i++){
00584                                         if (isprint(buf[i]))
00585                                                 putchar(buf[i]);
00586                                         else
00587                                                 putchar('.');
00588                                 }
00589                         }
00590                         putchar('\n');
00591                 }
00592                 printf("%02x ", buf[r]);
00593         };
00594         if (ascii){
00595                 for (i=r;i%16; i++)
00596                         printf("   ");
00597                 putchar(' ');
00598                 for (i=16*(r/16); i<r; i++){
00599                         if (isprint(buf[i]))
00600                                 putchar(buf[i]);
00601                         else
00602                                 putchar('.');
00603                 }
00604         }
00605         putchar('\n');
00606 }
00607 
00608 
00609 
00610 /* returns: -1 on error, number of bytes written on success */
00611 static int send_binrpc_cmd(int s, struct binrpc_cmd* cmd, int cookie)
00612 {
00613         struct iovec v[IOVEC_CNT];
00614         int r;
00615         unsigned char msg_body[MAX_BODY_SIZE];
00616         unsigned char msg_hdr[BINRPC_MAX_HDR_SIZE];
00617         struct binrpc_pkt body;
00618         int ret;
00619         int n;
00620         
00621         ret=binrpc_init_pkt(&body, msg_body, MAX_BODY_SIZE);
00622         if (ret<0) goto binrpc_err;
00623         ret=binrpc_addstr(&body, cmd->method, strlen(cmd->method));
00624         if (ret<0) goto binrpc_err;
00625         for (r=0; r<cmd->argc; r++){
00626                 switch(cmd->argv[r].type){
00627                         case BINRPC_T_STR:
00628                                 ret=binrpc_addstr(&body, cmd->argv[r].u.strval.s,
00629                                                                                 cmd->argv[r].u.strval.len);
00630                                 break;
00631                         case BINRPC_T_INT:
00632                                 ret=binrpc_addint(&body, cmd->argv[r].u.intval);
00633                                 break;
00634                         case BINRPC_T_DOUBLE:
00635                                 ret=binrpc_adddouble(&body, cmd->argv[r].u.fval);
00636                                 break;
00637                         default:
00638                                 fprintf(stderr, "ERROR: unsupported type %d\n",
00639                                                                 cmd->argv[r].type);
00640                 }
00641                 if (ret<0) goto binrpc_err;
00642         }
00643         ret=binrpc_build_hdr(BINRPC_REQ, binrpc_pkt_len(&body), cookie, msg_hdr,
00644                                                         BINRPC_MAX_HDR_SIZE);
00645         if (ret<0) goto binrpc_err;
00646         v[0].iov_base=msg_hdr;
00647         v[0].iov_len=ret;
00648         v[1].iov_base=msg_body;
00649         v[1].iov_len=binrpc_pkt_len(&body);
00650 write_again:
00651         if ((n=writev(s, v, 2))<0){
00652                 if (errno==EINTR)
00653                         goto write_again;
00654                 goto error_send;
00655         }
00656         
00657         return n;
00658 error_send:
00659         return -1;
00660 binrpc_err:
00661         return -2;
00662 }
00663 
00664 
00665 static int binrpc_errno=0;
00666 
00667 /* reads the whole reply
00668  * returns < 0 on error, reply size on success + initializes in_pkt
00669  * if ret==-2 (parse error), sets binrpc_errno to the binrpc error
00670  * error returns: -1 - read error (check errno)
00671  *                -2 - binrpc parse error (chekc binrpc_errno) 
00672  *                -3 - cookie error (the cookied doesn't match)
00673  *                -4 - message too big */
00674 static int get_reply(int s, unsigned char* reply_buf, int max_reply_size,
00675                                                 int cookie, struct binrpc_parse_ctx* in_pkt,
00676                                                 unsigned char** body)
00677 {
00678         unsigned char* crt;
00679         unsigned char* hdr_end;
00680         unsigned char* msg_end;
00681         int n;
00682         int ret;
00683         
00684         
00685         hdr_end=crt=reply_buf;
00686         msg_end=reply_buf+max_reply_size;
00687         binrpc_errno=0;
00688         do{
00689                 n=read(s, crt, (int)(msg_end-crt));
00690                 if (n<=0){
00691                         if (errno==EINTR)
00692                                 continue;
00693                         goto error_read;
00694                 }
00695                 if (verbose >= 3){
00696                         /* dump it in hex */
00697                         printf("received %d bytes in reply (@offset %d):\n",
00698                                         n, (int)(crt-reply_buf));
00699                         hexdump(crt, n, 1);
00700                 }
00701                 crt+=n;
00702                 /* parse header if not parsed yet */
00703                 if (hdr_end==reply_buf){
00704                         hdr_end=binrpc_parse_init(in_pkt, reply_buf, n, &ret);
00705                         if (ret<0){
00706                                 if (ret==E_BINRPC_MORE_DATA)
00707                                         continue;
00708                                 goto error_parse;
00709                         }
00710                         if (verbose>1){
00711                                 printf("new packet: type %02x, len %d, cookie %02x\n",
00712                                                 in_pkt->type, in_pkt->tlen, in_pkt->cookie);
00713                         }
00714                         if (in_pkt->cookie!=cookie){
00715                                 fprintf(stderr, "bad reply, cookie doesn't match: sent %02x "
00716                                                 "and received  %02x\n",
00717                                                 cookie, in_pkt->cookie);
00718                                 goto error;
00719                         }
00720                         msg_end=hdr_end+in_pkt->tlen;
00721                         if ((int)(msg_end-reply_buf)>max_reply_size)
00722                                 goto error_toolong;
00723                 }
00724         }while(crt<msg_end);
00725         
00726         *body=hdr_end;
00727         return (int)(msg_end-reply_buf);
00728 error_read:
00729         return -1;
00730 error_parse:
00731         binrpc_errno=ret;
00732         return -2;
00733 error:
00734         return -3;
00735 error_toolong:
00736         return -4;
00737 }
00738 
00739 
00740 
00741 /* returns a malloced copy of str, with all the escapes ('\') resolved */
00742 static char* str_escape(char* str)
00743 {
00744         char* n;
00745         char* ret;
00746         
00747         ret=n=malloc(strlen(str)+1);
00748         if (n==0)
00749                 goto end;
00750         
00751         for(;*str;str++){
00752                 *n=*str;
00753                 if (*str=='\\'){
00754                         switch(*(str+1)){
00755                                 case 'n':
00756                                         *n='\n';
00757                                         str++;
00758                                         break;
00759                                 case 'r':
00760                                         *n='\r';
00761                                         str++;
00762                                         break;
00763                                 case 't':
00764                                         *n='\t';
00765                                         str++;
00766                                         break;
00767                                 case '\\':
00768                                         str++;
00769                                         break;
00770                         }
00771                 }
00772                 n++;
00773         }
00774         *n=*str; /* terminating 0 */
00775 end:
00776         return ret;
00777 }
00778 
00779 
00780 
00781 /* parses strings like "bla bla %v 10%% %v\n test=%v",
00782  * and stops at each %v,  returning  a pointer after the %v, setting *size
00783  * to the string length (not including %v) and *type to the corresponding
00784  * BINRPC type (for now only BINRPC_T_ALL).
00785  * To escape a '%', use "%%", and check for type==-1 (which means skip an call
00786  *  again parse_fmt).
00787  * Usage:
00788  *        n="test: %v,%v,%v\n";
00789  *        while(*n){
00790  *          s=n;
00791  *          n=parse_fmt(n, &type, &size);
00792  *          printf("%.*s", size, s);
00793  *          if (type==-1)
00794  *            continue;
00795  *          else 
00796  *             printf("now we should get & print an object of type %d\n", type)
00797  *        }
00798  */
00799 static char* parse_fmt(char* fmt, int* type, int* size)
00800 {
00801         char* s;
00802 
00803         s=fmt;
00804         do{
00805                 for(;*fmt && *fmt!='%'; fmt++);
00806                 if (*fmt=='%'){
00807                         switch(*(fmt+1)){
00808                                 case 'v':
00809                                         *type=BINRPC_T_ALL;
00810                                         *size=(int)(fmt-s);
00811                                         return (fmt+2);
00812                                         break;
00813                                 case '%':
00814                                         /* escaped % */
00815                                         *size=(int)(fmt-s)+1;
00816                                         *type=-1; /* skip */
00817                                         return (fmt+2);
00818                                         break;
00819                         }
00820                 }
00821         }while(*fmt);
00822         *type=-1; /* no value */
00823         *size=(fmt-s);
00824         return fmt;
00825 }
00826 
00827 
00828 
00829 static int print_body(struct binrpc_parse_ctx* in_pkt, 
00830                                                 unsigned char* body, int size, char* fmt)
00831 {
00832         
00833         unsigned char* p;
00834         unsigned char* end;
00835         struct binrpc_val val;
00836         int ret;
00837         int rec;
00838         char *f;
00839         char* s;
00840         int f_size;
00841         int fmt_has_values;
00842         
00843         p=body;
00844         end=p+size;
00845         rec=0;
00846         f=fmt;
00847         fmt_has_values=0;
00848         /* read body */
00849         while(p<end){
00850                 if (f){
00851                         
00852                         do{
00853                                 if (*f==0)
00854                                         f=fmt; /* reset */
00855                                 s=f;
00856                                 f=parse_fmt(f, &val.type, &f_size);
00857                                 printf("%.*s", f_size, s);
00858                                 if (val.type!=-1){
00859                                         fmt_has_values=1;
00860                                         goto read_value;
00861                                 }
00862                         }while(*f || fmt_has_values);
00863                         val.type=BINRPC_T_ALL;
00864                 }else{
00865                         val.type=BINRPC_T_ALL;
00866                 }
00867 read_value:
00868                 val.name.s=0;
00869                 val.name.len=0;
00870                 p=binrpc_read_record(in_pkt, p, end, &val, &ret);
00871                 if (ret<0){
00872                         if (fmt)
00873                                 putchar('\n');
00874                         /*if (ret==E_BINRPC_MORE_DATA)
00875                                 goto error_read_again;*/
00876                         if (ret==E_BINRPC_EOP){
00877                                 printf("end of message detected\n");
00878                                 break;
00879                         }
00880                         fprintf(stderr, "ERROR while parsing the record %d,"
00881                                         " @%d: %02x : %s\n", rec,
00882                                         in_pkt->offset, *p, binrpc_error(ret));
00883                         goto error;
00884                 }
00885                 rec++;
00886                 if (fmt){
00887                         print_binrpc_val(&val, 0);
00888                 }else{
00889                         print_binrpc_val(&val, in_pkt->in_struct+in_pkt->in_array);
00890                         putchar('\n');
00891                 }
00892         }
00893         if (fmt && *f){
00894                 /* print the rest, with empty values */
00895                 while(*f){
00896                         s=f;
00897                         f=parse_fmt(f, &val.type, &f_size);
00898                         printf("%.*s", f_size, s);
00899                 }
00900         }
00901         return 0;
00902 error:
00903         return -1;
00904 /*error_read_again:
00905         fprintf(stderr, "ERROR: more data needed\n");
00906         return -2;
00907         */
00908 }
00909 
00910 
00911 
00912 static int print_fault(struct binrpc_parse_ctx* in_pkt, 
00913                                                 unsigned char* body, int size)
00914 {
00915         printf("error: ");
00916         return print_body(in_pkt, body, size, "%v - %v\n");
00917 }
00918 
00919 
00920 
00921 static int run_binrpc_cmd(int s, struct binrpc_cmd * cmd, char* fmt)
00922 {
00923         int cookie;
00924         unsigned char reply_buf[MAX_REPLY_SIZE];
00925         unsigned char* msg_body;
00926         struct binrpc_parse_ctx in_pkt;
00927         int ret;
00928         
00929         cookie=gen_cookie();
00930         if ((ret=send_binrpc_cmd(s, cmd, cookie))<0){
00931                 if (ret==-1) goto error_send;
00932                 else goto binrpc_err;
00933         }
00934         /* read reply */
00935         memset(&in_pkt, 0, sizeof(in_pkt));
00936         if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
00937                                         &msg_body))<0){
00938                 switch(ret){
00939                         case -1:
00940                                 goto error_read;
00941                         case -2:
00942                                 goto error_parse;
00943                         case -3:
00944                                 goto error_cookie;
00945                         case -4:
00946                                 goto error_toobig;
00947                 }
00948                 goto error;
00949         }
00950         switch(in_pkt.type){
00951                 case BINRPC_FAULT:
00952                         if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
00953                                 goto error;
00954                         }
00955                         break;
00956                 case BINRPC_REPL:
00957                         if (print_body(&in_pkt, msg_body, in_pkt.tlen, fmt)<0){
00958                                 goto error;
00959                         }
00960                         break;
00961                 default:
00962                         fprintf(stderr, "ERROR: not a reply\n");
00963                         goto error;
00964         }
00965         if (verbose) printf(".\n");
00966         /* normal exit */
00967         return 0;
00968 binrpc_err:
00969         fprintf(stderr, "ERROR while building the packet: %s\n", 
00970                                 binrpc_error(ret));
00971         goto error;
00972 error_parse:
00973         fprintf(stderr, "ERROR while parsing the reply: %s\n", 
00974                                 binrpc_error(binrpc_errno));
00975         goto error;
00976 error_cookie:
00977         fprintf(stderr, "ERROR: cookie does not match\n");
00978         goto error;
00979 error_toobig:
00980         fprintf(stderr, "ERROR: reply too big\n");
00981         goto error;
00982 error_send:
00983         fprintf(stderr, "ERROR: send packet failed: %s (%d)\n",
00984                         strerror(errno), errno);
00985         goto error;
00986 error_read:
00987         fprintf(stderr, "ERROR: read reply failed: %s (%d)\n",
00988                         strerror(errno), errno);
00989         goto error;
00990 error:
00991         return -1;
00992 }
00993 
00994 
00995 
00996 static int parse_line(struct binrpc_cmd* cmd, char* line)
00997 {
00998         char* p;
00999         int count;
01000         
01001         cmd->method=strtok(line, " \t");
01002         if (cmd->method==0)
01003                 goto error_no_method;
01004         count=0;
01005         for(p=strtok(0, " \t"); p; p=strtok(0, " \t")){
01006                 if (count>=MAX_BINRPC_ARGS)
01007                         goto error_too_many;
01008                 if (parse_arg(&cmd->argv[count], p)<0){
01009                         goto error_arg;
01010                 }
01011                 count++;
01012         }
01013         cmd->argc=count;
01014         return 0;
01015 error_no_method:
01016         printf( "ERROR: no method name\n");
01017         return -1;
01018 error_too_many:
01019         printf("ERROR: too many arguments (%d), no more than %d allowed\n",
01020                         count, MAX_BINRPC_ARGS);
01021         return -1;
01022 error_arg:
01023         printf("ERROR: bad argument %d: %s\n", count+1, p);
01024         return -1;
01025 }
01026 
01027 
01028 
01029 /* resolves builtin aliases */
01030 static void fix_cmd(struct binrpc_cmd* cmd, char** format)
01031 {
01032         int r;
01033         
01034         for (r=0; cmd_aliases[r].name; r++){
01035                 if (strcmp(cmd_aliases[r].name, cmd->method)==0){
01036                         cmd->method=cmd_aliases[r].method;
01037                         if (*format==0)
01038                                 *format=cmd_aliases[r].format;
01039                         break;
01040                 }
01041         }
01042 }
01043 
01044 
01045 
01046 /* intercept builtin commands, returns 1 if intercepted, 0 if not, <0 on error
01047  */
01048 static int run_builtins(int s, struct binrpc_cmd* cmd)
01049 {
01050         int r;
01051         int ret;
01052         
01053         for (r=0; builtins[r].name; r++){
01054                 if (strcmp(builtins[r].name, cmd->method)==0){
01055                         ret=builtins[r].f(s, cmd);
01056                         return (ret<0)?ret:1;
01057                 }
01058         }
01059         return 0;
01060 }
01061 
01062 
01063 
01064 /* runs command from cmd */
01065 inline static int run_cmd(int s, struct binrpc_cmd* cmd, char* format)
01066 {
01067         int ret;
01068         char* fmt;
01069 
01070         fmt=format;
01071         
01072         fix_cmd(cmd, &fmt);
01073         if (!(ret=run_builtins(s, cmd))){
01074                 ret=run_binrpc_cmd(s, cmd, fmt);
01075         }
01076         return (ret>0)?0:ret;
01077 }
01078 
01079 
01080 
01081 /* runs a command represented in line */
01082 inline static int run_line(int s, char* l, char* format)
01083 {
01084         struct binrpc_cmd cmd;
01085         int ret;
01086         
01087         if ((ret=parse_line(&cmd, l))==0){
01088                 return run_cmd(s, &cmd, format);
01089         }
01090         return ret;
01091 }
01092 
01093 
01094 
01095 static void free_rpc_array(struct binrpc_val* a, int size)
01096 {
01097         int r;
01098         for (r=0; r<size; r++){
01099                 if (a[r].name.s)
01100                         free(a[r].name.s);
01101                 if ((a[r].type==BINRPC_T_STR || a[r].type==BINRPC_T_BYTES) &&
01102                                 a[r].u.strval.s){
01103                         free(a[r].u.strval.s);
01104                 }
01105         }
01106         free(a);
01107 }
01108 
01109 
01110 
01111 /* parse the body into a malloc allocated,  binrpc_val array */
01112 static struct binrpc_val* parse_reply_body(int* records, 
01113                                                                                         struct binrpc_parse_ctx* in_pkt,
01114                                                                                         unsigned char* body, int size)
01115 {
01116         struct binrpc_val* a;
01117         struct binrpc_val* t;
01118         unsigned char* p;
01119         unsigned char* end;
01120         struct binrpc_val val;
01121         int ret;
01122         int rec;
01123 
01124         rec=0;
01125         if (*records==0){
01126                 *records=100; /* start with a reasonable size */
01127         };
01128         a=malloc(*records*sizeof(struct binrpc_val));
01129         if (a==0)
01130                 goto error_mem;
01131         p=body;
01132         end=p+size;
01133         
01134         /* read body */
01135         while(p<end){
01136                 val.type=BINRPC_T_ALL;
01137                 val.name.s=0;
01138                 val.name.len=0;
01139                 p=binrpc_read_record(in_pkt, p, end, &val, &ret);
01140                 if (ret<0){
01141                         if (ret==E_BINRPC_EOP){
01142                                 printf("end of message detected\n");
01143                                 break;
01144                         }
01145                         fprintf(stderr, "ERROR while parsing the record %d,"
01146                                         " @%d: %02x : %s\n", rec,
01147                                         in_pkt->offset, *p, binrpc_error(ret));
01148                         goto error;
01149                 }
01150                 if (rec>=*records){
01151                         t=realloc(a, *records*sizeof(struct binrpc_val)*2);
01152                         if (t==0)
01153                                 goto error_mem;
01154                         a=t;
01155                         *records*=2;
01156                 }
01157                 a[rec]=val;
01158                 if (val.name.s){
01159                         if ((a[rec].name.s=malloc(val.name.len+1))==0)
01160                                 goto error_mem;
01161                         memcpy(a[rec].name.s, val.name.s, val.name.len);
01162                         a[rec].name.s[val.name.len+1]=0; /* 0-term */
01163                 }
01164                 if (val.u.strval.s){
01165                         if (val.type==BINRPC_T_STR){
01166                                 if ((a[rec].u.strval.s=malloc(val.u.strval.len+1))==0)
01167                                         goto error_mem;
01168                                 memcpy(a[rec].u.strval.s, val.u.strval.s, val.u.strval.len);
01169                                 a[rec].u.strval.s[val.u.strval.len]=0; /* 0-term */
01170                         }else if (val.type==BINRPC_T_BYTES){
01171                                 if ((a[rec].u.strval.s=malloc(val.u.strval.len))==0)
01172                                         goto error_mem;
01173                                 memcpy(a[rec].u.strval.s, val.u.strval.s, val.u.strval.len);
01174                         }
01175                 }
01176                 rec++;
01177         }
01178         if (rec && (rec<*records)){
01179                 a=realloc(a, rec*sizeof(struct binrpc_val));
01180         }
01181         *records=rec;
01182         return a;
01183 error_mem:
01184         fprintf(stderr, "ERROR: parse_reply_body: out of memory\n");
01185 error:
01186         if (a){
01187                 free_rpc_array(a, rec);
01188         }
01189         *records=0;
01190         return 0;
01191 }
01192 
01193 
01194 
01195 static int get_sercmd_list(int s)
01196 {
01197         struct binrpc_cmd cmd;
01198         int cookie;
01199         unsigned char reply_buf[MAX_REPLY_SIZE];
01200         unsigned char* msg_body;
01201         struct binrpc_parse_ctx in_pkt;
01202         int ret;
01203         
01204         cmd.method="system.listMethods";
01205         cmd.argc=0;
01206         
01207         cookie=gen_cookie();
01208         if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
01209                 if (ret==-1) goto error_send;
01210                 else goto binrpc_err;
01211         }
01212         /* read reply */
01213         memset(&in_pkt, 0, sizeof(in_pkt));
01214         if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
01215                                         &msg_body))<0){
01216                 goto error;
01217         }
01218         switch(in_pkt.type){
01219                 case BINRPC_FAULT:
01220                         if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
01221                                 goto error;
01222                         }
01223                         break;
01224                 case BINRPC_REPL:
01225                         rpc_no=100; /* default cmd list */
01226                         if ((rpc_array=parse_reply_body(&rpc_no, &in_pkt, msg_body,
01227                                                                                                 in_pkt.tlen))==0)
01228                                 goto error;
01229                         break;
01230                 default:
01231                         fprintf(stderr, "ERROR: not a reply\n");
01232                         goto error;
01233         }
01234         return 0;
01235 binrpc_err:
01236 error_send:
01237 error:
01238         return -1;
01239 }
01240 
01241 
01242 
01243 #if defined(USE_CFG_VARS) || defined (USE_MI) || defined (USE_COUNTERS)
01244 
01249 static int is_rpc_cmd(char* cmd)
01250 {
01251         int r;
01252         int cmd_len;
01253         
01254         cmd_len=strlen(cmd);
01255         for (r=0; r<rpc_no; r++){
01256                 if ((rpc_array[r].type==BINRPC_T_STR) &&
01257                         (rpc_array[r].u.strval.len==cmd_len) &&
01258                         (strncmp(cmd, rpc_array[r].u.strval.s, cmd_len)==0))
01259                         return 1;
01260         }
01261         return 0;
01262 }
01263 #endif /* USE_CFG_VARS || USE_MI */
01264 
01265 
01266 
01267 #ifdef USE_CFG_VARS
01268 /* retrieve the cfg vars and group list */
01269 static int get_cfgvars_list(int s)
01270 {
01271         struct binrpc_cmd cmd;
01272         int cookie;
01273         unsigned char reply_buf[MAX_REPLY_SIZE];
01274         unsigned char* msg_body;
01275         struct binrpc_parse_ctx in_pkt;
01276         struct cfg_var_grp* grp;
01277         struct cfg_var_grp* last_grp;
01278         char* p;
01279         char* end;
01280         str grp_name;
01281         str var_name;
01282         int r;
01283         int ret;
01284         
01285         cmd.method="cfg.list";
01286         cmd.argc=0;
01287         if (!is_rpc_cmd(cmd.method)) goto error;
01288         
01289         cookie=gen_cookie();
01290         if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
01291                 if (ret==-1) goto error_send;
01292                 else goto binrpc_err;
01293         }
01294         /* read reply */
01295         memset(&in_pkt, 0, sizeof(in_pkt));
01296         if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
01297                                         &msg_body))<0){
01298                 goto error;
01299         }
01300         switch(in_pkt.type){
01301                 case BINRPC_FAULT:
01302                         if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
01303                                 goto error;
01304                         }
01305                         break;
01306                 case BINRPC_REPL:
01307                         cfg_vars_no=100; /* default cmd list */
01308                         if ((cfg_vars_array=parse_reply_body(&cfg_vars_no, &in_pkt,
01309                                                                                                 msg_body, in_pkt.tlen))==0)
01310                                 goto error;
01311                         break;
01312                 default:
01313                         fprintf(stderr, "ERROR: not a reply\n");
01314                         goto error;
01315         }
01316         /* get the config groups */
01317         last_grp=0;
01318         for (r=0; r<cfg_vars_no; r++){
01319                 grp_name.s=0; grp_name.len=0;
01320                 if (cfg_vars_array[r].type!=BINRPC_T_STR)
01321                         continue;
01322                 grp_name.s=cfg_vars_array[r].u.strval.s;
01323                 end=cfg_vars_array[r].u.strval.len+grp_name.s;
01324                 /* parse <grp>: <var_name>*/
01325                 for (p=grp_name.s; p<end; p++){
01326                         if (*p==':'){
01327                                 grp_name.len=(int)(long)(p-grp_name.s);
01328                                 break;
01329                         }
01330                 }
01331                 for (grp=cfg_grp_lst; grp; grp=grp->next){
01332                         if (grp->grp_name.len==grp_name.len &&
01333                                         memcmp(grp->grp_name.s, grp_name.s, grp_name.len)==0){
01334                                 break; /* found */
01335                         }
01336                 }
01337                 if (grp==0){
01338                         /* not found => create a new one  */
01339                         grp=malloc(sizeof(*grp));
01340                         if (grp==0) goto error_mem;
01341                         memset(grp, 0, sizeof(*grp));
01342                         grp->grp_name=grp_name;
01343                         if (last_grp){
01344                                 last_grp->next=grp;
01345                                 last_grp=grp;
01346                         }else{
01347                                 cfg_grp_lst=grp;
01348                                 last_grp=cfg_grp_lst;
01349                         }
01350                 }
01351                 grp->var_no++;
01352         }
01353         /* alloc the var arrays per group */
01354         for (grp=cfg_grp_lst; grp; grp=grp->next){
01355                 grp->var_names=malloc(sizeof(str)*grp->var_no);
01356                 if (grp->var_names==0) goto error_mem;
01357                 memset(grp->var_names, 0, sizeof(str)*grp->var_no);
01358                 grp->var_no=0;
01359         }
01360         /* reparse to get the var names per group */
01361         for (r=0; r<cfg_vars_no; r++){
01362                 grp_name.s=0; grp_name.len=0;
01363                 var_name.s=0; var_name.len=0;
01364                 if (cfg_vars_array[r].type!=BINRPC_T_STR)
01365                         continue;
01366                 grp_name.s=cfg_vars_array[r].u.strval.s;
01367                 end=cfg_vars_array[r].u.strval.len+grp_name.s;
01368                 /* parse <grp>: <var_name>*/
01369                 for (p=grp_name.s; p<end; p++){
01370                         if (*p==':'){
01371                                 grp_name.len=(int)(long)(p-grp_name.s);
01372                                 p++;
01373                                 for (; p<end && *p==' '; p++);
01374                                 var_name.s=p;
01375                                 var_name.len=(int)(long)(end-p);
01376                                 if (var_name.len==0) break;
01377                                 for (grp=cfg_grp_lst; grp; grp=grp->next){
01378                                         if (grp->grp_name.len==grp_name.len &&
01379                                                 memcmp(grp->grp_name.s, grp_name.s, grp_name.len)==0){
01380                                                 /* add var */
01381                                                 grp->var_names[grp->var_no]=var_name;
01382                                                 grp->var_no++;
01383                                         }
01384                                 }
01385                                 break;
01386                         }
01387                 }
01388         }
01389         return 0;
01390 binrpc_err:
01391 error_send:
01392 error:
01393 error_mem:
01394         return -1;
01395 }
01396 
01397 
01398 
01399 void free_cfg_grp_lst()
01400 {
01401         struct cfg_var_grp* grp;
01402         struct cfg_var_grp* last;
01403         
01404         grp=cfg_grp_lst;
01405         while(grp){
01406                 last=grp;
01407                 grp=grp->next;
01408                 free(last);
01409         }
01410         cfg_grp_lst=0;
01411 }
01412 #endif /* USE_CFG_VARS */
01413 
01414 
01415 
01416 #ifdef USE_MI
01417 /* retrieve the mi list */
01418 static int get_mi_list(int s)
01419 {
01420         struct binrpc_cmd cmd;
01421         int cookie;
01422         unsigned char reply_buf[MAX_REPLY_SIZE];
01423         unsigned char* msg_body;
01424         struct binrpc_parse_ctx in_pkt;
01425         char* p;
01426         char* end;
01427         str mi_name;
01428         int mi_which_results;
01429         int r;
01430         int ret;
01431         
01432         cmd.method="mi";
01433         cmd.argv[0].type=BINRPC_T_STR;
01434         cmd.argv[0].u.strval.s="which";
01435         cmd.argv[0].u.strval.len=strlen(cmd.argv[0].u.strval.s);
01436         cmd.argc=1;
01437         if (!is_rpc_cmd(cmd.method)) goto error;
01438         
01439         cookie=gen_cookie();
01440         if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
01441                 if (ret==-1) goto error_send;
01442                 else goto binrpc_err;
01443         }
01444         /* read reply */
01445         memset(&in_pkt, 0, sizeof(in_pkt));
01446         if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
01447                                         &msg_body))<0){
01448                 goto error;
01449         }
01450         switch(in_pkt.type){
01451                 case BINRPC_FAULT:
01452                         if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
01453                                 goto error;
01454                         }
01455                         break;
01456                 case BINRPC_REPL:
01457                         mi_which_no=25; /* default rpc list */
01458                         if ((mi_which_array=parse_reply_body(&mi_which_no, &in_pkt,
01459                                                                                                 msg_body, in_pkt.tlen))==0)
01460                                 goto error;
01461                         break;
01462                 default:
01463                         fprintf(stderr, "ERROR: not a reply\n");
01464                         goto error;
01465         }
01466         
01467         
01468         /* get the mi commands number */
01469         mi_which_results=0;
01470         for (r=0; r<mi_which_no; r++){
01471                 if (mi_which_array[r].type!=BINRPC_T_STR)
01472                         continue;
01473                 /* we are interestend only in lines starting with ':', e.g.:
01474                    :: version */
01475                 if ((mi_which_array[r].u.strval.len) &&
01476                         (mi_which_array[r].u.strval.s[0]==':'))
01477                         mi_which_results++;
01478         }
01479         /* no mi commands */
01480         if (mi_which_results==0)
01481                 goto error;
01482         /* alloc the mi_cmds array */
01483         mi_cmds=malloc(mi_which_results*sizeof(*mi_cmds));
01484         if (mi_cmds==0) goto error_mem;
01485         memset(mi_cmds, 0, mi_which_results* sizeof(mi_cmds));
01486         /* get the mi names list */
01487         for (r=0; r<mi_which_no; r++){
01488                 if (mi_which_array[r].type!=BINRPC_T_STR)
01489                         continue;
01490                 p=mi_which_array[r].u.strval.s;
01491                 end=p+mi_which_array[r].u.strval.len;
01492                 /* we are interestend only in lines starting with ':', e.g.:
01493                         :: version */
01494                 if ((p>=end) || (*p!=':'))
01495                         continue;
01496                 p++;
01497                 /* skip over to the next ':' */
01498                 for(;p<end && *p!=':'; p++);
01499                 if (p>=end) continue;
01500                 p++;
01501                 /* skip over spaces */
01502                 for(;p<end && (*p==' ' || *p=='\t'); p++);
01503                 if (p>=end || *p=='\n') continue;
01504                 if (mi_cmds_no >= mi_which_results){
01505                         fprintf(stderr, "BUG: wrong mi cmds no (%d >= %d)\n",
01506                                                         mi_cmds_no, mi_which_results);
01507                         goto error;
01508                 }
01509                 mi_name.s=p;
01510                 for(; p<end && *p!=' ' && *p!='\t' && *p!='\n'; p++);
01511                 mi_name.len=(int)(long)(p-mi_name.s);
01512                 mi_cmds[mi_cmds_no]=mi_name;
01513                 mi_cmds_no++;
01514         }
01515         
01516         return 0;
01517 binrpc_err:
01518 error_send:
01519 error:
01520 error_mem:
01521         return -1;
01522 }
01523 
01524 
01525 
01526 void free_mi_cmds()
01527 {
01528         if (mi_cmds){
01529                 free(mi_cmds);
01530                 mi_cmds=0;
01531                 mi_cmds_no=0;
01532         }
01533 }
01534 #endif /* USE_MI */
01535 
01536 
01537 
01538 #ifdef USE_COUNTERS
01539 /* retrieve the counters names and group list */
01540 static int get_counters_list(int s)
01541 {
01542         struct binrpc_cmd cmd;
01543         int cookie;
01544         unsigned char reply_buf[MAX_REPLY_SIZE];
01545         unsigned char* msg_body;
01546         struct binrpc_parse_ctx in_pkt;
01547         struct cnt_var_grp* grp;
01548         struct cnt_var_grp* last_grp;
01549         str grp_name;
01550         str var_name;
01551         int r;
01552         int ret;
01553         
01554         cmd.method="cnt.grps_list";
01555         cmd.argc=0;
01556         if (!is_rpc_cmd(cmd.method)) goto error;
01557         
01558         cookie=gen_cookie();
01559         if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
01560                 if (ret==-1) goto error_send;
01561                 else goto binrpc_err;
01562         }
01563         /* read reply */
01564         memset(&in_pkt, 0, sizeof(in_pkt));
01565         if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
01566                                         &msg_body))<0){
01567                 goto error;
01568         }
01569         switch(in_pkt.type){
01570                 case BINRPC_FAULT:
01571                         if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
01572                                 goto error;
01573                         }
01574                         break;
01575                 case BINRPC_REPL:
01576                         cnt_grps_no=20; /* default counter list */
01577                         if ((cnt_grps_array=parse_reply_body(&cnt_grps_no, &in_pkt,
01578                                                                                                 msg_body, in_pkt.tlen))==0)
01579                                 goto error;
01580                         break;
01581                 default:
01582                         fprintf(stderr, "ERROR: not a reply\n");
01583                         goto error;
01584         }
01585         /* get the config groups */
01586         last_grp=0;
01587         for (r=0; r<cnt_grps_no; r++){
01588                 grp_name.s=0; grp_name.len=0;
01589                 if (cnt_grps_array[r].type!=BINRPC_T_STR)
01590                         continue;
01591                 grp_name=cnt_grps_array[r].u.strval;
01592                 /* check for duplicates */
01593                 for (grp=cnt_grp_lst; grp; grp=grp->next){
01594                         if (grp->grp_name.len==grp_name.len &&
01595                                         memcmp(grp->grp_name.s, grp_name.s, grp_name.len)==0){
01596                                 break; /* found */
01597                         }
01598                 }
01599                 if (grp==0){
01600                         /* not found => create a new one  */
01601                         grp=malloc(sizeof(*grp));
01602                         if (grp==0) goto error_mem;
01603                         memset(grp, 0, sizeof(*grp));
01604                         grp->grp_name=grp_name;
01605                         if (last_grp){
01606                                 last_grp->next=grp;
01607                                 last_grp=grp;
01608                         }else{
01609                                 cnt_grp_lst=grp;
01610                                 last_grp=cnt_grp_lst;
01611                         }
01612                 }
01613         }
01614         /* gets vars per group */
01615         for (grp=cnt_grp_lst; grp; grp=grp->next){
01616                 cmd.method="cnt.var_list";
01617                 cmd.argv[0].type=BINRPC_T_STR;
01618                 cmd.argv[0].u.strval=grp->grp_name;
01619                 cmd.argc=1;
01620                 if (!is_rpc_cmd(cmd.method)) goto error;
01621                 cookie=gen_cookie();
01622                 if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
01623                         if (ret==-1) goto error_send;
01624                         else goto binrpc_err;
01625                 }
01626                 /* read reply */
01627                 memset(&in_pkt, 0, sizeof(in_pkt));
01628                 if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
01629                                                 &msg_body))<0){
01630                         goto error;
01631                 }
01632                 switch(in_pkt.type){
01633                         case BINRPC_FAULT:
01634                                 if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
01635                                         goto error;
01636                                 }
01637                                 break;
01638                         case BINRPC_REPL:
01639                                 grp->cnt_vars_no=100; /* default counter list */
01640                                 if ((grp->cnt_vars_array=parse_reply_body(&grp->cnt_vars_no,
01641                                                                                                 &in_pkt, msg_body,
01642                                                                                                 in_pkt.tlen))==0)
01643                                 goto error;
01644                                 break;
01645                         default:
01646                                 fprintf(stderr, "ERROR: not a reply\n");
01647                                 goto error;
01648                 }
01649                 grp->var_no = 0;
01650                 grp->var_names=malloc(sizeof(str)*grp->cnt_vars_no);
01651                 if (grp->var_names==0) goto error_mem;
01652                 memset(grp->var_names, 0, sizeof(str)*grp->var_no);
01653                 for (r=0; r<grp->cnt_vars_no; r++) {
01654                         if (grp->cnt_vars_array[r].type!=BINRPC_T_STR)
01655                                 continue;
01656                         var_name=grp->cnt_vars_array[r].u.strval;
01657                         grp->var_names[grp->var_no] = var_name;
01658                         grp->var_no++;
01659                 }
01660         }
01661         return 0;
01662 binrpc_err:
01663 error_send:
01664 error:
01665 error_mem:
01666         return -1;
01667 }
01668 
01669 
01670 
01671 void free_cnt_grp_lst()
01672 {
01673         struct cnt_var_grp* grp;
01674         struct cnt_var_grp* last;
01675         
01676         grp=cnt_grp_lst;
01677         while(grp){
01678                 last=grp;
01679                 grp=grp->next;
01680                 if (last->cnt_vars_array)
01681                         free_rpc_array(last->cnt_vars_array, last->cnt_vars_no);
01682                 free(last);
01683         }
01684         cnt_grp_lst=0;
01685 }
01686 #endif /* USE_COUNTERS */
01687 
01688 
01689 
01690 
01691 static void print_formatting(char* prefix, char* format, char* suffix)
01692 {
01693         if (format){
01694                 printf("%s", prefix);
01695                 for (;*format;format++){
01696                         switch(*format){
01697                                 case '\t':
01698                                         printf("\\t");
01699                                         break;
01700                                 case '\n':
01701                                         printf("\\n");
01702                                         break;
01703                                 case '\r':
01704                                         printf("\\r");
01705                                         break;
01706                                 default:
01707                                         putchar(*format);
01708                         }
01709                 }
01710                 printf("%s", suffix);
01711         }
01712 }
01713 
01714 
01715 
01716 static int sercmd_help(int s, struct binrpc_cmd* cmd)
01717 {
01718         int r;
01719         
01720         if (cmd->argc && (cmd->argv[0].type==BINRPC_T_STR)){
01721                 /* if it has args, try command help */
01722                 for (r=0; cmd_aliases[r].name; r++){
01723                          if (strcmp(cmd->argv[0].u.strval.s, cmd_aliases[r].name)==0){
01724                                  printf("%s is an alias for %s", cmd->argv[0].u.strval.s,
01725                                                                                                 cmd_aliases[r].method);
01726                                  print_formatting(" with reply formatting: \"",
01727                                                                         cmd_aliases[r].format, "\"");
01728                                  putchar('\n');
01729                                  return 0;
01730                          }
01731                 }
01732                 for(r=0; builtins[r].name; r++){
01733                          if (strcmp(cmd->argv[0].u.strval.s, builtins[r].name)==0){
01734                                  printf("builtin command: %s\n", 
01735                                                  builtins[r].doc?builtins[r].doc:"undocumented");
01736                                  return 0;
01737                          }
01738                 }
01739                 cmd->method="system.methodHelp";
01740                 if (run_binrpc_cmd(s, cmd, 0)<0){
01741                         printf("error: no such command %s\n", cmd->argv[0].u.strval.s);
01742                 }
01743                 return 0;
01744         }
01745                 
01746         if (rpc_no==0){
01747                 if (get_sercmd_list(s)<0)
01748                         goto error;
01749         }
01750         for (r=0; r<rpc_no; r++){
01751                 if (rpc_array[r].type==BINRPC_T_STR){
01752                         printf("%s\n", rpc_array[r].u.strval.s);
01753                 }
01754         }
01755         for (r=0; cmd_aliases[r].name; r++){
01756                 printf("alias: %s\n", cmd_aliases[r].name);
01757         }
01758         for(r=0; builtins[r].name; r++){
01759                 printf("builtin: %s\n", builtins[r].name);
01760         }
01761         return 0;
01762 error:
01763         return -1;
01764 }
01765 
01766 
01767 
01768 static int sercmd_ver(int s, struct binrpc_cmd* cmd)
01769 {
01770         printf("%s\n", version);
01771         printf("%s\n", id);
01772         printf("%s compiled on %s \n", __FILE__, compiled);
01773 #ifdef USE_READLINE
01774         printf("interactive mode command completion support\n");
01775 #endif
01776         return 0;
01777 }
01778 
01779 
01780 
01781 static int sercmd_quit(int s, struct binrpc_cmd* cmd)
01782 {
01783         quit=1;
01784         return 0;
01785 }
01786 
01787 
01788 
01789 static int sercmd_warranty(int s, struct binrpc_cmd *cmd)
01790 {
01791         printf("%s %s\n", NAME, VERSION);
01792         printf("%s\n", COPYRIGHT);
01793         printf("\n%s\n", LICENSE);
01794         return 0;
01795 }
01796 
01797 
01798 #ifdef USE_READLINE
01799 
01800 /* readline command generator */
01801 static char* sercmd_generator(const char* text, int state)
01802 {
01803         static int idx;
01804         static int list; /* aliases, builtins, rpc_array */
01805         static int len;
01806         char* name;
01807 #ifdef USE_CFG_VARS
01808         static struct cfg_var_grp* grp;
01809 #endif
01810 #ifdef USE_COUNTERS
01811         static struct cnt_var_grp* cnt_grp;
01812 #endif
01813         switch(attempted_completion_state){
01814                 case COMPLETE_INIT:
01815                 case COMPLETE_NOTHING:
01816                         return 0;
01817                 case COMPLETE_CMD_NAME:
01818                         if (state==0){
01819                                 /* init */
01820                                 idx=list=0;
01821                                 len=strlen(text);
01822                         }
01823                         /* return next partial match */
01824                         switch(list){
01825                                 case 0: /* aliases*/
01826                                         while((name=cmd_aliases[idx].name)){
01827                                                 idx++;
01828                                                 if (strncmp(name, text, len)==0)
01829                                                         return strdup(name);
01830                                         }
01831                                         list++;
01832                                         idx=0;
01833                                         /* no break */
01834                                 case 1: /* builtins */
01835                                         while((name=builtins[idx].name)){
01836                                                 idx++;
01837                                                 if (strncmp(name, text, len)==0)
01838                                                         return strdup(name);
01839                                         }
01840                                         list++;
01841                                         idx=0;
01842                                         /* no break */
01843                                 case 2: /* rpc_array */
01844                                         while(idx < rpc_no){
01845                                                 if (rpc_array[idx].type==BINRPC_T_STR){
01846                                                         name=rpc_array[idx].u.strval.s;
01847                                                         idx++;
01848                                                         if (strncmp(name, text, len)==0)
01849                                                                 return strdup(name);
01850                                                 }else{
01851                                                         idx++;
01852                                                 }
01853                                         }
01854                         }
01855                         break;
01856 #ifdef USE_CFG_VARS
01857                 case COMPLETE_CFG_GRP:
01858                         if (state==0){
01859                                 /* init */
01860                                 len=strlen(text);
01861                                 grp=cfg_grp_lst;
01862                         }else{
01863                                 grp=grp->next;
01864                         }
01865                         for(;grp; grp=grp->next){
01866                                 if (len<=grp->grp_name.len &&
01867                                                 memcmp(text, grp->grp_name.s, len)==0) {
01868                                         /* zero-term copy of the grp name */
01869                                         name=malloc(grp->grp_name.len+1);
01870                                         if (name){
01871                                                 memcpy(name, grp->grp_name.s, grp->grp_name.len);
01872                                                 name[grp->grp_name.len]=0;
01873                                         }
01874                                         return name;
01875                                 }
01876                         }
01877                         break;
01878                 case COMPLETE_CFG_VAR:
01879                         if (state==0){
01880                                 /* init */
01881                                 len=strlen(text);
01882                                 idx=0;
01883                         }
01884                         while(idx < crt_cfg_grp->var_no){
01885                                 if (len<=crt_cfg_grp->var_names[idx].len &&
01886                                                 memcmp(text, crt_cfg_grp->var_names[idx].s, len)==0) {
01887                                         /* zero-term copy of the var name */
01888                                         name=malloc(crt_cfg_grp->var_names[idx].len+1);
01889                                         if (name){
01890                                                 memcpy(name, crt_cfg_grp->var_names[idx].s,
01891                                                                          crt_cfg_grp->var_names[idx].len);
01892                                                 name[crt_cfg_grp->var_names[idx].len]=0;
01893                                         }
01894                                         idx++;
01895                                         return name;
01896                                 }
01897                                 idx++;
01898                         }
01899                         break;
01900 #endif /* USE_CFG_VARS */
01901 #ifdef USE_MI
01902                 case COMPLETE_MI:
01903                         if (state==0){
01904                                 /* init */
01905                                 len=strlen(text);
01906                                 idx=0;
01907                         }
01908                         while(idx < mi_cmds_no){
01909                                 if (len<=mi_cmds[idx].len &&
01910                                                 memcmp(text, mi_cmds[idx].s, len)==0) {
01911                                         /* zero-term copy of the var name */
01912                                         name=malloc(mi_cmds[idx].len+1);
01913                                         if (name){
01914                                                 memcpy(name, mi_cmds[idx].s, mi_cmds[idx].len);
01915                                                 name[mi_cmds[idx].len]=0;
01916                                         }
01917                                         idx++;
01918                                         return name;
01919                                 }
01920                                 idx++;
01921                         }
01922                         break;
01923 #endif /* USE_MI */
01924 #ifdef USE_COUNTERS
01925                 case COMPLETE_CNT_GRP:
01926                         if (state==0){
01927                                 /* init */
01928                                 len=strlen(text);
01929                                 cnt_grp=cnt_grp_lst;
01930                         }else{
01931                                 cnt_grp=cnt_grp->next;
01932                         }
01933                         for(;cnt_grp; cnt_grp=cnt_grp->next){
01934                                 if (len<=cnt_grp->grp_name.len &&
01935                                                 memcmp(text, cnt_grp->grp_name.s, len)==0) {
01936                                         /* zero-term copy of the cnt_grp name */
01937                                         name=malloc(cnt_grp->grp_name.len+1);
01938                                         if (name){
01939                                                 memcpy(name, cnt_grp->grp_name.s,
01940                                                                         cnt_grp->grp_name.len);
01941                                                 name[cnt_grp->grp_name.len]=0;
01942                                         }
01943                                         return name;
01944                                 }
01945                         }
01946                         break;
01947                 case COMPLETE_CNT_VAR:
01948                         if (state==0){
01949                                 /* init */
01950                                 len=strlen(text);
01951                                 idx=0;
01952                         }
01953                         while(idx < crt_cnt_grp->var_no){
01954                                 if (len<=crt_cnt_grp->var_names[idx].len &&
01955                                                 memcmp(text, crt_cnt_grp->var_names[idx].s, len)==0) {
01956                                         /* zero-term copy of the var name */
01957                                         name=malloc(crt_cnt_grp->var_names[idx].len+1);
01958                                         if (name){
01959                                                 memcpy(name, crt_cnt_grp->var_names[idx].s,
01960                                                                          crt_cnt_grp->var_names[idx].len);
01961                                                 name[crt_cnt_grp->var_names[idx].len]=0;
01962                                         }
01963                                         idx++;
01964                                         return name;
01965                                 }
01966                                 idx++;
01967                         }
01968                         break;
01969 #endif /* USE_COUNTERS */
01970         }
01971         /* no matches */
01972         return 0;
01973 }
01974 
01975 
01976 
01977 char** sercmd_completion(const char* text, int start, int end)
01978 {
01979         int i, j;
01980         int cmd_start, cmd_end, cmd_len;
01981         int whitespace;
01982 #ifdef USE_CFG_VARS
01983         struct cfg_var_grp* grp;
01984         static int grp_start;
01985         int grp_len;
01986 #endif /* USE_CFG_VARS */
01987 #ifdef USE_COUNTERS
01988         struct cnt_var_grp* cnt_grp;
01989         static int cnt_grp_start;
01990         int cnt_grp_len;
01991 #endif /* USE_COUNTERS */
01992         
01993         crt_param_no=0;
01994         /* skip over whitespace at the beginning */
01995         for (j=0; (j<start) && (rl_line_buffer[j]==' ' ||
01996                                                         rl_line_buffer[j]=='\t'); j++);
01997         cmd_start=j;
01998         if (start==cmd_start){
01999                 /* complete cmd name at beginning */
02000                 attempted_completion_state=COMPLETE_CMD_NAME;
02001 #ifdef USE_CFG_VARS
02002                 grp_start=0;
02003 #endif /* USE_CFG_VARS */
02004 #ifdef USE_COUNTERS
02005                 cnt_grp_start=0;
02006 #endif /* USE_COUNTERS */
02007         }else{ /* or if this is a command for which we complete the parameters */
02008                 /* find first whitespace after command name*/
02009                 for(; (j<start) && (rl_line_buffer[j]!=' ') &&
02010                                         (rl_line_buffer[j]!='\t'); j++);
02011                 cmd_end=j;
02012                 cmd_len=cmd_end-cmd_start;
02013                 /* count params before the current one */
02014                 whitespace=1;
02015                 for (; j<start; j++){
02016                         if (rl_line_buffer[j]!=' ' && rl_line_buffer[j]!='\t'){
02017                                 if (whitespace) crt_param_no++;
02018                                 whitespace=0;
02019                         }else
02020                                 whitespace=1;
02021                 }
02022                 crt_param_no++;
02023                 if (crt_param_no==1){
02024                         for(i=0; complete_params_methods[i]; i++){
02025                                 if ((cmd_len==strlen(complete_params_methods[i])) &&
02026                                                 (strncmp(&rl_line_buffer[cmd_start],
02027                                                                  complete_params_methods[i],
02028                                                                  cmd_len)==0)){
02029                                                 attempted_completion_state=COMPLETE_CMD_NAME;
02030                                                 goto end;
02031                                 }
02032                         }
02033 #ifdef USE_CFG_VARS
02034                         /* try  complete_param*_cfg_grp */
02035                         for(i=0; complete_params_cfg_var[i]; i++){
02036                                 if ((cmd_len==strlen(complete_params_cfg_var[i])) &&
02037                                                 (strncmp(&rl_line_buffer[cmd_start],
02038                                                                  complete_params_cfg_var[i],
02039                                                                  cmd_len)==0)){
02040                                                 attempted_completion_state=COMPLETE_CFG_GRP;
02041                                                 grp_start=start;
02042                                                 goto end;
02043                                 }
02044                         }
02045 #endif /* USE_CFG_VARS */
02046 #ifdef USE_MI
02047                         /* try complete_parms_mi */
02048                         for(i=0; complete_params_mi[i]; i++){
02049                                 if ((cmd_len==strlen(complete_params_mi[i])) &&
02050                                                 (strncmp(&rl_line_buffer[cmd_start],
02051                                                                  complete_params_mi[i],
02052                                                                  cmd_len)==0)){
02053                                                 attempted_completion_state=COMPLETE_MI;
02054                                                 goto end;
02055                                 }
02056                         }
02057 #endif /* USE_MI */
02058 #ifdef USE_COUNTERS
02059                         /* try  complete_param*_cfg_grp */
02060                         for(i=0; complete_param1_counter_grp[i]; i++){
02061                                 if ((cmd_len==strlen(complete_param1_counter_grp[i])) &&
02062                                                 (strncmp(&rl_line_buffer[cmd_start],
02063                                                                  complete_param1_counter_grp[i],
02064                                                                  cmd_len)==0)){
02065                                                 attempted_completion_state=COMPLETE_CNT_GRP;
02066                                                 cnt_grp_start=start;
02067                                                 goto end;
02068                                 }
02069                         }
02070 #endif /* USE_COUNTERS */
02071                 }else if (crt_param_no==2){
02072 #ifdef USE_CFG_VARS
02073                         /* see if we complete cfg. var names for this command */
02074                         for(i=0; complete_params_cfg_var[i]; i++){
02075                                 if ((cmd_len==strlen(complete_params_cfg_var[i])) &&
02076                                         (strncmp(&rl_line_buffer[cmd_start],
02077                                                                  complete_params_cfg_var[i],
02078                                                                  cmd_len)==0)){
02079                                         /* get the group name: */
02080                                         /* find grp_start */
02081                                         for(j=cmd_end; (j<start) && ((rl_line_buffer[j]==' ') ||
02082                                                         (rl_line_buffer[j]=='\t')); j++);
02083                                         grp_start=j;
02084                                         /* find group end / grp_len*/
02085                                         for(j=grp_start; (j<start) && (rl_line_buffer[j]!=' ') &&
02086                                                                 (rl_line_buffer[j]!='\t'); j++);
02087                                         grp_len=j-grp_start;
02088                                         for(grp=cfg_grp_lst; grp; grp=grp->next){
02089                                                 if (grp_len==grp->grp_name.len &&
02090                                                                 memcmp(&rl_line_buffer[grp_start],
02091                                                                                 grp->grp_name.s, grp_len)==0) {
02092                                                         attempted_completion_state=COMPLETE_CFG_VAR;
02093                                                         crt_cfg_grp=grp;
02094                                                         goto end;
02095                                                 }
02096                                         }
02097                                 }
02098                         }
02099 #endif /* USE_CFG_VARS */
02100 #ifdef USE_COUNTERS
02101                         /* see if we complete counter names for this command */
02102                         for(i=0; complete_param2_counter_name[i]; i++){
02103                                 if ((cmd_len==strlen(complete_param2_counter_name[i])) &&
02104                                                 (strncmp(&rl_line_buffer[cmd_start],
02105                                                                 complete_param2_counter_name[i],
02106                                                                 cmd_len)==0)){
02107                                         /* get the group name: */
02108                                         /* find grp_start */
02109                                         for(j=cmd_end; (j<start) && ((rl_line_buffer[j]==' ') ||
02110                                                                         (rl_line_buffer[j]=='\t')); j++);
02111                                         cnt_grp_start=j;
02112                                         /* find group end / cnt_grp_len*/
02113                                         for(j=cnt_grp_start; (j<start) &&
02114                                                         (rl_line_buffer[j]!=' ') &&
02115                                                         (rl_line_buffer[j]!='\t'); j++);
02116                                         cnt_grp_len=j-cnt_grp_start;
02117                                         for(cnt_grp=cnt_grp_lst; cnt_grp; cnt_grp=cnt_grp->next){
02118                                                 if (cnt_grp_len==cnt_grp->grp_name.len &&
02119                                                                 memcmp(&rl_line_buffer[cnt_grp_start],
02120                                                                                 cnt_grp->grp_name.s, cnt_grp_len)==0) {
02121                                                         attempted_completion_state=COMPLETE_CNT_VAR;
02122                                                         crt_cnt_grp=cnt_grp;
02123                                                         goto end;
02124                                                 }
02125                                         }
02126                                 }
02127                         }
02128 #endif /* COUNTERS */
02129                 }
02130                 attempted_completion_state=COMPLETE_NOTHING;
02131         }
02132 end:
02133         return 0; /* let readline call sercmd_generator */
02134 }
02135 
02136 #endif /* USE_READLINE */
02137 
02138 
02139 
02140 /* on exit cleanup */
02141 static void  cleanup()
02142 {
02143         if (unix_socket){
02144                 if (unlink(unix_socket)<0){
02145                         fprintf(stderr, "ERROR: failed to delete %s: %s\n",
02146                                         unix_socket, strerror(errno));
02147                 }
02148         }
02149 }
02150 
02151 
02152 
02153 int main(int argc, char** argv)
02154 {
02155         int c;
02156         char* sock_name;
02157         int port_no;
02158         int sock_type;
02159         int s;
02160         struct binrpc_cmd cmd;
02161         int rec;
02162         struct id_list* sock_id;
02163         char* format;
02164         int interactive;
02165         char* line;
02166         char* l;
02167 
02168         quit=0;
02169         format=0;
02170         line=0;
02171         interactive=0;
02172         rec=1;
02173         s=-1;
02174         sock_name=0;
02175         port_no=0;
02176         sock_type=UNIXS_SOCK;
02177         opterr=0;
02178         while((c=getopt(argc, argv, "UVhs:D:R:vf:"))!=-1){
02179                 switch(c){
02180                         case 'V':
02181                                 printf("version: %s\n", version);
02182                                 printf("%s\n", id);
02183                                 printf("%s compiled on %s \n", __FILE__,
02184                                                 compiled);
02185                                 exit(0);
02186                                 break;
02187                         case 'h':
02188                                 printf("version: %s\n", version);
02189                                 printf("%s", help_msg);
02190                                 exit(0);
02191                                 break;
02192                         case 's':
02193                                 sock_name=optarg;
02194                                 break;
02195                         case 'R':
02196                                 reply_socket=optarg;
02197                                 break;
02198                         case 'D':
02199                                 sock_dir=optarg;
02200                                 break;
02201                         case 'U':
02202                                 sock_type=UDP_SOCK;
02203                                 break;
02204                         case 'v':
02205                                 verbose++;
02206                                 break;
02207                         case 'f':
02208                                 format=str_escape(optarg);
02209                                 if (format==0){
02210                                         fprintf(stderr, "ERROR: memory allocation failure\n");
02211                                         goto error;
02212                                 }
02213                                 break;
02214                         case '?':
02215                                 if (isprint(optopt))
02216                                         fprintf(stderr, "Unknown option `-%c'.\n", optopt);
02217                                 else
02218                                         fprintf(stderr, 
02219                                                         "Unknown option character `\\x%x'.\n",
02220                                                         optopt);
02221                                 goto error;
02222                         case ':':
02223                                 fprintf(stderr, 
02224                                                 "Option `-%c' requires an argument.\n",
02225                                                 optopt);
02226                                 goto error;
02227                         default:
02228                                 abort();
02229                 }
02230         }
02231         if (sock_name==0){
02232                 sock_name=DEFAULT_CTL_SOCKET;
02233         }
02234         
02235         /* init the random number generator */
02236         srand(getpid()+time(0)); /* we don't need very strong random numbers */
02237         
02238         if (sock_name==0){
02239                 fprintf(stderr, "ERROR: no ser address specified\n");
02240                 goto error;
02241         }
02242         sock_id=parse_listen_id(sock_name, strlen(sock_name), sock_type);
02243         if (sock_id==0){
02244                 fprintf(stderr, "ERROR: error parsing ser adress %s\n", sock_name);
02245                 goto error;
02246         }
02247         
02248         switch(sock_id->proto){
02249                 case UDP_SOCK:
02250                 case TCP_SOCK:
02251                         if (sock_id->port==0){
02252                                 sock_id->port=DEFAULT_CTL_PORT;
02253                                 /*
02254                                 fprintf(stderr, "ERROR: no port specified: %s:<port>\n",
02255                                                                 sock_name);
02256                                 goto error;
02257                                 */
02258                         }
02259                         if ((s=connect_tcpudp_socket(sock_id->name, sock_id->port,
02260                                                 (sock_id->proto==UDP_SOCK)?SOCK_DGRAM:
02261                                                                                                         SOCK_STREAM))<0){
02262                                 goto error;
02263                         }
02264                         break;
02265                 case UNIXS_SOCK:
02266                 case UNIXD_SOCK:
02267                         if ((s=connect_unix_sock(sock_id->name,
02268                                                 (sock_id->proto==UNIXD_SOCK)?SOCK_DGRAM:
02269                                                                                                         SOCK_STREAM))<0)
02270                                 goto error;
02271                         break;
02272                 case UNKNOWN_SOCK:
02273                         fprintf(stderr, "ERROR: Bad socket type for %s\n", sock_name);
02274                         goto error;
02275         }
02276         free(sock_id); /* not needed anymore */
02277         sock_id=0;
02278         
02279         if (optind>=argc){
02280                         interactive=1;
02281                         /*fprintf(stderr, "ERROR: no command specified\n");
02282                         goto error; */
02283         }else{
02284                 if (parse_cmd(&cmd, &argv[optind], argc-optind)<0)
02285                         goto error;
02286                 if (run_cmd(s, &cmd, format)<0) 
02287                         goto error;
02288                 goto end;
02289         }
02290         /* interactive mode */
02291         if (get_sercmd_list(s)==0){
02292         #ifdef USE_CFG_VARS
02293                 get_cfgvars_list(s);
02294         #endif /* USE_CFG_VARS */
02295         #ifdef USE_MI
02296                 get_mi_list(s);
02297         #endif /* USE_MI */
02298         #ifdef USE_COUNTERS
02299                 get_counters_list(s);
02300         #endif /* USE_COUNTERS */
02301         }
02302         /* banners */
02303         printf("%s %s\n", NAME, VERSION);
02304         printf("%s\n", COPYRIGHT);
02305         printf("%s\n", DISCLAIMER);
02306 #ifdef USE_READLINE
02307         
02308         /* initialize readline */
02309         /* allow conditional parsing of the ~/.inputrc file*/
02310         rl_readline_name=NAME; 
02311         rl_completion_entry_function=sercmd_generator;
02312         rl_attempted_completion_function=sercmd_completion;
02313         
02314         while(!quit){
02315                 line=readline(NAME "> ");
02316                 if (line==0) /* EOF */
02317                         break; 
02318                 l=trim_ws(line); /* trim whitespace */
02319                 if (*l){
02320                         add_history(l);
02321                         run_line(s, l, format);
02322                 }
02323                 free(line);
02324                 line=0;
02325         }
02326 #else
02327         line=malloc(MAX_LINE_SIZE);
02328         if (line==0){
02329                 fprintf(stderr, "memory allocation error\n");
02330                 goto error;
02331         }
02332         printf(NAME "> "); fflush(stdout); /* prompt */
02333         while(!quit && fgets(line, MAX_LINE_SIZE, stdin)){
02334                 l=trim_ws(line);
02335                 if (*l){
02336                         run_line(s, l, format);
02337                 }
02338                 printf(NAME "> "); fflush(stdout); /* prompt */
02339         };
02340         free(line);
02341         line=0;
02342 #endif /* USE_READLINE */
02343 end:
02344         /* normal exit */
02345         if (line)
02346                 free(line);
02347         if (format)
02348                 free(format);
02349         if (rpc_array)
02350                 free_rpc_array(rpc_array, rpc_no);
02351 #ifdef USE_CFG_VARS
02352         if (cfg_grp_lst)
02353                 free_cfg_grp_lst();
02354         if (cfg_vars_array){
02355                 free_rpc_array(cfg_vars_array, cfg_vars_no);
02356                 cfg_vars_array=0;
02357                 cfg_vars_no=0;
02358         }
02359 #endif /* USE_CFG_VARS */
02360 #ifdef USE_MI
02361         if (mi_cmds)
02362                 free_mi_cmds();
02363         if (mi_which_array){
02364                 free_rpc_array(mi_which_array, mi_which_no);
02365                 mi_which_array=0;
02366                 mi_which_no=0;
02367         }
02368 #endif /* USE_MI */
02369 #ifdef USE_COUNTERS
02370         if (cnt_grp_lst)
02371                 free_cnt_grp_lst();
02372         if (cnt_grps_array){
02373                 free_rpc_array(cnt_grps_array, cnt_grps_no);
02374                 cnt_grps_array=0;
02375                 cnt_grps_no=0;
02376         }
02377 #endif /* USE_COUNTERS */
02378         cleanup();
02379         exit(0);
02380 error:
02381         if (line)
02382                 free(line);
02383         if (format)
02384                 free(format);
02385         if (rpc_array)
02386                 free_rpc_array(rpc_array, rpc_no);
02387 #ifdef USE_CFG_VARS
02388         if (cfg_grp_lst)
02389                 free_cfg_grp_lst();
02390         if (cfg_vars_array){
02391                 free_rpc_array(cfg_vars_array, cfg_vars_no);
02392                 cfg_vars_array=0;
02393                 cfg_vars_no=0;
02394         }
02395 #endif /* USE_CFG_VARS */
02396 #ifdef USE_MI
02397         if (mi_cmds)
02398                 free_mi_cmds();
02399         if (mi_which_array){
02400                 free_rpc_array(mi_which_array, mi_which_no);
02401                 mi_which_array=0;
02402                 mi_which_no=0;
02403         }
02404 #endif /* USE_MI */
02405 #ifdef USE_COUNTERS
02406         if (cnt_grp_lst)
02407                 free_cnt_grp_lst();
02408         if (cnt_grps_array){
02409                 free_rpc_array(cnt_grps_array, cnt_grps_no);
02410                 cnt_grps_array=0;
02411                 cnt_grps_no=0;
02412         }
02413 #endif /* USE_COUNTERS */
02414         cleanup();
02415         exit(-1);
02416 }