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