Blob Blame History Raw
/*
 * $Id: main.cpp,v 1.36 2013/09/19 14:34:26 hellerda Exp $
 *
 * main.cpp
 *
 * (C) Copyright IBM Corp. 2002, 2004, 2008
 *
 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
 * ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
 * CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
 *
 * You can obtain a current copy of the Eclipse Public License from
 * http://www.opensource.org/licenses/eclipse-1.0.php
 *
 * Author:       Adrian Schuur <schuur@de.ibm.com>
 * Contributors: Viktor Mihajlovski <mihajlov@de.ibm.com>
 *               Markus Mueller <markus_mueller@de.ibm.com>
 *               Steve Shepherd <steve.shepherd@configuresoft.com>
 *               Heidi Neumann  <heidineu@de.ibm.com>
 *               David Eger <dteger@us.ibm.com>
 *               Philip K. Warren <pkw@us.ibm.com>
 *               Tyrel Datwyler <tyreld@us.ibm.com>
 *
 * Description: Line command interface to DMTF conforming WBEM servers
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#if HAVE_STRING_H
#include <string.h>
#endif

#include "CimXml.h"

#ifdef HAVE_LIBWWW
#include "Cimwww.h"
#elif HAVE_LIBCURL
#include "CimCurl.h"
#elif HAVE_LIBGHTTP
#include "Cimghttp.h"
#elif WIN32
#include "CimWinHttp.h"
#else
#error "No HTTP Library Configured"
#endif

#ifndef WIN32
#include <ctype.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#endif

using namespace std;

extern int useNl;
extern int noVal;
extern int addType;
extern int openwbem;
extern int dlmRefs;
extern int reqChunking;
extern int expect100;
int waitTime;


static void usage(int indir, int op, char *cmd)
{
   cerr<<"usage:";
   cerr<<"\twbemcli gc|gcd|dc|ec|ecn|gi|ci|mi|di|ei|ein|ain|ai|rin|ri|gp|sp|cm|cmx\n"
         "\t        [-nl] [-dx] [-t] [-cte] [-h] [-v] [-w <waittime>] [-e100]\n"
         "\t        [-noverify] [-cacert <file>] [-clientcert <file>] [-clientkey <file>]\n"
         "\t        [-ac <assocClass>] [-arc <resultClass>] [-ar <role>] [-arr <resultRole>]\n"
         "\t        objectPath [prop=value,[...]] [props[,...]]\n"<<endl;
   cerr<<"\texample: wbemcli gi 'http://localhost:5988/root/cimv2:rpm_package.name=\"glibc\"'\n"<<endl;
   cerr<<"\tUse man wbemcli for details"<<endl;

}

static int hexValue(char v)
{
   if ((v-'0')<10) return v-'0';
   if (v>='a' && v<='f') return v-'a'+10;
   if (v>='A' && v<='F') return v-'A'+10;
   else return -1;
}

static void cleanUpMsg(string &msg)
{
   for (int m=msg.size(),i=0; i<m; i++) {
      if (msg.at(i)=='\n') {
         if (i<m-1 && msg.at(i+1)!='*') {
	    if (msg.at(i+1)=='\n') { msg.erase(i,1); i--; m--; continue; }
	    msg.insert(i+1,"* ");
	    m+=2;
	    i+=2;
	    continue;
	 }
      }
      else if (msg.at(i)=='%') {
         char c[2]=" ";
         if (i<m-2) {
	    if ((c[0]=hexValue(msg.at(i+1))*16)>=0) {
	       if (hexValue(msg.at(i+2))>=0) {
	          c[0]|=hexValue(msg.at(i+2));
	          msg.erase(i,3);
	          msg.insert(i,c);
	          m-=2;
	          continue;
	       }
	    }
	 }
      }
   }
}


int main (int argc, char *argv[]) {
   int pos, retval = 0;
   char *cmd, *params, *endptr, *opStr=NULL,*urlStr=NULL,*xtraStr=NULL;
   char *assocClass=NULL,*resultClass=NULL,*role=NULL,*resultRole=NULL;
   const char *cacert=CACERT, *clientcert=NULL, *clientkey=NULL;
   int n=1,err=0,op=0,cmdln,help=0,indir=0, noverify=0;
   ClassXml *cls=0;
   InstanceXml *inst=0;
   InstanceNameXml *in=0;
   InstanceNamesXml *ina=0;
   NamedInstancesXml *nia=0;
   ObjectsWithPathXml *owp=0;
   ValueXml *va=0;
   // InstancesXml *ia; // - not yet used
   ClassNamesXml *cna=0;
   ClassesXml *ca=0;
   MethodresponseXml *mrsp=0;
   string sb;
#ifdef HAVE_LIBWWW
   CimomWww cimom;
#elif HAVE_LIBCURL
   // This needs to be called once before any curl functions are called
   curl_global_init(CURL_GLOBAL_ALL);
   CimomCurl cimom;
#elif HAVE_LIBGHTTP
   CimomGhttp cimom;
#else
   CimomWinHttp cimom;
#endif

   cmd=argv[0];
   cmdln=strlen(cmd);
   n=1;

#ifdef DBGX
   cerr << "Invoked as: " << cmd << "\n";
#endif
 
   cimom.mErrorData.mStatusCode=0;
   
   indir=1;
   if (strcmp(cmd+cmdln-6,"wbemgi")==0) 	op=GetInstance;
   else if (strcmp(cmd+cmdln-7,"wbemein")==0) 	op=EnumInstanceNames;
   else if (strcmp(cmd+cmdln-6,"wbemei")==0) 	op=EnumInstances;
   else if (strcmp(cmd+cmdln-6,"wbemci")==0) 	op=CreateInstance;
   else if (strcmp(cmd+cmdln-6,"wbemmi")==0) 	op=ModifyInstance;
   else if (strcmp(cmd+cmdln-6,"wbemdi")==0) 	op=DeleteInstance;
   else if (strcmp(cmd+cmdln-6,"wbemgc")==0) 	op=GetClass;
   else if (strcmp(cmd+cmdln-6,"wbemec")==0) 	op=EnumClasses;
   else if (strcmp(cmd+cmdln-7,"wbemecn")==0) 	op=EnumClassNames;
   else if (strcmp(cmd+cmdln-6,"wbemdc")==0) 	op=DeleteClass;
   else if (strcmp(cmd+cmdln-7,"wbemgcd")==0) 	op=GetClassDef;
   /* ----------- Associator Provider Interface ---------------- */
   else if (strcmp(cmd+cmdln-7,"wbemain")==0) 	op=AssociatorNames;
   else if (strcmp(cmd+cmdln-6,"wbemai")==0) 	op=Associators;
   else if (strcmp(cmd+cmdln-7,"wbemrin")==0) 	op=ReferenceNames;
   else if (strcmp(cmd+cmdln-6,"wbemri")==0) 	op=References;
   /* -------- end of Associator Provider Interface ------------ */
   else if (strcmp(cmd+cmdln-6,"wbemgp")==0) 	op=GetProperty;
   else if (strcmp(cmd+cmdln-6,"wbemsp")==0) 	op=SetProperty;
   else if (strcmp(cmd+cmdln-6,"wbemcm")==0) 	op=CallMethod;
   else if (strcmp(cmd+cmdln-7,"wbemcmx")==0) 	op=CallMethodX;
   else n=op=indir=0;

   try {
     if (argc==1) {
       help=1; // force usage directions if no args
     }
      for (argv++; *argv; argv++) {
         if (*argv[0]=='-') {
           if (strcmp(*argv,"-nl")==0) useNl=1;
           else if (strcmp(*argv,"-noverify")==0) noverify=1;
           else if (strcmp(*argv,"-cacert")==0) cacert=*(++argv);
           else if (strcmp(*argv,"-clientcert")==0) clientcert=*(++argv);
           else if (strcmp(*argv,"-clientkey")==0) clientkey=*(++argv);
           else if (strcmp(*argv,"-dx")==0) dumpXml=1;
           else if (strcmp(*argv,"-cte")==0) reqChunking=1;
           else if (strcmp(*argv,"-t")==0) addType=1;
           else if (strcmp(*argv,"-dr")==0) dlmRefs=1;
           else if (strcmp(*argv,"-ow")==0) openwbem=1;
           else if (strcmp(*argv,"-h")==0) help=1;
	   else if (strcmp(*argv,"-ac")==0) assocClass=*(++argv);
 	   else if (strcmp(*argv,"-arc")==0) resultClass=*(++argv);
 	   else if (strcmp(*argv,"-ar")==0) role=*(++argv);
 	   else if (strcmp(*argv,"-arr")==0) resultRole=*(++argv);
           else if (strcmp(*argv,"-e100")==0) expect100 = 1;
           else if (strcmp(*argv,"-w")==0) {
             waitTime = (int) strtol(*(++argv),&endptr,0);
             if (endptr == *argv) err=1;  // no digits found
           }
           else if (strcmp(*argv,"-v")==0) {
              cerr<<"* wbemcli Version " PACKAGE_VERSION ", $Date: 2013/09/19 14:34:26 $" <<endl;
              goto fini;
           }
           else err=1;
         }
         else {
            if (n==0) opStr=*argv;
            else if (n==1) urlStr=strdup(*argv);
            else if (n==2) xtraStr=*argv;
            else err=1; //throw CmdException("Invalid command invocation");
            n++;
         }
      }


      if (help) {
         usage(indir,op,cmd);
         retval = 0;
	 goto fini;
      }

      if (err) {
         cerr<<cmd<<": Invalid invocation syntax"<<endl;
         usage(indir,op,cmd);
         retval = 16;
	 goto fini;
      }

      if (op==0 && opStr==NULL) throw CmdException("No operation specified");
      if (urlStr==NULL) throw CmdException("No URL specified");

      if (op==0) {
         if (strcmp(opStr,"gi")==0)		op=GetInstance;
         else if (strcmp(opStr,"ein")==0) 	op=EnumInstanceNames;
         else if (strcmp(opStr,"ei")==0) 	op=EnumInstances;

         else if (strcmp(opStr,"ci")==0) 	op=CreateInstance;
         else if (strcmp(opStr,"mi")==0) 	op=ModifyInstance;
         else if (strcmp(opStr,"di")==0) 	op=DeleteInstance;

         else if (strcmp(opStr,"gc")==0) 	op=GetClass;
         else if (strcmp(opStr,"ec")==0) 	op=EnumClasses;
         else if (strcmp(opStr,"ecn")==0) 	op=EnumClassNames;
         else if (strcmp(opStr,"dc")==0) 	op=DeleteClass;
         else if (strcmp(opStr,"gcd")==0) 	op=GetClassDef;

	 /* ---------- Associator Provider Interface ------------ */
         else if (strcmp(opStr,"ain")==0) 	op=AssociatorNames;
         else if (strcmp(opStr,"ai")==0) 	op=Associators;
         else if (strcmp(opStr,"rin")==0) 	op=ReferenceNames;
         else if (strcmp(opStr,"ri")==0) 	op=References;
	 /* -------- end of Associator Provider Interface ------- */

         else if (strcmp(opStr,"gp")==0) 	op=GetProperty;
         else if (strcmp(opStr,"sp")==0) 	op=SetProperty;
         else if (strcmp(opStr,"cm")==0) 	op=CallMethod;
         else if (strcmp(opStr,"cmx")==0) 	op=CallMethodX;

         else throw CmdException("Invalid operation");
      }

      URL url(urlStr);
      if ((op!=CreateInstance &&
           op!=GetInstance &&
           op!=GetClass &&
           op!=GetProperty &&
           op!=SetProperty &&
           op!=EnumInstances &&
           op!=Associators &&
           op!=References &&
           op!=CallMethod &&
           op!=CallMethodX &&
	   op!=ModifyInstance) && xtraStr)
         throw CmdException("Invalid command invocation 1");
      if ((op==CreateInstance ||
           op==GetProperty ||
           op==SetProperty ||
           op==CallMethod ||
           op==ModifyInstance) && !xtraStr)
         throw CmdException("Invalid command invocation 2");

      
      if (url.scheme == "https") {
	cimom.setClientCertificates(cacert,noverify,clientcert,clientkey);
      }
      switch (op) {

      case GetInstance:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (url.keys.size() == 0)
           throw CmdException("Keys not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((inst=cimom.getInstance(url,xtraStr))) {
            url.toStringBufferGI(sb);
            if (useNl) sb += "\n";
            else sb += " ";
	    inst->propagateKeyFlags(url.keys);
            inst->toStringBuffer(sb);
            cout << sb << endl;
         }
         break;

      case EnumInstanceNames:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((ina=cimom.enumInstanceNames(url))) {
            for (int i=0,s=ina->size(); i<s; i++) {
               sb.erase();
               InstanceNameXml& n=(*ina)[i];
               url.toStringBuffer(sb,1);
               n.toStringBuffer(sb,":");
               cout << sb << endl;
            }
         }
         break;

      case EnumInstances:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((nia=cimom.enumInstances(url,xtraStr))) {
            for (int i=0,s=nia->size(); i<s; i++) {
               sb.erase();
               InstanceXml in=nia->getInst(i);
               InstanceNameXml n=nia->getName(i);
               url.toStringBuffer(sb,1);
               n.toStringBuffer(sb,":");
	       in.propagateKeyFlags(n.keys);
               if (useNl) sb += "\n";
               else sb += " ";
               in.toStringBuffer(sb);
               cout << sb << endl;
            }
         }
         break;

      case CreateInstance:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (url.keys.size() == 0)
           throw CmdException("Keys not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((cls=cimom.getClass(url))) {
            if ((in=cimom.createInstance(url,cls,xtraStr))) {
               url.toStringBuffer(sb,1);
               in->toStringBuffer(sb,":");
               cout << sb << endl;
            }
         }
         break;

      case ModifyInstance:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (url.keys.size() == 0)
           throw CmdException("Keys not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((inst=cimom.getInstance(url)))
            cimom.modifyInstance(url,inst,xtraStr);
         break;

      case DeleteInstance:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (url.keys.size() == 0)
           throw CmdException("Keys not specified");
         cimom.deleteInstance(url);
         break;

      case GetClass:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         noVal=1;
         if ((cls=cimom.getClass(url,xtraStr))) {
            url.toStringBuffer(sb,0);
            if (useNl) sb += "\n";
            else sb += " ";
            cls->toStringBuffer(sb);
            cout << sb << endl;
         }
         break;

      case GetClassDef:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         noVal=1;
         sb = cimom.getClass2str(&url, NULL, false, false);
         sb.erase(0, sb.find("<IRETURNVALUE>") + 14);
         pos = sb.find("</IRETURNVALUE>");
         sb.erase(pos, sb.size() - pos);
         cout << sb << endl;
         break;

      case EnumClassNames:
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
//         try {
         if ((cna=cimom.enumClassNames(url))) {
            for (int i=0,s=cna->size(); i<s; i++) {
               sb.erase();
               ClassNameXml *n=cna->get(i);
               url.toStringBuffer(sb,1);
               n->toStringBuffer(sb,":");
               cout << sb << endl;
            }
         }
 /*        }
         catch (...) {
            string resp = cimom.enumClassesSMC(&url);
            if (resp.size() > 0) {
               char *response = (char *) malloc(resp.size() + 1);
               memcpy(response, resp.c_str(), resp.size());
               char *line = strtok(response, "\n");
               for (  ; line != NULL ; line = strtok(NULL, "\n") ) {
                  if (strstr(line, "<CLASS ")) {
                     char *name = strstr(line, "NAME=\"");
                     if (name) {
                        name += strlen("NAME=\"");
                        if (strchr(name, '"'))  *strchr(name, '"') = '\0';
                        sb.erase();
                        url.toStringBuffer(sb,1);
                        cout << sb << ":" << name << endl;
                     }
                  }
               }
               free(response);
            }
         } */
         break;

      case EnumClasses:
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         noVal=1;
         if ((ca=cimom.enumClasses(url))) {
            for (int i=0,s=ca->size(); i<s; i++) {
               sb.erase();
               ClassXml *n=ca->get(i);
               url.toStringBuffer(sb,2);
               if (useNl) sb = sb + ":" + n->clsName + " : " + n->superClass + "\n";
               else sb = sb + ":" + n->clsName + " ";
               n->toStringBuffer(sb,"");
               cout << sb << endl;
            }
         }
         break;

      case DeleteClass:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         cimom.deleteClass(url);
         break;

	 /* ------------- Associator Provider Interface ---------------- */

      case AssociatorNames:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 //	 if (BAD_ASSOC_NAMES_PARMS)
	 //           throw CmdException("Invalid command invocation");
         if ((ina=cimom.associatorNames(url,assocClass,resultClass,role,resultRole))) {
            for (int i=0,s=ina->size(); i<s; i++) {
               sb.erase();
               InstanceNameXml& n=(*ina)[i];
               // url.toStringBuffer(sb,1);
               n.toStringBuffer(sb,":");
               cout << sb << endl;
            }
         }
         break;

      case Associators:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if ((owp=cimom.associators(url,assocClass,resultClass,role,resultRole,xtraStr))) {
            for (int i=0,s=owp->size(); i<s; i++) {
               sb.erase();
               InstanceXml in=owp->getInst(i);
               InstancePathXml n=owp->getName(i);
               // url.toStringBuffer(sb,1);
               n.toStringBuffer(sb,":");
	            in.propagateKeyFlags(n.name.keys);
               if (useNl) sb += "\n";
               else sb += " ";
               in.toStringBuffer(sb);
               cout << sb << endl;
            }
         }
         break;

      case ReferenceNames:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 if (BAD_REFERENCES_PARMS)
           throw CmdException("Invalid command invocation");
         if ((ina=cimom.referenceNames(url,resultClass,role))) {
            for (int i=0,s=ina->size(); i<s; i++) {
               sb.erase();
               InstanceNameXml& n=(*ina)[i];
               //url.toStringBuffer(sb,1);
               n.toStringBuffer(sb,":");
               cout << sb << endl;
            }
         }
         break;

      case References:
         if (url.cName == "")
           throw CmdException("Class name not specified");
	 if (BAD_REFERENCES_PARMS)
           throw CmdException("Invalid command invocation");
         if ((owp=cimom.references(url,resultClass,role,xtraStr))) {
            for (int i=0,s=owp->size(); i<s; i++) {
               sb.erase();
               InstanceXml in=owp->getInst(i);
               InstancePathXml n=owp->getName(i);
               //url.toStringBuffer(sb,1);
               n.toStringBuffer(sb,":");
	       in.propagateKeyFlags(n.name.keys);
               if (useNl) sb += "\n";
               else sb += " ";
               in.toStringBuffer(sb);
               cout << sb << endl;
            }
         }
         break;

	 /* ---------- end of Associator Provider Interface ------------ */

      case GetProperty:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (url.keys.size() == 0)
           throw CmdException("Keys not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
	 try {
            if ((va=cimom.getProperty(url,xtraStr))) {
               va->toStringBuffer(sb,"");
               cout << sb << endl;
            }
	 }
	 catch (EmptyValue e) {
	    cout<<endl;
	 }
	 break;

      case SetProperty:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (url.keys.size() == 0)
           throw CmdException("Keys not specified");
	 if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((cls=cimom.getClass(url))) {
            cimom.setProperty(url,cls,xtraStr);
	 }
	 break;

      case CallMethodX:
         if (url.cName == "")
           throw CmdException("Class name not specified");
//         if (url.keys.size() == 0)
//           throw CmdException("Keys not specified");
         if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((params = strchr(xtraStr, '.')))
           *(params++) = '\0';

         sb = cimom.callMethod2str(&url, xtraStr, params);
         sb.erase(0, sb.find("<SIMPLERSP>") + 11);
         pos = sb.find("</SIMPLERSP>");
         sb.erase(pos, sb.size() - pos);
         cout << sb << endl;
         break;

       case CallMethod:
         if (url.cName == "")
           throw CmdException("Class name not specified");
         if (ASSOC_PARMS)
           throw CmdException("Invalid command invocation");
         if ((params = strchr(xtraStr, '.')))
           *(params++) = '\0';

         if ((mrsp=cimom.callMethod(url,xtraStr,params))) {
            url.toStringBuffer(sb,0);
	    sb += " ";
	    mrsp->toStringBuffer(sb);
            cout << sb << endl;
         }
         break;

     default:
         throw CmdException("Command not (yet) supported");
      }
   }

   catch (NoReturnValue e) {
     //   cout<<endl;
   }
   catch (XmlException e) {
     cleanUpMsg(e.msg);
      cerr<<"*"<<endl
          <<"* "<<cmd<<": "<<e.msg<<endl
          <<"*"<<endl;
      retval = 16;
      goto fini;
   } catch(...) {
     cerr<<"*"<<endl
         <<"* what happened? " <<endl
	 <<"*"<<endl;
     retval = 16;
     goto fini;
   }

fini:
   free(urlStr);

   delete cls;
   delete inst;
   delete in;
   delete ina;
   delete nia;
   delete owp;
   delete va;
   // delete ia; // - not yet used
   delete cna;
   delete ca;
   delete mrsp;
#ifdef HAVE_LIBCURL
   // These needs to be called once
   curl_global_cleanup();
#endif
   return 0;
}