Main Page | Modules | Data Structures | File List | Data Fields

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 559 2006-02-05 22:00:41Z ylecaillez $
00020 
00021 */
00022 
00023 
00024 
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029 #include "kdb.h"
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 "kdbLibLoader.h"
00054 
00055 #define CMD_GET       1
00056 #define CMD_SET       2
00057 #define CMD_REMOVE    3
00058 #define CMD_LIST      4
00059 #define CMD_LINK      5
00060 #define CMD_EDIT      6
00061 #define CMD_LOAD      7
00062 #define CMD_SAVE      8
00063 #define CMD_MONITOR   9
00064 #define CMD_MOVE      10
00065 #define CMD_INFO      25
00066 #define CMD_HELP      30
00067 
00068 #define ARGSIZE      30
00069 
00070 
00071 #ifdef HAVE_WIN32
00072 #define mkstemp(m) open(mktemp(m), O_RDWR)
00073 #endif
00074 
00075 /* we are cheating . . . */
00076 ssize_t unencode(char *encoded, void *returned);
00077 
00078 
00079 /* We'll load this methods dynamically to avoid libxml dependencies */
00080 int (*ksFromXMLfile)(KeySet *ks,char *filename);
00081 int (*ksFromXML)(KeySet *ks,int fd);
00082 
00083 
00084 
00090 char *argComment=0;
00091 char *argFile=0;
00092 char *argData=0;
00093 char *argKeyName=0;
00094 char *argDomain=0;
00095 uid_t *argUID=0;
00096 uid_t *argGID=0;
00097 int argCommand=0;
00098 int argRecursive=0;
00099 int argLong=0;
00100 int argValue=0;
00101 int argAll=0;
00102 int argSort=1;
00103 int argDescriptive=0;
00104 int argFullName=0;
00105 int argShow=1;
00106 int argShell=0;
00107 int argXML=0;
00108 int argHelp=0;
00109 mode_t argMode=0;
00110 int argType=KEY_TYPE_UNDEFINED;
00111 
00112 
00113 
00114 int commandHelp();
00115 
00116 
00117 int parseCommandLine(int argc, char *argv[]) {
00118     char sargType[ARGSIZE],argUser[ARGSIZE],argGroup[ARGSIZE];
00119     char sargMode[ARGSIZE],sargCommand[ARGSIZE];
00120     char * keyEnv;
00121     size_t keyEnvLength=0, keyOptLength=0, keyOldLength;
00122 
00123     int opt;
00124 
00125     *sargType=*argUser=*argGroup=*sargCommand=*sargMode=0;
00126 
00127     while ((opt=getopt(argc,argv,"ab:c:dfg:hilm:nrRst:u:vx"))!=-1)
00128     {
00129         if (opt == EOF)
00130             break;
00131         switch (opt)
00132         {
00133         case 'a':
00134             argAll=1;
00135             break;
00136         case 'b':
00137             argFile=realloc(argFile,strlen(optarg)+1);
00138             assert(argFile!=NULL);
00139             strcpy(argFile,optarg);
00140             break;
00141         case 'c':
00142             argComment=realloc(argComment,strlen(optarg)+1);
00143             assert(argComment!=NULL);
00144             strcpy(argComment,optarg);
00145             break;
00146         case 'd':
00147             argDescriptive=1;
00148             argLong=1;
00149             break;
00150         case 'f':
00151             argFullName=1;
00152             break;
00153         case 'g':
00154             strncpy(argGroup,optarg,ARGSIZE);
00155             break;
00156         case 'h':
00157             argHelp=1;
00158             break;
00159         case 'i':
00160             argShow=0;
00161             break;
00162         case 'l':
00163             argLong=1;
00164             break;
00165         case 'm':
00166             strncpy(sargMode,optarg,ARGSIZE);
00167             break;
00168         case 'n':
00169             argSort=0;
00170             break;
00171         case 'R':
00172         case 'r':
00173             argRecursive=KDB_O_RECURSIVE;
00174             break;
00175         case 's':
00176             argShell=1;
00177             break;
00178         case 't':
00179             strncpy(sargType,optarg,ARGSIZE);
00180             break;
00181         case 'u':
00182             strncpy(argUser,optarg,ARGSIZE);
00183             break;
00184         case 'v':
00185             argValue=1;
00186             break;
00187         case 'x':
00188             argXML=1;
00189             break;
00190         default:
00191             fprintf(stderr, "Unknown error (%d %c) in parsing arguments\n",
00192                     opt,opt);
00193             break;
00194         }
00195     }
00196 
00197     if (optind < argc) /*parse command*/
00198     {
00199         strncpy(sargCommand,argv[optind],ARGSIZE);
00200         optind ++;
00201     } else {
00202         commandHelp();
00203         exit(0);
00204     }
00205         
00207     keyEnv = getenv ("KDB_ROOT");
00208     if (keyEnv) keyEnvLength = strblen (keyEnv);
00209     else keyEnvLength = 0;
00210     if (optind < argc) /*parse key name*/
00211     {
00212         keyOptLength = strblen (argv[optind]);
00213         argKeyName=realloc(argKeyName,
00214             keyEnvLength + keyOptLength + 1);
00215         assert(argKeyName!=NULL);
00216         if (keyEnv) strncpy (argKeyName, keyEnv,   keyEnvLength);
00217         strncpy(argKeyName + keyEnvLength, argv[optind], keyOptLength);
00218         if (keyEnv) *(argKeyName+keyEnvLength-1) = '/';
00219         optind ++;
00220     } else if (keyEnv) {
00221         argKeyName=realloc(argKeyName, keyEnvLength + 1);
00222         assert(argKeyName!=NULL);
00223         if (keyEnv) strncpy (argKeyName, keyEnv, keyEnvLength);
00224     }
00225         
00226 
00227     keyOptLength = 0;
00228     keyOldLength = 0;
00229     while (optind < argc) /* parse value (rest of arguments) */
00230     {
00231         keyOptLength += strblen(argv[optind]);
00232         argData=realloc(argData,keyOptLength + 1);
00233         assert(argData!=NULL);
00234         if (keyOldLength > 0) *(argData+keyOldLength-1) = ' ';
00235         strcpy(argData+keyOldLength, argv[optind]);
00236         optind ++;
00237         keyOldLength = keyOptLength;
00238     }
00239     
00240     /* see if parsing worked:
00241     fprintf (stderr, "command: %s\n", sargCommand);
00242     fprintf (stderr, "key name: %s\n", argKeyName);
00243     fprintf (stderr, "value: %s\n", argData);
00244     exit (0);
00245     */
00246         
00247     /* End of command line argument reading. Now parse and finalize */
00248 
00249     /* Check parsed command */
00250     if (!strcmp(sargCommand,"ls")) argCommand=CMD_LIST;
00251     else if (!strcmp(sargCommand,"set")) argCommand=CMD_SET;
00252     else if (!strcmp(sargCommand,"get")) argCommand=CMD_GET;
00253     else if (!strcmp(sargCommand,"ln")) argCommand=CMD_LINK;
00254     else if (!strcmp(sargCommand,"rm")) argCommand=CMD_REMOVE;
00255     else if (!strcmp(sargCommand,"vi")) argCommand=CMD_EDIT;
00256     else if (!strcmp(sargCommand,"edit")) argCommand=CMD_EDIT;
00257     else if (!strcmp(sargCommand,"load")) argCommand=CMD_LOAD;
00258     else if (!strcmp(sargCommand,"import")) argCommand=CMD_LOAD;
00259     else if (!strcmp(sargCommand,"save")) argCommand=CMD_SAVE;
00260     else if (!strcmp(sargCommand,"export")) argCommand=CMD_SAVE;
00261     else if (!strcmp(sargCommand,"mon")) argCommand=CMD_MONITOR;
00262     else if (!strcmp(sargCommand,"monitor")) argCommand=CMD_MONITOR;
00263     else if (!strcmp(sargCommand,"mv")) argCommand=CMD_MOVE;
00264     else if (!strcmp(sargCommand,"info")) argCommand=CMD_INFO;
00265     else if (!strcmp(sargCommand,"help")) argCommand=CMD_HELP;
00266     else {
00267         fprintf(stderr,"kdb: Invalid subcommand.\n");
00268         exit(1);
00269     }
00270 
00271     /* Parse type */
00272     if (*sargType!=0) {
00273         /* TODO: use regex */
00274         if      (!strcmp(sargType,"string")) argType=KEY_TYPE_STRING;
00275         else if (!strcmp(sargType,"bin"))    argType=KEY_TYPE_BINARY;
00276         else if (!strcmp(sargType,"binary")) argType=KEY_TYPE_BINARY;
00277         else if (!strcmp(sargType,"dir"))    argType=KEY_TYPE_DIR;
00278         else if (!strcmp(sargType,"link"))   argType=KEY_TYPE_LINK;
00279         else {
00280             argType=strtol(sargType,0,10);
00281             if (errno == ERANGE || errno == EINVAL)
00282                 /* handle undefined later */
00283                 argType=KEY_TYPE_UNDEFINED;
00284         }
00285     } else if (argCommand==CMD_SET) { /* We must have a type */
00286         argType=KEY_TYPE_STRING;
00287     }
00288 
00289 #ifdef HAVE_PWD_H
00290     /* Parse UID */
00291     if (*argUser) {
00292         if (isdigit(*argUser)) {
00293             argUID=malloc(sizeof(uid_t));
00294             *argUID=atoi(argUser);
00295         } else {
00296             struct passwd *pwd;
00297             pwd=getpwnam(argUser);
00298             if (pwd) {
00299                 argUID=malloc(sizeof(uid_t));
00300                 *argUID=pwd->pw_uid;
00301             } else {
00302                 fprintf(stderr,"kdb: Invalid user \'%s\'. Ignoring\n", argUser);
00303             }
00304         }
00305     }
00306 #endif
00307 #ifdef HAVE_GRP_H
00308     /* Parse GID */
00309     if (*argGroup) {
00310         if (isdigit(*argGroup)) {
00311             argGID=malloc(sizeof(gid_t));
00312             *argGID=atoi(argGroup);
00313         } else {
00314             struct group *grp;
00315             grp=getgrnam(argGroup);
00316             if (grp) {
00317                 argGID=malloc(sizeof(gid_t));
00318                 *argGID=grp->gr_gid;
00319             } else {
00320                 fprintf(stderr,"kdb: Invalid group \'%s\'. Ignoring\n",argGroup);
00321             }
00322         }
00323     }
00324 #endif
00325 
00326 
00327     /* Parse permissions */
00328     if (*sargMode!=0) argMode=strtol(sargMode,0,8);
00329 
00330     return argCommand;
00331 }
00332 
00333 
00334 
00335 
00336 
00337 
00338 /*
00339  * Helper for the 'kdb ls' command
00340  *
00341  */
00342 void listAccess(Key *key,char *readable) {
00343     mode_t mode=keyGetAccess(key);
00344 
00345     if (S_ISDIR(mode)) readable[0]='d';
00346     #ifdef S_ISLNK
00347     else if (S_ISLNK(mode)) readable[0]='l';
00348     #endif
00349     else readable[0]='-';
00350 
00351     readable[1] = mode & S_IRUSR ? 'r' : '-';
00352     readable[2] = mode & S_IWUSR ? 'w' : '-';
00353     readable[3] = mode & S_IXUSR ? 'x' : '-';
00354     #ifdef HAVE_WIN32
00355     readable[4] = 0;
00356     #else
00357     readable[4] = mode & S_IRGRP ? 'r' : '-';
00358     readable[5] = mode & S_IWGRP ? 'w' : '-';
00359     readable[6] = mode & S_IXGRP ? 'x' : '-';
00360     readable[7] = mode & S_IROTH ? 'r' : '-';
00361     readable[8] = mode & S_IWOTH ? 'w' : '-';
00362     readable[9] = mode & S_IXOTH ? 'x' : '-';
00363     readable[10]= 0;
00364     #endif
00365 }
00366 
00367 
00368 
00369 
00370 /*
00371  * Helper for the 'kdb ls' command
00372  *
00373  */
00374 void listTime(time_t when,char *readable) {
00375     time_t current_time=time(0);
00376     char buf[400];
00377     #ifndef HAVE_CTIME_R
00378     char *ctimep = NULL;
00379     #endif
00380     time_t six_months_ago;
00381     int recent;
00382 
00383     /* If the file appears to be in the future, update the current
00384        time, in case the file happens to have been modified since
00385        the last time we checked the clock.  */
00386 
00387     /* Consider a time to be recent if it is within the past six
00388        months.  A Gregorian year has 365.2425 * 24 * 60 * 60 ==
00389        31556952 seconds on the average.  Write this value as an
00390        integer constant to avoid floating point hassles.  */
00391     six_months_ago = current_time - 31556952 / 2;
00392     recent = (six_months_ago <= when) && (when <= current_time);
00393     #ifdef HAVE_CTIME_R
00394     ctime_r(&when,buf); /* buf will become "Wed Jun 30 21:49:08 1993\n" */
00395     #else
00396     ctimep = ctime(&when);
00397     strncpy(buf, ctimep, sizeof(buf));
00398     #endif
00399     memcpy(readable,buf+4,7); /* take only month and day */
00400     if (recent) {
00401         memcpy(readable,buf+4,12);
00402         readable[12]=0;
00403     } else {
00404         memcpy(readable,buf+4,7);
00405         readable[7]=' ';
00406         memcpy(readable+8,buf+20,4);
00407         readable[12]=0;
00408     }
00409 }
00410 
00411 
00412 
00413 /*
00414  * Helper for the 'kdb ls' command
00415  *
00416  */
00417 void listSingleKey(Key *key) {
00418     char buffer[400];
00419     char *p=buffer;
00420 
00421     if (argLong) {
00422         struct passwd *pwd;
00423         struct group *grp;
00424 
00425         listAccess(key,p);
00426         p+=strlen(p);
00427         *p=' '; p++;
00428         *p=' '; p++;
00429         *p=' '; p++;
00430 #ifdef HAVE_PWD_H
00431         if ( (pwd=getpwuid(keyGetUID(key))) != NULL ) {
00432             strcpy(p,pwd->pw_name);
00433             p+=strlen(p);
00434             *p=' '; p++;
00435             *p=' '; p++;
00436         } else {
00437             strcpy(p, "<unknown>");
00438             p+=strlen(p);
00439             *p=' '; p++;
00440             *p=' '; p++;
00441         }
00442 #endif
00443 #ifdef HAVE_GRP_H
00444         if ( (grp=getgrgid(keyGetGID(key))) != NULL ) {
00445             strcpy(p,grp->gr_name);
00446             p+=strlen(p);
00447             *p=' '; p++;
00448         } else {
00449             strcpy(p, "<unknow>");
00450             p+=strlen(p);
00451             *p=' '; p++;
00452             *p=' '; p++;
00453         }
00454 #endif
00455         sprintf(p,"%*d ",5,keyGetRecordSize(key));
00456         p+=strlen(p);
00457 
00458         listTime(keyGetMTime(key),p);
00459         p+=strlen(p);
00460         *p=' '; p++;
00461     }
00462     if (argFullName) keyGetFullName(key,p,sizeof(buffer)-(p-buffer));
00463     else keyGetName(key,p,sizeof(buffer)-(p-buffer));
00464     if (argValue && (keyGetValueSize(key)>0)) {
00465         uint8_t ktype;
00466 
00467         p+=strlen(p);
00468         *p='='; p++;
00469 
00470         ktype=keyGetType(key);
00471         if (ktype >= KEY_TYPE_STRING)
00472             p+=keyGetString(key,p,sizeof(buffer)-(p-buffer));
00473         else if (ktype >= KEY_TYPE_BINARY)
00474             p+=sprintf(p,"<BINARY VALUE>");
00475         else if (ktype == KEY_TYPE_LINK)
00476             p+=keyGetLink(key,p,sizeof(buffer)-(p-buffer));
00477 
00478         *p=0;
00479     }
00480     puts(buffer);
00481 }
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00500 int commandRemove() {
00501     if (!argKeyName) {
00502         fprintf(stderr,"kdb rm: No key name\n");
00503         return -1;
00504     }
00505 
00506     if (kdbRemove(argKeyName)) {
00507         char error[300];
00508         
00509         sprintf(error,"kdb rm: \'%s\'",argKeyName);
00510         perror(error);
00511         return -1;
00512     }
00513     return 0;
00514 }
00515 
00516 
00517 
00531 int commandMove() {
00532     Key *key;
00533     size_t size=0;
00534     int rc;
00535     
00536     /* Consistency */
00537     if (!argKeyName) {
00538         fprintf(stderr,"kdb mv: No target specified\n");
00539         return -1;
00540     }
00541 
00542     if (!argData) {
00543         fprintf(stderr,"kdb mv: \'%s\': No destination specified\n",argKeyName);
00544         return -1;
00545     }
00546     
00547     key=keyNew(argKeyName,KEY_SWITCH_END);
00548     size=keyGetNameSize(key);
00549     
00550     if (size == 0) {
00551         char error[100];
00552         
00553         sprintf(error,"kdb mv: \'%s\'", argKeyName);
00554         perror(error);
00555         
00556         keyDel(key);
00557         return 1;
00558     }
00559     
00560     rc=kdbRename(key,argData);
00561     if (rc != 0) {
00562         /* Handle a non-zero rc, with same behavior of Unix mv command */
00563         switch (errno) {
00564             
00565         }
00566     }
00567     
00568     keyDel(key);
00569     
00570     return rc;
00571 }
00572 
00573 
00574 
00594 int commandSet() {
00595     Key *key;
00596     int ret;
00597     char error[200];
00598     size_t offset=0;
00599 
00600 
00601     /* Consistency */
00602     if (!argKeyName) {
00603         fprintf(stderr,"kdb set: No key name\n");
00604         return -1;
00605     }
00606 
00607     key=keyNew(argKeyName,KEY_SWITCH_END);
00608     ret=kdbGetKey(key);
00609     if (ret == 0) { /* Key already exists. Good. */
00610         /* Use existed key type if user didn't give us one */
00611         if (argType==KEY_TYPE_UNDEFINED) argType=keyGetType(key);
00612     } else if (errno!=KDB_RET_NOTFOUND) {
00613         /* Handle errors different from NOTFOUND */
00614         sprintf(error,"kdb set: %s",argKeyName);
00615         perror(error);
00616     }
00617 
00618     /* Set or overwrite everything else... */
00619     
00620     if (argUID) keySetUID(key,*argUID);
00621     if (argGID) keySetGID(key,*argGID);
00622     if (argMode) keySetAccess(key,argMode);
00623 
00624     if (argComment) keySetComment(key,argComment);
00625     
00626     if (argFile) {
00627         FILE *f;
00628         int end=0;
00629         
00630         if (argData) free(argData);
00631         argData=0;
00632         f=fopen(argFile,"r");
00633         
00634         if (!f) {
00635             sprintf(error,"kdb set: \'%s\'",argFile);
00636             perror(error);
00637             return -1;
00638         }
00639         while (! end) {
00640             char buffer[100];
00641             ssize_t r;
00642             
00643             r=read(fileno(f),buffer,sizeof(buffer));
00644             if (r == 0) {
00645                 r=lseek(fileno(f),0,SEEK_END)-offset;
00646                 end=1;
00647             }
00648             argData=realloc(argData,offset+r);
00649             assert(argData!=NULL);
00650             memcpy(argData+offset,buffer,r);
00651             offset+=r;
00652         }
00653         fclose(f);
00654     }
00655 
00656 
00657     /* Set key value . . . */
00658     if (argType == KEY_TYPE_UNDEFINED)
00659         keySetString(key,argData); /* the most common here */
00660     else if (argType == KEY_TYPE_DIR)
00661         keySetType(key,KEY_TYPE_DIR);
00662     else if (argType == KEY_TYPE_LINK)
00663         keySetLink(key,argData);
00664     else if (argData) { /* Handle special type values . . . */
00665     
00666         /* set raw data */
00667         if (offset) keySetRaw(key,argData,offset);
00668         else if (KEY_TYPE_BINARY <= argType && argType < KEY_TYPE_STRING)
00669              /* command-line-passed bin values have unwanted \0 in the end */
00670              keySetRaw(key,argData,strblen(argData)-1);
00671         else keySetRaw(key,argData,strblen(argData));
00672         
00673         /* set type explicitly */
00674         keySetType(key,argType);
00675     }
00676 
00677 
00678     ret=kdbSetKey(key);
00679     if (ret) {
00680         sprintf(error,"kdb set: \'%s\'",argKeyName);
00681         perror(error);
00682     }
00683     
00684     keyDel(key);
00685     
00686     return ret;
00687 }
00688 
00689 
00690 
00691 
00692 
00693 
00706 int commandLink() {
00707     int rc;
00708 
00709     /* Consistency */
00710     if (!argKeyName) {
00711         fprintf(stderr,"kdb ln: No target specified\n");
00712         return -1;
00713     }
00714 
00715     if (!argData) {
00716         fprintf(stderr,"kdb ln: \'%s\': No destination specified\n",argKeyName);
00717         return -1;
00718     }
00719 
00720     if ((rc=kdbLink(argKeyName,argData))) {
00721         perror("kdb ln");
00722     }
00723 
00724     return rc;
00725 }
00726 
00727 
00728 
00729 
00730 
00731 
00732 
00733 
00734 
00735 
00736 
00737 
00738 
00739 
00760 int commandList() {
00761     KeySet *ks; /* this is the container for all keys we'll collect bellow */
00762     ssize_t ret;
00763     if (!argKeyName) {
00764         fprintf(stderr,"kdb ls: No key name\n");
00765         return -1;
00766     }
00767 
00768 
00769     ks=ksNew();
00770 
00771     if (!argKeyName) {
00772         KeySet *roots;
00773         /* User don't want a specific key, so list the root keys */
00774 
00775         roots=ksNew();
00776         kdbGetRootKeys(roots);
00777 
00778         if (argRecursive) {
00779             Key *walker=0;
00780             
00781             while ((walker=ksPop(roots))) {
00782                 /* walk root by root, retrieve entire subtree
00783                  * and append it to ks
00784                  */
00785                 KeySet *thisRoot=ksNew();
00786                 
00787                 if (argValue) ret=kdbGetKeyChildKeys(walker,thisRoot,
00788                     (argSort?KDB_O_SORT:0) | (argRecursive?KDB_O_RECURSIVE:0) |
00789                     KDB_O_DIR | (argAll?KDB_O_INACTIVE:0) | KDB_O_NFOLLOWLINK);
00790                 else ret=kdbGetKeyChildKeys(walker,thisRoot,
00791                     (argSort?KDB_O_SORT:0) | KDB_O_STATONLY |
00792                     (argRecursive?KDB_O_RECURSIVE:0) | KDB_O_DIR |
00793                     (argAll?KDB_O_INACTIVE:0) | KDB_O_NFOLLOWLINK);
00794                 
00795                 /* A hack to transfer a key from a keyset to another.
00796                  * Don't do this at home.
00797                  */
00798                 ksAppend(ks,walker);
00799                 ksAppendKeys(ks,thisRoot);
00800                 ksDel(thisRoot); /* we don't need the container anymore */
00801             }
00802         } else ksAppendKeys(ks,roots);
00803         ksDel(roots);
00804     } else {
00805         /* User gave us a specific key to start with */
00806 
00807         if (argValue) ret=kdbGetChildKeys(argKeyName,ks,
00808             (argSort?KDB_O_SORT:0) | (argRecursive?KDB_O_RECURSIVE:0) |
00809             KDB_O_DIR | (argAll?KDB_O_INACTIVE:0) | KDB_O_NFOLLOWLINK);
00810         else ret=kdbGetChildKeys(argKeyName,ks,
00811             (argSort?KDB_O_SORT:0) | KDB_O_STATONLY |
00812             (argRecursive?KDB_O_RECURSIVE:0) | KDB_O_DIR |
00813             (argAll?KDB_O_INACTIVE:0) | KDB_O_NFOLLOWLINK);
00814     
00815         if (ret<0) {
00816             /* We got an error. Check if it is because its not a folder key */
00817             if (errno==ENOTDIR) {
00818                 /* We still have a chance, since there is something there */
00819                 Key *key=keyNew(argKeyName,KEY_SWITCH_END);
00820                 
00821                 if (argValue) ret=kdbGetKey(key);
00822                 else ret=kdbStatKey(key);
00823                 
00824                 if (ret == 0) ksAppend(ks,key);
00825                 else {
00826                     /* There is absolutelly nothing there */
00827                     char error[200];
00828 
00829                     keyDel(key);
00830                     ksDel(ks);
00831                     
00832                     sprintf(error,"kdb ls: %s",argKeyName);
00833                     perror(error);
00834                     return ret;
00835                 }
00836                 
00837             } else { /* A real error */
00838                 char error[200];
00839                 
00840                 ksDel(ks);
00841 
00842                 sprintf(error,"kdb ls: %s",argKeyName);
00843                 perror(error);
00844                 return ret;
00845             }
00846         }
00847     }
00848 
00849     if (argShow) {
00850         size_t listSize=ksGetSize(ks);
00851         
00852         if (argXML) ksToStream(ks,stdout,KDB_O_XMLHEADERS |
00853             (argFullName?(KDB_O_FULLNAME | KDB_O_FULLUGID):0));
00854         else {
00855             if (listSize == 1) listSingleKey(ksHead(ks));
00856             else if (listSize > 1) {
00857                 Key *walker;
00858             
00859                 ksRewind(ks);
00860                 while ((walker=ksNext(ks)))
00861                     listSingleKey(walker);
00862             }
00863         }
00864     }
00865 
00866     ksClose(ks);
00867     return 0;
00868 }
00869 
00870 
00871 
00872 
00873 
00874 
00875 
00895 int commandGet() {
00896     int ret;
00897     Key *key;
00898     char *buffer;
00899     char *p;
00900     size_t size,cs=0;
00901     uint8_t keyType;
00902 
00903     if (!argKeyName) {
00904         fprintf(stderr,"kdb get: No key name\n");
00905         return -1;
00906     }
00907 
00908     key=keyNew(argKeyName,KEY_SWITCH_END);
00909     
00910     ret=kdbGetKey(key);
00911 
00912     if (ret) {
00913         char error[200];
00914 
00915         keyDel(key);
00916         sprintf(error,"kdb get: %s",argKeyName);
00917         perror(error);
00918         return ret;
00919     }
00920     size=keyGetValueSize(key);
00921     if (argDescriptive) {
00922         cs=keyGetCommentSize(key);
00923         if (cs) size+=cs+3;
00924     }
00925     if (argShell) {
00926         size+=keyGetBaseNameSize(key);
00927         size+=2; /* for 2 '"' to wrap the value */
00928     } else if (argLong) {
00929         if (argFullName) size+=keyGetFullNameSize(key);
00930         else size+=keyGetNameSize(key);
00931     }
00932 
00933 
00934     p=buffer=malloc(size);
00935 
00936 
00937     if (argDescriptive) {
00938         if (cs) {
00939             p+=sprintf(p,"# ");
00940             p+=keyGetComment(key,p,size-(p-buffer));
00941             *--p='\n'; p++;
00942         }
00943     }
00944     if (argShell) {
00945         p+=keyGetBaseName(key,p,size-(p-buffer));
00946         *--p='='; p++;
00947         *p='\"'; p++;
00948     } else if (argLong) {
00949         if (argFullName) p+=keyGetFullName(key,p,size-(p-buffer));
00950         else p+=keyGetName(key,p,size-(p-buffer));
00951         *--p='='; p++;
00952     }
00953     
00954     keyType=keyGetType(key);
00955 
00956     if (keyIsBin(key)) p+=keyGetBinary(key,p,size-(p-buffer));
00957     else p+=keyGetString(key,p,size-(p-buffer));
00958     if (argShell) {
00959         *--p='\"'; p++;
00960         *p=0;
00961     }
00962     if (keyIsBin(key)) fwrite(buffer,size,1,stdout);
00963     else printf("%s\n",buffer);
00964 
00965 
00966     free(buffer);
00967     keyDel(key);
00968 
00969     return 0;
00970 }
00971 
00972 
00973 
00974 
00975 
00976 
00989 int commandHelp() {
00990     printf("Usage: kdb [OPTION] <command> [<key> [value ...]]\n");
00991     printf("Use kdb to manipulate the Key Database.\n");
00992     printf("\n");
00993 
00994     printf("ARGUMENTS\n");
00995     printf("Commands are explained with kdb -h command\n");
00996     printf("<key> is the name of the key. It can be prefixed\n");
00997     printf(" with environment KDB_ROOT. The slash between will\n");
00998     printf("be inserted.\n");
00999     printf(" export KDB_ROOT=\"user/test/dir\"\n");
01000     printf(" kdb get file/key ... will expand to user/test/dir/file/key\n");
01001     printf("[value ...] hold the value which should be set\n");
01002     printf("\n");
01003     
01004     printf("COMMANDS\n");
01005     printf(" kdb get [-dlr] key/name\n");
01006     printf(" kdb set [-t type] [-c \"A comment about this key\"] [-m mode] [-u uid]\n");
01007     printf("         [-g gid] key/name \"the value\"\n");
01008     printf(" kdb set [-t type] [-m mode] [-c \"A comment\"] key/name -- \"the value\"\n");
01009     printf(" kdb set [-t type] [-b file] key/name\n");
01010     printf(" kdb ls [-lRfv] [key/dir | key/name]\n");
01011     printf(" kdb ls [-lRfvx] [key/dir | key/name] > keys.xml\n");
01012     printf(" kdb edit [-R] [key/dir | key/name]\n");
01013     printf(" kdb rm key/name\n");
01014     printf(" kdb mv key/src key/dest\n");
01015     printf(" kdb ln key/src key/dest\n");
01016     printf(" kdb export system/some/tree.root > file.xml\n");
01017     printf(" kdb import < file.xml\n");
01018     printf(" kdb import file.xml\n");
01019     printf(" kdb monitor some/key/name\n");
01020     printf(" kdb info\n");
01021     printf("\n");
01022 }
01023 
01024 void optionr()
01025 {
01026     printf("-R -r\n");
01027     printf(" Causes to work recursively. In ls, will list recursively. \n");
01028     printf("\n");
01029 }
01030 
01031 void optionx()
01032 {
01033     printf("-x\n");
01034     printf(" Makes ls output an XML representation of the keys, instead of an ls-compatible output. \n");
01035     printf("\n");
01036 }
01037 
01038 void optionl()
01039 {
01040     printf("-l\n");
01041     printf(" Causes to display long results. With ls, will generate lists similar to ls -l. With get, will show also the key name. \n");
01042     printf("\n");
01043 }
01044 
01045 void optiona()
01046 {
01047     printf("-a\n");
01048     printf(" Causes ls to display also inactive keys. Generate lists similar to ls -a. Inactive keys are keys which basename begins with a '.' (dot). An example of inactive key: system/sw/XFree/current/Monitor/.Monitor1 \n");
01049     printf("\n");
01050 }
01051 
01052 void optionf()
01053 {
01054     printf("-f\n");
01055     printf(" Causes to work with full key names. A full key name makes sense only on user/* keys, and differentiate from the regular key names in specifying the owner user. If the current user is someuser, the user/some/key full name is user:someuser/some/key. Makes effect in ls, export and get subcommands. \n");
01056     printf("\n");
01057 }
01058 
01059 void optiond()
01060 {
01061     printf("-d\n");
01062     printf(" Causes get to work descriptivelly. When requesting a key it will show the comment, key name and its value in a fancy format \n");
01063     printf("\n");
01064 }
01065 
01066 void options()
01067 {
01068     printf("-s\n");
01069     printf(" Causes get to be more friendly to Shell scripts. For example, when requesting user/env/env2/PATH, the output will be PATH=\"the value\", that is, only the basename of the key will be showed and the value will be surrounded by  \".\n");
01070     printf("\n");
01071 }
01072 
01073 void optiont()
01074 {
01075     printf("-t type\n");
01076     printf(" When setting a key's value, you can specify the type with this switch. Currently accepted types are string for plain text, bin for binary as-is values, dir to create folder keys and link to create symbolic links between keys. Plain text are always stored as UTF-8(7) in Elektra, regardeless of your current encoding ($LANG). If you want to force a value to be stored without the UTF-8(7) encoding (a bad idea), you can set it as binary. Binary values should be avoided, because they are black boxes for system administrators. \n");
01077     printf("\n");
01078 }
01079 
01080 void optionb()
01081 {
01082     printf("-b filename\n");
01083     printf(" Set the key value as the content of file filename. This option is more usefull when setting binary keys. \n");
01084     printf("\n");
01085 }
01086 
01087 void optionm()
01088 {
01089     printf("-m mode\n");
01090     printf(" For the set command. Will set the key access permission to mode, which must be an octal number as for chmod(1). \n");
01091     printf("\n");
01092 }
01093 
01094 void optionu()
01095 {
01096     printf("-u uid\n");
01097     printf(" Create the key with uid user ID. It can be a user name or a uid number. \n");
01098     printf("\n");
01099 }
01100 
01101 void optiong()
01102 {
01103     printf("-g gid\n");
01104     printf(" Create the key with gid group ID. It can be a group name or a gid number \n");
01105     printf("\n");
01106 }
01107 
01108 void optionc()
01109 {
01110     printf("-c comment\n");
01111     printf(" When setting keys, you can use this argument to set a descriptive comment for it. This comment is exactly as a comment in a plain text configuration file. The comment is stored as UTF-8(7) regardeless of your current encoding ($LANG). \n");
01112     printf("\n");
01113 }
01114 
01115 
01116 void optionv()
01117 {
01118     printf("-v\n");
01119     printf(" With the ls subcommand, will make it show also the value stored in the key. \n");
01120     printf("\n");
01121 }
01122 
01123 void commandGetHelp ()
01124 {   
01125     printf("get\n");
01126     printf(" Get the value from the specified key. Accepts options: -d, -l, -f, -s \n");
01127     printf("\n");
01128     optiond();
01129     optionl();  
01130     optionf();  
01131     options();  
01132 }
01133 
01134 void commandSetHelp ()
01135 {
01136     printf("set\n");
01137     printf(" Set the value to the specified key. Accepts options: -c, -t, -m, -b \n");
01138     printf("\n");
01139     optionc();  
01140     optiont();  
01141     optionm();  
01142     optionb();  
01143 }
01144 
01145 void commandListHelp ()
01146 {
01147     printf("ls\n");
01148     printf(" As the ls(1) command, list key names for the specified key, or children keys, if specified a folder key. The -v argument will make it show also the values of each key. The -d (descriptive) will make it show the comment, key name and its value, as you are watching a plain text file. Accepts options: -x, -d, -l, -f, -v, -R \n");
01149     printf("\n");
01150     optionx();  
01151     optiond();  
01152     optionl();  
01153     optionf();  
01154     optionv();  
01155     optionr();  
01156 }
01157 
01158 void commandLinkHelp ()
01159 {
01160     printf("ln\n");
01161     printf("Creates a key that is a symbolic links to another key. \n");
01162     printf("\n");
01163 }
01164 
01165 void commandMoveHelp()
01166 {
01167     printf("mv\n");
01168     printf("Move, or renames a key. Currently it can't move keys across different filesystems.\n");
01169     printf("\n");
01170 }
01171 
01172 void commandRemoveHelp()
01173 {
01174     printf("rm\n");
01175     printf("As the rm(1) command, removes the key specified. \n");
01176     printf("\n");
01177 }
01178 
01179 void commandEditHelp()
01180 {
01181     printf("edit\n");
01182     printf("A very powerfull subcommand that lets you edit an XML representation of the keys. The parameters it accepts is usually a parent key, so its child keys will be gathered. Can be used with the -R flag to work recursively. The editor used is the one set in the $EDITOR environment variable, or vi. After editing the keys, kdb edit will analyze them and commit only the changed keys, remove the keys removed, and add the keys added. \n");
01183     printf("\n");
01184 }
01185 
01186 void commandExportHelp()
01187 {
01188     printf("export, save \n");
01189     printf("Export a subtree of keys to XML. If no subtree is defined right after the export command, system and current user trees will be exported. Output is written to standard output. The output encoding will allways be UTF-8, regardeless of your system encoding. UTF-8 is the most universal charset you can get when exchanging data between multiple systems. Accepts -f. \n");
01190     printf("\n");
01191     optionf();  
01192 }
01193 
01194 void commandImportHelp()
01195 {
01196     printf("import, load \n");
01197     printf("Import an XML representation of keys and save it to the keys database. If no filename is passed right after the import command, standard input is used. \n");
01198     printf("\n");
01199 }
01200 
01201 void commandInfoHelp()
01202 {
01203     printf("info\n");
01204     printf("Displays some information about the Elektra library being used, version, backends, etc.\n");
01205     printf("\n");
01206 }
01207 
01208 void commandMonitorHelp()
01209 {
01210     printf("monitor, mon, \n");
01211     printf("Monitor a key for some value change. It will block your command line until a change in the key value is detected, then return its new value.\n");
01212     printf("\n");
01213 }
01214 
01215 
01244 int commandEdit() {
01245     KeySet *ks;
01246     KeySet *ksEdited;
01247     KeySet *toRemove;
01248     Key *current;
01249     int ret;
01250     char filename[]="/var/tmp/kdbeditXXXXXX";
01251     char command[300];
01252     FILE *xmlfile=0;
01253     char choice[5];
01254 
01255     if (!ksFromXMLfile) return 1;
01256     
01257     ks=ksNew();
01258 
01259     kdbGetChildKeys(argKeyName,ks, KDB_O_SORT | KDB_O_NFOLLOWLINK |
01260         (argAll?KDB_O_INACTIVE:0) | (argRecursive?KDB_O_RECURSIVE:0));
01261 
01262     if (! ksGetSize(ks)) {
01263         /* Maybe the user parameter is not a parent key, but a single key */
01264         current=keyNew(argKeyName,KEY_SWITCH_END);
01265         if (kdbGetKey(current)) {
01266             /* Failed. Cleanup */
01267             keyDel(current);
01268             current=0;
01269         } else {
01270             /* We have something. */
01271             ksAppend(ks,current);
01272             current=0;
01273         }
01274     }
01275 
01276 /*
01277     for (current=ks.start; current; current=current->next) {
01278         if (keyNeedsSync(current)) {
01279             printf("%s needs sync\n",current->key);
01280         }
01281     }
01282 */
01283 
01284     xmlfile=fdopen(mkstemp(filename),"rw+");
01285 
01286     ksToStream(ks,xmlfile,KDB_O_XMLHEADERS | 
01287         (argFullName?(KDB_O_FULLNAME | KDB_O_FULLUGID):0));
01288     fclose(xmlfile);
01289 
01290     do 
01291         {
01292     /* execute the editor and wait for it to finish */
01293     sprintf(command,"[ -z \"$EDITOR\" ] && EDITOR=vi; $EDITOR %s",filename);
01294     system(command);
01295 
01296     toRemove=ksNew();
01297     ksEdited=ksNew();
01298 
01299     /* ksFromXML is not a library function.
01300      * It is implemented in and for this program only.
01301      * It is pretty reusable code, though.
01302      */
01303      ret=ksFromXMLfile(ksEdited,filename);
01304     if (ret!=0)
01305         {
01306         printf("kdb cannot import this file, because it is not valid !\n");
01307         strcpy(choice,"");
01308         while (choice[0]!='E' && choice[0]!='C')
01309             {
01310             printf("Do you want to edit it again or to cancel ? (E/C) : ");
01311             fgets(choice,4, stdin );
01312             }
01313         }
01314     }
01315     while (ret!=0 && choice[0]=='E');
01316     remove(filename);
01317     
01318     if (ret==0)
01319         {
01320 
01321         ksCompare(ks,ksEdited,toRemove);
01322     
01323         /* Discard ksEdited because there is nothing else here
01324         * after keyCompare() */
01325         ksDel(ksEdited);
01326         
01327         /* Commit changed keys */
01328         ksRewind(ks);
01329         while ((ret=kdbSetKeys(ks))) {
01330             /* We got an error. Warn user. */
01331             Key *problem;
01332             char error[500];
01333             char keyname[300]="";
01334             
01335             problem=ksCurrent(ks);
01336             if (problem) keyGetFullName(problem,keyname,sizeof(keyname));
01337             sprintf(error,"kdb edit: while setting/updating %s", keyname);
01338             perror(error);
01339             
01340             /* And try to set keys again starting from the next key,
01341             * unless we reached the end of the KeySet */
01342             if (ksNext(ks) == 0) break;
01343         }
01344         
01345         ksDel(ks); /* Finished with this KeySet */
01346     
01347         /* Remove removed keys */
01348         ksRewind(toRemove);
01349         while ((current=ksNext(toRemove))) {
01350             char keyName[800];
01351     
01352             keyGetFullName(current,keyName,sizeof(keyName));
01353             ret=kdbRemove(keyName);
01354             if (ret != 0) {
01355                 char error[850];
01356                 
01357                 sprintf(error,"kdb edit: while removing %s",keyName);
01358                 perror(error);
01359             }
01360         }
01361     
01362         /* Finished with this KeySet too */
01363         ksDel(toRemove);
01364         }
01365     
01366     return 0;
01367 }
01368 
01369 
01381 int commandInfo() {
01382     KDBInfo *libraryInfo;
01383     char textInfo[200];
01384 
01385     libraryInfo=kdbGetInfo();
01386     kdbInfoToString(libraryInfo, textInfo, sizeof(textInfo));
01387 
01388     printf("%s\n", textInfo);
01389 
01390     return 0;
01391 }
01392 
01393 
01407 int commandImport() {
01408     KeySet *ks;
01409     int ret;
01410 
01411     if (!ksFromXMLfile || !ksFromXML) return 1;
01412     
01413     
01414     ks=ksNew();
01415     /* The command line parsing function will put the XML filename
01416        in the argKeyName global. */
01417     if (argKeyName) ksFromXMLfile(ks,argKeyName);
01418     else ksFromXML(ks,fileno(stdin) /* more elegant then just '0' */);
01419 
01420     ksRewind(ks);
01421     while ((ret=kdbSetKeys(ks))) {
01422         /* We got an error. Warn user. */
01423         Key *problem;
01424         char error[500]="";
01425         char keyname[300]="";
01426 
01427         problem=ksCurrent(ks);
01428         if (problem) keyGetFullName(problem,keyname,sizeof(keyname));
01429         sprintf(error,"kdb import: while importing %s", keyname);
01430         perror(error);
01431         
01432         /* And try to set keys again starting from the next key,
01433          *  unless we reached the end of KeySet */
01434         if (ksNext(ks) == 0) break;
01435     }
01436     
01437     return ret;
01438 }
01439 
01440 
01441 
01442 
01443 
01460 int commandExport() {
01461 
01462     /* Equivalent to 'kdb ls -xRv
01463        So lets mimic and reuse code */
01464 
01465     argSort=1;
01466     argRecursive=1;
01467     argAll=1;
01468     argXML=1;
01469     argShow=1;
01470     argValue=1;
01471     /* argFullName=1; */
01472 
01473     /* force a superuniversal modern charset: UTF-8 */
01474     /*setenv("LANG","en_US.UTF-8",1);*/
01475     putenv("LANG=en_US.UTF-8");
01476     
01477     /* reopen key database to forced charset to take effect */
01478     kdbClose();
01479     kdbOpen();
01480 
01481     return commandList();
01482 }
01483 
01484 
01498 int commandMonitor() {
01499     Key *toMonitor;
01500     uint32_t diff;
01501     
01502     toMonitor=keyNew(argKeyName,KEY_SWITCH_NEEDSYNC,KEY_SWITCH_END);
01503     
01504     diff=kdbMonitorKey(
01505         toMonitor,           /* key to monitor */
01506         KEY_SWITCH_VALUE,    /* key info we are interested in */
01507         0,                   /* how many times to poll. 0 = ad-infinitum */
01508         500                  /* usecs between polls. 0 defaults to 1 second */);
01509 
01510     /*
01511      * Since in our case we'll hang completelly until we get a key's
01512      * value change, we don't have to check diff.
01513      * So if method returned, the value has changed, and toMonitor has it.
01514      */
01515     printf("New value is %s\n",(char *)keyStealValue(toMonitor));
01516     
01517     keyDel(toMonitor);
01518     return 0;
01519 }
01520 
01521 
01522 int loadToolsLib(void) {
01523     kdbLibHandle dlhandle=0;
01524 
01525     kdbLibInit();
01526 
01527     dlhandle=kdbLibLoad("libelektratools");
01528     if (dlhandle == 0) {
01529         return 1;
01530     }
01531     
01532     ksFromXMLfile=kdbLibSym(dlhandle,"ksFromXMLfile");
01533     ksFromXML=kdbLibSym(dlhandle,"ksFromXML");
01534     
01535     return 0;
01536 }
01537 
01538 int doCommand(int command) {
01539     switch (command) {
01540         case CMD_SET:             return commandSet();
01541         case CMD_LIST:            return commandList();
01542         case CMD_LINK:            return commandLink();
01543         case CMD_GET:             return commandGet();
01544         case CMD_REMOVE:          return commandRemove();
01545         case CMD_EDIT:            return commandEdit();
01546         case CMD_LOAD:            return commandImport();
01547         case CMD_SAVE:            return commandExport();
01548         case CMD_MONITOR:         return commandMonitor();
01549         case CMD_MOVE:            return commandMove();
01550         case CMD_INFO:            return commandInfo();
01551         case CMD_HELP:            return commandHelp();
01552     }
01553     return 0;
01554 }
01555 
01556 int helpCommand(int command) {
01557     switch (command) {
01558         case CMD_SET:             commandSetHelp(); break;
01559         case CMD_LIST:            commandListHelp(); break;
01560         case CMD_LINK:            commandLinkHelp(); break;
01561         case CMD_GET:             commandGetHelp(); break;
01562         case CMD_REMOVE:          commandRemoveHelp(); break;
01563         case CMD_EDIT:            commandEditHelp(); break;
01564         case CMD_LOAD:            commandImportHelp(); break;
01565         case CMD_SAVE:            commandExportHelp(); break;
01566         case CMD_MONITOR:         commandMonitorHelp(); break;
01567         case CMD_MOVE:            commandMoveHelp(); break;
01568         case CMD_INFO:            commandInfoHelp(); break;
01569     }
01570     exit (0);
01571 }
01572 
01573 void cleanup()
01574 {
01575     kdbClose();
01576 }
01577 
01578 int main(int argc, char **argv) {
01579     int command=0;
01580     int ret=0;
01581 
01582 
01583     if (loadToolsLib())
01584         fprintf(stderr,"kdb: XML importing and editing disabled\n");
01585     
01586     command=parseCommandLine(argc,argv);
01587 
01588     if (argHelp) helpCommand(command);
01589 
01590     kdbOpen();
01591     atexit(cleanup); 
01593     ret=doCommand(command);
01594 
01595     exit(ret);
01596 }
01597 

Generated on Sun Feb 19 10:05:36 2006 for Elektra Project by  doxygen 1.3.9.1