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 "Exceptions.h" 00036 00037 namespace Passenger { 00038 00039 using namespace std; 00040 using namespace boost; 00041 00042 /** 00043 * Convenience shortcut for creating a <tt>shared_ptr</tt>. 00044 * Instead of: 00045 * @code 00046 * shared_ptr<Foo> foo; 00047 * ... 00048 * foo = shared_ptr<Foo>(new Foo()); 00049 * @endcode 00050 * one can write: 00051 * @code 00052 * shared_ptr<Foo> foo; 00053 * ... 00054 * foo = ptr(new Foo()); 00055 * @endcode 00056 * 00057 * @param pointer The item to put in the shared_ptr object. 00058 * @ingroup Support 00059 */ 00060 template<typename T> shared_ptr<T> 00061 ptr(T *pointer) { 00062 return shared_ptr<T>(pointer); 00063 } 00064 00065 /** 00066 * Used internally by toString(). Do not use directly. 00067 * 00068 * @internal 00069 */ 00070 template<typename T> 00071 struct AnythingToString { 00072 string operator()(T something) { 00073 stringstream s; 00074 s << something; 00075 return s.str(); 00076 } 00077 }; 00078 00079 /** 00080 * Used internally by toString(). Do not use directly. 00081 * 00082 * @internal 00083 */ 00084 template<> 00085 struct AnythingToString< vector<string> > { 00086 string operator()(const vector<string> &v) { 00087 string result("["); 00088 vector<string>::const_iterator it; 00089 unsigned int i; 00090 for (it = v.begin(), i = 0; it != v.end(); it++, i++) { 00091 result.append("'"); 00092 result.append(*it); 00093 if (i == v.size() - 1) { 00094 result.append("'"); 00095 } else { 00096 result.append("', "); 00097 } 00098 } 00099 result.append("]"); 00100 return result; 00101 } 00102 }; 00103 00104 /** 00105 * Convert anything to a string. 00106 * 00107 * @param something The thing to convert. 00108 * @ingroup Support 00109 */ 00110 template<typename T> string 00111 toString(T something) { 00112 return AnythingToString<T>()(something); 00113 } 00114 00115 /** 00116 * Converts the given string to an integer. 00117 * @ingroup Support 00118 */ 00119 int atoi(const string &s); 00120 00121 /** 00122 * Split the given string using the given separator. 00123 * 00124 * @param str The string to split. 00125 * @param sep The separator to use. 00126 * @param output The vector to write the output to. 00127 * @ingroup Support 00128 */ 00129 void split(const string &str, char sep, vector<string> &output); 00130 00131 /** 00132 * Check whether the specified file exists. 00133 * 00134 * @param filename The filename to check. 00135 * @return Whether the file exists. 00136 * @throws FileSystemException Unable to check because of a filesystem error. 00137 * @ingroup Support 00138 */ 00139 bool fileExists(const char *filename); 00140 00141 /** 00142 * Find the location of the Passenger spawn server script. 00143 * If passengerRoot is given, t T 00144 * 00145 * @param passengerRoot The Passenger root folder. If NULL is given, then 00146 * the spawn server is found by scanning $PATH. For security reasons, 00147 * only absolute paths are scanned. 00148 * @return An absolute path to the spawn server script, or 00149 * an empty string on error. 00150 * @throws FileSystemException Unable to access parts of the filesystem. 00151 * @ingroup Support 00152 */ 00153 string findSpawnServer(const char *passengerRoot = NULL); 00154 00155 /** 00156 * Find the location of the Passenger ApplicationPool server 00157 * executable. 00158 * 00159 * @param passengerRoot The Passenger root folder. 00160 * @return An absolute path to the executable. 00161 * @throws FileSystemException Unable to access parts of the filesystem. 00162 * @pre passengerRoot != NULL 00163 * @ingroup Support 00164 */ 00165 string findApplicationPoolServer(const char *passengerRoot); 00166 00167 /** 00168 * Returns a canonical version of the specified path. All symbolic links 00169 * and relative path elements are resolved. 00170 * Returns an empty string if something went wrong. 00171 * 00172 * @ingroup Support 00173 */ 00174 string canonicalizePath(const string &path); 00175 00176 /** 00177 * Check whether the specified directory is a valid Ruby on Rails 00178 * 'public' directory. 00179 * 00180 * @throws FileSystemException Unable to check because of a system error. 00181 * @ingroup Support 00182 */ 00183 bool verifyRailsDir(const string &dir); 00184 00185 /** 00186 * Check whether the specified directory is a valid Rack 'public' 00187 * directory. 00188 * 00189 * @throws FileSystemException Unable to check because of a filesystem error. 00190 * @ingroup Support 00191 */ 00192 bool verifyRackDir(const string &dir); 00193 00194 /** 00195 * Check whether the specified directory is a valid WSGI 'public' 00196 * directory. 00197 * 00198 * @throws FileSystemException Unable to check because of a filesystem error. 00199 * @ingroup Support 00200 */ 00201 bool verifyWSGIDir(const string &dir); 00202 00203 /** 00204 * Represents a temporary file. The associated file is automatically 00205 * deleted upon object destruction. 00206 * 00207 * @ingroup Support 00208 */ 00209 class TempFile { 00210 public: 00211 /** The filename. If this temp file is anonymous, then the filename is an empty string. */ 00212 string filename; 00213 /** The file handle. */ 00214 FILE *handle; 00215 00216 /** 00217 * Create an empty, temporary file, and open it for reading and writing. 00218 * 00219 * @param anonymous Set to true if this temp file should be unlinked 00220 * immediately. Anonymous temp files are useful if one just wants 00221 * a big not-in-memory buffer to work with. 00222 * @throws SystemException Something went wrong. 00223 */ 00224 TempFile(bool anonymous = true) { 00225 const char *temp_dir; 00226 char templ[PATH_MAX]; 00227 int fd; 00228 00229 temp_dir = getenv("TMP"); 00230 if (temp_dir == NULL || *temp_dir == '\0') { 00231 temp_dir = "/tmp"; 00232 } 00233 00234 snprintf(templ, sizeof(templ), "%s/passenger.XXXXXX", temp_dir); 00235 templ[sizeof(templ) - 1] = '\0'; 00236 fd = mkstemp(templ); 00237 if (fd == -1) { 00238 throw SystemException("Cannot create a temporary file", errno); 00239 } 00240 if (anonymous) { 00241 fchmod(fd, 0000); 00242 unlink(templ); 00243 } else { 00244 filename.assign(templ); 00245 } 00246 handle = fdopen(fd, "w+"); 00247 } 00248 00249 ~TempFile() { 00250 fclose(handle); 00251 if (!filename.empty()) { 00252 unlink(filename.c_str()); 00253 } 00254 } 00255 }; 00256 00257 } // namespace Passenger 00258 00259 #endif /* _PASSENGER_UTILS_H_ */ 00260