00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef _PASSENGER_SERVER_INSTANCE_DIR_H_
00026 #define _PASSENGER_SERVER_INSTANCE_DIR_H_
00027
00028 #include <boost/noncopyable.hpp>
00029 #include <boost/shared_ptr.hpp>
00030
00031 #include <sys/types.h>
00032 #include <dirent.h>
00033 #include <unistd.h>
00034 #include <pwd.h>
00035 #include <grp.h>
00036 #include <cstdlib>
00037 #include <cstring>
00038 #include <string>
00039
00040 #include "Exceptions.h"
00041 #include "Utils.h"
00042
00043 namespace Passenger {
00044
00045 using namespace std;
00046 using namespace boost;
00047
00048 class ServerInstanceDir: public noncopyable {
00049 public:
00050
00051 static const int DIR_STRUCTURE_MAJOR_VERSION = 1;
00052 static const int DIR_STRUCTURE_MINOR_VERSION = 0;
00053 static const int GENERATION_STRUCTURE_MAJOR_VERSION = 1;
00054 static const int GENERATION_STRUCTURE_MINOR_VERSION = 0;
00055
00056 class Generation: public noncopyable {
00057 private:
00058 friend class ServerInstanceDir;
00059
00060 string path;
00061 unsigned int number;
00062 bool owner;
00063
00064 Generation(const string &serverInstanceDir, unsigned int number) {
00065 path = serverInstanceDir + "/generation-" + toString(number);
00066 this->number = number;
00067 owner = false;
00068 }
00069
00070 void create(bool userSwitching, const string &defaultUser,
00071 const string &defaultGroup, uid_t webServerWorkerUid,
00072 gid_t webServerWorkerGid)
00073 {
00074 bool runningAsRoot = geteuid() == 0;
00075 struct passwd *defaultUserEntry;
00076 struct group *defaultGroupEntry;
00077 uid_t defaultUid;
00078 gid_t defaultGid;
00079
00080 defaultUserEntry = getpwnam(defaultUser.c_str());
00081 if (defaultUserEntry == NULL) {
00082 throw NonExistentUserException("Default user '" + defaultUser +
00083 "' does not exist.");
00084 }
00085 defaultUid = defaultUserEntry->pw_uid;
00086 defaultGroupEntry = getgrnam(defaultGroup.c_str());
00087 if (defaultGroupEntry == NULL) {
00088 throw NonExistentGroupException("Default group '" + defaultGroup +
00089 "' does not exist.");
00090 }
00091 defaultGid = defaultGroupEntry->gr_gid;
00092
00093
00094
00095
00096
00097 makeDirTree(path, "u=rwxs,g=x,o=x");
00098
00099
00100 string structureVersionFile = path + "/structure_version.txt";
00101 createFile(structureVersionFile,
00102 toString(GENERATION_STRUCTURE_MAJOR_VERSION) + "." +
00103 toString(GENERATION_STRUCTURE_MINOR_VERSION),
00104 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
00105
00106
00107
00108
00109
00110
00111 if (runningAsRoot) {
00112 makeDirTree(path + "/buffered_uploads", "u=rwxs,g=,o=",
00113 webServerWorkerUid, webServerWorkerGid);
00114 } else {
00115 makeDirTree(path + "/buffered_uploads", "u=rwxs,g=,o=");
00116 }
00117
00118
00119 if (runningAsRoot) {
00120 if (userSwitching) {
00121
00122
00123
00124
00125
00126 makeDirTree(path + "/backends", "u=rwxs,g=wx,o=wx");
00127 } else {
00128
00129
00130
00131
00132
00133
00134
00135
00136 makeDirTree(path + "/backends", "u=rwxs,g=x,o=x", defaultUid, defaultGid);
00137 }
00138 } else {
00139
00140
00141
00142 makeDirTree(path + "/backends", "u=rwxs,g=,o=");
00143 }
00144
00145
00146
00147
00148 if (runningAsRoot) {
00149 if (userSwitching) {
00150
00151
00152
00153 makeDirTree(path + "/spawn-server", "u=rwxs,g=,o=");
00154 } else {
00155
00156
00157
00158 makeDirTree(path + "/spawn-server", "u=rwxs,g=,o=",
00159 defaultUid, defaultGid);
00160 }
00161 } else {
00162 makeDirTree(path + "/spawn-server", "u=rwxs,g=,o=");
00163 }
00164
00165 owner = true;
00166 }
00167
00168 public:
00169 ~Generation() {
00170 if (owner) {
00171 removeDirTree(path);
00172 }
00173 }
00174
00175 unsigned int getNumber() const {
00176 return number;
00177 }
00178
00179 string getPath() const {
00180 return path;
00181 }
00182
00183 void detach() {
00184 owner = false;
00185 }
00186 };
00187
00188 typedef shared_ptr<Generation> GenerationPtr;
00189
00190 private:
00191 string path;
00192 bool owner;
00193
00194 friend class Generation;
00195
00196 void initialize(const string &path, bool owner) {
00197 this->path = path;
00198 this->owner = owner;
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 makeDirTree(path, "u=rwxs,g=rx,o=rx");
00217 }
00218
00219 public:
00220 ServerInstanceDir(pid_t webServerPid, const string &parentDir = "", bool owner = true) {
00221 string theParentDir;
00222
00223 if (parentDir.empty()) {
00224 theParentDir = getSystemTempDir();
00225 } else {
00226 theParentDir = parentDir;
00227 }
00228
00229
00230
00231
00232
00233
00234 initialize(theParentDir + "/passenger." +
00235 toString(DIR_STRUCTURE_MAJOR_VERSION) + "." +
00236 toString(DIR_STRUCTURE_MINOR_VERSION) + "." +
00237 toString<unsigned long long>(webServerPid),
00238 owner);
00239
00240 }
00241
00242 ServerInstanceDir(const string &path, bool owner = true) {
00243 initialize(path, owner);
00244 }
00245
00246 ~ServerInstanceDir() {
00247 if (owner) {
00248 GenerationPtr newestGeneration;
00249 try {
00250 newestGeneration = getNewestGeneration();
00251 } catch (const FileSystemException &e) {
00252 if (e.code() == ENOENT) {
00253 return;
00254 } else {
00255 throw;
00256 }
00257 }
00258 if (newestGeneration == NULL) {
00259 removeDirTree(path);
00260 }
00261 }
00262 }
00263
00264 string getPath() const {
00265 return path;
00266 }
00267
00268 void detach() {
00269 owner = false;
00270 }
00271
00272 GenerationPtr newGeneration(bool userSwitching, const string &defaultUser,
00273 const string &defaultGroup, uid_t webServerWorkerUid,
00274 gid_t webServerWorkerGid)
00275 {
00276 GenerationPtr newestGeneration = getNewestGeneration();
00277 unsigned int newNumber;
00278 if (newestGeneration != NULL) {
00279 newNumber = newestGeneration->getNumber() + 1;
00280 } else {
00281 newNumber = 0;
00282 }
00283
00284 GenerationPtr generation(new Generation(path, newNumber));
00285 generation->create(userSwitching, defaultUser, defaultGroup,
00286 webServerWorkerUid, webServerWorkerGid);
00287 return generation;
00288 }
00289
00290 GenerationPtr getGeneration(unsigned int number) const {
00291 return ptr(new Generation(path, number));
00292 }
00293
00294 GenerationPtr getNewestGeneration() const {
00295 DIR *dir = opendir(path.c_str());
00296 struct dirent *entry;
00297 int result = -1;
00298
00299 if (dir == NULL) {
00300 int e = errno;
00301 throw FileSystemException("Cannot open directory " + path,
00302 e, path);
00303 }
00304 while ((entry = readdir(dir)) != NULL) {
00305 if (entry->d_type == DT_DIR
00306 && strncmp(entry->d_name, "generation-", sizeof("generation-") - 1) == 0) {
00307 const char *numberString = entry->d_name + sizeof("generation-") - 1;
00308 int number = atoi(numberString);
00309 if (number >= 0 && number > result) {
00310 result = number;
00311 }
00312 }
00313 }
00314 closedir(dir);
00315
00316 if (result == -1) {
00317 return GenerationPtr();
00318 } else {
00319 return getGeneration(result);
00320 }
00321 }
00322 };
00323
00324 typedef shared_ptr<ServerInstanceDir> ServerInstanceDirPtr;
00325
00326 }
00327
00328 #endif