#include "Server.h" #include "configuration.h" #include "exceptions.h" #include <pwd.h> #include <sys/types.h> #include <errno.h> #include <libgen.h> #include <unistd.h> #include <sys/wait.h> #include <assert.h> #include <iostream> #include <fstream> // the global variables are copied into the local variables // this has some interesting side effects: // local variables will override global variables // the order of when the variables are defined is important: // global variables defined *after* the server config are not considered Server::Server(const std::string& name, const std::string& type, Configuration * config) : Executable(name, type, config) { } Server::~Server() { } Server::var_map Server::VariableMap; bool Server::initializeVariableMap() { VariableMap["Server"] = &Server::setExecutable; VariableMap["Client"] = &Server::setClient; VariableMap["Owner"] = &Server::setUser; VariableMap["P4ROOT"] = &Server::setRoot; VariableMap["P4PORT"] = &Server::setPort; return true; } // local variables override global variables // this is done by checking the local variables first void Server::verifyVariables() throw(VerificationException) { static bool initialized = initializeVariableMap(); assert(initialized); env_map::iterator pos; var_map::const_iterator iter; for (iter = VariableMap.begin(); iter != VariableMap.end(); ++iter) { pos = _variables.find(iter->first); if (pos != _variables.end()) { (this->*iter->second)(pos->second); _variables.erase(pos); } else { std::string err = _type + " " + _name + ". No " + iter->first + " defined"; throw VerificationException(err); } } } void Server::prepareArgs(arg_vec& args) { std::string procname = _executable + " [" + _port + "]"; args.push_back(procname); args.push_back("-q"); addOption("P4JOURNAL", "-J", args); addOption("P4LOG", "-L", args); addOption("P4AUDIT", "-A", args); addOption("P4DEBUG", "-v", args); addOption("Options", NULL, args); args.push_back("-p"); args.push_back(_port); args.push_back("-r"); args.push_back(_root); } void Server::stopServer() { // Strategy one : call p4 admin stop. Will not succeed if: // - no "Client" defined // - wrong user // Strategy two : See Executable::stopServer() pid_t pid = fork(); if (-1 == pid) { std::cerr << "Fork failed, terminating program" << std::endl; _exit(1); } else if (0 == pid) { // I am child, execute the stop command changeUser(); arg_vec envs; prepareEnv(envs); arg_vec args; args.push_back("p4"); args.push_back("-p"); args.push_back(_port); addOption("P4USER", "-u", args); addOption("P4PASSWD", "-P", args); args.push_back("admin"); args.push_back("stop"); char ** argsArray = makeCharArray(args); char ** envsArray = makeCharArray(envs); if (execve(_client.c_str(), argsArray, envsArray)) { std::cerr << "Execution of " << _client << " failed with errno = " << errno << std::endl; _exit(errno); } } else { int child_result; (void) wait(&child_result); if (child_result) { Executable::stopServer(); } else { removePid(); } } } void Server::checkpointServer() { executeCommand("-jc"); } void Server::rotateJournalServer() { executeCommand("-jj"); } void Server::executeCommand(const char * command) { pid_t pid = fork(); if (-1 == pid) { std::cerr << "Fork failed, terminating program" << std::endl; _exit(1); } else if (0 == pid) { changeUser(); arg_vec envs; prepareEnv(envs); arg_vec args; args.push_back("p4d"); args.push_back("-r"); args.push_back(_root); if (_configuration->compressCheckpoint()) { args.push_back("-z"); } args.push_back(command); addOption("Checkpoint_Prefix", NULL, args); char ** argsArray = makeCharArray(args); char ** envsArray = makeCharArray(envs); if (!_verbose) { freopen( "/dev/null", "r", stdin ); freopen( "/dev/null", "w", stdout ); freopen( "/dev/null", "w", stderr ); } if (execve(_executable.c_str(), argsArray, envsArray)) { std::cerr << "Execution of " << _executable << " failed with errno = " << errno << std::endl; _exit(errno); } } else { _exit(0); } } // //void Server::statusServer() //{ // pid_t pid = fork(); // // if (-1 == pid) { // perror("Fork failed, terminating program"); // _exit(1); // } // else if (0 == pid) { // // child process, execute the status command // // setUser(); // // arg_vec args; // // args.push_back("p4"); // args.push_back("-p"); // args.push_back(_port); // args.push_back("info"); // // char ** argsArray = makeCharArray(args); // if (execvp(_client.c_str(), argsArray)) { // std::cerr << "Execution of " << _client << " failed with errno = " << errno << std::endl; // _exit(errno); // } // } // else { // // parent, wait for child process // int child_result; // int result = wait(&child_result); // // if (result < 0) { // std::cerr << "Wait failed with " << result << std::endl; // } // if (child_result) { // std::cerr << "Executing status failed with " << child_result << std::endl; // } // } //}
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 8039 | Sven Erik Knop |
P4FTPD is allowed to run as root. This also fixes an overloaded method that could cause confusion in the code. |
||
#2 | 5987 | Sven Erik Knop |
Few minor changes: All commands now accept variable called "Options". This can be used to collect all options for which Perforce has not defined an environment variable - for example the undocumented "-C1" for p4d to start a case insensitive server. p4d also accepts the variables P4USER and P4PASSWD. These are only used for stopping the service, which is done first via "p4 admin stop". Note that if the stop via the admin command fails, p4dcfg will stop the service via a kill |
||
#1 | 5882 | Sven Erik Knop | initial publish |