GCC Code Coverage Report


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