CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cmd_abort.cc
Go to the documentation of this file.
1 
6 #include "cmd_abort.h"
7 
8 #include <unistd.h>
9 
10 #include <cstdio>
11 #include <string>
12 
13 #include "publish/cmd_util.h"
14 #include "publish/except.h"
15 #include "publish/repository.h"
16 #include "publish/settings.h"
17 #include "util/logging.h"
18 #include "util/pointer.h"
19 #include "util/posix.h"
20 #include "util/string.h"
21 #include "whitelist.h"
22 
23 namespace {
24 std::string StripTrailingPath(const std::string &repo_and_path) {
25  if (!repo_and_path.empty()) {
26  std::vector<std::string> tokens = SplitString(repo_and_path, '/');
27  return tokens[0];
28  }
29 
30  return "";
31 }
32 } // namespace
33 
34 namespace publish {
35 
36 int CmdAbort::Main(const Options &options) {
37  SettingsBuilder builder;
38  const std::string session_dir = Env::GetEnterSessionDir();
39 
40  if (!session_dir.empty()) {
41  builder.SetConfigPath(session_dir);
42  }
43 
45  try {
46  // Legacy behaviour is that trailing paths after the repository name should
47  // be ignored, e.g. cvmfs_server abort repo.cern.ch/some/path is equivalent
48  // to cvmfs_server abort repo.cern.ch
49  const std::string repository_ident = StripTrailingPath(
50  options.plain_args().empty() ? "" : options.plain_args()[0].value_str);
51  settings = builder.CreateSettingsPublisher(repository_ident,
52  true /* needs_managed */);
53  } catch (const EPublish &e) {
56  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "CernVM-FS error: %s",
57  e.msg().c_str());
58  return 1;
59  }
60  throw;
61  }
62 
63  if (!SwitchCredentials(settings->owner_uid(), settings->owner_gid(),
64  false /* temporarily */)) {
65  throw EPublish("No write permission to repository",
67  }
68 
70  settings->transaction().spool_area().union_mnt() + "/",
71  false /* ignore_case */)) {
73  "Current working directory is in %s. Please release, "
74  "e.g. by 'cd $HOME'.",
75  settings->transaction().spool_area().union_mnt().c_str());
76  return 1;
77  }
78 
79  if (!options.Has("force")) {
81  "You are about to DISCARD ALL CHANGES OF THE CURRENT TRANSACTION "
82  "for %s! Are you sure (y/N)? ",
83  settings->fqrn().c_str());
84  char answer[] = {0, 0, 0};
85  char *rv_charp = fgets(answer, 3, stdin);
86  if (rv_charp && (answer[0] != 'Y') && (answer[0] != 'y'))
87  return EINTR;
88  } else {
89  // We may have an expired/invalid lease token in the spool area, in which
90  // case dropping the session fails but we still want to continue the
91  // local transaction abort.
92  settings->SetIgnoreInvalidLease(true);
93  }
94 
95  std::vector<LsofEntry> lsof_entries = Lsof(
96  settings->transaction().spool_area().union_mnt());
97  if (!lsof_entries.empty()) {
98  if (options.Has("force")) {
100  "WARNING: Open file descriptors on %s (possible race!)"
101  "\nThe following lsof report might show the culprit:\n",
102  settings->transaction().spool_area().union_mnt().c_str());
103  } else {
105  "\nWARNING! There are open read-only file descriptors in %s\n"
106  " --> This is potentially harmful and might cause problems "
107  "later on.\n"
108  " We can anyway perform the requested operation, but this "
109  "will most likely\n"
110  " break other processes with open file descriptors on %s!\n"
111  "\n"
112  " The following lsof report might show the processes with "
113  "open file handles\n",
114  settings->transaction().spool_area().union_mnt().c_str(),
115  settings->transaction().spool_area().union_mnt().c_str());
116  }
117 
118  for (unsigned i = 0; i < lsof_entries.size(); ++i) {
119  std::string owner_name;
120  GetUserNameOf(lsof_entries[i].owner, &owner_name);
121  LogCvmfs(kLogCvmfs, kLogStdout, "%s %d %s %s",
122  lsof_entries[i].executable.c_str(), lsof_entries[i].pid,
123  owner_name.c_str(), lsof_entries[i].path.c_str());
124  }
125 
126  if (!options.Has("force")) {
128  "\n Do you want to proceed anyway? (y/N) ");
129  char answer[] = {0, 0, 0};
130  char *rv_charp = fgets(answer, 3, stdin);
131  if (rv_charp && (answer[0] != 'Y') && (answer[0] != 'y'))
132  return EINTR;
133  }
134  }
135 
136  UniquePtr<Publisher> publisher;
137  publisher = new Publisher(*settings);
138 
139  LogCvmfs(kLogCvmfs, kLogSyslog, "(%s) aborting transaction",
140  settings->fqrn().c_str());
141 
142  int rvi = CallServerHook("abort_before_hook", settings->fqrn());
143  if (rvi != 0) {
145  "abort hook failed, not aborting");
146  return rvi;
147  }
148 
149  try {
150  publisher->Abort();
151  } catch (const EPublish &e) {
153  LogCvmfs(kLogCvmfs, kLogStderr, "%s", e.msg().c_str());
154  return EINVAL;
155  }
156  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s", e.msg().c_str());
157  return EIO;
158  }
159 
160  rvi = CallServerHook("abort_after_hook", settings->fqrn());
161  if (rvi != 0) {
162  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "post abort hook failed");
163  return rvi;
164  }
165 
166  if (settings->transaction().in_enter_session()) {
168  "Discarding changes and closing current transaction...");
169  SafeWriteToFile("abort", session_dir + "/shellaction.marker", 0600);
170  publisher->ExitShell();
171  }
172 
173  return 0;
174 }
175 
176 } // namespace publish
std::string StripTrailingPath(const std::string &repo_and_path)
Definition: cmd_abort.cc:24
SettingsPublisher * CreateSettingsPublisher(const std::string &ident, bool needs_managed=false)
Definition: settings.cc:573
int CallServerHook(const std::string &func, const std::string &fqrn, const std::string &path_hooks="/etc/cvmfs/cvmfs_server_hooks.sh")
Definition: cmd_util.cc:18
bool Has(const std::string &key) const
Definition: command.h:108
bool GetUserNameOf(uid_t uid, std::string *username)
Definition: posix.cc:1319
std::string msg() const
Definition: except.h:45
const SettingsPublisher & settings() const
Definition: repository.h:316
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2137
void SetConfigPath(const std::string &config_path)
Definition: settings.h:525
const std::vector< Argument > & plain_args() const
Definition: command.h:128
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:306
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:279
EFailures failure() const
Definition: except.h:44
bool SwitchCredentials(const uid_t uid, const gid_t gid, const bool temporarily)
Definition: posix.cc:773
std::vector< LsofEntry > Lsof(const std::string &path)
Definition: posix.cc:1497
Publisher(const SettingsPublisher &settings, const bool exists=true)
Definition: repository.cc:619
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1068
virtual int Main(const Options &options)
Definition: cmd_abort.cc:36
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545