kdb.c

00001 /***************************************************************************
00002                           kdb.c  -  Tool for the kdb administration
00003                              -------------------
00004     begin                : Mon Mar 02 2003
00005     copyright            : (C) 2003 by Avi Alkalay
00006     email                : avi@unix.sh
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the BSD License (revised).                      *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 
00017 /* Subversion stuff
00018 
00019 $Id: kdb.c 945 2006-12-23 21:31:13Z aviram $
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #ifndef HASGETOPT
00028 #include "BSDgetopt.h"
00029 #endif
00030 
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <stdio.h>
00034 #include <time.h>
00035 #include <locale.h>
00036 #include <unistd.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #ifdef HAVE_GRP_H
00040 #include <grp.h>
00041 #endif
00042 #ifdef HAVE_PWD_H
00043 #include <pwd.h>
00044 #endif
00045 #include <ctype.h>
00046 #include <ltdl.h>
00047 #include <assert.h>
00048 /* We need fcntl.h for open and related constants used in our definition of mkstemp */
00049 #ifdef HAVE_WIN32
00050 #include <fcntl.h>
00051 #endif
00052 
00053 #include "kdb.h"
00054 #include "kdbLibLoader.h"
00055 
00056 #define CMD_GET       1
00057 #define CMD_SET       2
00058 #define CMD_REMOVE    3
00059 #define CMD_LIST      4
00060 #define CMD_LINK      5
00061 #define CMD_EDIT      6
00062 #define CMD_LOAD      7
00063 #define CMD_SAVE      8
00064 #define CMD_MONITOR   9
00065 #define CMD_MOVE      10
00066 #define CMD_INFO      25
00067 #define CMD_HELP      30
00068 
00069 #define ARGSIZE      30
00070 
00071 
00072 #ifdef HAVE_WIN32
00073 #define mkstemp(m) open(mktemp(m), O_RDWR)
00074 #endif
00075 
00076 /* we are cheating . . . */
00077 ssize_t unencode(char *encoded, void *returned);
00078 
00079 
00080 /* We'll load this methods dynamically to avoid libxml dependencies */
00081 int (*ksFromXMLfile)(KeySet *ks,char *filename);
00082 int (*ksFromXML)(KeySet *ks,int fd);
00083 
00084 
00085 
00091 char *argComment=0;
00092 char *argFile=0;
00093 char *argData=0;
00094 char *argKeyName=0;
00095 char *argDomain=0;
00096 uid_t *argUID=0;
00097 uid_t *argGID=0;
00098 int argCommand=0;
00099 int argRecursive=0;
00100 int argLong=0;
00101 int argValue=0;
00102 int argAll=0;
00103 int argSort=1;
00104 int argDescriptive=0;
00105 int argFullName=0;
00106 int argShow=1;
00107 int argShell=0;
00108 int argXML=0;
00109 int argDir=0;
00110 int argHelp=0;
00111 mode_t argMode=0;
00112 int argType=KEY_TYPE_UNDEFINED;
00113 
00114 
00115 /* Exported functions from help.c */
00116 int commandHelp();
00117 int helpCommand(int command);
00118 
00119 
00120 int parseCommandLine(int argc, char *argv[]) {
00121     char sargType[ARGSIZE],argUser[ARGSIZE],argGroup[ARGSIZE];
00122     char sargMode[ARGSIZE],sargCommand[ARGSIZE];
00123     char * keyEnv;
00124     size_t keyEnvLength=0, keyOptLength=0, keyOldLength;
00125 
00126     int opt;
00127 
00128     *sargType=*argUser=*argGroup=*sargCommand=*sargMode=0;
00129 
00130     while ((opt=getopt(argc,argv,"ab:c:dfg:hilm:nrRst:u:vx"))!=-1)
00131     {
00132         if (opt == EOF)
00133             break;
00134         switch (opt)
00135         {
00136         case 'a':
00137             argAll=1;
00138             break;
00139         case 'b':
00140             argFile=realloc(argFile,strlen(optarg)+1);
00141             assert(argFile!=NULL);
00142             strcpy(argFile,optarg);
00143             break;
00144         case 'c':
00145             argComment=realloc(argComment,strlen(optarg)+1);
00146             assert(argComment!=NULL);
00147             strcpy(argComment,optarg);
00148             break;
00149         case 'd':
00150             argDescriptive=1;
00151             argLong=1;
00152             argDir=1;
00153             break;
00154         case 'f':
00155             argFullName=1;
00156             break;
00157         case 'g':
00158             strncpy(argGroup,optarg,ARGSIZE);
00159             break;
00160         case 'h':
00161             argHelp=1;
00162             break;
00163         case 'i':
00164             argShow=0;
00165             break;
00166         case 'l':
00167             argLong=1;
00168             break;
00169         case 'm':
00170             strncpy(sargMode,optarg,ARGSIZE);
00171             break;
00172         case 'n':
00173             argSort=0;
00174             break;
00175         case 'R':
00176         case 'r':
00177             argRecursive=KDB_O_RECURSIVE;
00178             break;
00179         case 's':
00180             argShell=1;
00181             break;
00182         case 't':
00183             strncpy(sargType,optarg,ARGSIZE);
00184             break;
00185         case 'u':
00186             strncpy(argUser,optarg,ARGSIZE);
00187             break;
00188         case 'v':
00189             argValue=1;
00190             break;
00191         case 'x':
00192             argXML=1;
00193             break;
00194         default:
00195             fprintf(stderr, "Unknown error (%d %c) in parsing arguments\n",
00196                     opt,opt);
00197             break;
00198         }
00199     }
00200 
00201     if (optind < argc) /*parse command*/
00202     {
00203         strncpy(sargCommand,argv[optind],ARGSIZE);
00204         optind ++;
00205     } else {
00206         commandHelp();
00207         exit(0);
00208     }
00209         
00211     keyEnv = getenv ("KDB_ROOT");
00212     if (keyEnv) keyEnvLength = strblen (keyEnv);
00213     else keyEnvLength = 0;
00214     if (optind < argc) /*parse key name*/
00215     {
00216         keyOptLength = strblen (argv[optind]);
00217         argKeyName=realloc(argKeyName,
00218             keyEnvLength + keyOptLength + 1);
00219         assert(argKeyName!=NULL);
00220         if (keyEnv) strncpy (argKeyName, keyEnv,   keyEnvLength);
00221         strncpy(argKeyName + keyEnvLength, argv[optind], keyOptLength);
00222         if (keyEnv) *(argKeyName+keyEnvLength-1) = '/';
00223         optind ++;
00224     } else if (keyEnv) {
00225         argKeyName=realloc(argKeyName, keyEnvLength + 1);
00226         assert(argKeyName!=NULL);
00227         if (keyEnv) strncpy (argKeyName, keyEnv, keyEnvLength);
00228     }
00229         
00230 
00231     keyOptLength = 0;
00232     keyOldLength = 0;
00233     while (optind < argc) /* parse value (rest of arguments) */
00234     {
00235         keyOptLength += strblen(argv[optind]);
00236         argData=realloc(argData,keyOptLength + 1);
00237         assert(argData!=NULL);
00238         if (keyOldLength > 0) *(argData+keyOldLength-1) = ' ';
00239         strcpy(argData+keyOldLength, argv[optind]);
00240         optind ++;
00241         keyOldLength = keyOptLength;
00242     }
00243     
00244     /* see if parsing worked:
00245     fprintf (stderr, "command: %s\n", sargCommand);
00246     fprintf (stderr, "key name: %s\n", argKeyName);
00247     fprintf (stderr, "value: %s\n", argData);
00248     exit (0);
00249     */
00250         
00251     /* End of command line argument reading. Now parse and finalize */
00252 
00253     /* Check parsed command */
00254     if (!strcmp(sargCommand,"ls"))           argCommand=CMD_LIST;
00255     else if (!strcmp(sargCommand,"set"))     argCommand=CMD_SET;
00256     else if (!strcmp(sargCommand,"get"))     argCommand=CMD_GET;
00257     else if (!strcmp(sargCommand,"ln"))      argCommand=CMD_LINK;
00258     else if (!strcmp(sargCommand,"rm"))      argCommand=CMD_REMOVE;
00259     else if (!strcmp(sargCommand,"vi"))      argCommand=CMD_EDIT;
00260     else if (!strcmp(sargCommand,"edit"))    argCommand=CMD_EDIT;
00261     else if (!strcmp(sargCommand,"load"))    argCommand=CMD_LOAD;
00262     else if (!strcmp(sargCommand,"import"))  argCommand=CMD_LOAD;
00263     else if (!strcmp(sargCommand,"save"))    argCommand=CMD_SAVE;
00264     else if (!strcmp(sargCommand,"export"))  argCommand=CMD_SAVE;
00265     else if (!strcmp(sargCommand,"mon"))     argCommand=CMD_MONITOR;
00266     else if (!strcmp(sargCommand,"monitor")) argCommand=CMD_MONITOR;
00267     else if (!strcmp(sargCommand,"mv"))      argCommand=CMD_MOVE;
00268     else if (!strcmp(sargCommand,"info"))    argCommand=CMD_INFO;
00269     else if (!strcmp(sargCommand,"help"))    argCommand=CMD_HELP;
00270     else {
00271         fprintf(stderr,"kdb: Invalid subcommand.\n");
00272         exit(1);
00273     }
00274 
00275     /* Parse type */
00276     if (*sargType!=0) {
00277         /* TODO: use regex */
00278         if      (!strcmp(sargType,"string")) argType=KEY_TYPE_STRING;
00279         else if (!strcmp(sargType,"bin"))    argType=KEY_TYPE_BINARY;
00280         else if (!strcmp(sargType,"binary")) argType=KEY_TYPE_BINARY;
00281         else if (!strcmp(sargType,"dir"))    argDir=1; /* bkwrds compatibility */
00282         else if (!strcmp(sargType,"link"))   argType=KEY_TYPE_LINK;
00283         else {
00284             argType=strtol(sargType,0,10);
00285             if (errno == ERANGE || errno == EINVAL)
00286                 /* handle undefined later */
00287                 argType=KEY_TYPE_UNDEFINED;
00288         }
00289     } else if (argCommand==CMD_SET) { /* We must have a type */
00290         argType=KEY_TYPE_STRING;
00291     }
00292 
00293 #ifdef HAVE_PWD_H
00294     /* Parse UID */
00295     if (*argUser) {
00296         if (isdigit(*argUser)) {
00297             argUID=malloc(sizeof(uid_t));
00298             *argUID=atoi(argUser);
00299         } else {
00300             struct passwd *pwd;
00301             pwd=getpwnam(argUser);
00302             if (pwd) {
00303                 argUID=malloc(sizeof(uid_t));
00304                 *argUID=pwd->pw_uid;
00305             } else {
00306                 fprintf(stderr,"kdb: Invalid user \'%s\'. Ignoring\n", argUser);
00307             }
00308         }
00309     }
00310 #endif
00311 #ifdef HAVE_GRP_H
00312     /* Parse GID */
00313     if (*argGroup) {
00314         if (isdigit(*argGroup)) {
00315             argGID=malloc(sizeof(gid_t));
00316             *argGID=atoi(argGroup);
00317         } else {
00318             struct group *grp;
00319             grp=getgrnam(argGroup);
00320             if (grp) {
00321                 argGID=malloc(sizeof(gid_t));
00322                 *argGID=grp->gr_gid;
00323             } else {
00324                 fprintf(stderr,"kdb: Invalid group \'%s\'. Ignoring\n",argGroup);
00325             }
00326         }
00327     }
00328 #endif
00329 
00330 
00331     /* Parse permissions */
00332     if (*sargMode!=0) argMode=strtol(sargMode,0,8);
00333 
00334     return argCommand;
00335 }
00336 
00337 
00338 
00339 
00340 
00341 
00342 /*
00343  * Helper for the 'kdb ls' command
00344  *
00345  */
00346 void listAccess(Key *key,char *readable) {
00347     mode_t mode=keyGetAccess(key);
00348 
00349     if (keyIsDir(key)) readable[0]='d';
00350     #ifdef S_ISLNK
00351     else if (keyIsLink(key)) readable[0]='l';
00352     #endif
00353     else readable[0]='-';
00354 
00355     readable[1] = mode & S_IRUSR ? 'r' : '-';
00356     readable[2] = mode & S_IWUSR ? 'w' : '-';
00357     readable[3] = mode & S_IXUSR ? 'x' : '-';
00358     #ifdef HAVE_WIN32
00359     readable[4] = 0;
00360     #else
00361     readable[4] = mode & S_IRGRP ? 'r' : '-';
00362     readable[5] = mode & S_IWGRP ? 'w' : '-';
00363     readable[6] = mode & S_IXGRP ? 'x' : '-';
00364     readable[7] = mode & S_IROTH ? 'r' : '-';
00365     readable[8] = mode & S_IWOTH ? 'w' : '-';
00366     readable[9] = mode & S_IXOTH ? 'x' : '-';
00367     readable[10]= 0;
00368     #endif
00369 }
00370 
00371 
00372 
00373 
00374 /*
00375  * Helper for the 'kdb ls' command
00376  *
00377  */
00378 void listTime(time_t when,char *readable) {
00379     time_t current_time=time(0);
00380     char buf[400];
00381     #ifndef HAVE_CTIME_R
00382     char *ctimep = NULL;
00383     #endif
00384     time_t six_months_ago;
00385     int recent;
00386 
00387     /* If the file appears to be in the future, update the current
00388        time, in case the file happens to have been modified since
00389        the last time we checked the clock.  */
00390 
00391     /* Consider a time to be recent if it is within the past six
00392        months.  A Gregorian year has 365.2425 * 24 * 60 * 60 ==
00393        31556952 seconds on the average.  Write this value as an
00394        integer constant to avoid floating point hassles.  */
00395     six_months_ago = current_time - 31556952 / 2;
00396     recent = (six_months_ago <= when) && (when <= current_time);
00397     #ifdef HAVE_CTIME_R
00398     ctime_r(&when,buf); /* buf will become "Wed Jun 30 21:49:08 1993\n" */
00399     #else
00400     ctimep = ctime(&when);
00401     strncpy(buf, ctimep, sizeof(buf));
00402     #endif
00403     memcpy(readable,buf+4,7); /* take only month and day */
00404     if (recent) {
00405         memcpy(readable,buf+4,12);
00406         readable[12]=0;
00407     } else {
00408         memcpy(readable,buf+4,7);
00409         readable[7]=' ';
00410         memcpy(readable+8,buf+20,4);
00411         readable[12]=0;
00412     }
00413 }
00414 
00415 
00416 
00417 /*
00418  * Helper for the 'kdb ls' command
00419  *
00420  */
00421 void listSingleKey(Key *key) {
00422     char buffer[400];
00423     char *p=buffer;
00424 
00425     if (argLong) {
00426         struct passwd *pwd;
00427         struct group *grp;
00428 
00429         listAccess(key,p);
00430         p+=strlen(p);
00431         *p=' '; p++;
00432         *p=' '; p++;
00433         *p=' '; p++;
00434 #ifdef HAVE_PWD_H
00435         if ( (pwd=getpwuid(keyGetUID(key))) != NULL ) {
00436             strcpy(p,pwd->pw_name);
00437             p+=strlen(p);
00438             *p=' '; p++;
00439             *p=' '; p++;
00440         } else {
00441             strcpy(p, "<unknown>");
00442             p+=strlen(p);
00443             *p=' '; p++;
00444             *p=' '; p++;
00445         }
00446 #endif
00447 #ifdef HAVE_GRP_H
00448         if ( (grp=getgrgid(keyGetGID(key))) != NULL ) {
00449             strcpy(p,grp->gr_name);
00450             p+=strlen(p);
00451             *p=' '; p++;
00452         } else {
00453             strcpy(p, "<unknow>");
00454             p+=strlen(p);
00455             *p=' '; p++;
00456             *p=' '; p++;
00457         }
00458 #endif
00459         sprintf(p,"%*d ",5,keyGetRecordSize(key));
00460         p+=strlen(p);
00461 
00462         listTime(keyGetMTime(key),p);
00463         p+=strlen(p);
00464         *p=' '; p++;
00465     }
00466     if (argFullName) keyGetFullName(key,p,sizeof(buffer)-(p-buffer));
00467     else keyGetName(key,p,sizeof(buffer)-(p-buffer));
00468     if (argValue && (keyGetValueSize(key)>0)) {
00469         uint8_t ktype;
00470 
00471         p+=strlen(p);
00472         *p='='; p++;
00473 
00474         ktype=keyGetType(key);
00475         if (ktype >= KEY_TYPE_STRING)
00476             p+=keyGetString(key,p,sizeof(buffer)-(p-buffer));
00477         else if (ktype >= KEY_TYPE_BINARY)
00478             p+=sprintf(p,"<BINARY VALUE>");
00479         else if (ktype == KEY_TYPE_LINK)
00480             p+=keyGetLink(key,p,sizeof(buffer)-(p-buffer));
00481 
00482         *p=0;
00483     }
00484     puts(buffer);
00485 }
00486 
00487 
00488 
00489 
00490 /*
00491  * Helper for the 'kdb ls' command
00492  *
00493  */
00494 void listAllKeys (KeySet * ks) {
00495     size_t listSize=ksGetSize(ks);
00496     Key *walker;
00497     
00498     if (listSize == 1) listSingleKey(ksHead(ks));
00499     else if (listSize > 1) {
00500         ksRewind(ks);
00501         while ((walker=ksNext(ks)))
00502             listSingleKey(walker);
00503     }
00504 }
00505 
00506 
00507 
00508 /*
00509  * Helper for the 'kdb ls -s' command
00510  *
00511  */
00512 void listAllKeysForShell(KeySet *ks) {
00513     Key *walker=0;
00514     int isParent=0;
00515     size_t parentNameSize=strlen(argKeyName);
00516     char *keyName=0;
00517     void *keyValue=0;
00518     char *child=0;
00519     
00520     ksRewind(ks);
00521     while ((walker=ksNext(ks))) {
00522         keyName=keyStealName(walker);
00523         isParent=(int)strstr(keyName,argKeyName);
00524         
00525         if (isParent) {
00526             keyName+=parentNameSize;
00527             while (*keyName && *keyName == '/') keyName++;
00528         } else {
00529             keyName=0;
00530         }
00531         
00532         /* At this point keyName points to the begining of the
00533            trailing key name after stripping argKeyName */
00534         if (keyName) {
00535             /* output key name */
00536             while ((child=strchr(keyName,'/'))) {
00537                 fwrite(keyName,child-keyName,1,stdout);
00538                 fputc('_',stdout);
00539                 keyName=child+1;
00540             }
00541             fputs(keyName,stdout); /* writes remaining stuff */
00542             
00543             /* now output the value surrounded by '"' */
00544             fputs("=\"",stdout);
00545             keyValue=keyStealValue(walker);
00546             if (keyValue) fputs(keyValue,stdout);
00547             fputs("\";\n",stdout);
00548         }
00549     }
00550 }
00551 
00552 
00553 
00554 
00565 int commandRemove(KDBHandle handle) {
00566     if (!argKeyName) {
00567         fprintf(stderr,"kdb rm: No key name\n");
00568         return -1;
00569     }
00570 
00571     if (kdbRemove(handle,argKeyName)) {
00572         char error[300];
00573         
00574         sprintf(error,"kdb rm: \'%s\'",argKeyName);
00575         kdbPrintError(error);
00576         return -1;
00577     }
00578     return 0;
00579 }
00580 
00581 
00582 
00596 int commandMove(KDBHandle handle) {
00597     Key *key;
00598     size_t size=0;
00599     int rc;
00600     
00601     /* Consistency */
00602     if (!argKeyName) {
00603         fprintf(stderr,"kdb mv: No target specified\n");
00604         return -1;
00605     }
00606 
00607     if (!argData) {
00608         fprintf(stderr,"kdb mv: \'%s\': No destination specified\n",argKeyName);
00609         return -1;
00610     }
00611     
00612     key=keyNew(argKeyName,KEY_SWITCH_END);
00613     size=keyGetNameSize(key);
00614     
00615     if (size == 0) {
00616         char error[100];
00617         
00618         sprintf(error,"kdb mv: \'%s\'", argKeyName);
00619         kdbPrintError(error);
00620         
00621         keyDel(key);
00622         return 1;
00623     }
00624     
00625     rc=kdbRename(handle,key,argData);
00626     if (rc != 0) {
00627         /* Handle a non-zero rc, with same behavior of Unix mv command */
00628         switch (errno) {
00629             
00630         }
00631     }
00632     
00633     keyDel(key);
00634     
00635     return rc;
00636 }
00637 
00638 
00639 
00659 int commandSet(KDBHandle handle) {
00660     Key *key=0;
00661     int ret=0;
00662     char error[200];
00663     size_t offset=0;
00664 
00665 
00666     /* Consistency */
00667     if (!argKeyName) {
00668         fprintf(stderr,"kdb set: No key name\n");
00669         return -1;
00670     }
00671 
00672     key=keyNew(argKeyName,KEY_SWITCH_END);
00673     ret=kdbGetKey(handle,key);
00674     if (ret == 0) { /* Key already exists. Good. */
00675         /* Use existed key type if user didn't give us one */
00676         if (argType==KEY_TYPE_UNDEFINED) argType=keyGetType(key);
00677     } else if (errno!=KDB_RET_NOTFOUND) {
00678         /* Handle errors different from NOTFOUND */
00679         sprintf(error,"kdb set: %s",argKeyName);
00680         kdbPrintError(error);
00681 
00682         return -1;
00683     }
00684 
00685     /* Set or overwrite everything else... */
00686     
00687     if (argUID) keySetUID(key,*argUID);
00688     if (argGID) keySetGID(key,*argGID);
00689     if (argMode) keySetAccess(key,argMode);
00690     if (argDir) {
00691         mode_t mask=umask(0);
00692         umask(mask);
00693         keySetDir(key,mask);
00694     }
00695 
00696     if (argComment) keySetComment(key,argComment);
00697     
00698     if (argFile) {
00699         FILE *f;
00700         int end=0;
00701         
00702         if (argData) free(argData);
00703         argData=0;
00704         f=fopen(argFile,"r");
00705         
00706         if (!f) {
00707             sprintf(error,"kdb set: \'%s\'",argFile);
00708             kdbPrintError(error);
00709             return -1;
00710         }
00711         while (! end) {
00712             char buffer[100];
00713             ssize_t r;
00714             
00715             r=read(fileno(f),buffer,sizeof(buffer));
00716             switch (r) {
00717                 case 0:
00718                     r=lseek(fileno(f),0,SEEK_END)-offset;
00719                     end=1;
00720                     break;
00721                 case -1:
00722                     /* those bizarre errors */
00723                     fprintf(stderr,"kdb set: \'%s\': problem reading file\n",argFile);
00724                     fclose(f);
00725                     return -1;
00726             }
00727             argData=realloc(argData,offset+r);
00728             assert(argData!=NULL);
00729             memcpy(argData+offset,buffer,r);
00730             offset+=r;
00731         }
00732         fclose(f);
00733     }
00734 
00735 
00736     /* Set key value . . . */
00737     if (argType == KEY_TYPE_UNDEFINED)
00738         keySetString(key,argData); /* the most common here */
00739     else if (argType == KEY_TYPE_LINK)
00740         keySetLink(key,argData);
00741     else if (argData) { /* Handle special type values . . . */
00742     
00743         /* set raw data */
00744         if (offset) keySetRaw(key,argData,offset);
00745         else if (KEY_TYPE_BINARY <= argType && argType < KEY_TYPE_STRING)
00746              /* command-line-passed bin values have unwanted \0 in the end */
00747              keySetRaw(key,argData,strblen(argData)-1);
00748         else keySetRaw(key,argData,strblen(argData));
00749         
00750         /* set type explicitly */
00751         keySetType(key,argType);
00752     }
00753 
00754 
00755     ret=kdbSetKey(handle,key);
00756     if (ret) {
00757         sprintf(error,"kdb set: \'%s\'",argKeyName);
00758         kdbPrintError(error);
00759     }
00760     
00761     keyDel(key);
00762     
00763     return ret;
00764 }
00765 
00766 
00767 
00768 
00769 
00770 
00783 int commandLink(KDBHandle handle) {
00784     int rc;
00785 
00786     /* Consistency */
00787     if (!argKeyName) {
00788         fprintf(stderr,"kdb ln: No target specified\n");
00789         return -1;
00790     }
00791 
00792     if (!argData) {
00793         fprintf(stderr,"kdb ln: \'%s\': No destination specified\n",argKeyName);
00794         return -1;
00795     }
00796 
00797     if ((rc=kdbLink(handle,argKeyName,argData))) {
00798         kdbPrintError("kdb ln");
00799     }
00800 
00801     return rc;
00802 }
00803 
00804 
00805 
00806 
00807 
00808 
00809 
00810 
00811 
00812 
00813 
00814 
00815 
00816 
00838 int commandList(KDBHandle handle) {
00839     KeySet *ks; /* this is the container for all keys we'll collect bellow */
00840     KeySet *tmp;
00841     ssize_t ret;
00842     unsigned long options=0;
00843     char * buffer;
00844     Key *walker=0;
00845 
00846     /* Build our option set */
00847     
00848     if (argSort)                options |= KDB_O_SORT;
00849     if (argRecursive)           options |= KDB_O_RECURSIVE;
00850     if (argAll)                 options |= KDB_O_INACTIVE;
00851     if (!argValue)              options |= KDB_O_STATONLY;
00852     
00853     /* these options make sense only to ksToStream() */
00854     if (argFullName)            options |= KDB_O_FULLNAME | KDB_O_FULLUGID;
00855     /* ksToStream() defaults */ options |= KDB_O_XMLHEADERS | KDB_O_HIER;
00856     
00857     /* bad options for argShell */
00858     if (!argShell)              options |= KDB_O_DIR | KDB_O_NFOLLOWLINK;
00859     
00860     ks=ksNew();
00861 
00862     if (!argKeyName || strcmp(argKeyName, "/") == 0) {
00863         /* User don't want a specific key, so list the root keys */
00864 
00865         tmp=ksNew();
00866         kdbGetRootKeys(handle,tmp);
00867 
00868         if (argRecursive) {
00869             
00870             while ((walker=ksPop(tmp))) {
00871                 /* walk root by root, retrieve entire subtree
00872                  * and append it to ks
00873                  */
00874                 KeySet *thisRoot=ksNew();
00875                 
00876                 ret=kdbGetKeyChildKeys(handle,walker,thisRoot,options);
00877                 
00878                 /* A hack to transfer a key from a keyset to another.
00879                  * Don't do this at home.
00880                  */
00881                 ksAppend(ks,walker);
00882                 ksAppendKeys(ks,thisRoot);
00883                 ksDel(thisRoot); /* we don't need the container anymore */
00884             }
00885         } else ksAppendKeys(ks,tmp);
00886         ksDel(tmp);
00887     } else {
00888         /* User gave us a specific key to start with */
00889     
00890         if (argKeyName[0] == '/')
00891         {
00892             buffer = malloc (strlen (argKeyName)+sizeof("system\0"));
00893             
00894             tmp = ksNew (); /* tmp workaround bug bec of filesys */
00895             strcpy (buffer, "system\0");
00896             ret=kdbGetChildKeys(handle,strcat (buffer, argKeyName),tmp,options);
00897             /*listAllKeys (tmp);*/
00898             ksAppendKeys (ks,tmp);
00899             ksDel (tmp);
00900         
00901             tmp = ksNew ();
00902             strcpy (buffer, "user\0");
00903             ret=kdbGetChildKeys(handle,strcat (buffer, argKeyName),tmp,options);
00904             /*listAllKeys (tmp);*/
00905             ksAppendKeys (ks,tmp);
00906             ksDel (tmp);
00907 
00908             free (buffer);
00909         } else {    
00910             ret=kdbGetChildKeys(handle,argKeyName,ks,options);
00911         }
00912     
00913         if (ret<0) {
00914             /* We got an error. Check if it is because its not a folder key */
00915             if (errno==ENOTDIR) {
00916                 /* We still have a chance, since there is something there */
00917                 Key *key=keyNew(argKeyName,KEY_SWITCH_END);
00918                 
00919                 if (argValue)
00920                     /*TODO: cascading*/
00921                     ret=kdbGetKey(handle,key);
00922                 else ret=kdbStatKey(handle,key);
00923                 
00924                 if (ret == 0) ksAppend(ks,key);
00925                 else {
00926                     /* There is absolutelly nothing there */
00927                     char error[200];
00928 
00929                     keyDel(key);
00930                     ksDel(ks);
00931                     
00932                     sprintf(error,"kdb ls: %s",argKeyName);
00933                     kdbPrintError(error);
00934                     return ret;
00935                 }
00936                 
00937             } else { /* A real error */
00938                 char error[200];
00939                 
00940                 ksDel(ks);
00941 
00942                 sprintf(error,"kdb ls: %s",argKeyName);
00943                 kdbPrintError(error);
00944                 return ret;
00945             }
00946         }
00947     }
00948 
00949     if (argShow) {
00950         if (argXML) ksToStream(ks,stdout,options);
00951         else if (argShell) listAllKeysForShell(ks);
00952         else listAllKeys(ks);
00953     }
00954 
00955     ksDel(ks);
00956     return 0;
00957 }
00958 
00959 
00960 
00961 
00962 
00963 
00964 
00984 int commandGet(KDBHandle handle) {
00985     int ret;
00986     Key *key = 0;
00987     char *buffer = 0; // used two times
00988     char *p;
00989     size_t size,cs=0;
00990     uint8_t keyType;
00991     char error[200];
00992 
00993 
00994     if (!argKeyName) {
00995         fprintf(stderr,"kdb get: No key name\n");
00996         fprintf(stderr,"run kdb get -h for more info\n");
00997         return -1;
00998     }
00999     
01000     key=keyNew(argKeyName,KEY_SWITCH_END);
01001 
01002     if (argKeyName[0] == '/')
01003     {
01004         buffer = malloc (strlen (argKeyName)+sizeof("system\0"));
01005         
01006         strcpy (buffer, "user\0");
01007         keySetName(key, strcat (buffer, argKeyName));
01008         ret=kdbGetKey(handle,key);
01009         if (ret == 0) goto done;
01010         
01011         strcpy (buffer, "system\0");
01012         keySetName(key, strcat (buffer, argKeyName));
01013         ret=kdbGetKey(handle,key);
01014         if (ret == 0) goto done;
01015     } else {    
01016         ret=kdbGetKey(handle,key);
01017     }
01018 
01019     if (ret) {
01020         sprintf(error,"kdb get: %s",argKeyName);
01021         kdbPrintError(error);
01022         goto cleanup;
01023     }
01024 done:
01025     size=keyGetValueSize(key);
01026     if (argDescriptive) {
01027         cs=keyGetCommentSize(key);
01028         if (cs) size+=cs+3;
01029     }
01030     if (argShell) {
01031         size+=keyGetBaseNameSize(key);
01032         size+=2; /* for 2 '"' to wrap the value */
01033     } else if (argLong) {
01034         if (argFullName) size+=keyGetFullNameSize(key);
01035         else size+=keyGetNameSize(key);
01036     }
01037 
01038 
01039     if (buffer) free (buffer);
01040     p=buffer=malloc(size);
01041 
01042 
01043     if (argDescriptive) {
01044         if (cs) {
01045             p+=sprintf(p,"# ");
01046             p+=keyGetComment(key,p,size-(p-buffer));
01047             *--p='\n'; p++;
01048         }
01049     }
01050     if (argShell) {
01051         p+=keyGetBaseName(key,p,size-(p-buffer));
01052         *--p='='; p++;
01053         *p='\"'; p++;
01054     } else if (argLong) {
01055         if (argFullName) p+=keyGetFullName(key,p,size-(p-buffer));
01056         else p+=keyGetName(key,p,size-(p-buffer));
01057         *--p='='; p++;
01058     }
01059     
01060     keyType=keyGetType(key);
01061 
01062     if (keyIsBin(key)) p+=keyGetBinary(key,p,size-(p-buffer));
01063     else p+=keyGetString(key,p,size-(p-buffer));
01064     if (argShell) {
01065         *--p='\"'; p++;
01066         *p=0;
01067     }
01068     if (keyIsBin(key)) fwrite(buffer,size,1,stdout);
01069     else printf("%s\n",buffer);
01070 
01071     ret = 0;
01072 
01073 cleanup:
01074     free(buffer);
01075     keyDel(key);
01076 
01077     return ret;
01078 }
01079 
01080 
01081 
01082 
01083 
01084 
01113 int commandEdit(KDBHandle handle) {
01114     KeySet *ks;
01115     KeySet *ksEdited;
01116     KeySet *toRemove;
01117     Key *current;
01118     int ret;
01119     char filename[]="/var/tmp/kdbeditXXXXXX";
01120     char command[300];
01121     FILE *xmlfile=0;
01122     char choice[5];
01123 
01124     if (!ksFromXMLfile) return 1;
01125     
01126     ks=ksNew();
01127 
01128     kdbGetChildKeys(handle,argKeyName,ks, KDB_O_SORT | KDB_O_NFOLLOWLINK |
01129         (argAll?KDB_O_INACTIVE:0) | (argRecursive?KDB_O_RECURSIVE:0));
01130 
01131     if (! ksGetSize(ks)) {
01132         /* Maybe the user parameter is not a parent key, but a single key */
01133         current=keyNew(argKeyName,KEY_SWITCH_END);
01134         if (kdbGetKey(handle,current)) {
01135             /* Failed. Cleanup */
01136             keyDel(current);
01137             current=0;
01138         } else {
01139             /* We have something. */
01140             ksAppend(ks,current);
01141             current=0;
01142         }
01143     }
01144 
01145 /*
01146     for (current=ks.start; current; current=current->next) {
01147         if (keyNeedsSync(current)) {
01148             printf("%s needs sync\n",current->key);
01149         }
01150     }
01151 */
01152 
01153     xmlfile=fdopen(mkstemp(filename),"rw+");
01154 
01155     ksToStream(ks,xmlfile,KDB_O_XMLHEADERS | KDB_O_HIER |
01156         KDB_O_FULLNAME | KDB_O_FULLUGID);
01157     fclose(xmlfile);
01158 
01159     do {
01160         /* execute the editor and wait for it to finish */
01161         sprintf(command,"[ -z \"$EDITOR\" ] && EDITOR=vi; $EDITOR %s",filename);
01162         system(command);
01163 
01164         toRemove=ksNew();
01165         ksEdited=ksNew();
01166 
01167         /* ksFromXML is not a library function.
01168          * It is implemented in and for this program only.
01169          * It is pretty reusable code, though.
01170          */
01171         ret=ksFromXMLfile(ksEdited,filename);
01172         if (ret!=0) {
01173             printf("kdb cannot import this file, because it is not valid !\n");
01174             strcpy(choice,"");
01175             while (choice[0]!='E' && choice[0]!='C') {
01176                 printf("Do you want to edit it again or to cancel ? (E/C) : ");
01177                 fgets(choice,4, stdin );
01178             }
01179         }
01180     } while (ret!=0 && choice[0]=='E');
01181     remove(filename);
01182     
01183     if (ret==0) {
01184         ksCompare(ks,ksEdited,toRemove);
01185     
01186         /* Discard ksEdited because there is nothing else here
01187         * after keyCompare() */
01188         ksDel(ksEdited);
01189         
01190         /* Commit changed keys */
01191         ksRewind(ks);
01192         while ((ret=kdbSetKeys(handle,ks))) {
01193             /* We got an error. Warn user. */
01194             Key *problem;
01195             char error[500];
01196             char keyname[300]="";
01197             
01198             problem=ksCurrent(ks);
01199             if (problem) keyGetFullName(problem,keyname,sizeof(keyname));
01200             sprintf(error,"kdb edit: while setting/updating %s", keyname);
01201             kdbPrintError(error);
01202             
01203             /* And try to set keys again starting from the next key,
01204             * unless we reached the end of the KeySet */
01205             if (ksNext(ks) == 0) break;
01206         }
01207         
01208         ksDel(ks); /* Finished with this KeySet */
01209     
01210         /* Remove removed keys */
01211         ksRewind(toRemove);
01212         while ((current=ksNext(toRemove))) {
01213             char keyName[800];
01214     
01215             keyGetFullName(current,keyName,sizeof(keyName));
01216             ret=kdbRemove(handle,keyName);
01217             if (ret != 0) {
01218                 char error[850];
01219                 
01220                 sprintf(error,"kdb edit: while removing %s",keyName);
01221                 kdbPrintError(error);
01222             }
01223         }
01224     
01225         /* Finished with this KeySet too */
01226         ksDel(toRemove);
01227         }
01228     
01229     return 0;
01230 }
01231 
01232 
01244 int commandInfo(KDBHandle handle) {
01245     KDBInfo *libraryInfo;
01246     char textInfo[200];
01247 
01248     libraryInfo=kdbGetInfo(handle);
01249     kdbInfoToString(libraryInfo, textInfo, sizeof(textInfo));
01250 
01251     printf("%s\n", textInfo);
01252 
01253     return 0;
01254 }
01255 
01256 
01270 int commandImport(KDBHandle handle) {
01271     KeySet *ks;
01272     int ret;
01273 
01274     if (!ksFromXMLfile || !ksFromXML) return 1;
01275     
01276     
01277     ks=ksNew();
01278     /* The command line parsing function will put the XML filename
01279        in the argKeyName global. */
01280     if (argKeyName) ksFromXMLfile(ks,argKeyName);
01281     else ksFromXML(ks,fileno(stdin) /* more elegant then just '0' */);
01282 
01283     ksRewind(ks);
01284     while ((ret=kdbSetKeys(handle,ks))) {
01285         /* We got an error. Warn user. */
01286         Key *problem;
01287         char error[500]="";
01288         char keyname[300]="";
01289 
01290         problem=ksCurrent(ks);
01291         if (problem) keyGetFullName(problem,keyname,sizeof(keyname));
01292         sprintf(error,"kdb import: while importing %s", keyname);
01293         kdbPrintError(error);
01294         
01295         /* And try to set keys again starting from the next key,
01296          *  unless we reached the end of KeySet */
01297         if (ksNext(ks) == 0) break;
01298     }
01299     
01300     ksDel(ks);
01301     
01302     return ret;
01303 }
01304 
01305 
01306 
01307 
01308 
01325 int commandExport(KDBHandle *handle) {
01326 
01327     /* Equivalent to 'kdb ls -xRv
01328        So lets mimic and reuse code */
01329 
01330     argSort=1;
01331     argRecursive=1;
01332     argAll=1;
01333     argXML=1;
01334     argShow=1;
01335     argValue=1;
01336     /* argFullName=1; */
01337 
01338     /* force a superuniversal modern charset: UTF-8 */
01339     /*setenv("LANG","en_US.UTF-8",1);*/
01340     putenv("LANG=en_US.UTF-8");
01341     /*setlocale(LC_CTYPE, "UTF-8");*/
01342     
01343     /* reopen key database to forced charset to take effect */
01344     kdbClose(handle);
01345     kdbOpen(handle);
01346 
01347     return commandList(*handle);
01348 }
01349 
01350 
01364 int commandMonitor(KDBHandle handle) {
01365     Key *toMonitor;
01366     uint32_t diff;
01367     
01368     toMonitor=keyNew(argKeyName,KEY_SWITCH_NEEDSYNC,handle,KEY_SWITCH_END);
01369     
01370     diff=kdbMonitorKey(handle,
01371         toMonitor,           /* key to monitor */
01372         KEY_SWITCH_VALUE,    /* key info we are interested in */
01373         0,                   /* how many times to poll. 0 = ad-infinitum */
01374         500                  /* usecs between polls. 0 defaults to 1 second */);
01375 
01376     /*
01377      * Since in our case we'll hang completelly until we get a key's
01378      * value change, we don't have to check diff.
01379      * So if method returned, the value has changed, and toMonitor has it.
01380      */
01381     printf("New value is %s\n",(char *)keyStealValue(toMonitor));
01382     
01383     keyDel(toMonitor);
01384     return 0;
01385 }
01386 
01387 
01388 int loadToolsLib(void) {
01389     kdbLibHandle dlhandle=0;
01390 
01391     kdbLibInit();
01392 
01393     dlhandle=kdbLibLoad("libelektratools");
01394     if (dlhandle == 0) {
01395         return 1;
01396     }
01397     
01398     ksFromXMLfile=kdbLibSym(dlhandle,"ksFromXMLfile");
01399     ksFromXML=kdbLibSym(dlhandle,"ksFromXML");
01400     
01401     return 0;
01402 }
01403 
01404 
01405 int doCommand(int command, KDBHandle *handle) {
01406     switch (command) {
01407         case CMD_SET:             return commandSet(*handle);
01408         case CMD_LIST:            return commandList(*handle);
01409         case CMD_LINK:            return commandLink(*handle);
01410         case CMD_GET:             return commandGet(*handle);
01411         case CMD_REMOVE:          return commandRemove(*handle);
01412         case CMD_EDIT:            return commandEdit(*handle);
01413         case CMD_LOAD:            return commandImport(*handle);
01414         case CMD_SAVE:            return commandExport(handle);
01415         case CMD_MONITOR:         return commandMonitor(*handle);
01416         case CMD_MOVE:            return commandMove(*handle);
01417         case CMD_INFO:            return commandInfo(*handle);
01418         case CMD_HELP:            return commandHelp(*handle);
01419     }
01420     return 0;
01421 }
01422 
01423 
01424 /*
01425 
01426 void cleanup() {
01427     kdbClose();
01428 }
01429 
01430 */
01431 
01432 int main(int argc, char **argv) {
01433     KDBHandle handle=0;
01434     int command=0;
01435     int ret=0;
01436 
01437 
01438     if (loadToolsLib())
01439         fprintf(stderr,"kdb: XML importing and editing disabled\n");
01440     
01441     /* Parse the command line */
01442     command=parseCommandLine(argc,argv);
01443 
01444     /* Check if user only wants some help (kdb -h {command})*/
01445     if (argHelp) helpCommand(command);
01446 
01447     /* Make sure kdbClose() will be used */
01448     /* atexit(cleanup); */
01449     
01450     /* Open key database */
01451     kdbOpen(&handle);
01452 
01453     /* Execute command with parameters from command line */
01454     ret=doCommand(command,&handle);
01455 
01456     kdbClose(&handle);
01457     
01458     exit(ret);
01459 }
01460 

Generated on Fri Sep 14 06:44:57 2007 for Elektra Project by  doxygen 1.5.1