LCOV - code coverage report
Current view: top level - src/bindings/intercept/env/src - getenv.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 226 330 68.5 %
Date: 2019-09-12 12:28:41 Functions: 27 37 73.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Source for the getenv library
       5             :  *
       6             :  * \note there are two necessary bootstrap phases:
       7             :  *
       8             :  * 1.) bootstrapping in pre-main phase when no allocation is possible
       9             :  * 2.) bootstrapping when elektra modules use getenv()
      10             :  *
      11             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
      12             :  *
      13             :  */
      14             : 
      15             : #ifndef _GNU_SOURCE
      16             : #define _GNU_SOURCE // for RTLD_NEXT (except BSDI)
      17             : #endif
      18             : 
      19             : #include <kdbconfig.h>
      20             : #include <kdbgetenv.h>
      21             : #include <kdbmacros.h>
      22             : 
      23             : #include <kdbcontext.hpp>
      24             : 
      25             : #include <kdbhelper.h>
      26             : 
      27             : #include <dlfcn.h>
      28             : #include <libgen.h>
      29             : #include <signal.h>
      30             : #include <stdio.h>
      31             : #include <stdlib.h>
      32             : #include <string.h>
      33             : #include <sys/types.h> // euid
      34             : #include <unistd.h>    // euid
      35             : 
      36             : #ifdef __powerpc__
      37             : #include <elf.h>
      38             : #include <link.h>
      39             : #include <sys/auxv.h>
      40             : #endif
      41             : 
      42             : #include <chrono>
      43             : #include <iostream>
      44             : #include <sstream>
      45             : #include <string>
      46             : 
      47             : /* BSDI has this functionality, but its not defined */
      48             : #if !defined(RTLD_NEXT)
      49             : #define RTLD_NEXT ((void *) -1L)
      50             : #endif
      51             : 
      52             : using namespace std;
      53             : using namespace ckdb;
      54             : 
      55             : #define LOG                                                                                                                                \
      56             :         if (elektraLog) (*elektraLog)
      57             : 
      58             : #define ELEKTRA_GETENV_USE_LOCKS 1
      59             : 
      60             : #if ELEKTRA_GETENV_USE_LOCKS
      61             : #if defined(__APPLE__) && defined(__MACH__)
      62             : #define ELEKTRA_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER
      63             : #else
      64             : #define ELEKTRA_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
      65             : #endif
      66             : #endif
      67             : 
      68             : namespace ckdb
      69             : {
      70             : 
      71             : extern "C" {
      72             : Key * elektraParentKey;
      73             : KeySet * elektraConfig;
      74             : KDB * elektraRepo;
      75             : Key * elektraFallbackParentKey;
      76             : KeySet * elektraFallbackConfig;
      77             : KDB * elektraFallbackRepo;
      78             : 
      79             : } // extern "C"
      80             : 
      81             : namespace
      82             : {
      83             : 
      84         120 : class KeyValueLayer : public kdb::Layer
      85             : {
      86             : public:
      87         210 :         KeyValueLayer (std::string key, std::string value_) : m_key (std::move (key)), m_value (std::move (value_))
      88             :         {
      89          70 :         }
      90         140 :         std::string id () const override
      91             :         {
      92         280 :                 return m_key;
      93             :         }
      94          16 :         std::string operator() () const override
      95             :         {
      96          32 :                 return m_value;
      97             :         }
      98             : 
      99             : private:
     100             :         std::string m_key;
     101             :         std::string m_value;
     102             : };
     103             : 
     104          24 : class GetEnvContext : public kdb::Context
     105             : {
     106             : public:
     107          70 :         void addLayer (std::string layername, std::string layervalue)
     108             :         {
     109         280 :                 std::shared_ptr<kdb::Layer> layer = make_shared<KeyValueLayer> (layername, layervalue);
     110          70 :                 activateLayer (layer);
     111          70 :         }
     112             :         void clearAllLayer ()
     113             :         {
     114           0 :                 kdb::Context::clearAllLayer ();
     115             :         }
     116          12 : } elektraEnvContext;
     117             : 
     118             : #ifdef __powerpc__
     119             : typedef int (*fcn) (int argc, char ** argv, char ** ev, ElfW (auxv_t) * auxvec, void (*rtld_fini) (void), void * stinfo,
     120             :                     char ** stack_on_entry);
     121             : #else
     122             : typedef int (*fcn) (int *(main) (int, char **, char **), int argc, char ** argv, void (*init) (void), void (*fini) (void),
     123             :                     void (*rtld_fini) (void), void(*stack_end));
     124             : #endif
     125             : typedef char * (*gfcn) (const char *);
     126             : 
     127             : union Start
     128             : {
     129             :         void * d;
     130             :         fcn f;
     131             : } start; // symbol for libc pre-main
     132             : union Sym
     133             : {
     134             :         void * d;
     135             :         gfcn f;
     136             : } sym, ssym; // symbols for libc (secure) getenv
     137             : 
     138             : typedef pid_t (*ffcn) (void);
     139             : union Fork
     140             : {
     141             :         void * d;
     142             :         ffcn f;
     143             : } ffork; // symbols for libc fork
     144             : 
     145             : std::chrono::milliseconds elektraReloadTimeout;
     146             : std::chrono::system_clock::time_point elektraReloadNext;
     147          12 : std::shared_ptr<ostream> elektraLog;
     148             : bool elektraInGetEnv;
     149          12 : KeySet * elektraDocu = ksNew (20,
     150             : #include "readme_elektrify-getenv.c"
     151             :                               KS_END);
     152             : 
     153           0 : int to_ (int c)
     154             : {
     155           0 :         if (c == '-') return '_';
     156           0 :         return c;
     157             : }
     158             : 
     159             : pthread_mutex_t elektraGetEnvMutex = ELEKTRA_MUTEX_INIT;
     160             : 
     161             : 
     162             : } // anonymous namespace
     163             : 
     164             : 
     165        1240 : extern "C" void elektraLockMutex ()
     166             : {
     167             : #if ELEKTRA_GETENV_USE_LOCKS
     168        1240 :         pthread_mutex_lock (&elektraGetEnvMutex);
     169             : #endif
     170        1240 : }
     171             : 
     172        1240 : extern "C" void elektraUnlockMutex ()
     173             : {
     174             : #if ELEKTRA_GETENV_USE_LOCKS
     175        1240 :         pthread_mutex_unlock (&elektraGetEnvMutex);
     176             : #endif
     177        1240 : }
     178             : 
     179             : 
     180           0 : void printVersion ()
     181             : {
     182           0 :         cout << "Elektra getenv is active" << std::endl;
     183           0 :         Key * k = keyNew ("system/elektra/version", KEY_END);
     184           0 :         KDB * kdb = kdbOpen (k);
     185           0 :         KeySet * c = ksNew (20, KS_END);
     186           0 :         kdbGet (kdb, c, k);
     187           0 :         kdbClose (kdb, k);
     188           0 :         keyDel (k);
     189           0 :         Key * kdb_version = ksLookupByName (c, "system/elektra/version/constants/KDB_VERSION", 0);
     190           0 :         if (!kdb_version)
     191             :         {
     192           0 :                 cerr << "Could not lookup KDB_VERSION key" << endl;
     193             :         }
     194             :         else
     195             :         {
     196           0 :                 cout << "KDB_VERSION: " << keyString (kdb_version) << endl;
     197             :         }
     198           0 :         cout << "KDB_GETENV_VERSION: " << KDB_GETENV_VERSION << endl;
     199           0 :         ksDel (c);
     200           0 : }
     201             : 
     202           4 : void addOverride (string kv)
     203             : {
     204           8 :         stringstream ss (kv);
     205          16 :         string k, v;
     206           4 :         getline (ss, k, '=');
     207           4 :         getline (ss, v);
     208           4 :         LOG << "add override " << k << " with " << v << endl;
     209             : 
     210          16 :         string fullName = "proc/elektra/intercept/getenv/override/";
     211           4 :         fullName += k;
     212           8 :         ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
     213           4 : }
     214             : 
     215           0 : void addOption (string kv)
     216             : {
     217           0 :         std::transform (kv.begin (), kv.end (), kv.begin (), to_);
     218           0 :         stringstream ss (kv);
     219           0 :         string k, v;
     220           0 :         getline (ss, k, '=');
     221           0 :         getline (ss, v);
     222           0 :         LOG << "add option " << k << " with " << v << endl;
     223             : 
     224           0 :         string fullName = "proc/elektra/intercept/getenv/option/";
     225           0 :         fullName += k;
     226           0 :         ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
     227           0 : }
     228             : 
     229           4 : void addLayer (string kv)
     230             : {
     231           8 :         stringstream ss (kv);
     232          16 :         string k, v;
     233           4 :         getline (ss, k, '%');
     234           4 :         if (ss.get () != '=') return;
     235           4 :         getline (ss, v);
     236           4 :         LOG << "add layer " << k << " with " << v << endl;
     237             : 
     238          16 :         string fullName = "proc/elektra/intercept/getenv/layer/";
     239           4 :         fullName += k;
     240           8 :         ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
     241             : }
     242             : 
     243          22 : void giveName (string name)
     244             : {
     245          22 :         char * n = elektraStrDup (name.c_str ());
     246          88 :         std::string basename = ::basename (n);
     247          22 :         elektraFree (n);
     248          22 :         LOG << "give name " << name << ", basename: " << basename << std::endl;
     249          22 :         ksAppendKey (elektraConfig, keyNew ("proc/elektra/intercept/getenv/layer/name", KEY_VALUE, name.c_str (), KEY_END));
     250          22 :         ksAppendKey (elektraConfig, keyNew ("proc/elektra/intercept/getenv/layer/basename", KEY_VALUE, basename.c_str (), KEY_END));
     251          22 : }
     252             : 
     253          22 : void parseArgs (int * argc, char ** argv)
     254             : {
     255          88 :         const string prefix = "--elektra";
     256          22 :         LOG << "Parsing args " << *argc << endl;
     257             : 
     258          88 :         giveName (argv[0]);
     259             : 
     260          22 :         int length = *argc;
     261          54 :         for (int i = 1; i < length; ++i)
     262             :         {
     263         128 :                 std::string argument = argv[i];
     264          32 :                 LOG << "Process argument " << argument << std::endl;
     265          32 :                 if (argument.size () < prefix.size ())
     266             :                 {
     267           4 :                         LOG << "Skip argument " << argument << std::endl;
     268             :                 }
     269          56 :                 else if (argument.substr (0, prefix.size ()) == prefix)
     270             :                 {
     271          16 :                         string kv = argument.substr (prefix.size ());
     272           8 :                         LOG << "Handling parameter: " << kv << endl;
     273             : 
     274           8 :                         if (kv.empty ())
     275             :                                 ; // ignore but consume --elektra
     276           8 :                         else if (kv[0] == '-')
     277             :                         {
     278           0 :                                 addOption (kv.substr (1));
     279             :                         }
     280           8 :                         else if (kv[0] == ':')
     281             :                         {
     282           8 :                                 addOverride (kv.substr (1));
     283             :                         }
     284           4 :                         else if (kv[0] == '%')
     285             :                         {
     286           8 :                                 addLayer (kv.substr (1));
     287             :                         }
     288             :                         // ignore but consume all others
     289             : 
     290             :                         // we consumed a parameter
     291           8 :                         argv[i] = nullptr;
     292             :                 }
     293             :         }
     294          22 :         char ** oldEnd = &argv[length];
     295          44 :         char ** newEnd = remove_if<char **> (argv, oldEnd, [](char * c) { return c == nullptr; });
     296          22 :         *newEnd = nullptr;
     297          22 :         const size_t toSubtract = oldEnd - newEnd;
     298          22 :         *argc -= toSubtract;
     299          22 : }
     300             : 
     301           0 : void addEnvironment (string kv)
     302             : {
     303           0 :         std::transform (kv.begin (), kv.end (), kv.begin (), ::tolower);
     304           0 :         stringstream ss (kv);
     305           0 :         string k, v;
     306           0 :         getline (ss, k, '=');
     307           0 :         getline (ss, v);
     308           0 :         LOG << "add option " << k << " with " << v << endl;
     309             : 
     310           0 :         string fullName = "proc/elektra/intercept/getenv/option/";
     311           0 :         fullName += k;
     312           0 :         ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
     313           0 : }
     314             : 
     315             : extern "C" {
     316             : extern char ** environ;
     317             : }
     318             : 
     319          68 : void parseEnvironment ()
     320             : {
     321         272 :         const string prefix = "ELEKTRA_";
     322             :         char ** env;
     323        3808 :         for (env = environ; *env != nullptr; env++)
     324             :         {
     325       14960 :                 std::string argument = *env;
     326        7480 :                 if (argument.substr (0, prefix.size ()) == prefix)
     327             :                 {
     328           0 :                         addEnvironment (argument.substr (prefix.size ()));
     329             :                 }
     330             :         }
     331          68 : }
     332             : 
     333         168 : void addLayersHelper (KeySet * lookupConfig, string prefix)
     334             : {
     335         168 :         ksRewind (elektraConfig);
     336             :         Key * c;
     337         656 :         while ((c = ksNext (elektraConfig)))
     338             :         {
     339         976 :                 std::string fullName = keyName (c);
     340         244 :                 size_t pos = fullName.find ('/');
     341         488 :                 if (pos != string::npos && fullName.substr (pos, prefix.size ()) == prefix)
     342             :                 {
     343         140 :                         std::string cascadingName = fullName.substr (fullName.find ('/'));
     344          70 :                         Key * found = ksLookupByName (lookupConfig, cascadingName.c_str (), 0);
     345         140 :                         string name = fullName.substr (fullName.find ('/') + prefix.size ());
     346         280 :                         string value = keyString (found);
     347          70 :                         LOG << "Will add layer " << name << " with " << value << endl;
     348         280 :                         elektraEnvContext.addLayer (name, value);
     349             :                 }
     350             :         }
     351         168 : }
     352             : 
     353          84 : void addLayers ()
     354             : {
     355             :         using namespace ckdb;
     356          84 :         KeySet * lookupConfig = ksDup (elektraConfig);
     357             : 
     358             :         // add fallback config
     359         336 :         addLayersHelper (lookupConfig, "/env/layer/");
     360             :         // override fallback config if new config is found
     361         336 :         addLayersHelper (lookupConfig, "/elektra/intercept/getenv/layer/");
     362             : 
     363          84 :         ksDel (lookupConfig);
     364          84 : }
     365             : 
     366          12 : void elektraSingleCleanup ()
     367             : {
     368             :         // make everything really proper clean:
     369          12 :         ksDel (elektraDocu);
     370          12 :         elektraLog.reset ();
     371          12 : }
     372             : 
     373             : 
     374             : // always preffer new config path over old/fallback path
     375             : 
     376          68 : void applyOptions ()
     377             : {
     378          68 :         Key * k = nullptr;
     379             : 
     380          68 :         elektraLog.reset ();
     381         204 :         if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/debug", 0)) ||
     382          68 :              (k = ksLookupByName (elektraConfig, "/env/option/debug", 0))) &&
     383           0 :             !keyIsBinary (k))
     384             :         {
     385           0 :                 if (keyGetValueSize (k) > 1)
     386             :                 {
     387           0 :                         elektraLog = make_shared<ofstream> (keyString (k), fstream::app);
     388             :                 }
     389             :                 else
     390             :                 {
     391           0 :                         elektraLog = shared_ptr<ostream> (&cerr, [](ostream *) {});
     392             :                 }
     393           0 :                 LOG << "Elektra getenv starts logging to ";
     394           0 :                 if (elektraLog.get () == &cerr)
     395             :                 {
     396           0 :                         LOG << "stderr";
     397             :                 }
     398             :                 else
     399             :                 {
     400           0 :                         LOG << keyString (k);
     401             :                 }
     402           0 :                 LOG << endl;
     403             :         }
     404             : 
     405         204 :         if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/clearenv", 0)) ||
     406          68 :              (k = ksLookupByName (elektraConfig, "/env/option/clearenv", 0))) &&
     407           0 :             !keyIsBinary (k))
     408             :         {
     409           0 :                 LOG << "clearing the environment" << endl;
     410             : #ifdef HAVE_CLEARENV
     411           0 :                 clearenv ();
     412             : #else
     413             : #warning Your system does not provide clearenv, this might be a security problem
     414             : #endif
     415           0 :                 environ = nullptr;
     416             :         }
     417             : 
     418          68 :         elektraReloadTimeout = std::chrono::milliseconds::zero ();
     419         204 :         if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/reload_timeout", 0)) ||
     420          68 :              (k = ksLookupByName (elektraConfig, "/env/option/reload_timeout", 0))) &&
     421           0 :             !keyIsBinary (k))
     422             :         {
     423           0 :                 LOG << "activate reloading feature" << endl;
     424             : 
     425             :                 // we do not care about errors, 0 is an invalid number anyway
     426           0 :                 std::chrono::milliseconds::rep v = atoi (keyString (k));
     427           0 :                 elektraReloadTimeout = std::chrono::milliseconds (v);
     428             :         }
     429             : 
     430         204 :         if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/help", 0)) ||
     431          68 :              (k = ksLookupByName (elektraConfig, "/env/option/help", 0))) &&
     432           0 :             !keyIsBinary (k))
     433             :         {
     434           0 :                 cout << keyString (ksLookupByName (elektraDocu, "system/elektra/modules/elektrify-getenv/infos/description", 0)) << endl;
     435           0 :                 exit (0);
     436             :         }
     437             : 
     438         204 :         if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/version", 0)) ||
     439          68 :              (k = ksLookupByName (elektraConfig, "/env/option/version", 0))) &&
     440           0 :             !keyIsBinary (k))
     441             :         {
     442           0 :                 printVersion ();
     443           0 :                 exit (0);
     444             :         }
     445          68 : }
     446             : 
     447          68 : extern "C" void elektraOpen (int * argc, char ** argv)
     448             : {
     449          68 :         elektraLockMutex ();
     450          68 :         if (elektraRepo) elektraClose (); // already opened
     451             : 
     452          68 :         LOG << "opening elektra" << endl;
     453             : 
     454          68 :         elektraParentKey = keyNew ("/elektra/intercept/getenv", KEY_END);
     455          68 :         elektraConfig = ksNew (20, KS_END);
     456          68 :         elektraRepo = kdbOpen (elektraParentKey);
     457          68 :         kdbGet (elektraRepo, elektraConfig, elektraParentKey);
     458             : 
     459          68 :         elektraFallbackParentKey = keyNew ("/env", KEY_END);
     460          68 :         elektraFallbackConfig = ksNew (20, KS_END);
     461          68 :         elektraFallbackRepo = kdbOpen (elektraFallbackParentKey);
     462          68 :         kdbGet (elektraFallbackRepo, elektraFallbackConfig, elektraFallbackParentKey);
     463          68 :         ksAppend (elektraConfig, elektraFallbackConfig);
     464             : 
     465          68 :         parseEnvironment ();
     466          68 :         if (argc && argv)
     467             :         {
     468          22 :                 parseArgs (argc, argv);
     469             :         }
     470             : 
     471             :         // reopen everything (if wrong variable names were used before)
     472          68 :         kdbClose (elektraRepo, elektraParentKey);
     473          68 :         elektraRepo = kdbOpen (elektraParentKey);
     474         272 :         std::string name = keyName (elektraParentKey);
     475          68 :         kdbGet (elektraRepo, elektraConfig, elektraParentKey);
     476          68 :         addLayers ();
     477          68 :         applyOptions ();
     478          68 :         elektraUnlockMutex ();
     479          68 : }
     480             : 
     481          78 : extern "C" void elektraClose ()
     482             : {
     483          78 :         elektraLockMutex ();
     484          78 :         if (elektraRepo)
     485             :         {
     486          68 :                 kdbClose (elektraRepo, elektraParentKey);
     487          68 :                 ksDel (elektraConfig);
     488          68 :                 keyDel (elektraParentKey);
     489          68 :                 elektraRepo = nullptr;
     490             :         }
     491          78 :         if (elektraFallbackRepo)
     492             :         {
     493          68 :                 kdbClose (elektraFallbackRepo, elektraFallbackParentKey);
     494          68 :                 ksDel (elektraFallbackConfig);
     495          68 :                 keyDel (elektraFallbackParentKey);
     496          68 :                 elektraFallbackRepo = nullptr;
     497             :         }
     498          78 :         elektraUnlockMutex ();
     499          78 : }
     500             : 
     501             : extern "C" int __real_main (int argc, char ** argv, char ** env);
     502             : 
     503             : #ifdef __powerpc__
     504             : extern "C" int __libc_start_main (int argc, char ** argv, char ** ev, ElfW (auxv_t) * auxvec, void (*rtld_fini) (void), void * stinfo,
     505             :                                   char ** stack_on_entry)
     506             : #else
     507          12 : extern "C" int __libc_start_main (int *(main) (int, char **, char **), int argc, char ** argv, void (*init) (void), void (*fini) (void),
     508             :                                   void (*rtld_fini) (void), void(*stack_end))
     509             : #endif
     510             : {
     511          12 :         elektraLockMutex (); // dlsym mutex
     512          12 :         LOG << "wrapping main" << endl;
     513          12 :         if (start.d)
     514             :         { // double wrapping situation, do not reopen, just forward to next __libc_start_main
     515           0 :                 start.d = dlsym (RTLD_NEXT, "__libc_start_main");
     516           0 :                 elektraUnlockMutex (); // dlsym mutex end
     517             : #ifdef __powerpc__
     518             :                 int ret = (*start.f) (argc, argv, ev, auxvec, rtld_fini, stinfo, stack_on_entry);
     519             : #else
     520           0 :                 int ret = (*start.f) (main, argc, argv, init, fini, rtld_fini, stack_end);
     521             : #endif
     522           0 :                 return ret;
     523             :         }
     524             : 
     525          12 :         start.d = dlsym (RTLD_NEXT, "__libc_start_main");
     526          12 :         sym.d = dlsym (RTLD_NEXT, "getenv");
     527          12 :         ssym.d = dlsym (RTLD_NEXT, "secure_getenv");
     528          12 :         ffork.d = dlsym (RTLD_NEXT, "fork");
     529             : 
     530          12 :         elektraOpen (&argc, argv);
     531          12 :         elektraUnlockMutex (); // dlsym mutex end
     532             : #ifdef __powerpc__
     533             :         int ret = (*start.f) (argc, argv, ev, auxvec, rtld_fini, stinfo, stack_on_entry);
     534             : #else
     535          12 :         int ret = (*start.f) (main, argc, argv, init, fini, rtld_fini, stack_end);
     536             : #endif
     537           0 :         elektraClose ();
     538           0 :         return ret;
     539             : }
     540             : 
     541          16 : extern "C" pid_t fork ()
     542             : {
     543          16 :         pid_t ret = ffork.f ();
     544          16 :         if (ret == 0)
     545             :         {
     546             :                 // reinitialize mutex in new process
     547             :                 // fixes deadlock in akonadictl
     548           8 :                 elektraGetEnvMutex = ELEKTRA_MUTEX_INIT;
     549             :         }
     550          16 :         return ret;
     551             : }
     552             : 
     553       11394 : Key * elektraContextEvaluation (ELEKTRA_UNUSED KeySet * ks, ELEKTRA_UNUSED Key * key, Key * found, option_t option)
     554             : {
     555       11394 :         if (found && !strncmp (keyName (found), "spec/", 5) && option == KDB_O_CALLBACK)
     556             :         {
     557          20 :                 const Key * meta = keyGetMeta (found, "context");
     558          20 :                 if (meta)
     559             :                 {
     560          80 :                         string contextName = elektraEnvContext.evaluate (keyString (meta));
     561          20 :                         LOG << ", in context: " << contextName;
     562             :                         // only consider context if key actually exists, otherwise continue searching
     563          20 :                         Key * ret = ksLookupByName (ks, contextName.c_str (), 0);
     564          40 :                         if (ret) return ret; // use context override!
     565             :                 }
     566             :                 else
     567             :                 {
     568           0 :                         LOG << ", NO context";
     569             :                 }
     570             :         }
     571             :         return found;
     572             : }
     573             : 
     574        2334 : Key * elektraLookupWithContext (std::string name)
     575             : {
     576        2334 :         Key * search = keyNew (name.c_str (), KEY_META, "callback", "", KEY_FUNC, elektraContextEvaluation, KEY_END);
     577        2334 :         Key * ret = ksLookup (elektraConfig, search, 0);
     578        2334 :         keyDel (search);
     579        2334 :         return ret;
     580             : }
     581             : 
     582        2312 : char * elektraGetEnvKey (std::string const & fullName, bool & finish)
     583             : {
     584        4624 :         Key * key = elektraLookupWithContext (fullName);
     585        2312 :         if (key)
     586             :         {
     587          24 :                 LOG << " found " << fullName << ": " << keyString (key) << endl;
     588          24 :                 finish = true;
     589          24 :                 if (keyIsBinary (key)) return nullptr;
     590          24 :                 return const_cast<char *> (keyString (key));
     591             :         }
     592             : 
     593        2288 :         finish = false;
     594        2288 :         LOG << " tried " << fullName << ",";
     595             :         return nullptr;
     596             : }
     597             : 
     598             : 
     599             : /**
     600             :  * @brief Uses Elektra to get from environment.
     601             :  *
     602             :  * @param name to be looked up in the environment.
     603             :  *
     604             :  * @return the value found for that key
     605             :  * @see getenv
     606             :  * @see secure_getenv
     607             :  */
     608        1082 : char * elektraGetEnv (const char * cname, gfcn origGetenv)
     609             : {
     610        1082 :         LOG << "elektraGetEnv(" << cname << ")";
     611        1082 :         if (!elektraRepo)
     612             :         { // no open Repo (needed for bootstrapping, if inside kdbOpen() getenv is used)
     613         252 :                 char * ret = (*origGetenv) (cname);
     614         252 :                 if (!ret)
     615             :                 {
     616          48 :                         LOG << " orig getenv returned null pointer" << endl;
     617             :                 }
     618             :                 else
     619         204 :                         LOG << " orig getenv returned (" << strlen (ret) << ") <" << ret << ">" << endl;
     620             :                 return ret;
     621             :         }
     622             : 
     623             :         // is reload feature enabled at all?
     624        1660 :         if (elektraReloadTimeout > std::chrono::milliseconds::zero ())
     625             :         {
     626           0 :                 std::chrono::system_clock::time_point const now = std::chrono::system_clock::now ();
     627             : 
     628             :                 // are we now ready to reload?
     629           0 :                 if (now >= elektraReloadNext)
     630             :                 {
     631           0 :                         int ret = kdbGet (elektraRepo, elektraConfig, elektraParentKey);
     632             : 
     633             :                         // was there a change?
     634           0 :                         if (ret == 1)
     635             :                         {
     636           0 :                                 elektraEnvContext.clearAllLayer ();
     637           0 :                                 addLayers ();
     638           0 :                                 applyOptions ();
     639             :                         }
     640             :                 }
     641             : 
     642           0 :                 elektraReloadNext = now + elektraReloadTimeout;
     643             :         }
     644             : 
     645        2490 :         std::string name = cname;
     646         830 :         bool finish = false;
     647         830 :         char * ret = nullptr;
     648        1660 :         ret = elektraGetEnvKey ("/elektra/intercept/getenv/override/" + name, finish);
     649        1644 :         if (!ret) ret = elektraGetEnvKey ("/env/override/" + name, finish);
     650         830 :         if (finish) return ret;
     651             : 
     652         806 :         ret = (*origGetenv) (name.c_str ());
     653         806 :         if (ret)
     654             :         {
     655         472 :                 LOG << " environ returned (" << strlen (ret) << ") <" << ret << ">" << endl;
     656             :                 return ret;
     657             :         }
     658             :         else
     659         334 :                 LOG << " tried environ,";
     660             : 
     661         668 :         ret = elektraGetEnvKey ("/elektra/intercept/getenv/fallback/" + name, finish);
     662         668 :         if (!ret) ret = elektraGetEnvKey ("/env/fallback/" + name, finish);
     663         334 :         if (finish) return ret;
     664             : 
     665         334 :         LOG << " nothing found" << endl;
     666             :         return nullptr;
     667             : }
     668             : 
     669             : /*
     670             : // Nice trick to find next execution of elektraMalloc
     671             : // set foo to (int*)-1 to trigger it
     672             : int *foo = 0;
     673             : extern "C" void* elektraMalloc (size_t size)
     674             : {
     675             :         // LOG << "elektraMalloc " << size << endl;
     676             :         if (foo) printf("%d\n", *foo);
     677             :         return malloc(size);
     678             : }
     679             : */
     680             : 
     681             : /**
     682             :  * @brief Search in environ, should be identical to getenv
     683             :  *
     684             :  * implementation is needed for bootstrapping in pre-main phases
     685             :  * where memory allocation hangs or crashes and thus dlsym cannot be used!
     686             :  *
     687             :  * @see getenv()
     688             :  */
     689           0 : char * elektraBootstrapGetEnv (const char * name)
     690             : {
     691           0 :         int len = strlen (name);
     692           0 :         if (environ == nullptr || len == 0)
     693             :         {
     694             :                 return nullptr;
     695             :         }
     696             : 
     697             :         char ** env;
     698           0 :         for (env = environ; *env != nullptr; env++)
     699             :         {
     700           0 :                 if (!strncmp (*env, name, len))
     701             :                 {
     702           0 :                         if ((*env)[len] == '=')
     703             :                         {
     704           0 :                                 return &((*env)[len + 1]);
     705             :                         }
     706             :                 }
     707             :         }
     708             : 
     709             :         return nullptr;
     710             : }
     711             : 
     712           0 : char * elektraBootstrapSecureGetEnv (const char * name)
     713             : {
     714           0 :         return (geteuid () != getuid () || getegid () != getgid ()) ? nullptr : elektraBootstrapGetEnv (name);
     715             : }
     716             : 
     717        1082 : extern "C" char * getenv (const char * name) // throw ()
     718             : {
     719        1082 :         elektraLockMutex ();
     720        1082 :         if (!sym.f || elektraInGetEnv)
     721             :         {
     722           0 :                 char * ret = elektraBootstrapGetEnv (name);
     723           0 :                 elektraUnlockMutex ();
     724           0 :                 return ret;
     725             :         }
     726             : 
     727        1082 :         elektraInGetEnv = true;
     728        1082 :         char * ret = elektraGetEnv (name, sym.f);
     729        1082 :         elektraInGetEnv = false;
     730        1082 :         elektraUnlockMutex ();
     731        1082 :         return ret;
     732             : }
     733             : 
     734           0 : extern "C" char * secure_getenv (const char * name) // throw ()
     735             : {
     736           0 :         elektraLockMutex ();
     737           0 :         if (!ssym.f || elektraInGetEnv)
     738             :         {
     739           0 :                 char * ret = elektraBootstrapSecureGetEnv (name);
     740           0 :                 elektraUnlockMutex ();
     741           0 :                 return ret;
     742             :         }
     743             : 
     744           0 :         elektraInGetEnv = true;
     745           0 :         char * ret = elektraGetEnv (name, ssym.f);
     746           0 :         elektraInGetEnv = false;
     747           0 :         elektraUnlockMutex ();
     748           0 :         return ret;
     749             : }
     750          36 : } // namespace ckdb

Generated by: LCOV version 1.13