1 /***************************************************************************
2 kdb-tool.c - Tool for the kdb administration
4 begin : Mon Mar 02 2003
5 copyright : (C) 2003 by Avi Alkalay
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the BSD License (revised). *
14 ***************************************************************************/
19 * @defgroup libexample The kdb Command Source Code: Example of Full Library Utilization
31 int argNoRecursive=KDB_O_NORECURSIVE;
45 int argType=KEY_TYPE_UNDEFINED;
48 /* We'll load this methods dynamically to avoid libxml dependencies */
49 KSFromXMLfile ksFromXMLfile;
59 * Prints an error message related to @c errno on standard error, prefixed by @p msg.
63 int kdbPrintError(const char * msg) {
64 fprintf (stderr, "%s\n", msg);
69 * Uses getopt to parse commandline options
71 int parseCommandLine(int argc, char *argv[]) {
72 char sargType[ARGSIZE],argUser[ARGSIZE],argGroup[ARGSIZE];
73 char sargMode[ARGSIZE],sargCommand[ARGSIZE];
75 size_t keyEnvLength=0, keyOptLength=0, keyOldLength;
79 *sargType=*argUser=*argGroup=*sargCommand=*sargMode=0;
81 while ((opt=getopt(argc,argv,"ab:c:dfg:Ghilm:nOrRst:u:vXx"))!=-1)
91 argFile=realloc(argFile,strlen(optarg)+1);
92 assert(argFile!=NULL);
93 strcpy(argFile,optarg);
96 argComment=realloc(argComment,strlen(optarg)+1);
97 assert(argComment!=NULL);
98 strcpy(argComment,optarg);
109 strncpy(argGroup,optarg,ARGSIZE);
121 strncpy(sargMode,optarg,ARGSIZE);
137 strncpy(sargType,optarg,ARGSIZE);
140 strncpy(argUser,optarg,ARGSIZE);
150 fprintf(stderr, "Unknown error (%d %c) in parsing arguments\n",
156 if (optind < argc) /*parse command*/
158 strncpy(sargCommand,argv[optind],ARGSIZE);
165 keyEnv = getenv ("KDB_ROOT");
166 if (keyEnv) keyEnvLength = strlen (keyEnv) + 1;
167 else keyEnvLength = 0;
168 if (optind < argc) /*parse key name*/
170 keyOptLength = strlen (argv[optind]) + 1;
171 argKeyName=realloc(argKeyName,
172 keyEnvLength + keyOptLength + 1);
173 assert(argKeyName!=NULL);
174 if (keyEnv) strncpy (argKeyName, keyEnv, keyEnvLength);
175 strncpy(argKeyName + keyEnvLength, argv[optind], keyOptLength);
176 if (keyEnv) *(argKeyName+keyEnvLength-1) = '/';
179 argKeyName=realloc(argKeyName, keyEnvLength + 1);
180 assert(argKeyName!=NULL);
181 if (keyEnv) strncpy (argKeyName, keyEnv, keyEnvLength);
186 while (optind < argc) /* parse value (rest of arguments) */
188 keyOptLength += strlen(argv[optind]) + 1;
189 argData=realloc(argData,keyOptLength + 1);
190 assert(argData!=NULL);
191 if (keyOldLength > 0) *(argData+keyOldLength-1) = ' ';
192 strcpy(argData+keyOldLength, argv[optind]);
194 keyOldLength = keyOptLength;
197 /* see if parsing worked:
198 fprintf (stderr, "command: %s\n", sargCommand);
199 fprintf (stderr, "key name: %s\n", argKeyName);
200 fprintf (stderr, "value: %s\n", argData);
204 /* End of command line argument reading. Now parse and finalize */
206 /* Check parsed command */
207 if (!strcmp(sargCommand,"ls")) argCommand=CMD_LIST;
208 else if (!strcmp(sargCommand,"set")) argCommand=CMD_SET;
209 else if (!strcmp(sargCommand,"get")) argCommand=CMD_GET;
210 else if (!strcmp(sargCommand,"rm")) argCommand=CMD_REMOVE;
211 else if (!strcmp(sargCommand,"vi")) argCommand=CMD_EDIT;
212 else if (!strcmp(sargCommand,"edit")) argCommand=CMD_EDIT;
213 else if (!strcmp(sargCommand,"load")) argCommand=CMD_LOAD;
214 else if (!strcmp(sargCommand,"import")) argCommand=CMD_LOAD;
215 else if (!strcmp(sargCommand,"save")) argCommand=CMD_SAVE;
216 else if (!strcmp(sargCommand,"export")) argCommand=CMD_SAVE;
217 else if (!strcmp(sargCommand,"mon")) argCommand=CMD_MONITOR;
218 else if (!strcmp(sargCommand,"monitor")) argCommand=CMD_MONITOR;
219 else if (!strcmp(sargCommand,"mv")) argCommand=CMD_MOVE;
220 else if (!strcmp(sargCommand,"info")) argCommand=CMD_INFO;
221 else if (!strcmp(sargCommand,"help")) argCommand=CMD_HELP;
223 fprintf(stderr,"kdb: Invalid subcommand.\n");
229 /* TODO: use regex */
230 if (!strcmp(sargType,"string")) argType=KEY_TYPE_STRING;
231 #ifdef TUNNING_ELEKTRA_0_7
232 else if (!strcmp(sargType,"int")) argType=KEY_TYPE_STRING+1;
233 else if (!strcmp(sargType,"double")) argType=KEY_TYPE_STRING+2;
234 else if (!strcmp(sargType,"bool")) argType=KEY_TYPE_STRING+3;
236 else if (!strcmp(sargType,"bin")) argType=KEY_TYPE_BINARY;
237 else if (!strcmp(sargType,"binary")) argType=KEY_TYPE_BINARY;
238 else if (!strcmp(sargType,"dir")) argDir=1; /* bkwrds compatibility */
240 argType=strtol(sargType,0,10);
241 if (errno == ERANGE || errno == EINVAL)
242 /* handle undefined later */
243 argType=KEY_TYPE_UNDEFINED;
245 } else if (argCommand==CMD_SET) { /* We must have a type */
246 argType=KEY_TYPE_STRING;
252 if (isdigit(*argUser)) {
253 argUID=malloc(sizeof(uid_t));
254 *argUID=atoi(argUser);
257 pwd=getpwnam(argUser);
259 argUID=malloc(sizeof(uid_t));
262 fprintf(stderr,"kdb: Invalid user \'%s\'. Ignoring\n", argUser);
270 if (isdigit(*argGroup)) {
271 argGID=malloc(sizeof(gid_t));
272 *argGID=atoi(argGroup);
275 grp=getgrnam(argGroup);
277 argGID=malloc(sizeof(gid_t));
280 fprintf(stderr,"kdb: Invalid group \'%s\'. Ignoring\n",argGroup);
287 /* Parse permissions */
288 if (*sargMode!=0) argMode=strtol(sargMode,0,8);
299 * Helper for the 'kdb ls' command
302 int listMode(Key *key,char *readable) {
303 mode_t mode=keyGetMode(key);
305 if (keyIsDir(key)) readable[0]='d';
306 else readable[0]='-';
308 readable[1] = mode & S_IRUSR ? 'r' : '-';
309 readable[2] = mode & S_IWUSR ? 'w' : '-';
310 readable[3] = mode & S_IXUSR ? 'x' : '-';
314 readable[4] = mode & S_IRGRP ? 'r' : '-';
315 readable[5] = mode & S_IWGRP ? 'w' : '-';
316 readable[6] = mode & S_IXGRP ? 'x' : '-';
317 readable[7] = mode & S_IROTH ? 'r' : '-';
318 readable[8] = mode & S_IWOTH ? 'w' : '-';
319 readable[9] = mode & S_IXOTH ? 'x' : '-';
328 * Helper for the 'kdb ls' command
331 int listTime(time_t when,char *readable) {
332 time_t current_time=time(0);
337 time_t six_months_ago;
340 /* If the file appears to be in the future, update the current
341 time, in case the file happens to have been modified since
342 the last time we checked the clock. */
344 /* Consider a time to be recent if it is within the past six
345 months. A Gregorian year has 365.2425 * 24 * 60 * 60 ==
346 31556952 seconds on the average. Write this value as an
347 integer constant to avoid floating point hassles. */
348 six_months_ago = current_time - 31556952 / 2;
349 recent = (six_months_ago <= when) && (when <= current_time);
353 ctimep = ctime(&when);
354 strncpy(buf, ctimep, sizeof(buf));
357 buf now is like "Wed Jun 30 21:49:08 1993\n"
358 fprintf (stderr, "(%d), recent: %d buf: %s", strlen(buf), recent, buf);
362 memcpy(readable,buf+4,12); // copy "Jun 30 21:49"
363 /* in readable are now the parts "Jun 30 21:49" */
365 memcpy(readable,buf+4,7); // copy "Jun 30 "
366 /* in readable are now the parts "Jun 30 " */
368 memcpy(readable+8,buf+20,4); // copy date
370 if (readable[4] == 32) readable[4] = '0'; // prefix date
376 * Helper for the 'kdb ls' command
379 void listSingleKey(Key *key) {
382 char *unknown = "<unknown>";
383 int unknown_length= strlen (unknown);
384 char *binary = "<binary>";
385 int binary_length = strlen (binary);
395 if ( (pwd=getpwuid(keyGetUID(key))) != NULL ) {
396 strcpy(p,pwd->pw_name);
397 p+=strlen(pwd->pw_name);
408 if ( (grp=getgrgid(keyGetGID(key))) != NULL ) {
409 strcpy(p,grp->gr_name);
410 p+=strlen(grp->gr_name);
419 /*sprintf(p,"%*d ",5,keyGetRecordSize(key));
422 p+=listTime(keyGetMTime(key),p);
427 p+=keyGetFullName(key,p,sizeof(buffer)-(p-buffer))-1;
429 p+=keyGetName(key,p,sizeof(buffer)-(p-buffer))-1;
431 if (argValue && (keyGetValueSize(key)>1))
435 if (keyIsString (key))
437 p+=keyGetString(key,p,sizeof(buffer)-(p-buffer))-1;
438 } else if (keyIsBinary(key)) {
451 * Helper for the 'kdb ls' command
454 void listAllKeys (KeySet * ks) {
455 size_t listSize=ksGetSize(ks);
458 if (listSize == 1) listSingleKey(ksHead(ks));
459 else if (listSize > 1) {
461 while ((walker=ksNext(ks)))
462 listSingleKey(walker);
469 * Helper for the 'kdb ls -s' command
472 void listAllKeysForShell(KeySet *ks) {
475 size_t parentNameSize=strlen(argKeyName);
476 const char *keyname=0;
477 const void *keyvalue=0;
481 while ((walker=ksNext(ks))) {
482 keyname=keyName(walker);
483 isParent=strstr(keyname,argKeyName);
486 keyname+=parentNameSize;
487 while (*keyname && *keyname == '/') keyname++;
492 /* At this point keyname points to the begining of the
493 trailing key name after stripping argKeyName */
495 /* output key name */
496 while ((child=strchr(keyname,'/'))) {
497 fwrite(keyname,child-keyname,1,stdout);
501 fputs(keyname,stdout); /* writes remaining stuff */
503 /* now output the value surrounded by '"' */
505 keyvalue=keyValue(walker);
506 if (keyvalue) fputs(keyvalue,stdout);
507 fputs("\";\n",stdout);
516 * The business logic behind 'kdb rm' command
519 * bash$ kdb rm user/env/alias/ls # get rid to the ls alias
523 * @param argKeyName name of the key that will be removed
525 int commandRemove(KDB *handle)
528 fprintf(stderr,"kdb rm: No key name\n");
534 if (kdbRemove(handle,argKeyName) == -1)
538 sprintf(error,"kdb rm: \'%s\'",argKeyName);
539 kdbPrintError(error);
542 } else { /* -R set */
544 KeySet *ks = ksNew(0);
546 key=keyNew(argKeyName,KEY_END);
549 fprintf(stderr,"kdb rm: No valid key name\n");
553 if (kdbGet(handle, ks, key, KDB_O_INACTIVE) == -1)
558 sprintf(error,"kdb rm: Could not get keys, problem appeared at \'%s\'",
559 keyName(ksCurrent(ks)));
561 sprintf(error,"kdb rm: Could not get keys below \'%s\'", argKeyName);
562 kdbPrintError(error);
567 if (kdbSet(handle, ks, key, KDB_O_REMOVEONLY) == -1)
572 sprintf(error,"kdb rm: Could not rm keys, problem appeared at \'%s\'", keyName(ksCurrent(ks)));
574 sprintf(error,"kdb rm: Could not remove keys below \'%s\'", argKeyName);
575 kdbPrintError(error);
589 * Renames the key to a given newname in backend in an atomic way.
591 * @note the key will not exist afterwards in database
593 * @param handle contains internal information of @link kdbOpen() opened @endlink key database
594 * @param key an initialized Key retrieved from backend
595 * @param newname the new name which the name should have in backend
596 * @return 0 on success
597 * @return -1 on failure and @c errno is propagated
601 int kdbRename(KDB *handle, const Key *key, const char *newname) {
602 KeySet * ks = ksNew(0);
603 Key * toRename = keyDup(key);
604 Key * toRemove = keyDup(key);
605 keyRemove (toRemove);
606 ksAppendKey(ks, toRemove);
608 if (keySetName (toRename, newname) == -1)
613 ksAppendKey(ks, toRename);
615 if (kdbSet (handle, ks,0,0) == -1)
618 printf ("kdbRename: kdbSet failed\n");
631 * The business logic behind 'kdb mv' command.
632 * The central method used is kdbRename() but this function is
633 * way more robust, and is an example on how to handle errors.
636 * bash# kdb mv user/env user:tatiana/env
640 * @param argKeyName name of the source key
641 * @param argData name of the target key
643 int commandMove(KDB *handle) {
650 fprintf(stderr,"kdb mv: No target specified\n");
655 fprintf(stderr,"kdb mv: \'%s\': No destination specified\n",argKeyName);
659 key=keyNew(argKeyName,KEY_END);
660 size=keyGetNameSize(key);
665 sprintf(error,"kdb mv: \'%s\'", argKeyName);
666 kdbPrintError(error);
672 rc=kdbRename(handle,key,argData);
674 /* Handle a non-zero rc, with same behavior of Unix mv command */
688 * The business logic behind 'kdb set' command.
689 * Sets value to a single key.
693 * bash$ kdb set -c "My shell prompt" user/env/env1/PS1 '\h:\w\$'
696 * @param argKeyName name of the key that will be set
697 * @param argComment comment to be set to key (-c)
698 * @param argType type of the key (-t)
699 * @param argMode mode permissions that will be set to sey (-m)
700 * @param argUID UID to be set to sey
701 * @param argGID GID to be set to sey
702 * @param argData the value to the key
703 * @param argFile a filename to use as the input for the value
706 int commandSet(KDB *handle) {
715 fprintf(stderr,"kdb set: No key name\n");
719 key=keyNew(argKeyName,KEY_END);
722 fprintf(stderr,"kdb set: No key name\n");
725 ret=kdbGetKey(handle,key);
726 if (ret == 0) { /* Key already exists. Good. */
727 /* Use existed key type if user didn't give us one */
728 if (argType==KEY_TYPE_UNDEFINED) argType=keyGetType(key);
731 /* Set or overwrite everything else... */
733 if (argUID) keySetUID(key,*argUID);
734 if (argGID) keySetGID(key,*argGID);
735 if (argMode) keySetMode(key,argMode);
740 if (argComment) keySetComment(key,argComment);
746 if (argData) free(argData);
748 f=fopen(argFile,"r");
751 sprintf(error,"kdb set: \'%s\'",argFile);
752 kdbPrintError(error);
759 r=read(fileno(f),buffer,sizeof(buffer));
762 r=lseek(fileno(f),0,SEEK_END)-offset;
766 /* those bizarre errors */
767 fprintf(stderr,"kdb set: \'%s\': problem reading file\n",argFile);
771 argData=realloc(argData,offset+r);
772 assert(argData!=NULL);
773 memcpy(argData+offset,buffer,r);
780 /* Set key value . . . */
781 if (argType == KEY_TYPE_UNDEFINED)
782 keySetString(key,argData); /* the most common here */
783 else if (argData) { /* Handle special type values . . . */
786 if (offset) keySetRaw(key,argData,offset);
787 else if (KEY_TYPE_BINARY <= argType && argType < KEY_TYPE_STRING)
788 /* command-line-passed bin values have unwanted \0 in the end */
789 keySetRaw(key,argData,strlen(argData));
790 else keySetRaw(key,argData,strlen(argData)+1);
792 /* set type explicitly */
793 keySetType(key,argType);
797 ret=kdbSetKey(handle,key);
799 sprintf(error,"kdb set: \'%s\'",argKeyName);
800 kdbPrintError(error);
812 * The business logic behind 'kdb ls' command.
813 * @param argKeyName key name to be listed
814 * @param argNoRecursive whether to act recursively (-R)
815 * @param argValue whether to show key values or not (-v)
816 * @param argAll whether to list also inactive keys (-a)
817 * @param argShell operate in a shell script friendly mode (-s)
818 * @param argXML whether to create XML output (-x)
822 * bash$ kdb ls -R # list all keys from system and user trees
823 * bash$ kdb ls -Ra # list them all plus the hidden/inactive keys
824 * bash$ kdb ls -Rav # list all showing value
825 * bash# kdb ls -Rxv # equivalent to 'kdb export'
826 * bash$ kdb ls -Rv user/env # list my aliases and environment vars
829 * @see keyToStream(), ksToStream()
830 * @see commandExport() for the 'kdb export' command
832 int commandList(KDB *handle) {
833 KeySet *ks; /* this is the container for all keys we'll collect bellow */
835 unsigned long options=0;
837 /* Build our option set */
839 if (argSort) options |= KDB_O_SORT;
840 if (argNoRecursive) options |= KDB_O_NORECURSIVE;
841 if (argAll) options |= KDB_O_INACTIVE;
842 if (!argValue) options |= KDB_O_STATONLY;
844 /* these options make sense only to ksToStream() */
845 if (argFullName) options |= KDB_O_FULLNAME;
846 /* ksToStream() defaults */ options |= KDB_O_HEADER | KDB_O_HIER;
850 if (!argKeyName || strcmp(argKeyName, "/") == 0)
853 KeySet *tmp = ksNew(0);
855 /* User don't want a specific key, so list the root keys */
856 kdbGet(handle,tmp,0,0);
858 if (! argNoRecursive) {
860 while ((walker=ksPop(tmp))) {
861 /* walk root by root, retrieve entire subtree
862 * and append it to ks
864 KeySet *thisRoot=ksNew(0);
866 ret=kdbGet(handle,thisRoot,walker,options | KDB_O_POP);
868 /* A hack to transfer a key from a keyset to another.
869 * Don't do this at home.
871 ksAppendKey(ks,walker);
872 ksAppend(ks,thisRoot);
873 ksDel(thisRoot); /* we don't need the container anymore */
875 } else ksAppend(ks,tmp);
878 /* User gave us a specific key to start with */
880 ret=kdbGetByName (handle,ks,argKeyName,options);
883 /* We got an error. Check if it is because its not a folder key */
884 if (errno==ENOTDIR) {
885 /* We still have a chance, since there is something there */
886 Key *key=keyNew(argKeyName,KEY_END);
895 sprintf(error,"kdb ls: %s",argKeyName);
896 kdbPrintError(error);
901 ret=kdbGetKey(handle,key);
902 else ret=kdbStatKey(handle,key);
904 if (ret == 0) ksAppendKey(ks,key);
906 /* There is absolutely nothing there */
912 sprintf(error,"kdb ls: %s",argKeyName);
913 kdbPrintError(error);
917 } else { /* A real error */
922 sprintf(error,"kdb ls: %s",argKeyName);
923 kdbPrintError(error);
929 /* Better give it a sort */
930 if (ksNeedSort (ks)) ksSort (ks);
932 if (argXML) ksToStream(ks,stdout,options);
933 else if (argShell) listAllKeysForShell(ks);
934 else if (argGenerate) ksGenerate(ks,stdout, 0);
935 else if (argOutput) ksOutput(ks,stdout, KEY_VALUE|KEY_COMMENT);
936 else listAllKeys(ks);
949 * Business logic behind the 'kdb get' command.
950 * Get a key and return its value to you.
954 * bash$ kdb get user/env/alias/ls
958 * @param argKeyName key to get value
959 * @param argDescriptive show also the key comment (-d)
960 * @param argShell output suitable for shell scripts (-s)
961 * @param argLong show also the key name (-l)
962 * @param argFullName with @p argLong, show the user domain too (-f)
964 * @see kdbGetKey(), kdbGetBaseName(), keyGetComment(), keyGetString()
967 int commandGet(KDB *handle) {
970 char *buffer = 0; // used two times
978 fprintf(stderr,"kdb get: No key name\n");
979 fprintf(stderr,"run kdb get -h for more info\n");
983 key=keyNew(argKeyName,KEY_END);
985 if (argKeyName[0] == '/')
987 buffer = malloc (strlen (argKeyName)+sizeof("system\0"));
989 strcpy (buffer, "user\0");
990 keySetName(key, strcat (buffer, argKeyName));
991 ret=kdbGetKey(handle,key);
992 if (ret == 0) goto done;
994 strcpy (buffer, "system\0");
995 keySetName(key, strcat (buffer, argKeyName));
996 ret=kdbGetKey(handle,key);
997 if (ret == 0) goto done;
999 ret=kdbGetKey(handle,key);
1003 sprintf(error,"kdb get: %s",argKeyName);
1004 kdbPrintError(error);
1008 size=keyGetValueSize(key);
1009 if (argDescriptive) {
1010 cs=keyGetCommentSize(key);
1014 size+=keyGetBaseNameSize(key);
1015 size+=2; /* for 2 '"' to wrap the value */
1016 } else if (argLong) {
1017 if (argFullName) size+=keyGetFullNameSize(key);
1018 else size+=keyGetNameSize(key);
1022 if (buffer) free (buffer);
1023 p=buffer=malloc(size);
1026 if (argDescriptive) {
1029 p+=keyGetComment(key,p,size-(p-buffer));
1034 p+=keyGetBaseName(key,p,size-(p-buffer));
1037 } else if (argLong) {
1038 if (argFullName) p+=keyGetFullName(key,p,size-(p-buffer));
1039 else p+=keyGetName(key,p,size-(p-buffer));
1043 keyType=keyGetType(key);
1045 if (keyIsBinary(key)) p+=keyGetBinary(key,p,size-(p-buffer));
1046 else p+=keyGetString(key,p,size-(p-buffer));
1051 if (keyIsBinary(key)) fwrite(buffer,size,1,stdout);
1052 else printf("%s\n",buffer);
1069 * Opens an editor to edit an XML representation of the keys.
1070 * This is one of the most complex commands of the kdb program.
1072 * -# retrieve the desired keys
1073 * -# put them inside an editor in an XML format to let the user change them
1074 * -# wait for the editor to finish
1075 * -# reread the edited XML, converting to an internal KeySet
1076 * -# compare original and edited KeySets, with ksCompare(), to detect
1078 * -# remove removed keys
1079 * -# update updated keys
1081 * -# leave untouched the not-changed keys
1085 * bash$ EDITOR=kedit kdb edit -R user/env # edit with kedit
1086 * bash# kdb edit -R system/sw/MyApp # defaults to vi editor
1089 * @param argKeyName the parent key name (and children) that will be edited
1090 * @param argRecursive whether to act recursivelly or not
1091 * @param argAll whether to edit inactive keys or not
1092 * @param EDITOR environment var that defines editor to use, or @p vi
1093 * @see keyCompare(), ksCompare(), kdbGetByName()
1094 * ksToStream(), kdbRemoveKey()
1096 int commandEdit(KDB *handle) {
1102 char filename[]="/var/tmp/kdbeditXXXXXX";
1107 if (!ksFromXMLfile) return 1;
1111 kdbGetByName(handle, ks, argKeyName, (argAll?KDB_O_INACTIVE:0) | (argNoRecursive?KDB_O_NORECURSIVE:0));
1113 if (! ksGetSize(ks)) {
1114 /* Maybe the user parameter is not a parent key, but a single key */
1115 current=keyNew(argKeyName,KEY_END);
1116 if (kdbGetKey(handle,current)) {
1117 /* Failed. Cleanup */
1121 /* We have something. */
1122 ksAppendKey(ks,current);
1128 for (current=ks.start; current; current=current->next) {
1129 if (keyNeedSync(current)) {
1130 printf("%s needs sync\n",current->key);
1137 xmlfile=fdopen(mkstemp(filename),"rw+");
1139 ksToStream(ks,xmlfile,KDB_O_XMLHEADERS | KDB_O_HIER |
1140 KDB_O_FULLNAME | KDB_O_FULLUGID);
1145 /* execute the editor and wait for it to finish */
1146 sprintf(command,"[ -z \"$EDITOR\" ] && EDITOR=vi; $EDITOR %s",filename);
1152 /* ksFromXML is not a library function.
1153 * It is implemented in and for this program only.
1154 * It is pretty reusable code, though.
1156 ret=ksFromXMLfile(ksEdited,filename);
1158 printf("kdb cannot import this file, because it is not valid !\n");
1160 while (choice[0]!='E' && choice[0]!='C') {
1161 printf("Do you want to edit it again or to cancel ? (E/C) : ");
1162 fgets(choice,4, stdin );
1165 } while (ret!=0 && choice[0]=='E');
1170 ksCompare(ks,ksEdited,toRemove);
1173 /* Discard ksEdited because there is nothing else here
1174 * after keyCompare() */
1177 /* Commit changed keys */
1179 while ((ret=kdbSet(handle,ks,0,0))) {
1180 /* We got an error. Warn user. */
1183 char keyname[300]="";
1185 problem=ksCurrent(ks);
1186 if (problem) keyGetFullName(problem,keyname,sizeof(keyname));
1187 sprintf(error,"kdb edit: while setting/updating %s", keyname);
1188 kdbPrintError(error);
1190 /* And try to set keys again starting from the next key,
1191 * unless we reached the end of the KeySet */
1192 if (ksNext(ks) == 0) break;
1195 ksDel(ks); /* Finished with this KeySet */
1197 /* Remove removed keys */
1199 while ((current=ksNext(toRemove))) {
1202 keyGetFullName(current,keyname,sizeof(keyname));
1203 ret=kdbRemove(handle,keyname);
1207 sprintf(error,"kdb edit: while removing %s",keyname);
1208 kdbPrintError(error);
1212 /* Finished with this KeySet too */
1219 ssize_t kdbbGetFullFilename(KDB *handle, const Key *forKey,char *returned,size_t maxSize);
1222 * Business logic behind the 'kdb info' command.
1223 * Displays some information about the Elektra library, version, backend, etc.
1230 * @see kdbGetInfo(), kdbInfoToString(), kdbFreeInfo()
1232 int commandInfo(KDB *handle)
1234 char buffer [MAX_PATH_LENGTH];
1240 printf ("Supply a keyname as second argument to deduce where the key will be stored on disk.\n");
1244 k = keyNew (argKeyName, KEY_END);
1248 printf ("Supply a valid keyname.\n");
1252 rc = kdbbGetFullFilename(handle, k, buffer, MAX_PATH_LENGTH);
1256 printf ("failure\n");
1259 printf ("%s\n", buffer);
1266 * Business logic behind the 'kdb import' command.
1267 * Import an XML file (or standard input) into the key database.
1268 * This is usefull to import full application's keys, or restore backups.
1272 * bash$ kdb import myAppDefaultKeys.xml
1273 * bash$ generateKeys | kdb import
1276 * @see commandExport()
1278 int commandImport(KDB *handle) {
1282 if (!ksFromXMLfile || !ksFromXML) return 1;
1286 /* The command line parsing function will put the XML filename
1287 in the argKeyName global. */
1288 if (argKeyName) ksFromXMLfile(ks,argKeyName);
1289 else ksFromXML(ks,fileno(stdin) /* more elegant then just '0' */);
1292 while ((ret=kdbSet(handle,ks,0,0))==-1) {
1293 /* We got an error. Warn user. */
1296 char keyname[300]="";
1298 problem=ksCurrent(ks);
1299 if (problem) keyGetFullName(problem,keyname,sizeof(keyname));
1300 sprintf(error,"kdb import: while importing %s", keyname);
1301 kdbPrintError(error);
1303 /* And try to set keys again starting from the next key,
1304 * unless we reached the end of KeySet */
1305 if (ksNext(ks) == 0) break;
1318 * Business logic behind the 'kdb export' command.
1319 * Export a set of keys to an XML format. Usefull to make backups or copy
1320 * keys to other machine or user.
1321 * Equivalent to 'kdb ls -xRv base/key/name'
1325 * bash# kdb export system > systemConfigurationBackup.xml
1326 * bash# kdb export system/sw/MyApp > myAppConfiguration.xml
1327 * bash$ kdb export system/sw/MyApp | sed -e 's|system/sw|user/sw|g' | kdb import
1330 * @see commandList(), commandImport()
1333 int commandExport(KDB *handle)
1340 printf ("You have to pass a keyname as argument\n");
1345 ret = kdbGetByName(handle, ks, argKeyName, KDB_O_INACTIVE);
1349 fprintf (stderr, "You try to print in the middle of a backend which does not support\n");
1350 fprintf (stderr, "getting only some keys.\n");
1355 kdbPrintError ("Could not get keys, reason:");
1360 else if (argGenerate) ksGenerate(ks,stdout, 0);
1361 else if (argOutput) ksOutput(ks,stdout, KEY_VALUE|KEY_COMMENT);
1362 else ksToStream(ks,stdout,0);
1371 * Business logic behind 'kdb mon' command.
1373 * Will block your command line until some change happens to the
1378 * bash$ kdb mon system/sw/MyApp/someKey
1381 * @see kdbMonitorKey(), kdbMonitorKeys()
1383 int commandMonitor(KDB *handle) {
1389 toMonitor=keyNew(argKeyName,KEY_NEEDSYNC,handle,KEY_END);
1391 diff=kdbMonitorKey(handle,
1392 toMonitor, /* key to monitor */
1393 KEY_VALUE, /* key info we are interested in */
1394 0, /* how many times to poll. 0 = ad-infinitum */
1395 500 /* usecs between polls. 0 defaults to 1 second */);
1398 * Since in our case we'll hang completelly until we get a key's
1399 * value change, we don't have to check diff.
1400 * So if method returned, the value has changed, and toMonitor has it.
1402 printf("New value is %s\n",(char *)keyValue(toMonitor));
1411 kdbLibHandle dlhandle=0;
1413 void closeToolsLib(void)
1415 kdbLibClose (dlhandle);
1418 int loadToolsLib(void)
1423 dlhandle=kdbLibLoad("libelektratools");
1424 if (dlhandle == 0) {
1428 ksFromXMLfile=(KSFromXMLfile)kdbLibSym(dlhandle,"ksFromXMLfile");
1429 ksFromXML=(KSFromXML)kdbLibSym(dlhandle,"ksFromXML");
1431 ksToStream = (output) kdbLibSym (dlhandle, "ksToStream");
1432 ksOutput = (output) kdbLibSym (dlhandle, "ksOutput");
1433 ksGenerate = (output) kdbLibSym (dlhandle, "ksGenerate");
1435 atexit(closeToolsLib);
1441 int doCommand(int command, KDB *handle) {
1443 case CMD_SET: return commandSet(handle);
1444 case CMD_LIST: return commandList(handle);
1445 case CMD_GET: return commandGet(handle);
1446 case CMD_REMOVE: return commandRemove(handle);
1447 case CMD_EDIT: return commandEdit(handle);
1448 case CMD_LOAD: return commandImport(handle);
1449 case CMD_SAVE: return commandExport(handle);
1450 case CMD_MONITOR: return commandMonitor(handle);
1451 case CMD_MOVE: return commandMove(handle);
1452 case CMD_INFO: return commandInfo(handle);
1453 case CMD_HELP: return commandHelp(handle);
1459 int main(int argc, char **argv) {
1466 fprintf(stderr,"kdb: XML importing and editing disabled\n");
1468 /* Parse the command line */
1469 command=parseCommandLine(argc,argv);
1471 /* Check if user only wants some help (kdb -h {command})*/
1472 if (argHelp) helpCommand(command);
1474 /* Open key database */
1478 fprintf (stderr, "kdb: could not open key database\n");
1482 /* Execute command with parameters from command line and exit
1483 * program afterwards.*/
1484 ret = doCommand(command,handle);