Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "kdbconfig.h"
10 : #include <external.hpp>
11 : #include <kdb.h>
12 : #include <kdb.hpp>
13 :
14 : #include <iostream>
15 : #include <string>
16 : #include <vector>
17 :
18 : #include <errno.h>
19 : #include <limits.h>
20 : #include <stdlib.h>
21 : #include <string.h>
22 : #include <sys/stat.h>
23 : #include <sys/types.h>
24 : #include <unistd.h>
25 :
26 : #ifndef _WIN32
27 : #include <sys/types.h>
28 : #include <sys/wait.h>
29 : #endif
30 :
31 : const char * buildinExecPath = BUILTIN_EXEC_FOLDER;
32 :
33 0 : static std::string cwd ()
34 : {
35 0 : std::vector<char> current_dir;
36 0 : current_dir.resize (KDB_MAX_PATH_LENGTH);
37 0 : errno = 0;
38 0 : while (getcwd (¤t_dir[0], current_dir.size ()) == nullptr && errno == ERANGE)
39 : {
40 0 : current_dir.resize (current_dir.size () * 2);
41 : }
42 :
43 0 : if (errno != 0)
44 : {
45 : return std::string ();
46 : }
47 :
48 0 : return std::string (¤t_dir[0]);
49 : }
50 :
51 78 : void tryExternalCommand (char ** argv)
52 : {
53 156 : std::vector<std::string> pathes;
54 :
55 78 : char * execPath = getenv ("KDB_EXEC_PATH");
56 78 : if (execPath)
57 : {
58 390 : pathes.push_back (execPath);
59 : }
60 390 : pathes.push_back (buildinExecPath);
61 :
62 468 : for (auto & pathe : pathes)
63 : {
64 156 : std::string command;
65 156 : char * savedArg = nullptr;
66 :
67 156 : if (pathe[0] != '/')
68 : {
69 : // no absolute path, so work with current path
70 0 : const std::string currentPath = cwd ();
71 :
72 0 : if (currentPath.empty ())
73 : {
74 : std::cerr << "Could not determine "
75 : << "current path for " << pathe << " with command name: " << argv[0]
76 0 : << " because: " << strerror (errno) << std::endl;
77 0 : continue;
78 : }
79 0 : command += currentPath;
80 0 : command += "/";
81 : }
82 :
83 156 : command += pathe;
84 156 : command += "/";
85 312 : command += argv[0];
86 :
87 : struct stat buf;
88 312 : if (stat (command.c_str (), &buf) == -1)
89 : {
90 156 : if (errno == ENOENT)
91 : {
92 : // the file simply does not exist
93 : // so it seems like it is an
94 : // UnknownCommand
95 : continue;
96 : }
97 : else
98 : {
99 0 : std::cerr << "The external command " << command << " could not be found, because: " << strerror (errno)
100 : << std::endl;
101 : continue;
102 : }
103 : }
104 :
105 0 : savedArg = argv[0];
106 0 : argv[0] = const_cast<char *> (command.c_str ());
107 :
108 0 : elektraExecve (command.c_str (), argv);
109 :
110 0 : std::cerr << "Could not execute external command " << command << " because: " << strerror (errno) << std::endl;
111 :
112 0 : argv[0] = savedArg;
113 : }
114 :
115 156 : throw UnknownCommand ();
116 : }
117 :
118 : #ifndef _WIN32
119 : extern char ** environ;
120 : #endif
121 :
122 0 : void elektraExecve (const char * filename, char * const argv[])
123 : {
124 : #ifdef _WIN32
125 : execve (filename, argv, 0);
126 : #else
127 0 : execve (filename, argv, environ);
128 : #endif
129 0 : }
130 :
131 :
132 0 : void runManPage (std::string command, std::string profile)
133 : {
134 0 : if (command.empty ())
135 : {
136 : command = "kdb";
137 : }
138 : else
139 : {
140 0 : command = "kdb-" + command;
141 : }
142 0 : const char * man = "/usr/bin/man";
143 : using namespace kdb;
144 0 : Key k = nullptr;
145 0 : if (profile != "nokdb")
146 : {
147 : try
148 : {
149 0 : KDB kdb;
150 0 : KeySet conf;
151 0 : std::string dirname;
152 0 : for (int i = 0; i <= 2; ++i)
153 : {
154 0 : switch (i)
155 : {
156 : case 0:
157 0 : dirname = "/sw/elektra/kdb/#0/" + profile + "/";
158 0 : break;
159 : case 1:
160 : dirname = "/sw/elektra/kdb/#0/%/";
161 : break;
162 : case 2:
163 0 : dirname = "/sw/kdb/" + profile + "/";
164 0 : break; // legacy
165 : }
166 0 : kdb.get (conf, dirname);
167 0 : if (!k) // first one wins, because we do not reassign
168 : {
169 0 : k = conf.lookup (dirname + "man");
170 : }
171 : }
172 : }
173 0 : catch (kdb::KDBException const & ce)
174 : {
175 : std::cerr << "There is a severe problem with your installation!\n"
176 0 : << "kdbOpen() failed with the info:" << std::endl
177 0 : << ce.what () << std::endl;
178 : }
179 : }
180 0 : if (k)
181 : {
182 0 : man = k.get<std::string> ().c_str ();
183 : }
184 0 : char * const argv[3] = { const_cast<char *> (man), const_cast<char *> (command.c_str ()), nullptr };
185 :
186 0 : elektraExecve (man, argv);
187 0 : std::cout << "Sorry, I was not able to execute the man-page viewer: \"" << man << "\".\n";
188 0 : std::cout << "Try to change /sw/elektra/kdb/#0/" + profile + "/man with full path to man.\n\n";
189 : std::cout << "If you did not modify settings related to the man-page viewer,\nplease report the issue at "
190 0 : "https://issues.libelektra.org/"
191 0 : << std::endl;
192 0 : exit (1);
193 : }
194 :
195 : #ifndef _WIN32
196 0 : bool runEditor (std::string editor, std::string file)
197 : {
198 0 : char * const argv[3] = { const_cast<char *> (editor.c_str ()), const_cast<char *> (file.c_str ()), 0 };
199 :
200 0 : pid_t childpid = fork ();
201 0 : if (!childpid)
202 : {
203 0 : elektraExecve (editor.c_str (), argv);
204 0 : exit (23);
205 : }
206 : else
207 : {
208 : int status;
209 0 : waitpid (childpid, &status, 0);
210 0 : if (WIFEXITED (status))
211 : {
212 0 : if (WEXITSTATUS (status) != 23)
213 : {
214 0 : return true;
215 : }
216 : }
217 : }
218 0 : return false;
219 7164 : }
220 : #else
221 : bool runEditor (std::string, std::string)
222 : {
223 : // TODO: impl
224 : return false;
225 : }
226 : #endif
|