GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/cmd_transaction.cc
Date: 2024-04-21 02:33:16
Exec Total Coverage
Lines: 0 84 0.0%
Branches: 0 242 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "cvmfs_config.h"
6 #include "cmd_transaction.h"
7
8 #include <errno.h>
9
10 #include <ctime>
11 #include <string>
12 #include <vector>
13
14 #include "publish/cmd_util.h"
15 #include "publish/except.h"
16 #include "publish/repository.h"
17 #include "publish/settings.h"
18 #include "util/logging.h"
19 #include "util/posix.h"
20 #include "util/string.h"
21 #include "whitelist.h"
22
23 namespace publish {
24
25 int CmdTransaction::Main(const Options &options) {
26 // Repository name and lease path are submitted as a single argument
27 // for historical reasons
28 std::string fqrn;
29 std::string lease_path;
30 if (!options.plain_args().empty()) {
31 std::vector<std::string> tokens =
32 SplitStringBounded(2, options.plain_args()[0].value_str, '/');
33 fqrn = tokens[0];
34 if (tokens.size() == 2)
35 lease_path = MakeCanonicalPath(tokens[1]);
36 }
37
38 SettingsBuilder builder;
39 UniquePtr<SettingsPublisher> settings;
40 try {
41 settings = builder.CreateSettingsPublisher(fqrn, true /* needs_managed */);
42 } catch (const EPublish &e) {
43 if (e.failure() == EPublish::kFailRepositoryNotFound) {
44 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "CernVM-FS error: %s",
45 e.msg().c_str());
46 return 1;
47 }
48 throw;
49 }
50 if (settings->transaction().in_enter_session()) {
51 throw EPublish(
52 "opening a transaction is unsupported within the ephemeral "
53 "writable shell",
54 EPublish::kFailInvocation);
55 }
56 if (options.Has("retry-timeout")) {
57 settings->GetTransaction()->SetTimeout(options.GetInt("retry-timeout"));
58 }
59 if (options.Has("template-from")) {
60 if (!options.Has("template-to"))
61 throw EPublish("invalid parameter combination for templates");
62 settings->GetTransaction()->SetTemplate(
63 options.GetString("template-from"), options.GetString("template-to"));
64 }
65 if (options.Has("template")) {
66 if (options.Has("template-from") || options.Has("template-to"))
67 throw EPublish("invalid parameter combination for templates");
68 std::string templ = options.GetString("template");
69 std::vector<std::string> tokens = SplitString(templ, '=');
70 if (tokens.size() != 2)
71 throw EPublish("invalid syntax for --template parameter: " + templ);
72 settings->GetTransaction()->SetTemplate(tokens[0], tokens[1]);
73 }
74
75 if (!SwitchCredentials(settings->owner_uid(), settings->owner_gid(),
76 false /* temporarily */))
77 {
78 throw EPublish("No write permission to repository",
79 EPublish::kFailPermission);
80 }
81 FileSystemInfo fs_info = GetFileSystemInfo("/cvmfs");
82 if (fs_info.type == kFsTypeAutofs)
83 throw EPublish("Autofs on /cvmfs has to be disabled");
84
85 settings->GetTransaction()->SetLeasePath(lease_path);
86
87
88 UniquePtr<Publisher> publisher;
89 try {
90 publisher = new Publisher(*settings);
91 if (publisher->whitelist()->IsExpired()) {
92 throw EPublish("Repository whitelist for $name is expired",
93 EPublish::kFailWhitelistExpired);
94 }
95 } catch (const EPublish &e) {
96 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s", e.msg().c_str());
97 if (e.failure() == EPublish::kFailLayoutRevision ||
98 e.failure() == EPublish::kFailWhitelistExpired)
99 {
100 return EINVAL;
101 }
102 return EIO;
103 }
104
105 double whitelist_valid_s =
106 difftime(publisher->whitelist()->expires(), time(NULL));
107 if (whitelist_valid_s < (12 * 60 * 60)) {
108 LogCvmfs(kLogCvmfs, kLogStdout,
109 "Warning: Repository whitelist stays valid for less than 12 hours!");
110 }
111
112 int rvi = CallServerHook("transaction_before_hook", fqrn);
113 if (rvi != 0) {
114 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
115 "transaction hook failed, not opening a transaction");
116 return rvi;
117 }
118
119 try {
120 publisher->Transaction();
121 } catch (const EPublish &e) {
122 const char *msg_prefix = "CernVM-FS transaction error: ";
123 if (e.failure() == EPublish::kFailTransactionState) {
124 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s",
125 msg_prefix, e.msg().c_str());
126 return EEXIST;
127 } else if (e.failure() == EPublish::kFailLeaseBusy) {
128 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s",
129 msg_prefix, e.msg().c_str());
130 return EBUSY;
131 } else if (e.failure() == EPublish::kFailLeaseNoEntry) {
132 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s",
133 msg_prefix, e.msg().c_str());
134 return ENOENT;
135 } else if (e.failure() == EPublish::kFailLeaseNoDir) {
136 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s",
137 msg_prefix, e.msg().c_str());
138 return ENOTDIR;
139 } else if (e.failure() == EPublish::kFailInput) {
140 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s",
141 msg_prefix, e.msg().c_str());
142 return EINVAL;
143 }
144 throw;
145 }
146
147 publisher->session()->SetKeepAlive(true);
148
149 rvi = CallServerHook("transaction_after_hook", fqrn);
150 if (rvi != 0) {
151 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
152 "post transaction hook failed");
153 return rvi;
154 }
155
156 return 0;
157 }
158
159 } // namespace publish
160