11 #include <sys/xattr.h>
39 *calling_uid = getuid();
40 *effective_uid = geteuid();
43 static void ExecAsRoot(
const char *binary,
const char *arg1,
const char *arg2,
44 const char *arg3,
const char *arg4) {
45 char *argv[] = {strdup(binary),
46 arg1 ? strdup(arg1) : NULL,
47 arg2 ? strdup(arg2) : NULL,
48 arg3 ? strdup(arg3) : NULL,
49 arg4 ? strdup(arg4) : NULL,
51 char *environ[] = {NULL};
53 int retval = setuid(0);
55 fprintf(stderr,
"failed to gain root privileges (%d)\n", errno);
59 execve(binary, argv, environ);
60 fprintf(stderr,
"failed to run %s... (%d)\n", binary, errno);
65 const char *arg2,
const char *arg3,
69 fprintf(stderr,
"failed to fork %s... (%d)\n", binary, errno);
71 }
else if (child == 0) {
75 waitpid(child, &wstatus, 0);
76 if (WIFSIGNALED(wstatus)) {
77 exit(128 + WTERMSIG(wstatus));
78 }
else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) {
79 exit(WEXITSTATUS(wstatus));
85 string remount_option =
"remount,";
88 remount_option +=
"rw";
91 remount_option +=
"ro";
94 fprintf(stderr,
"internal error\n");
101 ExecAsRoot(
"/bin/mount",
"-o", remount_option.c_str(),
"dev", path.c_str());
104 static void Mount(
const string &path) {
114 if (resolved_path.empty()) {
115 fprintf(stderr,
"cannot resolve %s\n", path.c_str());
122 ExecAsRoot(
"/bin/systemctl",
"reset-failed", systemd_unit.c_str(), NULL,
125 ExecAsRoot(
"/bin/mount", path.c_str(), NULL, NULL, NULL);
130 ExecAsRoot(
"/bin/umount", path.c_str(), NULL, NULL, NULL);
134 ExecAsRoot(
"/bin/umount",
"-l", path.c_str(), NULL, NULL);
140 if (fqrn.find(
"/") != string::npos || fqrn.find(
"\\") != string::npos) {
144 const string mountpoint = string(
kSpoolArea) +
"/" + fqrn +
"/rdonly";
146 if (!retval || pid.empty())
149 if (!pid_sanitizer.
IsValid(pid))
151 ExecAsRoot(
"/bin/kill",
"-9", pid.c_str(), NULL, NULL);
158 ChangeDirectory(path);
159 directory_handle_ = opendir(
".");
163 if (directory_handle_ != NULL) {
164 closedir(directory_handle_);
166 ChangeDirectory(previous_path_);
169 operator bool()
const {
return directory_handle_ != NULL; }
179 && IsDotEntry(dirent)) {
181 if (dirent == NULL) {
191 entry->
name = dirent->d_name;
198 const char *cwd = getcwd(path, PATH_MAX);
204 const int retval = chdir(path.c_str());
209 return (strcmp(dirent->d_name,
".") == 0)
210 || (strcmp(dirent->d_name,
"..") == 0);
228 && (rmdir(dirent.
name.c_str()) == 0)
229 : (unlink(dirent.
name.c_str()) == 0);
237 fprintf(stderr,
"failed to clear %s\n", path.c_str());
244 const string scratch = string(
kSpoolArea) +
"/" + fqrn +
"/scratch/current";
249 const string wastebin = string(
kSpoolArea) +
"/" + fqrn +
"/scratch/wastebin";
254 if ((pid = fork()) == 0) {
255 int retval = setsid();
257 if ((pid = fork()) == 0) {
258 int null_read = open(
"/dev/null", O_RDONLY);
259 int null_write = open(
"/dev/null", O_WRONLY);
260 assert((null_read >= 0) && (null_write >= 0));
261 retval = dup2(null_read, 0);
263 retval = dup2(null_write, 1);
265 retval = dup2(null_write, 2);
275 waitpid(pid, &statloc, 0);
282 static void Usage(
const string &exe, FILE *output) {
284 "Usage: %s lock|open|rw_mount|rw_umount|rdonly_mount|rdonly_umount|"
285 "clear_scratch|clear_scratch_async|kill_cvmfs <fqrn>\n"
286 "Example: %s rw_umount atlas.cern.ch\n"
287 "This binary is typically called by cvmfs_server.\n",
288 exe.c_str(), exe.c_str());
292 int main(
int argc,
char *argv[]) {
297 uid_t calling_uid, effective_uid, repository_uid;
299 if (effective_uid != 0) {
300 fprintf(stderr,
"Needs to run as root\n");
306 Usage(argv[0], stderr);
309 const string command = argv[1];
310 const string fqrn = argv[2];
316 fprintf(stderr,
"unknown repository: %s\n", fqrn.c_str());
319 repository_uid = info.st_uid;
322 if ((calling_uid != 0) && (calling_uid != repository_uid)) {
323 fprintf(stderr,
"called as %d, repository owned by %d\n", calling_uid,
328 if (command ==
"lock") {
330 }
else if (command ==
"open") {
332 }
else if (command ==
"kill_cvmfs") {
334 }
else if (command ==
"rw_mount") {
335 Mount(
"/cvmfs/" + fqrn);
336 }
else if (command ==
"rw_umount") {
338 }
else if (command ==
"rw_lazy_umount") {
340 }
else if (command ==
"rdonly_mount") {
342 }
else if (command ==
"rdonly_umount") {
344 }
else if (command ==
"rdonly_lazy_umount") {
346 }
else if (command ==
"clear_scratch") {
348 }
else if (command ==
"clear_scratch_async") {
351 Usage(argv[0], stderr);
static void Remount(const string &path, const RemountType how)
const string previous_path_
static void Mount(const string &path)
static void ForkAndExecAsRoot(const char *binary, const char *arg1, const char *arg2, const char *arg3, const char *arg4)
static void Usage(const char *progname)
static int CleanupDirectory(const string &path)
assert((mem||(size==0))&&"Out Of Memory")
static void GetCredentials(uid_t *calling_uid, uid_t *effective_uid)
bool IsDotEntry(const platform_dirent64 *dirent)
static void ExecAsRoot(const char *binary, const char *arg1, const char *arg2, const char *arg3, const char *arg4)
~ScopedWorkingDirectory()
string GetCurrentWorkingDirectory()
string EscapeSystemdUnit(const string &path)
static void Umount(const string &path)
string ResolvePath(const std::string &path)
ScopedWorkingDirectory(const string &path)
bool PathExists(const std::string &path)
static bool ClearDirectory(const string &path)
static void KillCvmfs(const string &fqrn)
bool NextDirectoryEntry(DirectoryEntry *entry)
void ChangeDirectory(const string &path)
static int DoAsynchronousScratchCleanup(const string &fqrn)
std::string GetCurrentWorkingDirectory()
static int DoSynchronousScratchCleanup(const string &fqrn)
static void LazyUmount(const string &path)