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

kdbtools.c

00001 /***************************************************************************
00002             kdbtools.c  -  Elektra High Level Methods
00003                              -------------------
00004     begin                : Sat Jan 22 2005
00005     copyright            : (C) 2005 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 
00018 
00019 /* Subversion stuff
00020 
00021 $Id: kdbtools.c 610 2006-02-16 03:05:24Z aviram $
00022 $LastChangedBy: aviram $
00023 
00024 */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029 
00030 #include <libxml/xmlreader.h>
00031 #include <libxml/xmlschemas.h>
00032 
00033 // #define KDB_SCHEMA_PATH       DATADIR KDB_SCHEMA_REL_PATH
00034 #define KDB_SCHEMA_PATH_KEY   "system/sw/kdb/current/schemapath"
00035 
00036 
00037 
00038 #include "kdbtools.h"
00039 #include "kdbprivate.h"
00040 #include "kdb.h"
00041 
00042 #include <ctype.h>
00043 #include <string.h>
00044 #ifdef HAVE_GRP_H
00045 #include <grp.h>
00046 #endif
00047 #ifdef HAVE_PWD_H
00048 #include <pwd.h>
00049 #endif
00050 #include <unistd.h>
00051 #include <stdlib.h>
00052 
00053 
00054 
00071 /*
00072  * Processes the current <key> node from reader, converting from XML
00073  * to a Key object, and ksAppend() it to ks.
00074  * 
00075  * See keyToStream() for an example of a <key> node.
00076  * 
00077  * 
00078  * This function is completelly dependent on libxml.
00079  */
00080 int processKeyNode(KeySet *ks, const char *context, xmlTextReaderPtr reader) {
00081     xmlChar *nodeName=0;
00082     xmlChar *buffer=0;
00083     xmlChar *privateContext=0;
00084     xmlChar fullContext[800]="";
00085     Key *newKey=0;
00086     int appended=0;
00087 
00088     /* printf("%s", KDB_SCHEMA_PATH); */
00089     
00090     nodeName=xmlTextReaderName(reader);
00091     if (!strcmp(nodeName,"key")) {
00092         uint8_t type=KEY_TYPE_STRING; /* default type */
00093         int end=0;
00094         
00095         newKey=keyNew(0);
00096 
00097         xmlFree(nodeName); nodeName=0;
00098 
00099 
00100         /* a <key> must have one of the following:
00101            - a "name" attribute, used as an absolute name overriding the context
00102            - a "basename" attribute, that will be added to the current context
00103            - a "parent" plus "basename" attributes, both added to current context
00104            - only a "parent", added to current context
00105         */
00106         buffer=xmlTextReaderGetAttribute(reader,"name");
00107         if (buffer) {
00108             /* set absolute name */
00109             keySetName(newKey,(char *)buffer);
00110             xmlFree(buffer); buffer=0;
00111         } else {
00112             /* logic for relative name calculation */
00113             
00114             privateContext=xmlTextReaderGetAttribute(reader,"parent");
00115             buffer=xmlTextReaderGetAttribute(reader,"basename");
00116 
00117             if (context) keySetName(newKey,context);
00118             if (privateContext) keyAddBaseName(newKey, privateContext);
00119             if (buffer) keyAddBaseName(newKey,buffer);
00120 
00121             xmlFree(privateContext); privateContext=0;
00122             xmlFree(buffer); buffer=0;
00123         }
00124 
00125 
00126         /* test for a short value attribute, instead of <value> bellow */
00127         buffer=xmlTextReaderGetAttribute(reader,"value");
00128         if (buffer) {
00129             keySetRaw(newKey,buffer,strblen(buffer));
00130             xmlFree(buffer); buffer=0;
00131         }
00132 
00133         
00134         buffer=xmlTextReaderGetAttribute(reader,"type");
00135         if (buffer) {
00136             if (!strcmp(buffer,"string"))
00137                 type=KEY_TYPE_STRING;
00138             else if (!strcmp(buffer,"link"))
00139                 type=KEY_TYPE_LINK;
00140             else if (!strcmp(buffer,"directory"))
00141                 type=KEY_TYPE_DIR;
00142             else if (!strcmp(buffer,"binary"))
00143                 type=KEY_TYPE_BINARY;
00144             else if (!strcmp(buffer,"undefined"))
00145                 type=KEY_TYPE_UNDEFINED;
00146             else { /* special user-defined value types */
00147                 void *converter=0;
00148 
00149                 type=strtol(buffer,(char **)&converter,10);
00150                 if ((void *)buffer==converter)
00151                     /* in case of error, fallback to default type again */
00152                     type=KEY_TYPE_STRING;
00153             }
00154         }
00155 
00156         keySetType(newKey,type);
00157 
00158         xmlFree(buffer); buffer=0;
00159 
00160 
00161 #ifdef HAVE_PWD_H
00162         /* Parse UID */
00163         buffer=xmlTextReaderGetAttribute(reader,"uid");
00164         if (buffer) {
00165             if (isdigit(*buffer))
00166                 keySetUID(newKey,atoi(buffer));
00167             else {
00168                 struct passwd *pwd;
00169                 pwd=getpwnam(buffer);
00170                 if (pwd) keySetUID(newKey,pwd->pw_uid);
00171                 else fprintf(stderr,"kdb: Ignoring invalid user %s.\n",
00172                         buffer);
00173             }
00174             xmlFree(buffer); buffer=0;
00175         }
00176 #endif
00177 
00178 #ifdef HAVE_GRP_H
00179         /* Parse GID */
00180         buffer=xmlTextReaderGetAttribute(reader,"gid");
00181         if (buffer) {
00182             if (isdigit(*buffer)) {
00183                 keySetGID(newKey,atoi(buffer));
00184             } else {
00185                 struct group *grp;
00186                 grp=getgrnam(buffer);
00187                 if (grp) keySetGID(newKey,grp->gr_gid);
00188                 else fprintf(stderr,"kdb: Ignoring invalid group %s.\n",
00189                         buffer);
00190             }
00191             xmlFree(buffer); buffer=0;
00192         }
00193 #endif
00194 
00195         /* Parse permissions */
00196         buffer=xmlTextReaderGetAttribute(reader,"mode");
00197         if (buffer) keySetAccess(newKey,strtol(buffer,0,0));
00198         xmlFree(buffer); buffer=0;
00199 
00200         if (xmlTextReaderIsEmptyElement(reader)) {
00201             /* we have a <key ..../> element */
00202             if (newKey && !appended) {
00203                 ksAppend(ks,newKey);
00204                 appended=1;
00205                 end=1;
00206                 /* printf("key appended: %s\n",newKey->key); */
00207             }
00208         }
00209 
00210         /* Parse everything else */
00211         while (!end) {
00212             xmlFree(nodeName); nodeName=0;
00213             xmlTextReaderRead(reader);
00214             nodeName=xmlTextReaderName(reader);
00215 
00216             if (!strcmp(nodeName,"value")) {
00217                 if (xmlTextReaderIsEmptyElement(reader) ||
00218                     xmlTextReaderNodeType(reader)==15) continue;
00219                     
00220                 xmlTextReaderRead(reader);
00221                 buffer=xmlTextReaderValue(reader);
00222                 if (buffer) {
00223                     /* Key's value type was already set above */
00224                     if (KEY_TYPE_BINARY <= type && type < KEY_TYPE_STRING) {
00225                         char *unencoded=0;
00226                         size_t unencodedSize;
00227                         
00228                         unencodedSize=strblen(buffer)/2;
00229                         unencoded=malloc(unencodedSize);
00230                         unencodedSize=unencode(buffer,unencoded);
00231                         if (!unencodedSize) return -1;
00232                             keySetRaw(newKey,unencoded,unencodedSize);
00233                         free(unencoded);
00234                     } else keySetRaw(newKey,buffer,strblen(buffer));
00235                 }
00236             } else if (!strcmp(nodeName,"comment")) {
00237                 ssize_t commentSize=0;
00238                 
00239                 if (xmlTextReaderIsEmptyElement(reader) ||
00240                     xmlTextReaderNodeType(reader)==15) continue;
00241                     
00242                 xmlTextReaderRead(reader);
00243                 buffer=xmlTextReaderValue(reader);
00244                 
00245                 if ((commentSize=keyGetCommentSize(newKey)) > 0) {
00246                     char *tmpComment=0;
00247                     tmpComment=malloc(commentSize+
00248                         xmlStrlen(buffer)*sizeof(xmlChar)+1);
00249 
00250                     if (tmpComment) {
00251                         keyGetComment(newKey,tmpComment,commentSize);
00252 
00253                         strcat(tmpComment,"\n");
00254                         strcat(tmpComment,buffer);
00255 
00256                         keySetComment(newKey,tmpComment);
00257 
00258                         free(tmpComment); tmpComment=0;
00259                     }
00260                 } else keySetComment(newKey,buffer);
00261             } else if (!strcmp(nodeName,"key")) {
00262                 /* Here we found </key> or a sub <key>.
00263                    So include current key in the KeySet. */
00264                 if (newKey && !appended) {
00265                     ksAppend(ks,newKey);
00266                     appended=1;
00267                 }
00268                 
00269                 if (xmlTextReaderNodeType(reader)==15)
00270                     /* found a </key> */
00271                     end=1;
00272                 else {
00273                     /* found a sub <key> */
00274                     keySetType(newKey,KEY_TYPE_DIR);
00275                     /* prepare the context (parent) */
00276                     processKeyNode(ks,newKey->key,reader);
00277                 }
00278             }
00279             xmlFree(buffer); buffer=0;
00280         }
00281 
00282 /*      printf("%s: %o\n",newKey->key,keyGetAccess(newKey)); */
00283         if (privateContext) xmlFree(privateContext);
00284     }
00285 
00286     if (nodeName) xmlFree(nodeName),nodeName=0;
00287     return 0;
00288 }
00289 
00290 
00291 
00292 
00293 int processKeySetNode(KeySet *ks, const char *context, xmlTextReaderPtr reader) {
00294     xmlChar *nodeName=0;
00295     xmlChar *privateContext=0;
00296     xmlChar fullContext[800]="";
00297     
00298     nodeName=xmlTextReaderName(reader);
00299     if (!strcmp(nodeName,"keyset")) {
00300         int end=0;
00301 
00302         privateContext=xmlTextReaderGetAttribute(reader,"parent");
00303         if (context && privateContext) {
00304             xmlStrPrintf(fullContext,sizeof(fullContext),"%s/%s",
00305                 context,privateContext);
00306 
00307             /* printf("\nCurrent parent is %s\n",fullContext); */
00308         }
00309 
00310         /* Parse everything else */
00311         while (!end) {
00312             xmlFree(nodeName); nodeName=0;
00313             xmlTextReaderRead(reader);
00314             nodeName=xmlTextReaderName(reader);
00315 
00316             if (!strcmp(nodeName,"key")) {
00317                 if (privateContext) processKeyNode(ks,*fullContext?fullContext:privateContext,reader);
00318                 else processKeyNode(ks,context,reader);
00319             } else if (!strcmp(nodeName,"keyset")) {
00320                 /* A <keyset> can have nested <keyset>s */
00321                 if (xmlTextReaderNodeType(reader)==15)
00322                     /* found a </keyset> */
00323                     end=1;
00324                 else if (privateContext)
00325                     processKeySetNode(ks, *fullContext?fullContext:privateContext, reader);
00326                 else processKeySetNode(ks, context, reader);
00327             }
00328         }
00329     }
00330     return 0;
00331 }
00332 
00333 
00334 
00335 /*
00336  * This is the workhorse behind for ksFromXML() and ksFromXMLfile().
00337  * It will process the entire XML document in reader and convert and
00338  * save it in ks KeySet. Each node is processed by the processNode() function.
00339  *
00340  * This function is completelly dependent on libxml.
00341  */
00342 int ksFromXMLReader(KeySet *ks,xmlTextReaderPtr reader) {
00343     int ret;
00344     xmlChar *nodeName=0;
00345 
00346     ret = xmlTextReaderRead(reader); /* go to first node */
00347     while (ret == 1) {
00348         /* walk node per node until the end of the stream */
00349         nodeName=xmlTextReaderName(reader);
00350         
00351         if (!strcmp(nodeName,"key"))
00352             processKeyNode(ks, 0, reader);
00353         else if (!strcmp(nodeName,"keyset"))
00354             processKeySetNode(ks, 0, reader);
00355         
00356         ret = xmlTextReaderRead(reader);
00357     }
00358     xmlFreeTextReader(reader);
00359     if (ret) fprintf(stderr,"kdb: Failed to parse XML input\n");
00360 
00361     return ret;
00362 }
00363 
00364 
00365 
00366 int isValidXML(xmlDocPtr doc,char *schemaPath) {
00367     xmlSchemaPtr wxschemas = NULL;
00368     xmlSchemaValidCtxtPtr ctxt;
00369     xmlSchemaParserCtxtPtr ctxt2=NULL;
00370     int ret=0;
00371 
00372     ctxt2 = xmlSchemaNewParserCtxt(schemaPath);
00373 
00374 
00375     if (ctxt2==NULL) {
00376         xmlFreeDoc(doc);
00377         return 1;
00378     }
00379     
00380     xmlSchemaSetParserErrors(ctxt2,
00381         (xmlSchemaValidityErrorFunc) fprintf,
00382         (xmlSchemaValidityWarningFunc) fprintf,
00383         stderr);
00384     wxschemas = xmlSchemaParse(ctxt2);
00385     
00386     if (wxschemas==NULL) {
00387         xmlSchemaFreeParserCtxt(ctxt2);
00388         xmlFreeDoc(doc);
00389         return 1;
00390     }
00391     
00392     /* try to validate the doc against the xml schema */
00393     ctxt = xmlSchemaNewValidCtxt(wxschemas);
00394     xmlSchemaSetValidErrors(ctxt,
00395         (xmlSchemaValidityErrorFunc) fprintf,
00396         (xmlSchemaValidityWarningFunc) fprintf,
00397         stderr);
00398     
00399     if (ctxt==NULL) {
00400         xmlSchemaFree(wxschemas);
00401         xmlSchemaFreeParserCtxt(ctxt2);
00402         xmlFreeDoc(doc);
00403         return 1;
00404     }
00405     
00406     ret = xmlSchemaValidateDoc(ctxt, doc);
00407     xmlSchemaFreeValidCtxt(ctxt);
00408     xmlSchemaFree(wxschemas);
00409     xmlSchemaFreeParserCtxt(ctxt2);
00410 
00411     return ret;
00412 }
00413 
00414 
00415 
00425 int ksFromXMLfile(KeySet *ks,const char *filename) {
00426     xmlTextReaderPtr reader;
00427     xmlDocPtr doc;
00428     int ret=0;
00429     char schemaPath[513];
00430 
00431     doc = xmlParseFile(filename);
00432     if (doc==NULL) return 1;
00433     
00434     /* Open the kdb to get the xml schema path */
00435     schemaPath[0]=0;
00436     // ret=kdbGetValue(KDB_SCHEMA_PATH_KEY,schemaPath,sizeof(schemaPath));
00437 
00438 //  if (ret==0) ret = isValidXML(filename,schemaPath);
00439 //  else ret = isValidXML(filename,KDB_SCHEMA_PATH); /* fallback to builtin */
00440 
00441     
00442     /* if the validation was successful */
00443     if (!ret) {
00444         reader=xmlReaderWalker(doc);
00445         if (reader) ret=ksFromXMLReader(ks,reader);
00446         else {
00447             perror("kdb");
00448             return 1;
00449         }
00450     }
00451     xmlFreeDoc(doc);
00452     return ret;
00453 }
00454 
00455 
00456 
00457 
00458 
00459 /* FIXME: not working when fd is stdin */
00465 int ksFromXML(KeySet *ks,int fd) {
00466     /* Start of support for old XML library (no xmlReaderForFd()) */
00467     char filename[]="/var/tmp/kdbeditXXXXXX";
00468     FILE *xmlfile=0;
00469     xmlfile=fdopen(mkstemp(filename),"rw+");
00470     while (! feof(xmlfile)) {
00471         char buffer[1000];
00472         ssize_t readed, writen;
00473 
00474         readed=read(fd,buffer,sizeof(buffer));
00475         if (readed<0) {
00476             perror("kdb");
00477             fclose(xmlfile);
00478             remove(filename);
00479             return 1;
00480         }
00481 
00482         writen=write(fileno(xmlfile),buffer,readed);
00483         if (writen<0) {
00484             perror("kdb");
00485             fclose(xmlfile);
00486             remove(filename);
00487             return 1;
00488         }
00489     }
00490     fclose(xmlfile);
00491     return ksFromXMLfile(ks,filename);
00492     /* end of support */
00493 
00494     /* This code requires a newer version of XML library, not present in all
00495        Linux/BSD/Unix distros. Don't use it yet.
00496     // a complete XML document is expected
00497     xmlTextReaderPtr reader=0;
00498     int ret;
00499     reader=xmlReaderForFd(fd,"file:/tmp/imp.xml",0,0);
00500     if (reader) {
00501         ret=ksFromXMLReader(ks,reader);
00502     } else {
00503         printf("kdb: Unable to open file descriptor %d for XML reading\n", fd);
00504         return 1;
00505     }
00506     return ret;
00507     // end of newer code */
00508 }
00509 
00510 
00511 
00512 
00513 
00514 
00515 

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