GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/settings.cc
Date: 2026-10-04 02:40:33
Exec Total Coverage
Lines: 0 364 0.0%
Branches: 0 812 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "publish/settings.h"
7
8 #include <unistd.h>
9
10 #include <cstdlib>
11 #include <memory>
12 #include <string>
13 #include <vector>
14
15 #include "crypto/hash.h"
16 #include "options.h"
17 #include "publish/except.h"
18 #include "publish/repository.h"
19 #include "sanitizer.h"
20 #include "util/posix.h"
21 #include "util/string.h"
22
23 namespace publish {
24
25 ✗ void SettingsSpoolArea::UseSystemTempDir() {
26 ✗ if (getenv("TMPDIR") != NULL)
27 ✗ tmp_dir_ = getenv("TMPDIR");
28 else
29 ✗ tmp_dir_ = "/tmp";
30 }
31
32 ✗ void SettingsSpoolArea::SetSpoolArea(const std::string &path) {
33 ✗ workspace_ = path;
34 ✗ tmp_dir_ = workspace_() + "/tmp";
35 }
36
37 ✗ void SettingsSpoolArea::SetUnionMount(const std::string &path) {
38 ✗ union_mnt_ = path;
39 }
40
41 ✗ void SettingsSpoolArea::SetRepairMode(const EUnionMountRepairMode val) {
42 ✗ repair_mode_ = val;
43 }
44
45 ✗ void SettingsSpoolArea::EnsureDirectories() {
46 ✗ std::vector<std::string> targets;
47 ✗ targets.push_back(tmp_dir());
48 ✗ targets.push_back(readonly_mnt());
49 ✗ targets.push_back(scratch_dir());
50 ✗ targets.push_back(cache_dir());
51 ✗ targets.push_back(log_dir());
52 ✗ targets.push_back(ovl_work_dir());
53
54 ✗ for (unsigned i = 0; i < targets.size(); ++i) {
55 ✗ const bool rv = MkdirDeep(targets[i], 0700, true /* veryfy_writable */);
56 ✗ if (!rv)
57 ✗ throw publish::EPublish("cannot create directory " + targets[i]);
58 }
59 }
60
61
62 //------------------------------------------------------------------------------
63
64
65 ✗ void SettingsTransaction::SetLayoutRevision(const unsigned revision) {
66 ✗ layout_revision_ = revision;
67 }
68
69 ✗ void SettingsTransaction::SetInEnterSession(const bool value) {
70 ✗ in_enter_session_ = value;
71 }
72
73 ✗ void SettingsTransaction::SetBaseHash(const shash::Any &hash) {
74 ✗ base_hash_ = hash;
75 }
76
77 ✗ void SettingsTransaction::SetHashAlgorithm(const std::string &algorithm) {
78 ✗ hash_algorithm_ = shash::ParseHashAlgorithm(algorithm);
79 }
80
81 ✗ void SettingsTransaction::SetCompressionAlgorithm(
82 const std::string &algorithm) {
83 ✗ compression_algorithm_ = zlib::ParseCompressionAlgorithm(algorithm);
84 }
85
86 ✗ void SettingsTransaction::SetEnforceLimits(bool value) {
87 ✗ enforce_limits_ = value;
88 }
89
90 ✗ void SettingsTransaction::SetEnableMtimeNs(bool value) {
91 ✗ enable_mtime_ns_ = value;
92 }
93
94 ✗ void SettingsTransaction::SetLimitNestedCatalogKentries(unsigned value) {
95 ✗ limit_nested_catalog_kentries_ = value;
96 }
97
98 ✗ void SettingsTransaction::SetLimitRootCatalogKentries(unsigned value) {
99 ✗ limit_root_catalog_kentries_ = value;
100 }
101
102 ✗ void SettingsTransaction::SetLimitFileSizeMb(unsigned value) {
103 ✗ limit_file_size_mb_ = value;
104 }
105
106 ✗ void SettingsTransaction::SetUseCatalogAutobalance(bool value) {
107 ✗ use_catalog_autobalance_ = value;
108 }
109
110 ✗ void SettingsTransaction::SetAutobalanceMaxWeight(unsigned value) {
111 ✗ autobalance_max_weight_ = value;
112 }
113
114 ✗ void SettingsTransaction::SetAutobalanceMinWeight(unsigned value) {
115 ✗ autobalance_min_weight_ = value;
116 }
117
118 ✗ void SettingsTransaction::SetPrintChangeset(bool value) {
119 ✗ print_changeset_ = value;
120 }
121
122 ✗ void SettingsTransaction::SetDryRun(bool value) { dry_run_ = value; }
123
124 ✗ void SettingsTransaction::SetAllowNonexistentPath(bool value) {
125 ✗ allow_nonexistent_path_ = value;
126 }
127
128 ✗ void SettingsTransaction::SetUnionFsType(const std::string &union_fs) {
129 ✗ if (union_fs == "aufs") {
130 ✗ union_fs_ = kUnionFsAufs;
131 ✗ } else if ((union_fs == "overlay") || (union_fs == "overlayfs")) {
132 ✗ union_fs_ = kUnionFsOverlay;
133 ✗ } else if (union_fs == "tarball") {
134 ✗ union_fs_ = kUnionFsTarball;
135 } else {
136 ✗ throw EPublish("unsupported union file system: " + union_fs);
137 }
138 }
139
140 ✗ void SettingsTransaction::DetectUnionFsType() {
141 // TODO(jblomer): shall we switch the order?
142 ✗ if (DirectoryExists("/sys/fs/aufs")) {
143 ✗ union_fs_ = kUnionFsAufs;
144 ✗ return;
145 }
146 // TODO(jblomer): modprobe aufs, try again
147 ✗ if (DirectoryExists("/sys/module/overlay")) {
148 ✗ union_fs_ = kUnionFsOverlay;
149 ✗ return;
150 }
151 // TODO(jblomer): modprobe overlay, try again
152 ✗ throw EPublish("neither AUFS nor OverlayFS detected on the system");
153 }
154
155 ✗ bool SettingsTransaction::ValidateUnionFs() {
156 // TODO(jblomer)
157 ✗ return true;
158 }
159
160 ✗ void SettingsTransaction::SetTimeout(unsigned seconds) { timeout_s_ = seconds; }
161
162 ✗ int SettingsTransaction::GetTimeoutS() const {
163 ✗ if (timeout_s_.is_default())
164 ✗ return -1;
165 ✗ return timeout_s_();
166 }
167
168 ✗ void SettingsTransaction::SetLeasePath(const std::string &path) {
169 ✗ lease_path_ = path;
170 }
171
172 ✗ void SettingsTransaction::SetTemplate(const std::string &from,
173 const std::string &to) {
174 ✗ if (from.empty())
175 ✗ throw EPublish("template transaction's 'from' path must not be empty");
176 ✗ if (to.empty())
177 ✗ throw EPublish("template transaction's 'to' path must not be empty");
178 ✗ template_from_ = (from[0] == '/') ? from.substr(1) : from;
179 ✗ template_to_ = (to[0] == '/') ? to.substr(1) : to;
180 }
181
182 //------------------------------------------------------------------------------
183
184
185 ✗ std::string SettingsStorage::GetLocator() const {
186 ✗ return std::string(upload::SpoolerDefinition::kDriverNames[type_()]) + ","
187 ✗ + tmp_dir_() + "," + endpoint_();
188 }
189
190 ✗ void SettingsStorage::MakeS3(const std::string &s3_config,
191 const std::string &tmp_dir) {
192 ✗ type_ = upload::SpoolerDefinition::S3;
193 ✗ tmp_dir_ = tmp_dir;
194 ✗ endpoint_ = "cvmfs/" + fqrn_() + "@" + s3_config;
195 }
196
197 ✗ void SettingsStorage::MakeLocal(const std::string &path) {
198 ✗ type_ = upload::SpoolerDefinition::Local;
199 ✗ endpoint_ = path;
200 ✗ tmp_dir_ = path + "/data/txn";
201 }
202
203 ✗ void SettingsStorage::MakeGateway(const std::string &host,
204 unsigned int port,
205 const std::string &tmp_dir) {
206 ✗ type_ = upload::SpoolerDefinition::Gateway;
207 ✗ endpoint_ = "http://" + host + ":" + StringifyInt(port) + "/api/v1";
208 ✗ tmp_dir_ = tmp_dir;
209 }
210
211 ✗ void SettingsStorage::SetLocator(const std::string &locator) {
212 ✗ std::vector<std::string> tokens = SplitString(locator, ',');
213 ✗ if (tokens.size() != 3) {
214 ✗ throw EPublish("malformed storage locator, expected format is "
215 ✗ "<type>,<temporary directory>,<endpoint>");
216 }
217 ✗ if (tokens[0] == "local") {
218 ✗ type_ = upload::SpoolerDefinition::Local;
219 ✗ } else if (tokens[0] == "S3") {
220 ✗ type_ = upload::SpoolerDefinition::S3;
221 ✗ } else if (tokens[0] == "gw") {
222 ✗ type_ = upload::SpoolerDefinition::Gateway;
223 } else {
224 ✗ throw EPublish("unsupported storage type: " + tokens[0]);
225 }
226 ✗ tmp_dir_ = tokens[1];
227 ✗ endpoint_ = tokens[2];
228 }
229
230
231 //------------------------------------------------------------------------------
232
233 ✗ void SettingsKeychain::SetKeychainDir(const std::string &keychain_dir) {
234 ✗ keychain_dir_ = keychain_dir;
235 ✗ master_private_key_path_ = keychain_dir + "/" + fqrn_() + ".masterkey";
236 ✗ master_public_key_path_ = keychain_dir + "/" + fqrn_() + ".pub";
237 ✗ private_key_path_ = keychain_dir + "/" + fqrn_() + ".key";
238 ✗ certificate_path_ = keychain_dir + "/" + fqrn_() + ".crt";
239 ✗ gw_key_path_ = keychain_dir + "/" + fqrn_() + ".gw";
240 }
241
242
243 ✗ bool SettingsKeychain::HasDanglingMasterKeys() const {
244 ✗ return (FileExists(master_private_key_path_())
245 ✗ && !FileExists(master_public_key_path_()))
246 ✗ || (!FileExists(master_private_key_path_())
247 ✗ && FileExists(master_public_key_path_()));
248 }
249
250
251 ✗ bool SettingsKeychain::HasMasterKeys() const {
252 ✗ return FileExists(master_private_key_path_())
253 ✗ && FileExists(master_public_key_path_());
254 }
255
256
257 ✗ bool SettingsKeychain::HasDanglingRepositoryKeys() const {
258 ✗ return (FileExists(private_key_path_()) && !FileExists(certificate_path_()))
259 ✗ || (!FileExists(private_key_path_())
260 ✗ && FileExists(certificate_path_()));
261 }
262
263
264 ✗ bool SettingsKeychain::HasRepositoryKeys() const {
265 ✗ return FileExists(private_key_path_()) && FileExists(certificate_path_());
266 }
267
268 ✗ bool SettingsKeychain::HasGatewayKey() const {
269 ✗ return FileExists(gw_key_path_());
270 }
271
272 //------------------------------------------------------------------------------
273
274
275 ✗ SettingsRepository::SettingsRepository(
276 ✗ const SettingsPublisher &settings_publisher)
277 ✗ : fqrn_(settings_publisher.fqrn())
278 ✗ , url_(settings_publisher.url())
279 ✗ , proxy_(settings_publisher.proxy())
280 ✗ , tmp_dir_(settings_publisher.transaction().spool_area().tmp_dir())
281 ✗ , keychain_(settings_publisher.fqrn()) {
282 ✗ keychain_.SetKeychainDir(settings_publisher.keychain().keychain_dir());
283 }
284
285
286 ✗ SettingsRepository::SettingsRepository(const SettingsReplica &settings_replica)
287 ✗ : fqrn_(settings_replica.fqrn())
288 ✗ , url_(settings_replica.url())
289 ✗ , keychain_(settings_replica.fqrn()) { }
290
291
292 ✗ void SettingsRepository::SetUrl(const std::string &url) {
293 // TODO(jblomer): sanitiation, check availability
294 ✗ url_ = url;
295 }
296
297
298 ✗ void SettingsRepository::SetProxy(const std::string &proxy) { proxy_ = proxy; }
299
300
301 ✗ void SettingsRepository::SetTmpDir(const std::string &tmp_dir) {
302 ✗ tmp_dir_ = tmp_dir;
303 }
304
305
306 ✗ void SettingsRepository::SetCertBundle(const std::string &cert_bundle) {
307 ✗ cert_bundle_ = cert_bundle;
308 }
309
310
311 //------------------------------------------------------------------------------
312
313
314 const unsigned SettingsPublisher::kDefaultWhitelistValidity = 30;
315
316
317 ✗ SettingsPublisher::SettingsPublisher(
318 ✗ const SettingsRepository &settings_repository)
319 ✗ : fqrn_(settings_repository.fqrn())
320 ✗ , url_(settings_repository.url())
321 ✗ , proxy_(settings_repository.proxy())
322 ✗ , owner_uid_(0)
323 ✗ , owner_gid_(0)
324 ✗ , whitelist_validity_days_(kDefaultWhitelistValidity)
325 ✗ , is_silent_(false)
326 ✗ , is_managed_(false)
327 ✗ , storage_(fqrn_())
328 ✗ , transaction_(fqrn_())
329 ✗ , keychain_(fqrn_()) {
330 ✗ keychain_.SetKeychainDir(settings_repository.keychain().keychain_dir());
331 }
332
333
334 ✗ void SettingsPublisher::SetUrl(const std::string &url) {
335 // TODO(jblomer): sanitiation, check availability
336 ✗ url_ = url;
337 }
338
339
340 ✗ void SettingsPublisher::SetProxy(const std::string &proxy) { proxy_ = proxy; }
341
342
343 ✗ void SettingsPublisher::SetOwner(const std::string &user_name) {
344 ✗ const bool retval = GetUidOf(
345 user_name, owner_uid_.GetPtr(), owner_gid_.GetPtr());
346 ✗ if (!retval) {
347 ✗ throw EPublish("unknown user name for repository owner: " + user_name);
348 }
349 }
350
351 ✗ void SettingsPublisher::SetOwner(uid_t uid, gid_t gid) {
352 ✗ owner_uid_ = uid;
353 ✗ owner_gid_ = gid;
354 }
355
356 ✗ void SettingsPublisher::SetIsSilent(bool value) { is_silent_ = value; }
357
358 ✗ void SettingsPublisher::SetIsManaged(bool value) { is_managed_ = value; }
359
360 ✗ void SettingsPublisher::SetIgnoreInvalidLease(bool value) {
361 ✗ ignore_invalid_lease_ = value;
362 }
363
364
365 //------------------------------------------------------------------------------
366
367
368 ✗ SettingsBuilder::~SettingsBuilder() { delete options_mgr_; }
369
370
371 ✗ std::map<std::string, std::string> SettingsBuilder::GetSessionEnvironment() {
372 ✗ std::map<std::string, std::string> result;
373 ✗ const std::string session_dir = Env::GetEnterSessionDir();
374 ✗ if (session_dir.empty())
375 ✗ return result;
376
377 // Get the repository name from the ephemeral writable shell
378 ✗ BashOptionsManager omgr;
379 ✗ omgr.set_taint_environment(false);
380 ✗ omgr.ParsePath(session_dir + "/env.conf", false /* external */);
381
382 // We require at least CVMFS_FQRN to be set
383 ✗ std::string fqrn;
384 ✗ if (!omgr.GetValue("CVMFS_FQRN", &fqrn)) {
385 ✗ throw EPublish("no repositories found in ephemeral writable shell",
386 ✗ EPublish::kFailInvocation);
387 }
388
389 ✗ std::vector<std::string> keys = omgr.GetAllKeys();
390 ✗ for (unsigned i = 0; i < keys.size(); ++i) {
391 ✗ result[keys[i]] = omgr.GetValueOrDie(keys[i]);
392 }
393 ✗ return result;
394 }
395
396
397 ✗ std::string SettingsBuilder::GetSingleAlias() {
398 ✗ std::map<std::string, std::string> session_env = GetSessionEnvironment();
399 ✗ if (!session_env.empty())
400 ✗ return session_env["CVMFS_FQRN"];
401
402 ✗ std::vector<std::string> repositories = FindDirectories(config_path_);
403 ✗ if (repositories.empty()) {
404 ✗ throw EPublish("no repositories available in " + config_path_,
405 ✗ EPublish::kFailInvocation);
406 }
407
408 ✗ for (unsigned i = 0; i < repositories.size(); ++i) {
409 ✗ repositories[i] = GetFileName(repositories[i]);
410 }
411 ✗ if (repositories.size() > 1) {
412 ✗ throw EPublish("multiple repositories available in " + config_path_
413 ✗ + ":\n " + JoinStrings(repositories, "\n "),
414 ✗ EPublish::kFailInvocation);
415 }
416 ✗ return repositories[0];
417 }
418
419
420 ✗ SettingsRepository SettingsBuilder::CreateSettingsRepository(
421 const std::string &ident) {
422 ✗ if (HasPrefix(ident, "http://", true /* ignore case */)
423 ✗ || HasPrefix(ident, "https://", true /* ignore case */)
424 ✗ || HasPrefix(ident, "file://", true /* ignore case */)) {
425 ✗ const std::string fqrn = Repository::GetFqrnFromUrl(ident);
426 ✗ const sanitizer::RepositorySanitizer sanitizer;
427 ✗ if (!sanitizer.IsValid(fqrn)) {
428 ✗ throw EPublish("malformed repository name: " + fqrn);
429 }
430 ✗ SettingsRepository settings(fqrn);
431 ✗ settings.SetUrl(ident);
432 ✗ return settings;
433 }
434
435 ✗ const std::string alias = ident.empty() ? GetSingleAlias() : ident;
436 ✗ const std::string repo_path = config_path_ + "/" + alias;
437 ✗ const std::string server_path = repo_path + "/server.conf";
438 ✗ const std::string replica_path = repo_path + "/replica.conf";
439 ✗ std::string fqrn = alias;
440
441 ✗ delete options_mgr_;
442 ✗ options_mgr_ = new BashOptionsManager();
443 ✗ std::string arg;
444 ✗ options_mgr_->set_taint_environment(false);
445 ✗ options_mgr_->ParsePath("/etc/cvmfs/server.local", false /* external */);
446 ✗ options_mgr_->ParsePath(server_path, false /* external */);
447 ✗ options_mgr_->ParsePath(replica_path, false /* external */);
448 ✗ if (options_mgr_->GetValue("CVMFS_REPOSITORY_NAME", &arg))
449 ✗ fqrn = arg;
450 ✗ SettingsRepository settings(fqrn);
451
452 ✗ if (options_mgr_->GetValue("CVMFS_PUBLIC_KEY", &arg))
453 ✗ settings.GetKeychain()->SetKeychainDir(arg);
454 ✗ if (options_mgr_->GetValue("CVMFS_STRATUM0", &arg))
455 ✗ settings.SetUrl(arg);
456 ✗ if (options_mgr_->GetValue("CVMFS_SERVER_PROXY", &arg))
457 ✗ settings.SetProxy(arg);
458 // For a replica, the stratum 1 url is the "local" location, hence it takes
459 // precedence over the stratum 0 url
460 ✗ if (options_mgr_->GetValue("CVMFS_STRATUM1", &arg))
461 ✗ settings.SetUrl(arg);
462 ✗ if (options_mgr_->GetValue("CVMFS_SPOOL_DIR", &arg))
463 ✗ settings.SetTmpDir(arg + "/tmp");
464 ✗ if (options_mgr_->GetValue("X509_CERT_BUNDLE", &arg))
465 ✗ settings.SetCertBundle(arg);
466
467 ✗ return settings;
468 }
469
470 ✗ std::string SettingsPublisher::GetReadOnlyXAttr(const std::string &attr) {
471 ✗ std::string value;
472 ✗ const bool rvb = platform_getxattr(
473 ✗ this->transaction().spool_area().readonly_mnt(), attr, &value);
474 ✗ if (!rvb) {
475 ✗ throw EPublish("cannot get extended attribute " + attr);
476 }
477 ✗ return value;
478 }
479
480 ✗ SettingsPublisher *SettingsBuilder::CreateSettingsPublisherFromSession() {
481 ✗ const std::string session_dir = Env::GetEnterSessionDir();
482 ✗ std::map<std::string, std::string> session_env = GetSessionEnvironment();
483 ✗ const std::string fqrn = session_env["CVMFS_FQRN"];
484
485 std::unique_ptr<SettingsPublisher> settings_publisher(
486 ✗ new SettingsPublisher(SettingsRepository(fqrn)));
487 // TODO(jblomer): work in progress
488 ✗ settings_publisher->GetTransaction()->SetInEnterSession(true);
489 ✗ settings_publisher->GetTransaction()->GetSpoolArea()->SetSpoolArea(
490 session_dir);
491
492 const std::string base_hash = settings_publisher->GetReadOnlyXAttr(
493 ✗ "user.root_hash");
494
495 ✗ BashOptionsManager omgr;
496 ✗ omgr.set_taint_environment(false);
497 ✗ omgr.ParsePath(settings_publisher->transaction().spool_area().client_config(),
498 false /* external */);
499
500 ✗ std::string arg;
501 ✗ settings_publisher->SetUrl(settings_publisher->GetReadOnlyXAttr("user.host"));
502 ✗ settings_publisher->SetProxy(
503 ✗ settings_publisher->GetReadOnlyXAttr("user.proxy"));
504 ✗ if (omgr.GetValue("CVMFS_KEYS_DIR", &arg))
505 ✗ settings_publisher->GetKeychain()->SetKeychainDir(arg);
506 ✗ settings_publisher->GetTransaction()->SetLayoutRevision(
507 Publisher::kRequiredLayoutRevision);
508 ✗ settings_publisher->GetTransaction()->SetBaseHash(
509 ✗ shash::MkFromHexPtr(shash::HexPtr(base_hash), shash::kSuffixCatalog));
510 ✗ settings_publisher->GetTransaction()->SetUnionFsType("overlayfs");
511 ✗ settings_publisher->SetOwner(geteuid(), getegid());
512
513 ✗ return settings_publisher.release();
514 }
515
516 ✗ void SettingsBuilder::ApplyOptionsFromServerPath(
517 const OptionsManager &options_mgr_, SettingsPublisher *settings_publisher) {
518 ✗ std::string arg;
519 ✗ if (options_mgr_.GetValue("CVMFS_CREATOR_VERSION", &arg)) {
520 ✗ settings_publisher->GetTransaction()->SetLayoutRevision(String2Uint64(arg));
521 }
522 ✗ if (options_mgr_.GetValue("CVMFS_UNION_FS_TYPE", &arg)) {
523 ✗ settings_publisher->GetTransaction()->SetUnionFsType(arg);
524 }
525 ✗ if (options_mgr_.GetValue("CVMFS_HASH_ALGORITHM", &arg)) {
526 ✗ settings_publisher->GetTransaction()->SetHashAlgorithm(arg);
527 }
528 ✗ if (options_mgr_.GetValue("CVMFS_UPSTREAM_STORAGE", &arg)) {
529 ✗ settings_publisher->GetStorage()->SetLocator(arg);
530 }
531 ✗ if (options_mgr_.GetValue("CVMFS_KEYS_DIR", &arg)) {
532 ✗ settings_publisher->GetKeychain()->SetKeychainDir(arg);
533 }
534 ✗ if (options_mgr_.GetValue("CVMFS_COMPRESSION_ALGORITHM", &arg)) {
535 ✗ settings_publisher->GetTransaction()->SetCompressionAlgorithm(arg);
536 }
537 ✗ if (options_mgr_.GetValue("CVMFS_ENFORCE_LIMITS", &arg)) {
538 ✗ settings_publisher->GetTransaction()->SetEnforceLimits(
539 ✗ options_mgr_.IsOn(arg));
540 }
541 ✗ if (options_mgr_.GetValue("CVMFS_ENABLE_MTIME_NS", &arg)) {
542 ✗ settings_publisher->GetTransaction()->SetEnableMtimeNs(
543 ✗ options_mgr_.IsOn(arg));
544 }
545 ✗ if (options_mgr_.GetValue("CVMFS_NESTED_KCATALOG_LIMIT", &arg)) {
546 ✗ settings_publisher->GetTransaction()->SetLimitNestedCatalogKentries(
547 ✗ String2Uint64(arg));
548 }
549 ✗ if (options_mgr_.GetValue("CVMFS_ROOT_KCATALOG_LIMIT", &arg)) {
550 ✗ settings_publisher->GetTransaction()->SetLimitRootCatalogKentries(
551 ✗ String2Uint64(arg));
552 }
553 ✗ if (options_mgr_.GetValue("CVMFS_FILE_MBYTE_LIMIT", &arg)) {
554 ✗ settings_publisher->GetTransaction()->SetLimitFileSizeMb(
555 ✗ String2Uint64(arg));
556 }
557 ✗ if (options_mgr_.GetValue("CVMFS_AUTOCATALOGS", &arg)) {
558 ✗ settings_publisher->GetTransaction()->SetUseCatalogAutobalance(
559 ✗ options_mgr_.IsOn(arg));
560 }
561 ✗ if (options_mgr_.GetValue("CVMFS_AUTOCATALOGS_MAX_WEIGHT", &arg)) {
562 ✗ settings_publisher->GetTransaction()->SetAutobalanceMaxWeight(
563 ✗ String2Uint64(arg));
564 }
565 ✗ if (options_mgr_.GetValue("CVMFS_AUTOCATALOGS_MIN_WEIGHT", &arg)) {
566 ✗ settings_publisher->GetTransaction()->SetAutobalanceMinWeight(
567 ✗ String2Uint64(arg));
568 }
569 ✗ if (options_mgr_.GetValue("CVMFS_ALLOW_NONEXISTENT_PATH", &arg)) {
570 ✗ settings_publisher->GetTransaction()->SetAllowNonexistentPath(
571 ✗ options_mgr_.IsOn(arg));
572 }
573 ✗ if (options_mgr_.GetValue("CVMFS_AUTO_REPAIR_MOUNTPOINT", &arg)) {
574 ✗ if (!options_mgr_.IsOn(arg)) {
575 ✗ settings_publisher->GetTransaction()->GetSpoolArea()->SetRepairMode(
576 kUnionMountRepairNever);
577 }
578 }
579 }
580
581 ✗ SettingsPublisher *SettingsBuilder::CreateSettingsPublisher(
582 const std::string &ident, bool needs_managed) {
583 // we are creating a publisher, it need to have the `server.conf` file
584 // present, otherwise something is wrong and we should exit early
585 ✗ const std::string alias(ident.empty() ? GetSingleAlias() : ident);
586
587 ✗ std::map<std::string, std::string> session_env = GetSessionEnvironment();
588 // We can be in an ephemeral writable shell but interested in a different
589 // repository
590
591 ✗ const std::string server_path = config_path_ + "/" + alias + "/server.conf";
592
593 // Instead of returning the Settings from session, we need more processing
594 ✗ if (!session_env.empty() && (session_env["CVMFS_FQRN"] == alias)) {
595 SettingsPublisher
596 ✗ *settings_publisher = CreateSettingsPublisherFromSession();
597 ✗ if (FileExists(server_path)) {
598 ✗ delete options_mgr_;
599 ✗ options_mgr_ = new BashOptionsManager();
600 ✗ options_mgr_->set_taint_environment(false);
601 ✗ options_mgr_->ParsePath(server_path, false /* external */);
602 ✗ ApplyOptionsFromServerPath(*options_mgr_, settings_publisher);
603 }
604 ✗ return settings_publisher;
605 }
606
607 ✗ if (FileExists(server_path) == false) {
608 ✗ throw EPublish(
609 "Unable to find the configuration file `server.conf` for the cvmfs "
610 "publisher: "
611 ✗ + alias,
612 ✗ EPublish::kFailRepositoryNotFound);
613 }
614
615 const SettingsRepository settings_repository = CreateSettingsRepository(
616 ✗ alias);
617 ✗ if (needs_managed && !IsManagedRepository())
618 ✗ throw EPublish("remote repositories are not supported in this context");
619
620 ✗ if (options_mgr_->GetValueOrDie("CVMFS_REPOSITORY_TYPE") != "stratum0") {
621 ✗ throw EPublish("Repository " + alias + " is not a stratum 0 repository",
622 ✗ EPublish::kFailRepositoryType);
623 }
624
625 std::unique_ptr<SettingsPublisher> settings_publisher(
626 ✗ new SettingsPublisher(settings_repository));
627
628 try {
629 const std::string xattr = settings_publisher->GetReadOnlyXAttr(
630 ✗ "user.root_hash");
631 ✗ settings_publisher->GetTransaction()->SetBaseHash(
632 ✗ shash::MkFromHexPtr(shash::HexPtr(xattr), shash::kSuffixCatalog));
633 ✗ } catch (const EPublish &e) {
634 // We ignore the exception.
635 // In case of exception, the base hash remains unset.
636 }
637
638 ✗ settings_publisher->SetIsManaged(IsManagedRepository());
639 ✗ settings_publisher->SetOwner(options_mgr_->GetValueOrDie("CVMFS_USER"));
640 ✗ settings_publisher->GetStorage()->SetLocator(
641 ✗ options_mgr_->GetValueOrDie("CVMFS_UPSTREAM_STORAGE"));
642
643 ✗ ApplyOptionsFromServerPath(*options_mgr_, &*settings_publisher);
644
645 // TODO(jblomer): process other parameters
646 ✗ return settings_publisher.release();
647 }
648
649 } // namespace publish
650