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 <iostream>
10 : #include <memory>
11 : #include <string>
12 : #include <vector>
13 :
14 : #include <coloredkdbio.hpp>
15 :
16 : #include <cmdline.hpp>
17 : #include <command.hpp>
18 : #include <external.hpp>
19 : #include <factory.hpp>
20 : #include <signal.h>
21 : #include <toolexcept.hpp>
22 :
23 : #include <kdb.hpp>
24 : #include <key.hpp>
25 :
26 : using namespace kdb;
27 : using namespace std;
28 :
29 78 : int displayHelp (std::string app, Factory const & f)
30 : {
31 312 : std::cout << "Usage: " << app << " <command> [args]\n" << std::endl;
32 : std::cout << app << " is a program to manage Elektra's key database.\n"
33 : << "Please run a command with -H or --help as args to show a help text for\n"
34 312 : << "a specific command.\n"
35 78 : << std::endl;
36 156 : std::cout << "Known commands are:" << std::endl;
37 156 : std::vector<std::string> commands;
38 : try
39 : {
40 156 : commands = f.getPrettyCommands ();
41 : }
42 0 : catch (kdb::KDBException const & ce)
43 : {
44 : std::cerr << "Sorry, I have a severe problem, it seems like I am not installed correctly!\n"
45 0 : << "kdbOpen() failed with the info:" << std::endl
46 0 : << ce.what () << std::endl
47 0 : << "Please report the issue at https://issues.libelektra.org/";
48 : return 8;
49 : }
50 3510 : for (auto & command : commands)
51 : {
52 6396 : std::cout << command << std::endl;
53 : }
54 : return 0;
55 : }
56 :
57 2 : void displayVersion ()
58 : {
59 4 : kdb::KDB kdb;
60 4 : kdb::KeySet versions;
61 4 : kdb::Key k ("system/elektra/version", KEY_END);
62 2 : kdb.get (versions, k);
63 12 : kdb::Key kdb_version = versions.lookup ("system/elektra/version/constants/KDB_VERSION");
64 2 : if (!kdb_version)
65 : {
66 0 : cerr << "Could not lookup KDB_VERSION key" << endl;
67 : }
68 : else
69 : {
70 10 : cout << "KDB_VERSION: " << kdb_version.getString () << endl;
71 : }
72 12 : kdb::Key so_version = versions.lookup ("system/elektra/version/constants/SO_VERSION");
73 2 : if (!so_version)
74 : {
75 0 : cerr << "Could not lookup SO_VERSION key" << endl;
76 : }
77 : else
78 : {
79 10 : cout << "SO_VERSION: " << so_version.getString () << endl;
80 : }
81 2 : }
82 :
83 0 : void printSignal (int signum)
84 : {
85 0 : switch (signum)
86 : {
87 : case SIGILL:
88 0 : cerr << "SIGILL";
89 0 : break;
90 : case SIGABRT:
91 0 : cerr << "SIGABRT";
92 0 : break;
93 : case SIGFPE:
94 0 : cerr << "SIGFPE";
95 0 : break;
96 : case SIGSEGV:
97 0 : cerr << "SIGSEGV";
98 0 : break;
99 : }
100 0 : }
101 :
102 :
103 0 : void catchSignal (int signum)
104 : {
105 0 : cerr << endl << "Sorry, I crashed by the signal ";
106 0 : printSignal (signum);
107 0 : cerr << endl << "This should not have happened!" << endl;
108 0 : cerr << endl << "Please report the issue at https://issues.libelektra.org/" << std::endl;
109 0 : signal (SIGABRT, SIG_DFL);
110 0 : abort ();
111 : }
112 :
113 14328 : void setupSignal (int signum)
114 : {
115 14328 : if (signal (signum, catchSignal) == SIG_ERR)
116 : {
117 0 : cerr << "Sorry, I could not setup signal ";
118 0 : printSignal (signum);
119 0 : cerr << " because: " << strerror (errno) << std::endl;
120 0 : cerr << "Please report the issue at https://issues.libelektra.org/" << std::endl;
121 : }
122 14328 : }
123 :
124 3582 : void setupSignals ()
125 : {
126 3582 : setupSignal (SIGILL);
127 3582 : setupSignal (SIGABRT);
128 3582 : setupSignal (SIGFPE);
129 3582 : setupSignal (SIGSEGV);
130 3582 : }
131 :
132 3582 : int main (int argc, char ** argv)
133 : {
134 3582 : setupSignals ();
135 7164 : Factory f;
136 :
137 3582 : if (argc < 2)
138 : {
139 0 : return displayHelp (argv[0], f);
140 : }
141 :
142 10746 : string command = argv[1];
143 10746 : if (command == "help" || command == "-H" || command == "--help")
144 : {
145 0 : if (argc >= 3)
146 : {
147 0 : runManPage (argv[2]);
148 : }
149 : else
150 : {
151 0 : runManPage ();
152 : }
153 :
154 0 : return displayHelp (argv[0], f);
155 : }
156 :
157 7163 : if (command == "-V" || command == "--version")
158 : {
159 2 : displayVersion ();
160 : return 0;
161 : }
162 :
163 3580 : bool printVerbose = false;
164 3580 : bool printDebug = false;
165 : try
166 : {
167 10740 : std::vector<char *> origArguments (argv + 1, argv + argc);
168 7285 : origArguments.push_back (0);
169 7160 : CommandPtr cmd = f.get (command);
170 7160 : Cmdline cl (argc, argv, cmd.get ());
171 3580 : printVerbose = cl.verbose;
172 3580 : printDebug = cl.debug;
173 :
174 3580 : if (cl.help)
175 : {
176 0 : runManPage (command, cl.profile);
177 : // does not return, but may throw
178 : }
179 :
180 : // version and invalidOpt might be implemented
181 : // differently for external command
182 3580 : if (dynamic_cast<ExternalCommand *> (cmd.get ()))
183 : {
184 78 : tryExternalCommand (&origArguments[0]);
185 : // does not return, but may throw
186 : }
187 :
188 3502 : if (cl.version)
189 : {
190 0 : displayVersion ();
191 : return 0;
192 : }
193 :
194 3502 : if (cl.invalidOpt)
195 : {
196 2 : cerr << cl << endl;
197 : return 1;
198 : }
199 :
200 : try
201 : {
202 3500 : return cmd->execute (cl);
203 : }
204 30 : catch (std::invalid_argument const & ia)
205 : {
206 60 : cerr << "Sorry, I could not process the arguments: " << ia.what () << endl << endl;
207 30 : cerr << cl << endl;
208 : return 2;
209 : }
210 : }
211 4 : catch (CommandException const & ce)
212 : {
213 4 : std::cerr << "The command " << getErrorColor (ANSI_COLOR::BOLD) << argv[0] << " " << command
214 6 : << getErrorColor (ANSI_COLOR::RESET) << " terminated " << getErrorColor (ANSI_COLOR::RED) << "unsuccessfully"
215 4 : << getErrorColor (ANSI_COLOR::RESET) << " with the info:\n"
216 26 : << ce.what () << std::endl;
217 2 : if (ce.errorCode () != 3 && (ce.errorCode () < 11 || ce.errorCode () > 20))
218 : {
219 0 : std::cerr << "Command used invalid return value (" << ce.errorCode ()
220 0 : << "), please report the issue at https://issues.libelektra.org/" << std::endl;
221 : return 3;
222 : }
223 2 : return ce.errorCode ();
224 : }
225 156 : catch (UnknownCommand const & uc)
226 : {
227 156 : std::cerr << "The command " << getErrorColor (ANSI_COLOR::BOLD) << argv[0] << " " << command
228 234 : << getErrorColor (ANSI_COLOR::RESET) << " is " << getErrorColor (ANSI_COLOR::RED) << "not known"
229 1014 : << getErrorColor (ANSI_COLOR::RESET) << std::endl;
230 312 : displayHelp (argv[0], f);
231 : return 4;
232 : }
233 80 : catch (kdb::KDBException const & ce)
234 : {
235 80 : std::cerr << ce.whatWithArguments (printVerbose, printDebug) << std::endl;
236 : return 5;
237 : }
238 10 : catch (std::exception const & ce)
239 : {
240 10 : std::cerr << "The command " << getErrorColor (ANSI_COLOR::BOLD) << argv[0] << " " << command
241 15 : << getErrorColor (ANSI_COLOR::RESET) << " terminated " << getErrorColor (ANSI_COLOR::RED) << "unsuccessfully"
242 70 : << getErrorColor (ANSI_COLOR::RESET) << " with the info:" << endl
243 15 : << ce.what () << endl
244 10 : << "Please report the issue at https://issues.libelektra.org/" << std::endl;
245 : return 7;
246 : }
247 0 : catch (...)
248 : {
249 0 : std::cerr << "The command " << getErrorColor (ANSI_COLOR::BOLD) << argv[0] << " " << command
250 0 : << getErrorColor (ANSI_COLOR::RESET) << " terminated with an " << getErrorColor (ANSI_COLOR::RED)
251 0 : << "unknown error" << getErrorColor (ANSI_COLOR::RESET) << endl
252 0 : << "Please report the issue at https://issues.libelektra.org/" << std::endl;
253 0 : displayHelp (argv[0], f);
254 : return 7;
255 : }
256 7164 : }
|