// ----------------------------------------------------------------------
// File: proc/admin/Chown.cc
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2011 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "XrdOuc/XrdOucEnv.hh"
#include "common/Path.hh"
#include "mgm/XrdMgmOfs.hh"
#include "mgm/Access.hh"
#include "mgm/Macros.hh"
EOSMGMNAMESPACE_BEGIN
int
ProcCommand::Chown()
{
XrdOucString spath = pOpaque->Get("mgm.path");
XrdOucString option = pOpaque->Get("mgm.chown.option");
XrdOucString owner = pOpaque->Get("mgm.chown.owner");
const char* inpath = spath.c_str();
NAMESPACEMAP;
PROC_BOUNCE_ILLEGAL_NAMES;
PROC_BOUNCE_NOT_ALLOWED;
spath = path;
PROC_TOKEN_SCOPE;
bool nodereference = (option.find("h") != STR_NPOS) ? true : false;
bool singlefile = false;
if ((!spath.length()) || (!owner.length())) {
stdErr = "error: you have to provide a path and the owner to set!\n";
retc = EINVAL;
} else {
// find everything to be modified
std::map > found;
std::map >::const_iterator foundit;
std::set::const_iterator fileit;
if ((option.find("r") != STR_NPOS)) {
if (gOFS->_find(spath.c_str(), *mError, stdErr, *pVid, found)) {
stdErr += "error: unable to search in path";
retc = errno;
}
} else {
struct stat buf;
if (!gOFS->_stat(spath.c_str(), &buf, *mError, *pVid, 0, 0, false)) {
if (S_ISDIR(buf.st_mode)) {
(void) found[spath.c_str()].size();
} else {
eos::common::Path cPath(spath.c_str());
found[cPath.GetParentPath()].insert(cPath.GetName());
singlefile = true;
}
} else {
(void) found[spath.c_str()].size();
}
}
std::string uid = owner.c_str();
std::string gid = owner.c_str();
bool failure = false;
uid_t uidt = 99;
gid_t gidt = 99;
int dpos = 0;
if ((dpos = owner.find(":")) != STR_NPOS) {
uid.erase(dpos);
gid.erase(0, dpos + 1);
if (uid == "") {
uidt = 0xffffffff;
}
if ((gid != "0")) {
// try to translate with password database
int terrc = 0;
gidt = eos::common::Mapping::GroupNameToGid(gid, terrc);
if (terrc) {
// cannot translate this name
stdErr = "error: I cannot translate your gid string using the pwd database";
retc = terrc;
failure = true;
}
} else {
gidt = 0;
}
} else {
gid = "0";
gidt = 0xffffffff;
}
if (uid != "0") {
if (uid.length()) {
int terrc = 0;
uidt = eos::common::Mapping::UserNameToUid(uid, terrc);
if (terrc) {
stdErr = "error: I cannot translate your uid string using the pwd database";
retc = terrc;
failure = true;
}
}
} else {
uidt = 0;
}
if (pVid->uid && ((!uidt) || (!gidt))) {
stdErr = "error: you are changing to uid/gid=0 but you are not root!";
retc = EPERM;
failure = true;
}
ACCESSMODE_W;
if (!failure) {
if (!singlefile) {
// for directories
for (foundit = found.begin(); foundit != found.end(); foundit++) {
RECURSIVE_STALL("Chown", (*pVid));
std::string dirname = foundit->first;
size_t linkpos = (dirname.find(" -> "));
if (linkpos != std::string::npos) {
dirname = foundit->first.substr(0, linkpos);
}
if (gOFS->_chown(dirname.c_str(), uidt, gidt, *mError, *pVid,
(char*) 0, nodereference)) {
stdErr += "error: unable to chown of directory ";
stdErr += dirname.c_str();
stdErr += "\n";
retc = errno;
} else {
stdOut += "success: owner of directory ";
stdOut += dirname.c_str();
stdOut += " is now ";
stdOut += "uid=";
stdOut += uid.c_str();
if (!pVid->uid) {
if (gidt) {
stdOut += " gid=";
stdOut += gid.c_str();
}
}
stdOut += "\n";
}
}
}
// for files
for (foundit = found.begin(); foundit != found.end(); foundit++) {
for (fileit = foundit->second.begin(); fileit != foundit->second.end();
fileit++) {
std::string fpath = foundit->first;
std::string filename = *fileit;
size_t linkpos = (filename.find(" -> "));
if (linkpos != std::string::npos) {
filename = filename.substr(0, linkpos);
}
fpath += filename;
if (gOFS->_chown(fpath.c_str(), uidt, gidt, *mError, *pVid, (char*) 0,
nodereference)) {
stdErr += "error: unable to chown of file ";
stdErr += fpath.c_str();
stdErr += "\n";
retc = errno;
} else {
stdOut += "success: owner of file ";
stdOut += fpath.c_str();
stdOut += " is now ";
stdOut += "uid=";
stdOut += uid.c_str();
if (!pVid->uid) {
if (gidt) {
stdOut += " gid=";
stdOut += gid.c_str();
}
stdOut += "\n";
}
}
}
}
}
}
return SFS_OK;
}
EOSMGMNAMESPACE_END