CernVM-FS  2.12.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 }
33 
34 namespace publish {
35 
36 int CmdAbort::Main(const Options &options) {
37  SettingsBuilder builder;
38  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  std::string repository_ident = StripTrailingPath(
50  options.plain_args().empty() ? "" : options.plain_args()[0].value_str);
51  settings = builder.CreateSettingsPublisher(
52  repository_ident, true /* needs_managed */);
53  } catch (const EPublish &e) {
56  {
57  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "CernVM-FS error: %s",
58  e.msg().c_str());
59  return 1;
60  }
61  throw;
62  }
63 
64  if (!SwitchCredentials(settings->owner_uid(), settings->owner_gid(),
65  false /* temporarily */))
66  {
67  throw EPublish("No write permission to repository",
69  }
70 
72  settings->transaction().spool_area().union_mnt() + "/",
73  false /* ignore_case */))
74  {
76  "Current working directory is in %s. Please release, "
77  "e.g. by 'cd $HOME'.",
78  settings->transaction().spool_area().union_mnt().c_str());
79  return 1;
80  }
81 
82  if (!options.Has("force")) {
84  "You are about to DISCARD ALL CHANGES OF THE CURRENT TRANSACTION "
85  "for %s! Are you sure (y/N)? ", settings->fqrn().c_str());
86  char answer[] = {0, 0, 0};
87  char *rv_charp = fgets(answer, 3, stdin);
88  if (rv_charp && (answer[0] != 'Y') && (answer[0] != 'y'))
89  return EINTR;
90  } else {
91  // We may have an expired/invalid lease token in the spool area, in which
92  // case dropping the session fails but we still want to continue the
93  // local transaction abort.
94  settings->SetIgnoreInvalidLease(true);
95  }
96 
97  std::vector<LsofEntry> lsof_entries =
98  Lsof(settings->transaction().spool_area().union_mnt());
99  if (!lsof_entries.empty()) {
100  if (options.Has("force")) {
102  "WARNING: Open file descriptors on %s (possible race!)"
103  "\nThe following lsof report might show the culprit:\n",
104  settings->transaction().spool_area().union_mnt().c_str());
105  } else {
107  "\nWARNING! There are open read-only file descriptors in %s\n"
108  " --> This is potentially harmful and might cause problems "
109  "later on.\n"
110  " We can anyway perform the requested operation, but this "
111  "will most likely\n"
112  " break other processes with open file descriptors on %s!\n"
113  "\n"
114  " The following lsof report might show the processes with "
115  "open file handles\n",
116  settings->transaction().spool_area().union_mnt().c_str(),
117  settings->transaction().spool_area().union_mnt().c_str());
118  }
119 
120  for (unsigned i = 0; i < lsof_entries.size(); ++i) {
121  std::string owner_name;
122  GetUserNameOf(lsof_entries[i].owner, &owner_name);
123  LogCvmfs(kLogCvmfs, kLogStdout, "%s %d %s %s",
124  lsof_entries[i].executable.c_str(),
125  lsof_entries[i].pid,
126  owner_name.c_str(),
127  lsof_entries[i].path.c_str());
128  }
129 
130  if (!options.Has("force")) {
132  "\n Do you want to proceed anyway? (y/N) ");
133  char answer[] = {0, 0, 0};
134  char *rv_charp = fgets(answer, 3, stdin);
135  if (rv_charp && (answer[0] != 'Y') && (answer[0] != 'y'))
136  return EINTR;
137  }
138  }
139 
140  UniquePtr<Publisher> publisher;
141  publisher = new Publisher(*settings);
142 
143  LogCvmfs(kLogCvmfs, kLogSyslog, "(%s) aborting transaction",
144  settings->fqrn().c_str());
145 
146  int rvi = CallServerHook("abort_before_hook", settings->fqrn());
147  if (rvi != 0) {
149  "abort hook failed, not aborting");
150  return rvi;
151  }
152 
153  try {
154  publisher->Abort();
155  } catch (const EPublish &e) {
157  LogCvmfs(kLogCvmfs, kLogStderr, "%s", e.msg().c_str());
158  return EINVAL;
159  }
160  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s", e.msg().c_str());
161  return EIO;
162  }
163 
164  rvi = CallServerHook("abort_after_hook", settings->fqrn());
165  if (rvi != 0) {
167  "post abort hook failed");
168  return rvi;
169  }
170 
171  if (settings->transaction().in_enter_session()) {
173  "Discarding changes and closing current transaction...");
174  SafeWriteToFile("abort", session_dir + "/shellaction.marker", 0600);
175  publisher->ExitShell();
176  }
177 
178  return 0;
179 }
180 
181 } // 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:602
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:114
bool GetUserNameOf(uid_t uid, std::string *username)
Definition: posix.cc:1332
std::string msg() const
Definition: except.h:46
const SettingsPublisher & settings() const
Definition: repository.h:317
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2158
void SetConfigPath(const std::string &config_path)
Definition: settings.h:535
const std::vector< Argument > & plain_args() const
Definition: command.h:137
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:308
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:285
EFailures failure() const
Definition: except.h:45
bool SwitchCredentials(const uid_t uid, const gid_t gid, const bool temporarily)
Definition: posix.cc:772
std::vector< LsofEntry > Lsof(const std::string &path)
Definition: posix.cc:1510
Publisher(const SettingsPublisher &settings, const bool exists=true)
Definition: repository.cc:594
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1071
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:528