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 * Escape the given raw string into an XML value. 00215 * 00216 * @throws std::bad_alloc Something went wrong. 00217 * @ingroup Support 00218 */ 00219 string escapeForXml(const string &input); 00220 00221 /** 00222 * Return the path name for the directory in which temporary files are 00223 * to be stored. 00224 * 00225 * @ensure result != NULL 00226 * @ingroup Support 00227 */ 00228 const char *getTempDir(); 00229 00230 /** 00231 * Return the path name for the directory in which Phusion Passenger-specific 00232 * temporary files are to be stored. This directory is unique for this instance 00233 * of the web server in which Phusion Passenger is running. 00234 * 00235 * The result will be cached into the PHUSION_PASSENGER_TMP environment variable, 00236 * which will be used for future calls to this function. To bypass this cache, 00237 * set 'bypassCache' to true. 00238 * 00239 * @ensure !result.empty() 00240 * @ingroup Support 00241 */ 00242 string getPassengerTempDir(bool bypassCache = false); 00243 00244 /* Create a temp folder for storing Phusion Passenger-specific temp files, 00245 * such as temporarily buffered uploads, sockets for backend processes, etc. 00246 * This call also sets the PHUSION_PASSENGER_TMP environment variable, which 00247 * allows backend processes to find this temp folder. 00248 * 00249 * Does nothing if this folder already exists. 00250 * 00251 * @throws IOException Something went wrong. 00252 * @throws SystemException Something went wrong. 00253 */ 00254 void createPassengerTempDir(); 00255 00256 /** 00257 * Create the directory at the given path, creating intermediate directories 00258 * if necessary. The created directories' permissions are as specified by the 00259 * 'mode' parameter. 00260 * 00261 * If 'path' already exists, then nothing will happen. 00262 * 00263 * @throws IOException Something went wrong. 00264 * @throws SystemException Something went wrong. 00265 */ 00266 void makeDirTree(const char *path, const char *mode = "u=rwx,g=,o="); 00267 00268 /** 00269 * Remove an entire directory tree recursively. 00270 * 00271 * @throws SystemException Something went wrong. 00272 */ 00273 void removeDirTree(const char *path); 00274 00275 /** 00276 * Check whether the specified directory is a valid Ruby on Rails 00277 * application root directory. 00278 * 00279 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00280 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00281 * @throws FileSystemException Unable to check because of a system error. 00282 * @ingroup Support 00283 */ 00284 bool verifyRailsDir(const string &dir, CachedMultiFileStat *mstat = 0, 00285 unsigned int throttleRate = 0); 00286 00287 /** 00288 * Check whether the specified directory is a valid Rack application 00289 * root directory. 00290 * 00291 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00292 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00293 * @throws FileSystemException Unable to check because of a filesystem error. 00294 * @ingroup Support 00295 */ 00296 bool verifyRackDir(const string &dir, CachedMultiFileStat *mstat = 0, 00297 unsigned int throttleRate = 0); 00298 00299 /** 00300 * Check whether the specified directory is a valid WSGI application 00301 * root directory. 00302 * 00303 * @param mstat A CachedMultiFileStat object, if you want to use cached statting. 00304 * @param throttleRate A throttle rate for mstat. Only applicable if mstat is not NULL. 00305 * @throws FileSystemException Unable to check because of a filesystem error. 00306 * @ingroup Support 00307 */ 00308 bool verifyWSGIDir(const string &dir, CachedMultiFileStat *mstat = 0, 00309 unsigned int throttleRate = 0); 00310 00311 /** 00312 * Represents a temporary file. The associated file is automatically 00313 * deleted upon object destruction. 00314 * 00315 * @ingroup Support 00316 */ 00317 class TempFile { 00318 public: 00319 /** The filename. If this temp file is anonymous, then the filename is an empty string. */ 00320 string filename; 00321 /** The file handle. */ 00322 FILE *handle; 00323 00324 /** 00325 * Create an empty, temporary file, and open it for reading and writing. 00326 * 00327 * @param anonymous Set to true if this temp file should be unlinked 00328 * immediately. Anonymous temp files are useful if one just wants 00329 * a big not-in-memory buffer to work with. 00330 * @throws SystemException Something went wrong. 00331 */ 00332 TempFile(const char *identifier = "temp", bool anonymous = true) { 00333 char templ[PATH_MAX]; 00334 int fd; 00335 00336 snprintf(templ, sizeof(templ), "%s/%s.XXXXXX", getPassengerTempDir().c_str(), identifier); 00337 templ[sizeof(templ) - 1] = '\0'; 00338 fd = mkstemp(templ); 00339 if (fd == -1) { 00340 char message[1024]; 00341 snprintf(message, sizeof(message), "Cannot create a temporary file '%s'", templ); 00342 message[sizeof(message) - 1] = '\0'; 00343 throw SystemException(message, errno); 00344 } 00345 if (anonymous) { 00346 fchmod(fd, 0000); 00347 unlink(templ); 00348 } else { 00349 filename.assign(templ); 00350 } 00351 handle = fdopen(fd, "w+"); 00352 } 00353 00354 ~TempFile() { 00355 fclose(handle); 00356 if (!filename.empty()) { 00357 unlink(filename.c_str()); 00358 } 00359 } 00360 }; 00361 00362 } // namespace Passenger 00363 00364 #endif /* _PASSENGER_UTILS_H_ */ 00365