kdb.c

00001 /***************************************************************************
00002             kdb.c  -  High level functions for accessing the Key Database
00003                              -------------------
00004     begin                : Mon Dec 29 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 
00018 
00019 /* Subversion stuff
00020 
00021 $Id: kdb.c 945 2006-12-23 21:31:13Z aviram $
00022 
00023 */
00024 
00080 #ifdef HAVE_CONFIG_H
00081 #include "config.h"
00082 #endif
00083 
00084 #ifdef HAVE_UNISTD_H
00085 #include <unistd.h>
00086 #endif
00087 
00088 #ifdef HAVE_ICONV
00089 #include <iconv.h>
00090 #endif
00091 
00092 #ifdef HAVE_LOCALE_H
00093 #include <locale.h>
00094 #endif
00095 
00096 #ifdef HAVE_LANGINFO_H
00097 #include <langinfo.h>
00098 #endif
00099 
00100 #ifdef HAVE_SYS_TYPES_H
00101 #include <sys/types.h>
00102 #endif
00103 
00104 #ifdef HAVE_SYS_STAT_H
00105 #include <sys/stat.h>
00106 #endif
00107 
00108 
00109 #include <stdlib.h>
00110 #include <stdarg.h>
00111 #include <ctype.h>
00112 #include <string.h>
00113 #include <errno.h>
00114 #include <stdio.h>
00115 
00116 
00117 /* kdbbackend.h will include kdb.h and kdbprivate.h */
00118 #include "kdbbackend.h"
00119 #include "kdbprivate.h"
00120 #include "kdbLibLoader.h"
00121 
00122 /* usleep doesn't exist on win32, so we use Sleep() */
00123 #ifdef WIN32
00124 #define usleep(x) Sleep(x)
00125 #endif
00126 
00127 
00128 
00129 struct _KDBBackend {
00130     /* environment for which this backend was opened */
00131     pid_t pid;
00132     pthread_t tid;
00133     uid_t uid;
00134     gid_t gid;
00135     mode_t umask;
00136     char *userName;
00137     
00138     /* backend specific data to carry along on kdb*() calls */
00139     void *backendData;
00140     
00141     /* backend name */
00142     char *name;
00143     
00144     
00145     /* These are the interfaces that must be implemented */
00146     
00147     kdbOpenPtr kdbOpen;
00148     kdbClosePtr kdbClose;
00149     
00150     kdbGetKeyPtr kdbGetKey;
00151     kdbSetKeyPtr kdbSetKey;
00152     kdbStatKeyPtr kdbStatKey;
00153     kdbRenamePtr kdbRename;
00154     kdbRemoveKeyPtr kdbRemoveKey;
00155     kdbGetChildKeysPtr kdbGetKeyChildKeys;
00156     
00157     
00158     /* These are the optional methods */
00159     
00160     kdbSetKeysPtr kdbSetKeys;
00161     kdbMonitorKeyPtr kdbMonitorKey;
00162     kdbMonitorKeysPtr kdbMonitorKeys;
00163     
00164     /* dynamic libloader data */
00165     kdbLibHandle dlHandle;
00166 };
00167 
00168 
00169 
00170 
00200 int kdbOpen(KDBHandle *handle) {
00201     char *backendName=0;
00202     
00203     backendName=getenv("KDB_BACKEND");
00204     if (backendName) return kdbOpenBackend(handle,backendName);
00205     else return kdbOpenBackend(handle,DEFAULT_BACKEND);
00206 }
00207 
00208 
00209 
00231 int kdbOpenDefault(KDBHandle *handle) {
00232     return kdbOpenBackend(handle,DEFAULT_BACKEND);
00233 }
00234 
00235 
00236 
00237 
00291 int kdbOpenBackend(KDBHandle *handle, char *backendName) {
00292     /* TODO: review error codes on errno */
00293     kdbLibHandle dlhandle=0;
00294     char backendlib[300];
00295     KDBBackendFactory kdbBackendFactory=0;
00296     int rc=0;
00297     
00298     *handle=0;
00299     
00300     /* load the environment and make us aware of codeset conversions */
00301     #ifdef HAVE_SETLOCALE
00302     setlocale(LC_ALL,"");
00303     #endif
00304     
00305     /* init */
00306     if ( (rc = kdbLibInit()) ) {
00307         errno=KDB_RET_NOSYS;
00308         return -1; /* error */
00309     }   
00310     
00311     sprintf(backendlib,"libelektra-%s",backendName);
00312     dlhandle=kdbLibLoad(backendlib);
00313     if (dlhandle == 0) {
00314         errno=KDB_RET_EBACKEND;
00315         return -1; /* error */
00316     }
00317     
00318     /* load the "kdbBackendFactory" symbol from backend */
00319     /*kdbBackendFactory=(KDBBackendFactory)kdbLibSym(dlhandle,
00320     *(void **)(&kdbBackendFactory)=kdbLibSym(dlhandle,*/
00321     kdbBackendFactory=kdbLibSym(dlhandle,
00322         "kdbBackendFactory");
00323     if (kdbBackendFactory == 0) {
00324         errno=KDB_RET_NOSYS;
00325         return -1; /* error */
00326     }
00327     
00328     *handle=(*kdbBackendFactory)();
00329     if ((*handle) == 0) {
00330         fprintf(stderr,"libelektra: Can't initialize \"%s\" backend\n",
00331             backendName);
00332         errno=KDB_RET_NOSYS;
00333         return -1; /* error */
00334     }
00335 
00336     /* save the libloader handle for future use */
00337     (*handle)->dlHandle=dlhandle;
00338     
00339     /* Give some context to the handle in the case backend is remote */
00340     (*handle)->pid      = getpid();
00341     (*handle)->uid      = getuid();
00342     (*handle)->gid      = getgid();
00343     kdbhSetUserName(*handle, getenv("USER"));
00344     (*handle)->umask    = umask(0); umask((*handle)->umask);
00345     
00346     /* let the backend initialize itself */
00347     if ((*handle)->kdbOpen) rc=(*handle)->kdbOpen(handle);
00348     else {
00349         errno=KDB_RET_NOSYS;
00350         rc=-1;
00351     }
00352     return rc;
00353 }
00354 
00355 
00356 
00379 int kdbClose(KDBHandle *handle) {
00380     int rc=0;
00381     
00382     if (*handle && (*handle)->kdbClose) rc=(*handle)->kdbClose(handle);
00383     else {
00384         errno=KDB_RET_NOSYS;
00385         return -1;
00386     }
00387     
00388     if (rc == 0) {
00389         kdbLibClose((*handle)->dlHandle);
00390         free((*handle)->name);
00391         free((*handle)->userName);
00392         free(*handle); *handle=0;
00393     }
00394     
00395     return rc;
00396 }
00397 
00398 
00399 
00400 
00401 
00402 
00496 ssize_t kdbGetKeyChildKeys(KDBHandle handle, const Key *parentKey,
00497         KeySet *returned, unsigned long options) {
00498     
00499     if (handle && handle->kdbGetKeyChildKeys)
00500         return handle->kdbGetKeyChildKeys(handle,parentKey,returned,options);
00501     else {
00502         errno=KDB_RET_NOSYS;
00503         return -1;
00504     }
00505 }
00506 
00507 
00508 
00527 int kdbStatKey(KDBHandle handle, Key *key) {
00528     int rc=0;
00529     
00530     if (handle && handle->kdbStatKey)
00531         rc=handle->kdbStatKey(handle,key);
00532     else {
00533         errno=KDB_RET_NOSYS;
00534         return -1;
00535     }
00536     
00537     return rc;
00538 }
00539 
00540 
00541 
00554 int kdbGetKey(KDBHandle handle, Key *key) {
00555     int rc=0;
00556     
00557     if (handle && handle->kdbGetKey)
00558         rc=handle->kdbGetKey(handle,key);
00559     else {
00560         errno=KDB_RET_NOSYS;
00561         return -1;
00562     }
00563     
00564     return rc;
00565 }
00566 
00567 
00568 
00611 int kdbSetKeys(KDBHandle handle, KeySet *ks) {
00612     int rc=0;
00613     
00614     if (handle) {
00615         if(handle->kdbSetKeys)
00616             rc=handle->kdbSetKeys(handle,ks);
00617         else
00618             /* If backend doesn't provide kdbSetKeys, use the default */
00619             rc=kdbSetKeys_default(handle,ks);
00620     }
00621     else {
00622         errno=KDB_RET_NOSYS;
00623         return -1;
00624     }
00625     
00626     return rc;
00627 }
00628 
00629 
00630 
00631 
00644 int kdbSetKey(KDBHandle handle, Key *key) {
00645     int rc=0;
00646     
00647     if (handle && handle->kdbSetKey)
00648         rc=handle->kdbSetKey(handle,key);
00649     else {
00650         errno=KDB_RET_NOSYS;
00651         return -1;
00652     }
00653     
00654     return rc;
00655 }
00656 
00657 
00658 
00659 
00676 int kdbRename(KDBHandle handle, Key *key, const char *newName) {
00677     int rc=0;
00678     
00679     if (handle) {
00680         if ( handle->kdbRename )
00681             rc=handle->kdbRename(handle,key,newName);
00682         else
00683             rc=kdbRename_default(handle, key, newName);
00684             
00685     } else {
00686         errno=KDB_RET_NOSYS;
00687         return -1;
00688     }
00689     
00690     return rc;
00691 }
00692 
00693 
00694 
00709 int kdbRemoveKey(KDBHandle handle, const Key *key) {
00710     int rc=0;
00711     
00712     if (handle && handle->kdbRemoveKey)
00713         rc=handle->kdbRemoveKey(handle,key);
00714     else {
00715         errno=KDB_RET_NOSYS;
00716         return -1;
00717     }
00718     
00719     return rc;
00720 }
00721 
00722 
00723 
00724 
00736 int kdbLink(KDBHandle handle, const char *oldPath, const char *newKeyName) {
00737     Key *key;
00738     int rc;
00739 
00740     key=keyNew(newKeyName,KEY_SWITCH_END);
00741     keySetLink(key,oldPath);
00742 
00743     rc=kdbSetKey(handle,key);
00744     keyDel(key);
00745 
00746     return rc;
00747 }
00748 
00749 
00750 
00751 
00814 uint32_t kdbMonitorKeys(KDBHandle handle, KeySet *interests, uint32_t diffMask,
00815         unsigned long iterations, unsigned sleep) {
00816     
00817     uint32_t rc=0;
00818     
00819     if (handle) {
00820         if(handle->kdbMonitorKeys) 
00821             rc=handle->kdbMonitorKeys(handle,interests,diffMask,iterations,
00822                 sleep);
00823         else 
00824             /* If backend doesn't provide kdbMonitorKeys, then use the default*/
00825             rc = kdbMonitorKeys_default(handle,interests,diffMask,iterations,
00826                 sleep);
00827     }
00828     else {
00829         errno=KDB_RET_NOSYS;
00830         return 0;
00831     }
00832     
00833     return rc;
00834 }
00835 
00836 
00846 uint32_t kdbMonitorKeys_default(KDBHandle handle, KeySet *interests,
00847         uint32_t diffMask, unsigned long iterations, unsigned sleeptime) {
00848     Key *start,*current;
00849     uint32_t diff;
00850     int infinitum=0;
00851 
00852     if (!interests || !interests->size) return 0;
00853 
00854     /* Unacceptable 0 usecs sleep. Defaults to 1 second */
00855     if (!sleeptime) sleeptime=1000;
00856 
00857     if (!iterations) infinitum=1;
00858     else infinitum=0;
00859 
00860     current=start=ksCurrent(interests);
00861 
00862     while (infinitum || --iterations) {
00863         do {
00864             diff=kdbMonitorKey(handle,current,diffMask,1,0);
00865             if (diff) return diff;
00866             current=ksNext(interests);
00867         } while (current!=start);
00868 
00869         /* Test if some iterations left . . . */
00870         if (infinitum || iterations) usleep(sleeptime);
00871     }
00872     return 0;
00873 }
00874 
00875 
00876 
00918 uint32_t kdbMonitorKey(KDBHandle handle, Key *interest, uint32_t diffMask,
00919         unsigned long iterations, unsigned sleep) {
00920     
00921     int rc=0;
00922     
00923     if (handle) {
00924         if(handle->kdbMonitorKey)
00925           rc=handle->kdbMonitorKey(handle,interest,diffMask,iterations,sleep);
00926         else
00927             rc=kdbMonitorKey_default(handle,interest,diffMask,iterations,sleep);
00928     }
00929     else {
00930         errno=KDB_RET_NOSYS;
00931         return 0;
00932     }
00933     
00934     return rc;
00935 }
00936 
00937 
00938 
00939 
00968 KDBInfo *kdbGetInfo(KDBHandle handle) {
00969     KDBInfo *info=0;
00970 
00971     info=malloc(sizeof(struct _KDBInfo));
00972     memset(info,0,sizeof(struct _KDBInfo));
00973 
00974 #ifdef HAVE_CONFIG_H
00975     info->version=VERSION;
00976 #endif
00977 
00978     if (handle) {
00979         info->backendName=handle->name;
00980         info->backendIsOpen=1;
00981     } else {
00982         info->backendName=getenv("KDB_BACKEND");
00983         if (!info->backendName) info->backendName="default";
00984 
00985         info->backendIsOpen=0;
00986     }
00987 
00988     return info;
00989 }
00990 
00991 
00992 
01003 void kdbFreeInfo(KDBInfo *info) {
01004     free(info);
01005     info=0;
01006 }
01007 
01008 
01009 
01010 
01011 
01022 void *kdbhSetBackendData(KDBHandle handle, void *data) {
01023     return handle->backendData = data;
01024 }
01025 
01026 
01088 void *kdbhGetBackendData(const KDBHandle handle) {
01089     return handle->backendData;
01090 }
01091 
01096 pid_t kdbhGetPID(const KDBHandle handle) {
01097     return handle->pid;
01098 }
01099 
01105 pid_t kdbhSetPID(KDBHandle handle,pid_t pid) {
01106     return handle->pid=pid;
01107 }
01108 
01113 pthread_t kdbhGetTID(const KDBHandle handle) {
01114     return handle->tid;
01115 }
01116 
01122 pthread_t kdbhSetTID(KDBHandle handle,pthread_t tid) {
01123     return handle->tid=tid;
01124 }
01125 
01126 
01131 uid_t kdbhGetUID(const KDBHandle handle) {
01132     return handle->uid;
01133 }
01134 
01140 uid_t kdbhSetUID(KDBHandle handle,uid_t uid) {
01141     return handle->uid=uid;
01142 }
01143 
01148 gid_t kdbhGetGID(const KDBHandle handle) {
01149     return handle->gid;
01150 }
01151 
01157 gid_t kdbhSetGID(KDBHandle handle,gid_t gid) {
01158     return handle->gid=gid;
01159 }
01160 
01165 mode_t kdbhGetUMask(const KDBHandle handle) {
01166     return handle->umask;
01167 }
01168 
01174 mode_t kdbhSetUMask(KDBHandle handle,mode_t umask) {
01175     return handle->umask=umask;
01176 }
01177 
01183 char *kdbhGetUserName(const KDBHandle handle) {
01184     return handle->userName;
01185 }
01186 
01193 char *kdbhSetUserName(KDBHandle handle,char *userName) {
01194     char *tmp;
01195     size_t size;
01196     
01197     if ( userName ) {
01198         size = strblen(userName);
01199         tmp = realloc(handle->userName, size);
01200         if ( tmp ) {
01201             handle->userName = tmp;
01202             memcpy(handle->userName, userName, size);
01203         }
01204     } else {
01205         free(handle->userName);
01206         handle->userName = NULL;
01207     }
01208     
01209     return handle->userName;
01210 }
01211 
01218 char *kdbhSetBackendName(KDBHandle handle,char *backendName) {
01219     char *tmp;
01220     size_t size;
01221     
01222     if ( backendName ) {
01223         size = strblen(backendName);
01224         tmp = realloc(handle->name, size);
01225         if ( tmp ) {
01226             handle->name = tmp;
01227             memcpy(handle->name, backendName, size);
01228         }
01229     } else {
01230         free(handle->name);
01231         handle->name = NULL;
01232     }
01233             
01234     return handle->name;
01235 }
01236 
01241 char *kdbhGetBackendName(KDBHandle handle) {
01242     return handle->name;
01243 }
01244 
01274 int kdbInfoToString(KDBInfo *info,char *string,size_t maxSize) {
01275     if (!info) {
01276         strncpy(string,"No info",maxSize);
01277         return -1;
01278     }
01279 
01280     snprintf(string,maxSize,
01281         "Elektra version: %s\nBackend name: %s\nBackend open: %s",
01282         info->version,
01283         info->backendName,
01284         info->backendIsOpen?"yes":"no");
01285 
01286     return 0;
01287 }
01288 
01289 
01290 
01361 KDBBackend *kdbBackendExport(const char *backendName, ...) {
01362     va_list va;
01363     KDBBackend *returned;
01364     uint32_t method=0;
01365 
01366     if (backendName == 0) return 0;
01367 
01368     returned=malloc(sizeof(KDBBackend));
01369     memset(returned,0,sizeof(KDBBackend));
01370     
01371     returned->name=(char *)malloc(strblen(backendName));
01372     strcpy(returned->name,backendName);
01373     
01374     /* Start processing parameters */
01375     
01376     va_start(va,backendName);
01377 
01378     while ((method=va_arg(va,uint32_t))) {
01379         switch (method) {
01380             case KDB_BE_OPEN:
01381                 returned->kdbOpen=va_arg(va,kdbOpenPtr);
01382                 break;
01383             case KDB_BE_CLOSE:
01384                 returned->kdbClose=va_arg(va,kdbClosePtr);
01385                 break;
01386             case KDB_BE_STATKEY:
01387                 returned->kdbStatKey=va_arg(va,kdbStatKeyPtr);
01388                 break;
01389             case KDB_BE_GETKEY:
01390                 returned->kdbGetKey=va_arg(va,kdbGetKeyPtr);
01391                 break;
01392             case KDB_BE_SETKEY:
01393                 returned->kdbSetKey=va_arg(va,kdbSetKeyPtr);
01394                 break;
01395             case KDB_BE_RENAME:
01396                 returned->kdbRename=va_arg(va,kdbRenamePtr);
01397                 break;
01398             case KDB_BE_REMOVEKEY:
01399                 returned->kdbRemoveKey=va_arg(va,kdbRemoveKeyPtr);
01400                 break;
01401             case KDB_BE_GETCHILD:
01402                 returned->kdbGetKeyChildKeys=
01403                     va_arg(va,kdbGetChildKeysPtr);
01404                 break;
01405             case KDB_BE_SETKEYS:
01406                 returned->kdbSetKeys=va_arg(va,kdbSetKeysPtr);
01407                 break;
01408             case KDB_BE_MONITORKEY:
01409                 returned->kdbMonitorKey=
01410                     va_arg(va,kdbMonitorKeyPtr);
01411                 break;
01412             case KDB_BE_MONITORKEYS:
01413                 returned->kdbMonitorKeys=
01414                     va_arg(va,kdbMonitorKeysPtr);
01415                 break;
01416         }
01417     }
01418     va_end(va);
01419     
01420     return returned;
01421 }
01422 
01437 static int kdbResolveKey(KDBHandle handle, const Key *key, char **resolvedKeyName) {
01438     Key     *resolvedKey;
01439     char    *kName, *tmp, *ptr;
01440     size_t  size;
01441     int     ret;
01442     
01443     resolvedKey = keyNew(KEY_SWITCH_END);
01444     if ( resolvedKey == NULL ) return -1;
01445     
01446     size = keyGetFullNameSize(key);
01447     kName = (char *) malloc(size);
01448     tmp = (char *) malloc(size);
01449     if ( (kName == NULL) || (tmp == NULL) ) {
01450         keyDel(resolvedKey);
01451         free(tmp);
01452         free(kName);
01453         return -1;
01454     }
01455     
01456     if ( keyGetFullName(key, tmp, size) == -1 ) {
01457         keyDel(resolvedKey);
01458         free(tmp);
01459         free(kName);
01460         return -1;
01461     }
01462     
01463     size = 0;
01464     ptr = tmp;
01465     while ( *(ptr = keyNameGetOneLevel(ptr+size, &size)) != 0 ) {
01466         strncpy(kName, ptr, size);
01467         kName[size] = '\0';
01468         
01469         if ( keyAddBaseName(resolvedKey, kName) == -1 ) {
01470             /* Probably not enought memory ... */
01471             keyDel(resolvedKey);
01472             free(tmp);
01473             free(kName);
01474             return -1;
01475         }
01476         
01477         /* Resolve key link .. */
01478         for(;;) {
01479             ret = kdbStatKey(handle, resolvedKey);
01480             if ( (ret == 0) && !keyIsLink(resolvedKey) ) {
01481                 /* Key isn't a link, stop resolution. */
01482                 break;
01483                 
01484             } else if ( (ret == -1) && (errno == KDB_RET_NOTFOUND) ) {
01485                 /* Key isn't existing. Stop resolution */
01486                 break;
01487                 
01488             } else if ( ret == -1 ) {
01489                 /* kdbStatKey() failed because of an internal
01490                  * error or access denied. Propagate errno. */
01491                 keyDel(resolvedKey);
01492                 free(tmp);
01493                 free(kName);
01494                 return -1;
01495             }
01496             
01497             /* Key is a link. Target key is contained in the value
01498              * of the stated key */
01499             ret = keySetName(resolvedKey, keyStealValue(resolvedKey));
01500             if ( ret == 0 ) {
01501                 /* Target key's name isn't valid. Propagate errno.
01502                  * (NULL target isn't valid too) */
01503                 keyDel(resolvedKey);
01504                 free(tmp);
01505                 free(kName);
01506                 return -1;
01507             }
01508             
01509             /* Perhaps the resolved key is a key link too, so iterate
01510              * now ... */
01511         }
01512     }
01513     free(tmp);
01514     free(kName);
01515     
01516     size = keyGetFullNameSize(resolvedKey);
01517     *resolvedKeyName = (char *) malloc(size);
01518     if ( *resolvedKeyName == NULL ) {
01519         keyDel(resolvedKey);
01520         return -1;
01521     }
01522     
01523     keyGetFullName(resolvedKey, *resolvedKeyName, size);
01524     keyDel(resolvedKey);
01525     
01526     return 0;
01527 }

Generated on Sun Mar 25 21:36:06 2007 for Elektra Project by  doxygen 1.5.1