GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/repository_util.cc
Date: 2026-04-05 02:35:23
Exec Total Coverage
Lines: 0 119 0.0%
Branches: 0 232 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "repository_util.h"
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11
12 #include <cstdio>
13 #include <map>
14 #include <set>
15 #include <string>
16 #include <vector>
17
18 #include "crypto/hash.h"
19 #include "publish/except.h"
20 #include "util/logging.h"
21 #include "util/posix.h"
22 #include "util/string.h"
23
24 namespace publish {
25
26 CheckoutMarker *CheckoutMarker::CreateFrom(const std::string &path) {
27 if (!FileExists(path))
28 return NULL;
29
30 FILE *f = fopen(path.c_str(), "r");
31 if (f == NULL)
32 throw publish::EPublish("cannot open checkout marker");
33 std::string line;
34 const bool retval = GetLineFile(f, &line);
35 fclose(f);
36 if (!retval)
37 throw publish::EPublish("empty checkout marker");
38 line = Trim(line, true /* trim_newline */);
39 std::vector<std::string> tokens = SplitString(line, ' ');
40 std::string previous_branch;
41 if (tokens.size() == 4)
42 previous_branch = tokens[3];
43 if (tokens.size() < 3 || tokens.size() > 4)
44 throw publish::EPublish("checkout marker not parsable: " + line);
45
46 CheckoutMarker *marker = new CheckoutMarker(
47 tokens[0], tokens[2],
48 shash::MkFromHexPtr(shash::HexPtr(tokens[1]), shash::kSuffixCatalog),
49 previous_branch);
50 return marker;
51 }
52
53 void CheckoutMarker::SaveAs(const std::string &path) const {
54 std::string marker = tag_ + " " + hash_.ToString(false /* with_suffix */)
55 + " " + branch_;
56 if (!previous_branch_.empty())
57 marker += " " + previous_branch_;
58 marker += "\n";
59 SafeWriteToFile(marker, path, kDefaultFileMode);
60 }
61
62
63 //------------------------------------------------------------------------------
64
65
66 void ServerLockFile::Lock() {
67 if (!TryLock()) {
68 throw EPublish("Could not acquire lock " + path_,
69 EPublish::kFailTransactionState);
70 }
71 }
72
73
74 bool ServerLockFile::TryLock() {
75 const int new_fd = TryLockFile(path_);
76 if (new_fd >= 0) {
77 assert(fd_ < 0);
78 fd_ = new_fd;
79 return true;
80 } else if (new_fd == -1) {
81 throw EPublish("Error while attempting to acquire lock " + path_);
82 } else {
83 return false;
84 }
85 }
86
87
88 void ServerLockFile::Touch() {
89 if (fd_ >= 0)
90 return;
91 // Pre-create the lock file without locking it, so that a subsequent Lock()
92 // can open the existing file even when the disk is full (e.g. during abort
93 // after the repository's spool area has been filled up).
94 const int fd = open(path_.c_str(), O_WRONLY | O_CREAT, 0600);
95 if (fd >= 0) {
96 close(fd);
97 } else {
98 LogCvmfs(kLogCvmfs, kLogSyslogWarn,
99 "failed to pre-create lock file %s (errno: %d)",
100 path_.c_str(), errno);
101 }
102 }
103
104
105 void ServerLockFile::Unlock() {
106 const int old_fd = fd_;
107 assert(old_fd >= 0);
108 fd_ = -1;
109 unlink(path_.c_str());
110 close(old_fd);
111 }
112
113
114 //------------------------------------------------------------------------------
115
116
117 void ServerFlagFile::Set() {
118 const int fd = open(path_.c_str(), O_CREAT | O_RDWR, 0600);
119 if (fd < 0)
120 throw EPublish("cannot create flag file " + path_);
121 close(fd);
122 }
123
124
125 void ServerFlagFile::Clear() { unlink(path_.c_str()); }
126
127
128 bool ServerFlagFile::IsSet() const { return FileExists(path_); }
129
130
131 //------------------------------------------------------------------------------
132
133
134 void RunSuidHelper(const std::string &verb, const std::string &fqrn) {
135 std::vector<std::string> cmd_line;
136 cmd_line.push_back("/usr/bin/cvmfs_suid_helper");
137 cmd_line.push_back(verb);
138 cmd_line.push_back(fqrn);
139 std::set<int> preserved_fds;
140 preserved_fds.insert(1);
141 preserved_fds.insert(2);
142 pid_t child_pid;
143 const bool retval = ManagedExec(cmd_line, preserved_fds, std::map<int, int>(),
144 false /* drop_credentials */,
145 true /* clear_env */, false /* double_fork */,
146 &child_pid);
147 if (!retval)
148 throw EPublish("cannot spawn suid helper");
149 const int exit_code = WaitForChild(child_pid);
150 if (exit_code != 0)
151 throw EPublish("error calling suid helper: " + StringifyInt(exit_code));
152 }
153
154
155 void SetInConfig(const std::string &path, const std::string &key,
156 const std::string &value) {
157 const int fd = open(path.c_str(), O_RDWR | O_CREAT, kDefaultFileMode);
158 if (fd < 0)
159 throw EPublish("cannot modify configuration file " + path);
160
161 std::string new_content;
162 std::string line;
163 bool key_exists = false;
164 while (GetLineFd(fd, &line)) {
165 const std::string trimmed = Trim(line);
166 if (HasPrefix(trimmed, key + "=", false /* ignore_case */)) {
167 key_exists = true;
168 if (!value.empty())
169 new_content += key + "=" + value + "\n";
170 } else {
171 new_content += line + "\n";
172 }
173 }
174 if (!key_exists && !value.empty())
175 new_content += key + "=" + value + "\n";
176
177 const off_t off_zero = lseek(fd, 0, SEEK_SET);
178 if (off_zero != 0) {
179 close(fd);
180 throw EPublish("cannot rewind configuration file " + path);
181 }
182 const int rvi = ftruncate(fd, 0);
183 if (rvi != 0) {
184 close(fd);
185 throw EPublish("cannot truncate configuration file " + path);
186 }
187 const bool rvb = SafeWrite(fd, new_content.data(), new_content.length());
188 close(fd);
189 if (!rvb)
190 throw EPublish("cannot rewrite configuration file " + path);
191 }
192
193
194 std::string SendTalkCommand(const std::string &socket, const std::string &cmd) {
195 const int fd = ConnectSocket(socket);
196 if (fd < 0) {
197 if (errno == ENOENT)
198 throw EPublish("Socket " + socket + " not found");
199 throw EPublish("Socket " + socket + " inaccessible");
200 }
201
202 WritePipe(fd, cmd.data(), cmd.size());
203
204 std::string result;
205 char buf;
206 int retval;
207 while ((retval = read(fd, &buf, 1)) == 1) {
208 result.push_back(buf);
209 }
210 close(fd);
211 if (retval != 0)
212 throw EPublish("Broken socket: " + socket);
213
214 return result;
215 }
216
217 } // namespace publish
218