GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/cmd_transaction.cc
Date: 2025-06-29 02:35:41
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
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 = SplitStringBounded(
32 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("opening a transaction is unsupported within the ephemeral "
52 "writable shell",
53 EPublish::kFailInvocation);
54 }
55 if (options.Has("retry-timeout")) {
56 settings->GetTransaction()->SetTimeout(options.GetInt("retry-timeout"));
57 }
58 if (options.Has("template-from")) {
59 if (!options.Has("template-to"))
60 throw EPublish("invalid parameter combination for templates");
61 settings->GetTransaction()->SetTemplate(options.GetString("template-from"),
62 options.GetString("template-to"));
63 }
64 if (options.Has("template")) {
65 if (options.Has("template-from") || options.Has("template-to"))
66 throw EPublish("invalid parameter combination for templates");
67 const std::string templ = options.GetString("template");
68 std::vector<std::string> tokens = SplitString(templ, '=');
69 if (tokens.size() != 2)
70 throw EPublish("invalid syntax for --template parameter: " + templ);
71 settings->GetTransaction()->SetTemplate(tokens[0], tokens[1]);
72 }
73
74 if (!SwitchCredentials(settings->owner_uid(), settings->owner_gid(),
75 false /* temporarily */)) {
76 throw EPublish("No write permission to repository",
77 EPublish::kFailPermission);
78 }
79 const FileSystemInfo fs_info = GetFileSystemInfo("/cvmfs");
80 if (fs_info.type == kFsTypeAutofs)
81 throw EPublish("Autofs on /cvmfs has to be disabled");
82
83 settings->GetTransaction()->SetLeasePath(lease_path);
84
85
86 UniquePtr<Publisher> publisher;
87 try {
88 publisher = new Publisher(*settings);
89 if (publisher->whitelist()->IsExpired()) {
90 throw EPublish("Repository whitelist for $name is expired",
91 EPublish::kFailWhitelistExpired);
92 }
93 } catch (const EPublish &e) {
94 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s", e.msg().c_str());
95 if (e.failure() == EPublish::kFailLayoutRevision
96 || e.failure() == EPublish::kFailWhitelistExpired) {
97 return EINVAL;
98 }
99 return EIO;
100 }
101
102 const double whitelist_valid_s = difftime(publisher->whitelist()->expires(),
103 time(NULL));
104 if (whitelist_valid_s < (12 * 60 * 60)) {
105 LogCvmfs(
106 kLogCvmfs, kLogStdout,
107 "Warning: Repository whitelist stays valid for less than 12 hours!");
108 }
109
110 int rvi = CallServerHook("transaction_before_hook", fqrn);
111 if (rvi != 0) {
112 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
113 "transaction hook failed, not opening a transaction");
114 return rvi;
115 }
116
117 try {
118 publisher->Transaction();
119 } catch (const EPublish &e) {
120 const char *msg_prefix = "CernVM-FS transaction error: ";
121 if (e.failure() == EPublish::kFailTransactionState) {
122 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s", msg_prefix,
123 e.msg().c_str());
124 return EEXIST;
125 } else if (e.failure() == EPublish::kFailLeaseBusy) {
126 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s", msg_prefix,
127 e.msg().c_str());
128 return EBUSY;
129 } else if (e.failure() == EPublish::kFailLeaseNoEntry) {
130 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s", msg_prefix,
131 e.msg().c_str());
132 return ENOENT;
133 } else if (e.failure() == EPublish::kFailLeaseNoDir) {
134 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s", msg_prefix,
135 e.msg().c_str());
136 return ENOTDIR;
137 } else if (e.failure() == EPublish::kFailInput) {
138 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s%s", msg_prefix,
139 e.msg().c_str());
140 return EINVAL;
141 }
142 throw;
143 }
144
145 publisher->session()->SetKeepAlive(true);
146
147 rvi = CallServerHook("transaction_after_hook", fqrn);
148 if (rvi != 0) {
149 LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
150 "post transaction hook failed");
151 return rvi;
152 }
153
154 return 0;
155 }
156
157 } // namespace publish
158