00001 /* 00002 * Phusion Passenger - http://www.modrails.com/ 00003 * Copyright (C) 2008 Phusion 00004 * 00005 * Phusion Passenger is a trademark of Hongli Lai & Ninh Bui. 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; version 2 of the License. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 #ifndef _PASSENGER_UTILS_H_ 00021 #define _PASSENGER_UTILS_H_ 00022 00023 #include <boost/shared_ptr.hpp> 00024 #include <sys/types.h> 00025 #include <sys/stat.h> 00026 #include <string> 00027 #include <vector> 00028 #include <utility> 00029 #include <sstream> 00030 #include <cstdio> 00031 #include <climits> 00032 #include <cstdlib> 00033 #include <cstring> 00034 #include <errno.h> 00035 #include <unistd.h> 00036 #include "Exceptions.h" 00037 00038 typedef struct CachedMultiFileStat CachedMultiFileStat; 00039 00040 namespace Passenger { 00041 00042 using namespace std; 00043 using namespace boost; 00044 00045 /** Enumeration which indicates what kind of file a file is. */ 00046 typedef enum { 00047 /** The file doesn't exist. */ 00048 FT_NONEXISTANT, 00049 /** A regular file or a symlink to a regular file. */ 00050 FT_REGULAR, 00051 /** A directory. */ 00052 FT_DIRECTORY, 00053 /** Something else, e.g. a pipe or a socket. */ 00054 FT_OTHER 00055 } FileType; 00056 00057 /** 00058 * Convenience shortcut for creating a <tt>shared_ptr</tt>. 00059 * Instead of: 00060 * @code 00061 * shared_ptr<Foo> foo; 00062 * ... 00063 * foo = shared_ptr<Foo>(new Foo()); 00064 * @endcode 00065 * one can write: 00066 * @code 00067 * shared_ptr<Foo> foo; 00068 * ... 00069 * foo = ptr(new Foo()); 00070 * @endcode 00071 * 00072 * @param pointer The item to put in the shared_ptr object. 00073 * @ingroup Support 00074 */ 00075 template<typename T> shared_ptr<T> 00076 ptr(T *pointer) { 00077 return shared_ptr<T>(pointer); 00078 } 00079 00080 /** 00081 * Used internally by toString(). Do not use directly. 00082 * 00083 * @internal 00084 */ 00085 template<typename T> 00086 struct AnythingToString { 00087 string operator()(T something) { 00088 stringstream s; 00089 s << something; 00090 return s.str(); 00091 } 00092 }; 00093 00094 /** 00095 * Used internally by toString(). Do not use directly. 00096 * 00097 * @internal 00098 */ 00099 template<> 00100 struct AnythingToString< vector<string> > { 00101 string operator()(const vector<string> &v) { 00102 string result("["); 00103 vector<string>::const_iterator it; 00104 unsigned int i; 00105 for (it = v.begin(), i = 0; it != v.end(); it++, i++) { 00106 result.append("'"); 00107 result.append(*it); 00108 if (i == v.size() - 1) { 00109 result.append("'"); 00110 } else { 00111 result.append("', "); 00112 } 00113 } 00114 result.append("]"); 00115 return result; 00116 } 00117 }; 00118 00119 /** 00120 * Convert anything to a string. 00121 * 00122 * @param something The thing to convert. 00123 * @ingroup Support 00124 */ 00125 template<typename T> string 00126 toString(T something) { 00127 return AnythingToString<T>()(something); 00128 } 00129 00130 /** 00131 * Converts the given string to an integer. 00132 * @ingroup Support 00133 */ 00134 int atoi(const string &s); 00135 00136 /** 00137 * Converts the given string to a long integer. 00138 * @ingroup Support 00139 */ 00140 long atol(const string &s); 00141 00142 /** 00143 * Split the given string using the given separator. 00144 * 00145 * @param str The string to split. 00146 * @param sep The separator to use. 00147 * @param output The vector to write the output to. 00148 * @ingroup Support 00149 */ 00150 void split(const string &str, char sep, vector<string> &output); 00151 00152 /** 00153 * Check whether the specified file exists. 00154 * 00155 * @param filename The filename to check. 00156 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00157 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00158 * @return Whether the file exists. 00159 * @throws FileSystemException Unable to check because of a filesystem error. 00160 * @ingroup Support 00161 */ 00162 bool fileExists(const char *filename, CachedMultiFileStat *mstat = 0, 00163 unsigned int throttleRate = 0); 00164 00165 /** 00166 * Check whether 'filename' exists and what kind of file it is. 00167 * 00168 * @param filename The filename to check. 00169 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00170 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00171 * @return The file type. 00172 * @throws FileSystemException Unable to check because of a filesystem error. 00173 * @ingroup Support 00174 */ 00175 FileType getFileType(const char *filename, CachedMultiFileStat *mstat = 0, 00176 unsigned int throttleRate = 0); 00177 00178 /** 00179 * Find the location of the Passenger spawn server script. 00180 * If passengerRoot is given, t T 00181 * 00182 * @param passengerRoot The Passenger root folder. If NULL is given, then 00183 * the spawn server is found by scanning $PATH. For security reasons, 00184 * only absolute paths are scanned. 00185 * @return An absolute path to the spawn server script, or 00186 * an empty string on error. 00187 * @throws FileSystemException Unable to access parts of the filesystem. 00188 * @ingroup Support 00189 */ 00190 string findSpawnServer(const char *passengerRoot = NULL); 00191 00192 /** 00193 * Find the location of the Passenger ApplicationPool server 00194 * executable. 00195 * 00196 * @param passengerRoot The Passenger root folder. 00197 * @return An absolute path to the executable. 00198 * @throws FileSystemException Unable to access parts of the filesystem. 00199 * @pre passengerRoot != NULL 00200 * @ingroup Support 00201 */ 00202 string findApplicationPoolServer(const char *passengerRoot); 00203 00204 /** 00205 * Returns a canonical version of the specified path. All symbolic links 00206 * and relative path elements are resolved. 00207 * 00208 * @throws FileSystemException Something went wrong. 00209 * @ingroup Support 00210 */ 00211 string canonicalizePath(const string &path); 00212 00213 /** 00214 * If <em>path</em> refers to a symlink, then this function resolves the 00215 * symlink for 1 level. That is, if the symlink points to another symlink, 00216 * then the other symlink will not be resolved. The resolved path is returned. 00217 * 00218 * If the symlink doesn't point to an absolute path, then this function will 00219 * prepend <em>path</em>'s directory to the result. 00220 * 00221 * If <em>path</em> doesn't refer to a symlink then this method will return 00222 * <em>path</em>. 00223 * 00224 * @throws FileSystemException Something went wrong. 00225 * @ingroup Support 00226 */ 00227 string resolveSymlink(const string &path); 00228 00229 /** 00230 * Given a path, extracts its directory name. 00231 * 00232 * @ingroup Support 00233 */ 00234 string extractDirName(const string &path); 00235 00236 /** 00237 * Escape the given raw string into an XML value. 00238 * 00239 * @throws std::bad_alloc Something went wrong. 00240 * @ingroup Support 00241 */ 00242 string escapeForXml(const string &input); 00243 00244 /** 00245 * Given a username that's supposed to be the "lowest user" in the user switching mechanism, 00246 * checks whether this username exists. If so, this users's UID and GID will be stored into 00247 * the arguments of the same names. If not, <em>uid</em> and <em>gid</em> will be set to 00248 * the UID and GID of the "nobody" user. If that user doesn't exist either, then <em>uid</em> 00249 * and <em>gid</em> will be set to -1. 00250 */ 00251 void determineLowestUserAndGroup(const string &user, uid_t &uid, gid_t &gid); 00252 00253 /** 00254 * Return the path name for the directory in which the system stores general 00255 * temporary files. This is usually "/tmp", but might be something else depending 00256 * on some environment variables. 00257 * 00258 * @ensure result != NULL 00259 * @ingroup Support 00260 */ 00261 const char *getSystemTempDir(); 00262 00263 /** 00264 * Return the path name for the directory in which Phusion Passenger-specific 00265 * temporary files are to be stored. This directory is unique for this instance 00266 * of the web server in which Phusion Passenger is running. 00267 * 00268 * If the environment variable PASSENGER_INSTANCE_TEMP_DIR is set, then that value 00269 * will be returned. If this environment variable is not set, then it will be set 00270 * with the return value. 00271 * 00272 * To bypass the usage of the PASSENGER_INSTANCE_TEMP_DIR environment variable, 00273 * set 'bypassCache' to true. 00274 * 00275 * @param bypassCache Whether PASSENGER_INSTANCE_TEMP_DIR should be bypassed. 00276 * @param systemTempDir The directory under which the Phusion Passenger-specific 00277 * temp directory should be located. If set to the empty string, 00278 * then the return value of getSystemTempDir() will be used. 00279 * @ensure !result.empty() 00280 * @ingroup Support 00281 */ 00282 string getPassengerTempDir(bool bypassCache = false, const string &systemTempDir = ""); 00283 00284 /* Create a temp directory under <em>systemTempDir</em>, for storing Phusion 00285 * Passenger-specific temp files, such as temporarily buffered uploads, 00286 * sockets for backend processes, etc. This call also sets the 00287 * PASSENGER_INSTANCE_TEMP_DIR environment variable, which allows subprocesses 00288 * to find this temp directory. 00289 * 00290 * The created temp directory will have several subdirectories: 00291 * - webserver_private - for storing the web server's buffered uploads. 00292 * - info - for storing files that allow external tools to query information 00293 * about a running Phusion Passenger instance. 00294 * - backends - for storing Unix sockets created by backend processes. 00295 * - var - for storing all other kinds of temp files that the backend processes 00296 * create. 00297 * 00298 * If a (sub)directory already exists, then it will not result in an error. 00299 * 00300 * The <em>userSwitching</em> and <em>lowestUser</em> arguments passed to 00301 * this method are used for determining the optimal permissions for the 00302 * (sub)directories. The permissions will be set as tightly as possible based 00303 * on the values. The <em>workerUid</em> and <em>workerGid</em> arguments 00304 * will be used for determining the owner of certain subdirectories. 00305 * 00306 * @note You should only call this method inside the web server's master 00307 * process. In case of Apache, this is the Apache control process, 00308 * the one that tends to run as root. This is because this function 00309 * will set directory permissions and owners/groups, which may require 00310 * root privileges. 00311 * 00312 * @param systemTempDir The directory under which the Phusion Passenger-specific 00313 * temp directory should be created. You should normally 00314 * specify the return value of getSystemTempDir(). 00315 * @param userSwitching Whether user switching is turned on. 00316 * @param lowestUser The user that the spawn manager and the pool server will 00317 * run as, if user switching is turned off. 00318 * @param workerUid The UID that the web server's worker processes are running 00319 * as. On Apache, this is the UID that's associated with the 00320 * 'User' directive. 00321 * @param workerGid The GID that the web server's worker processes are running 00322 * as. On Apache, this is the GID that's associated with the 00323 * 'Group' directive. 00324 * @throws IOException Something went wrong. 00325 * @throws SystemException Something went wrong. 00326 * @throws FileSystemException Something went wrong. 00327 */ 00328 void createPassengerTempDir(const string &systemTempDir, bool userSwitching, 00329 const string &lowestUser, 00330 uid_t workerUid, gid_t workerGid); 00331 00332 /** 00333 * Create the directory at the given path, creating intermediate directories 00334 * if necessary. The created directories' permissions are as specified by the 00335 * 'mode' parameter. You can specify this directory's owner and group through 00336 * the 'owner' and 'group' parameters. A value of -1 for 'owner' or 'group' 00337 * means that the owner/group should not be changed. 00338 * 00339 * If 'path' already exists, then nothing will happen. 00340 * 00341 * @throws IOException Something went wrong. 00342 * @throws SystemException Something went wrong. 00343 * @throws FileSystemException Something went wrong. 00344 */ 00345 void makeDirTree(const string &path, const char *mode = "u=rwx,g=,o=", uid_t owner = -1, gid_t group = -1); 00346 00347 /** 00348 * Remove an entire directory tree recursively. 00349 * 00350 * @throws FileSystemException Something went wrong. 00351 */ 00352 void removeDirTree(const string &path); 00353 00354 /** 00355 * Check whether the specified directory is a valid Ruby on Rails 00356 * application root directory. 00357 * 00358 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00359 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00360 * @throws FileSystemException Unable to check because of a system error. 00361 * @ingroup Support 00362 */ 00363 bool verifyRailsDir(const string &dir, CachedMultiFileStat *mstat = 0, 00364 unsigned int throttleRate = 0); 00365 00366 /** 00367 * Check whether the specified directory is a valid Rack application 00368 * root directory. 00369 * 00370 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00371 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00372 * @throws FileSystemException Unable to check because of a filesystem error. 00373 * @ingroup Support 00374 */ 00375 bool verifyRackDir(const string &dir, CachedMultiFileStat *mstat = 0, 00376 unsigned int throttleRate = 0); 00377 00378 /** 00379 * Check whether the specified directory is a valid WSGI application 00380 * root directory. 00381 * 00382 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00383 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00384 * @throws FileSystemException Unable to check because of a filesystem error. 00385 * @ingroup Support 00386 */ 00387 bool verifyWSGIDir(const string &dir, CachedMultiFileStat *mstat = 0, 00388 unsigned int throttleRate = 0); 00389 00390 /** 00391 * Represents a buffered upload file. 00392 * 00393 * @ingroup Support 00394 */ 00395 class BufferedUpload { 00396 public: 00397 /** The file handle. */ 00398 FILE *handle; 00399 00400 /** 00401 * Create an empty upload bufer file, and open it for reading and writing. 00402 * 00403 * @throws SystemException Something went wrong. 00404 */ 00405 BufferedUpload(const char *identifier = "temp") { 00406 char templ[PATH_MAX]; 00407 int fd; 00408 00409 snprintf(templ, sizeof(templ), "%s/%s.XXXXXX", getDir().c_str(), identifier); 00410 templ[sizeof(templ) - 1] = '\0'; 00411 fd = mkstemp(templ); 00412 if (fd == -1) { 00413 char message[1024]; 00414 int e = errno; 00415 00416 snprintf(message, sizeof(message), "Cannot create a temporary file '%s'", templ); 00417 message[sizeof(message) - 1] = '\0'; 00418 throw SystemException(message, e); 00419 } 00420 00421 /* We use a POSIX trick here: the file's permissions are set to "u=,g=,o=" 00422 * and the file is deleted immediately from the filesystem, while we 00423 * keep its file handle open. The result is that no other processes 00424 * will be able to access this file's contents anymore, except us. 00425 * We now have an anonymous disk-backed buffer. 00426 */ 00427 fchmod(fd, 0000); 00428 unlink(templ); 00429 00430 handle = fdopen(fd, "w+"); 00431 } 00432 00433 ~BufferedUpload() { 00434 fclose(handle); 00435 } 00436 00437 /** 00438 * Returns the directory in which upload buffer files are stored. 00439 * This is a subdirectory of the directory returned by getPassengerTempDir(). 00440 */ 00441 static string getDir() { 00442 return getPassengerTempDir() + "/webserver_private"; 00443 } 00444 }; 00445 00446 } // namespace Passenger 00447 00448 #endif /* _PASSENGER_UTILS_H_ */ 00449