CernVM-FS  2.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
repository_util.cc
Go to the documentation of this file.
1 
5 #include "cvmfs_config.h"
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 "hash.h"
19 #include "publish/except.h"
20 #include "util/posix.h"
21 #include "util/string.h"
22 
23 namespace publish {
24 
25 CheckoutMarker *CheckoutMarker::CreateFrom(const std::string &path) {
26  if (!FileExists(path))
27  return NULL;
28 
29  FILE *f = fopen(path.c_str(), "r");
30  if (f == NULL)
31  throw publish::EPublish("cannot open checkout marker");
32  std::string line;
33  bool retval = GetLineFile(f, &line);
34  fclose(f);
35  if (!retval)
36  throw publish::EPublish("empty checkout marker");
37  line = Trim(line, true /* trim_newline */);
38  std::vector<std::string> tokens = SplitString(line, ' ');
39  std::string previous_branch;
40  if (tokens.size() == 4)
41  previous_branch = tokens[3];
42  if (tokens.size() < 3 || tokens.size() > 4)
43  throw publish::EPublish("checkout marker not parsable: " + line);
44 
45  CheckoutMarker *marker = new CheckoutMarker(tokens[0], tokens[2],
47  previous_branch);
48  return marker;
49 }
50 
51 void CheckoutMarker::SaveAs(const std::string &path) const {
52  std::string marker =
53  tag_ + " " + hash_.ToString(false /* with_suffix */) + " " + branch_;
54  if (!previous_branch_.empty())
55  marker += " " + previous_branch_;
56  marker += "\n";
57  SafeWriteToFile(marker, path, kDefaultFileMode);
58 }
59 
60 
61 //------------------------------------------------------------------------------
62 
63 
64 bool ServerLockFile::Acquire(const std::string &path, bool ignore_stale) {
65  std::string tmp_path;
66  FILE *ftmp = CreateTempFile(path + ".tmp", kDefaultFileMode, "w", &tmp_path);
67  if (ftmp == NULL)
68  throw EPublish("cannot create lock temp file " + path);
69  std::string pid = StringifyInt(getpid());
70  bool retval = SafeWrite(fileno(ftmp), pid.data(), pid.length());
71  fclose(ftmp);
72  if (!retval)
73  throw EPublish("cannot create transaction marker " + path);
74 
75  if (IsLocked(path, ignore_stale)) {
76  unlink(tmp_path.c_str());
77  return false;
78  }
79 
80  Release(path);
81  if (link(tmp_path.c_str(), path.c_str()) == 0) {
82  unlink(tmp_path.c_str());
83  return true;
84  }
85  unlink(tmp_path.c_str());
86  if (errno == EEXIST)
87  return false;
88  throw EPublish("cannot commit lock file " + path);
89 }
90 
91 
92 bool ServerLockFile::IsLocked(const std::string &path, bool ignore_stale) {
93  int fd = open(path.c_str(), O_RDONLY);
94  if (fd < 0) {
95  if (errno == ENOENT)
96  return false;
97  throw EPublish("cannot open transaction marker " + path);
98  }
99 
100  if (ignore_stale) {
101  close(fd);
102  return true;
103  }
104 
105  std::string line;
106  bool retval = GetLineFd(fd, &line);
107  close(fd);
108  if (!retval || line.empty()) {
109  // invalid marker, seen as stale
110  return false;
111  }
112  line = Trim(line, true /* trim_newline */);
113  pid_t pid = String2Int64(line);
114  if (pid <= 0) {
115  // invalid marker, seen as stale
116  return false;
117  }
118 
119  return ProcessExists(pid);
120 }
121 
122 
123 void ServerLockFile::Release(const std::string &path) {
124  unlink(path.c_str());
125 }
126 
127 
128 void RunSuidHelper(const std::string &verb, const std::string &fqrn) {
129  std::vector<std::string> cmd_line;
130  cmd_line.push_back("/usr/bin/cvmfs_suid_helper");
131  cmd_line.push_back(verb);
132  cmd_line.push_back(fqrn);
133  std::set<int> preserved_fds;
134  preserved_fds.insert(1);
135  preserved_fds.insert(2);
136  pid_t child_pid;
137  bool retval = ManagedExec(cmd_line, preserved_fds, std::map<int, int>(),
138  false /* drop_credentials */,
139  true /* clear_env */,
140  false /* double_fork */,
141  &child_pid);
142  if (!retval)
143  throw EPublish("cannot spawn suid helper");
144  int exit_code = WaitForChild(child_pid);
145  if (exit_code != 0)
146  throw EPublish("error calling suid helper: " + StringifyInt(exit_code));
147 }
148 
149 
150 void SetInConfig(const std::string &path,
151  const std::string &key, const std::string &value)
152 {
153  int fd = open(path.c_str(), O_RDWR | O_CREAT, kDefaultFileMode);
154  if (fd < 0)
155  throw EPublish("cannot modify configuration file " + path);
156 
157  std::string new_content;
158  std::string line;
159  bool key_exists = false;
160  while (GetLineFd(fd, &line)) {
161  std::string trimmed = Trim(line);
162  if (HasPrefix(trimmed, key + "=", false /* ignore_case */)) {
163  key_exists = true;
164  if (!value.empty())
165  new_content += key + "=" + value + "\n";
166  } else {
167  new_content += line + "\n";
168  }
169  }
170  if (!key_exists && !value.empty())
171  new_content += key + "=" + value + "\n";
172 
173  off_t off_zero = lseek(fd, 0, SEEK_SET);
174  if (off_zero != 0) {
175  close(fd);
176  throw EPublish("cannot rewind configuration file " + path);
177  }
178  int rvi = ftruncate(fd, 0);
179  if (rvi != 0) {
180  close(fd);
181  throw EPublish("cannot truncate configuration file " + path);
182  }
183  bool rvb = SafeWrite(fd, new_content.data(), new_content.length());
184  close(fd);
185  if (!rvb)
186  throw EPublish("cannot rewrite configuration file " + path);
187 }
188 
189 
190 std::string SendTalkCommand(const std::string &socket, const std::string &cmd) {
191  int fd = ConnectSocket(socket);
192  if (fd < 0) {
193  if (errno == ENOENT)
194  throw EPublish("Socket " + socket + " not found");
195  throw EPublish("Socket " + socket + " inaccessible");
196  }
197 
198  WritePipe(fd, cmd.data(), cmd.size());
199 
200  std::string result;
201  char buf;
202  int retval;
203  while ((retval = read(fd, &buf, 1)) == 1) {
204  result.push_back(buf);
205  }
206  close(fd);
207  if (retval != 0)
208  throw EPublish("Broken socket: " + socket);
209 
210  return result;
211 }
212 
213 } // namespace publish
vector< string > SplitString(const string &str, const char delim, const unsigned max_chunks)
Definition: string.cc:288
const int kDefaultFileMode
Definition: posix.h:31
string Trim(const string &raw, bool trim_newline)
Definition: string.cc:421
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1030
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:248
bool ManagedExec(const std::vector< std::string > &command_line, const std::set< int > &preserve_fildes, const std::map< int, int > &map_fildes, const bool drop_credentials, const bool clear_env, const bool double_fork, pid_t *child_pid)
Definition: posix.cc:1784
bool SafeWrite(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:1929
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2027
int WaitForChild(pid_t pid, const std::vector< int > &sig_ok)
Definition: posix.cc:1617
bool FileExists(const std::string &path)
Definition: posix.cc:816
int64_t String2Int64(const string &value)
Definition: string.cc:222
bool GetLineFile(FILE *f, std::string *line)
Definition: string.cc:379
std::string previous_branch() const
CheckoutMarker(const std::string &t, const std::string &b, const shash::Any &h, const std::string &p)
const char kSuffixCatalog
Definition: hash.h:53
void SetInConfig(const std::string &path, const std::string &key, const std::string &value)
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:83
static bool Acquire(const std::string &path, bool ignore_stale)
string StringifyInt(const int64_t value)
Definition: string.cc:78
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:265
void SaveAs(const std::string &path) const
std::string SendTalkCommand(const std::string &socket, const std::string &cmd)
bool GetLineFd(const int fd, std::string *line)
Definition: string.cc:397
void RunSuidHelper(const std::string &verb, const std::string &fqrn)
int ConnectSocket(const std::string &path)
Definition: posix.cc:460
static void Release(const std::string &path)
bool ProcessExists(pid_t pid)
Definition: posix.cc:1576
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:534
static bool IsLocked(const std::string &path, bool ignore_stale)
static CheckoutMarker * CreateFrom(const std::string &path)