Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief source file of mount command
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 :
11 : #include <backend.hpp>
12 : #include <backendbuilder.hpp>
13 : #include <backends.hpp>
14 : #include <cmdline.hpp>
15 : #include <mount.hpp>
16 :
17 : #include <keysetio.hpp>
18 :
19 : #include <fstream>
20 : #include <iostream>
21 : #include <iterator>
22 : #include <string>
23 : #include <vector>
24 :
25 : #include <kdbmodule.h>
26 : #include <kdbprivate.h>
27 :
28 : using namespace std;
29 : using namespace kdb;
30 : using namespace kdb::tools;
31 :
32 385 : MountCommand::MountCommand ()
33 : {
34 385 : }
35 :
36 :
37 : /**
38 : * @brief Output what currently is mounted
39 : */
40 74 : void MountCommand::outputMtab (Cmdline const & cl)
41 : {
42 296 : Backends::BackendInfoVector mtab = Backends::getBackendInfo (mountConf);
43 74 : bool all = cl.first && cl.second && cl.third;
44 74 : char delim = '\n';
45 74 : if (cl.null)
46 : {
47 0 : delim = '\0';
48 : }
49 354 : for (Backends::BackendInfoVector::const_iterator it = mtab.begin (); it != mtab.end (); ++it)
50 : {
51 29 : if (cl.first)
52 : {
53 58 : std::cout << it->path;
54 29 : if (all)
55 29 : std::cout << " on ";
56 : else
57 0 : std::cout << delim << std::flush;
58 : }
59 :
60 29 : if (cl.second)
61 : {
62 58 : std::cout << it->mountpoint;
63 29 : if (all)
64 29 : std::cout << " with name ";
65 : else
66 0 : std::cout << delim << std::flush;
67 : }
68 :
69 : // TODO: remove next version
70 29 : if (cl.third)
71 : {
72 58 : std::cout << it->name;
73 58 : std::cout << delim << std::flush;
74 : }
75 : }
76 74 : }
77 :
78 233 : void MountCommand::processArguments (Cmdline const & cl)
79 : {
80 466 : if (!cl.interactive && cl.arguments.size () == 1)
81 : {
82 0 : throw invalid_argument ("wrong number of arguments, 0 or more than 1 needed");
83 : }
84 :
85 233 : if (cl.interactive)
86 : {
87 0 : cout << "Welcome to interactive mounting" << endl;
88 0 : cout << "Note that nothing will be made persistent" << endl;
89 0 : cout << "until you say y at the very end of the mounting process" << endl;
90 0 : cout << endl;
91 0 : cout << "Please provide a unique name." << endl;
92 : }
93 233 : }
94 :
95 233 : void MountCommand::buildBackend (Cmdline const & cl)
96 : {
97 466 : MountBackendBuilder backend;
98 :
99 932 : Key mpk (mp, KEY_CASCADING_NAME, KEY_END);
100 :
101 233 : if (!mpk.isValid ())
102 : {
103 0 : throw invalid_argument (mp + " is not a valid mountpoint");
104 : }
105 :
106 932 : KeySet dupMountConf = mountConf.dup ();
107 :
108 466 : if (cl.force || cl.strategy != "preserve")
109 : {
110 0 : Key cutKey (Backends::mountpointsPath, KEY_END);
111 0 : cutKey.addBaseName (mpk.getName ());
112 0 : mountConf.cut (cutKey);
113 : }
114 :
115 1165 : backend.setMountpoint (mpk, mountConf);
116 :
117 1145 : backend.setBackendConfig (cl.getPluginsConfig ("system/"));
118 :
119 1145 : PluginSpec resolver (cl.resolver);
120 229 : if (cl.debug)
121 : {
122 0 : cout << "Trying to load the resolver plugin " << resolver.getName () << endl;
123 : }
124 :
125 458 : backend.addPlugin (PluginSpec (resolver));
126 :
127 229 : if (cl.interactive)
128 : {
129 0 : cout << endl;
130 0 : cout << "Enter a path to a file in the filesystem." << endl;
131 0 : cout << "The path must either not exist or be a file." << endl;
132 0 : cout << "For user or cascading mountpoints it must be a relative path." << endl;
133 0 : cout << "Then, the path will be resolved dynamically." << endl;
134 0 : cout << "Path: ";
135 0 : cin >> path;
136 : }
137 : else
138 : {
139 229 : path = cl.arguments[0];
140 : }
141 :
142 687 : backend.useConfigFile (path);
143 :
144 582 : if (!cl.quiet && path[0] == '/' && !(mpk.isSystem () || mpk.isSpec () || mpk.isCascading ()))
145 : {
146 30 : std::cout << "Note that absolute paths are still relative to their namespace (see `kdb info resolver`)." << std::endl;
147 30 : std::cout << "Only system+spec mountpoints are actually absolute." << std::endl;
148 75 : std::cout << "Use `kdb file " << mp << "` to determine where the file(s) are." << std::endl;
149 15 : std::cout << "Use `-q` or use `kdb set /sw/elektra/kdb/#0/current/quiet 1` to suppress infos." << std::endl;
150 : }
151 :
152 229 : if (cl.debug)
153 : {
154 0 : cout << "Trying to add default plugins " << cl.plugins << endl;
155 : }
156 :
157 916 : backend.needPlugin ("storage");
158 916 : backend.needPlugin ("sync");
159 458 : backend.addPlugins (parseArguments (cl.plugins));
160 :
161 229 : if (cl.interactive)
162 : {
163 0 : cout << "Now enter a sequence of plugins you want in the backend" << endl;
164 0 : appendPlugins (backend);
165 : }
166 : else
167 : {
168 229 : const size_t nonPlugins = 2;
169 1145 : backend.addPlugins (parseArguments (cl.arguments.begin () + nonPlugins, cl.arguments.end ()));
170 : }
171 :
172 : // Call it a day
173 229 : outputMissingRecommends (backend.resolveNeeds (cl.withRecommends));
174 229 : backend.serialize (mountConf);
175 :
176 456 : if (cl.strategy == "unchanged" && cl.debug)
177 : {
178 0 : cout << "The new configuration is:" << endl;
179 0 : std::cout << mountConf;
180 0 : std::cout << "------------------------" << std::endl;
181 0 : cout << "The configuration originally was:" << endl;
182 0 : std::cout << dupMountConf;
183 : }
184 :
185 456 : if (!cl.force && (cl.strategy == "unchanged" && mountConf != dupMountConf))
186 : {
187 : // throw error because it is not unchanged
188 : try
189 : {
190 0 : backend.setMountpoint (mpk, dupMountConf);
191 : }
192 0 : catch (MountpointAlreadyInUseException const & e)
193 : {
194 : throw MountpointAlreadyInUseException (
195 0 : std::string ("Requested unchanged mountpoint but mount would lead to changes\n") + e.what ());
196 : }
197 : }
198 228 : }
199 :
200 0 : void MountCommand::readPluginConfig (KeySet & pluginConfig)
201 : {
202 0 : string keyName;
203 0 : string value;
204 :
205 0 : cout << "Enter the plugin configuration" << endl;
206 0 : cout << "Use '.' as Key name to finish" << endl;
207 :
208 : while (true)
209 : {
210 0 : cout << "Enter the Key name: ";
211 0 : cin >> keyName;
212 :
213 0 : if (keyName == ".") break;
214 :
215 0 : cout << "Enter the Key value: ";
216 0 : cin >> value;
217 :
218 0 : pluginConfig.append (Key ("user/" + keyName, KEY_VALUE, value.c_str (), KEY_END));
219 : }
220 0 : }
221 :
222 0 : void MountCommand::appendPlugins (MountBackendInterface & backend)
223 : {
224 0 : std::string pname;
225 0 : KeySet pluginConfig;
226 0 : cout << "First Plugin: ";
227 0 : cin >> pname;
228 0 : readPluginConfig (pluginConfig);
229 :
230 0 : while (pname != "." || !backend.validated ())
231 : {
232 : try
233 : {
234 0 : backend.addPlugin (PluginSpec (pname, pluginConfig));
235 : pluginConfig.clear ();
236 : }
237 0 : catch (PluginCheckException const & e)
238 : {
239 0 : cerr << "Could not add that plugin" << endl;
240 0 : cerr << e.what () << endl;
241 : }
242 0 : if (!backend.validated ())
243 0 : cout << "Not validated, try to add another plugin (. to abort)" << endl;
244 : else
245 0 : cout << "Enter . to finish entering plugins" << endl;
246 :
247 0 : cout << endl;
248 0 : cout << "Next Plugin: ";
249 0 : cin >> pname;
250 :
251 0 : if (pname != ".")
252 : {
253 0 : readPluginConfig (pluginConfig);
254 : }
255 :
256 0 : if (pname == "." && !backend.validated ())
257 : {
258 0 : std::ostringstream os;
259 0 : backend.status (os);
260 0 : throw CommandAbortException (os.str ());
261 : }
262 : }
263 0 : }
264 :
265 :
266 : /**
267 : * @brief Its quite linear whats going on, but there are many steps involved
268 : *
269 : * @param cl the commandline
270 : *
271 : * @retval 0 on success (otherwise exception)
272 : */
273 307 : int MountCommand::execute (Cmdline const & cl)
274 : {
275 307 : readMountConf (cl);
276 :
277 614 : if (!cl.interactive && cl.arguments.empty ())
278 : {
279 : // no interactive mode, so lets output the mtab
280 74 : outputMtab (cl);
281 74 : return 0;
282 : }
283 :
284 233 : processArguments (cl);
285 233 : getMountpoint (cl);
286 233 : buildBackend (cl);
287 228 : askForConfirmation (cl);
288 228 : doIt ();
289 :
290 228 : return 0;
291 : }
292 :
293 385 : MountCommand::~MountCommand ()
294 : {
295 7549 : }
|