GIF89a=( õ' 7IAXKgNgYvYx\%wh…hŽth%ˆs%—x¨}9®Œ©€&©‰%¶†(¹–.¹5·œD¹&Çš)ÇŸ5ǘ;Í£*È¡&Õ²)ׯ7×µ<Ñ»4ï°3ø‘HÖ§KͯT÷¨Yÿšqÿ»qÿÔFØ !ù ' !ÿ NETSCAPE2.0 , =( þÀ“pH,È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§gª«ªE¯°¨¬ª±²Œ¹º¹E¾­”´ÂB¶¯ §Åȸ»ÑD¾¿Á•ÄÅ®° ÝH¾ÒLÀÆDÙ«D¶BÝïðÀ¾DÑÑÔTÌÍíH òGö¨A RÎڐ |¥ ٭&ºìE8œ¹kGÔAÞpx­a¶­ã R2XB®åE8I€Õ6Xî:vT)äžþÀq¦è³¥ì仕F~%xñ  4#ZÔ‰O|-4Bs‘X:= QÉ œš lºÒyXJŠGȦ|s hÏíK–3l7·B|¥$'7Jީܪ‰‡àá”Dæn=Pƒ ¤Òëí‰`䌨ljóá¯Éüv>á–Á¼5 ½.69ûϸd«­ºÀûnlv©‹ªîf{¬ÜãPbŸ  l5‘ޝpß ´ ˜3aÅùäI«O’ý·‘áÞ‡˜¾Æ‚ÙÏiÇÿ‹Àƒ #öó)pâš Þ½ ‘Ý{ó)vmÞü%D~ 6f s}ŃƒDØW Eþ`‡þ À…L8xá†ç˜{)x`X/> Ì}mø‚–RØ‘*|`D=‚Ø_ ^ð5 !_…'aä“OÚ—7âcð`D”Cx`ÝÂ¥ä‹éY¹—F¼¤¥Š?¡Õ™ n@`} lď’ÄÉ@4>ñd œ à‘vÒxNÃ×™@žd=ˆgsžG±æ ´²æud &p8Qñ)ˆ«lXD©øÜéAžHìySun jª×k*D¤LH] †¦§C™Jä–´Xb~ʪwStŽ6K,°£qÁœ:9ت:¨þªl¨@¡`‚ûÚ ».Û¬¯t‹ÆSÉ[:°=Š‹„‘Nåû”Ìî{¿ÂA ‡Rà›ÀÙ6úë°Ÿð0Ä_ ½;ÃϱîÉì^ÇÛÇ#Ëë¼ôº!±Ä˜íUîÅÇ;0L1óÁµö«p% AÀºU̬ݵ¼á%霼€‡¯Á~`ÏG¯»À× ­²± =4ªnpð3¾¤³¯­ü¾¦îuÙuµÙ®|%2ÊIÿür¦#0·ÔJ``8È@S@5ê¢ ö×Þ^`8EÜ]ý.뜃Âç 7 ú ȉÞj œ½Dç zý¸iþœÑÙûÄë!ˆÞÀl§Ïw‹*DçI€nEX¯¬¼ &A¬Go¼QföõFç°¯;é¦÷îŽêJ°îúôF5¡ÌQ|îúöXªæ»TÁÏyñêï]ê² o óÎC=öõ›ÒÓPB@ D×½œä(>èCÂxŽ`±«Ÿ–JЀ»Û á¤±p+eE0`ëŽ`A Ú/NE€Ø†À9‚@¤à H½7”à‡%B‰`Àl*ƒó‘–‡8 2ñ%¸ —€:Ù1Á‰E¸àux%nP1ð!‘ðC)¾P81lÑɸF#ˆ€{´âé°ÈB„0>±û °b¡Š´±O‚3È–Ù()yRpbµ¨E.Z‘D8ÊH@% òŒx+%Ù˜Æcü »¸˜fõ¬b·d`Fê™8èXH"ÉÈ-±|1Ô6iI, 2““¬$+](A*jÐ QTÂo‰.ÛU슬Œã„Ž`¯SN¡–¶Äåyše¯ª’­¬‚´b¦Éož œ)åyâ@Ì®3 ÎtT̉°&Ø+žLÀf"Ø-|žçÔ>‡Ðv¦Ðžì\‚ Q1)Ž@Žh#aP72”ˆ™¨$‚ !ù " , =( …7IAXG]KgNgYvYxR"k\%w]'}hŽth%ˆg+ˆs%—r.—m3šx3˜x¨}9®€&©€+¨‡7§‰%¶†(¹–.¹œD¹&ǘ;Í•&ײ)×»4ïÌ6ò§KÍ þ@‘pH,È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§g «¬ E ±± ¨­¶°ººE Á´”·®C¬²§Ç¶Œ»ÓDÃÕƷ¯Ê±H½ºM×ÁGÚ¬D¶BËÁ½î½DÓôTÏÛßîG»ôõC×CÌ l&âž:'òtU³6ɹ#·Ø)€'Ü.6±&ëÍÈ» K(8p0N?!æ2"ÛˆNIJX>R¼ÐO‚M '¡¨2¸*Ÿþ>#n↠å@‚<[:¡Iïf’ ¤TÚ˘CdbÜÙ“[«ŽEú5MBo¤×@€`@„€Êt W-3 ¶Ÿ¡BíêäjIÝ…Eò9[T…$íêﯧ„…•s»Óȳ¹€ÅÚdc®UUρ#±Ùïldj?´í¼²`\ŽÁðÞu|3'ÖŒ]ë6 ¶S#²‡˜FKLÈ *N E´‘áäŠ$˜›eÄYD„ºq«.è촁ƒs \-ÔjA 9²õ÷å- üúM[Âx(ís÷ì®x€|í¡Ù’p¦‚ ŽkÛTÇDpE@WÜ ²Ç]kŠ1¨ þ€·Yb ÓÁ‰l°*n0 ç™—žzBdОu¾7ĉBl€â‰-ºx~|UåU‰  h*Hœ|e"#"?vpÄiŠe6^ˆ„+qâŠm8 #VÇá ‘å–ÄV„œ|Аè•m"сœn|@›U¶ÆÎž—Špb¥G¨ED”€±Úê2FÌIç? >Éxå Œ± ¡¤„%‘žjŸ‘ꄯ<Ìaà9ijÐ2˜D¦È&›†Z`‚å]wþ¼Â:ç6àB¤7eFJ|õÒ§Õ,¨äàFÇ®cS·Ê¶+B°,‘Þ˜ºNûãØ>PADÌHD¹æž«ÄÀnÌ¥}­#Ë’ë QÀÉSÌÂÇ2ÌXÀ{æk²lQÁ2«ÊðÀ¯w|2Í h‹ÄÂG€,m¾¶ë3ÐÙ6-´ÅE¬L°ÆIij*K½ÀÇqï`DwVÍQXœÚÔpeœ±¬Ñ q˜§Tœ½µƒ°Œìu Â<¶aØ*At¯lmEØ ü ôÛN[P1ÔÛ¦­±$ÜÆ@`ùåDpy¶yXvCAyåB`ŽD¶ 0QwG#¯ æš[^Äþ $ÀÓÝǦ{„L™[±úKÄgÌ;ï£S~¹ìGX.ôgoT.»åˆ°ùŸûù¡?1zö¦Ÿž:ÅgÁ|ìL¹ „®£œŠ‚à0œ]PÁ^p F<"•ç?!,ñ‡N4—…PÄ Á„ö¨Û:Tè@hÀ‹%táÿ:ø-žI<`þ‹p I….)^ 40D#p@ƒj4–؀:²‰1Øâr˜¼F2oW¼#Z†;$Q q” ‘ ÂK¦ñNl#29 !’F@¥Bh·ᏀL!—XFóLH‘Kh¤.«hE&JòG¨¥<™WN!€ÑÙÚˆY„@†>Œž19J" 2,/ &.GXB%ÌRÈ9B6¹W]’î×ÔW¥’IÎ$ ñ‹ÓŒE8YÆ ¼³™ñA5“à®Q.aŸB€&Ø©³ JÁ—! ¦t)K%tœ-¦JF bòNMxLôþ)ÐR¸Ð™‘ èÝ6‘O!THÌ„HÛ ‰ !ù ) , =( …AXKgNgYvYxR"k\%wh…hŽh%ˆg+ˆs%—r.—x3˜x¨}9®€&©€+¨Œ,©‡7§‰%¶†(¹–.¹5·&Çš)ǘ;Í•&×£*Ȳ)ׯ7×»4ï°3øÌ6ò‘HÖ§KÍ»Hó¯T÷¨Yÿ»qÿÇhÿ þÀ”pH,È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§g ª« E$±²¨ª­ · °²½$E$ÂÕ««D· Í ¿¦Ç¶¸ÌŒ¾³CÃÅÆ E ééH½MÛÂGâªD­ çBêêϾD²ÒaÀà€Š1r­ðÓ¤ ÔožzU!L˜C'¾yW½UGtäÇïÙllê0×àÂuGþ)AÀs[þ·xì ÁxO%ƒûX2ó—  P£n›R/¡ÑšHše+êDm?# —‘Ç£6¡8íJ¡ŸâDiäªM¥Ö„ôj“¬¹£5oQ7°- <‡ *´lãÓŒ2r/a!l)dÈ A™ÈE¢ôÔ͆…ð ;Ö˜c ¡%ß‚’Ùˆâ¸b½—pe~C"BíëÚHïeF2§æŠ8qb t_`urŠeü wÅu3êæPv§h•"ß`íÍxçLĹÜÖ3á  ~Öº“®›¸ÏMDfJÙ °„ÛµáWõ%§œ‚à©–‚X ÓØ)@®Ñ›Eþ´wëuÅSxb8y\mÖzœ¥§ZbºE—ÂLªÌw!y(>¡™wú=Ç|ÅÝs¢d €CÁW)HÜcC$€L Ä7„r.á\{)@ð` @ äXÈ$PD” `šaG:§æˆOˆ72EÐamn]ù"ŒcÊxÑŒ° &dR8`g«iÙŸLR!¦P …d’ä¡“¦ðÎTƒ¦ià|À _ ¥ Qi#¦Šg›Æ ›noMµ ›V ã£)p ç£ÎW…š=Âeªk§†j„ ´®1ß²sÉxéW«jšl|0¯B0Û, \jÛ´›6±¬¶C ÛíWþï|ëÙ‹¸ñzĸV {ì;Ýñn¼òVˆm³I¼³.Ðã¤PN¥ ²µ¼„µCã+¹ÍByî£Ñ¾HŸ›ëê 7ìYÆFTk¨SaoaY$Dµœìï¿Ã29RÈkt Çïfñ ÇÒ:ÀÐSp¹3ÇI¨â¥DZÄ ü9Ïýögñ½­uÔ*3)O‘˜Ö[_hv ,àî×Et Ÿé¶BH€ Õ[ü±64M@ÔSÌM7dÐl5-ÄÙU܍´©zߌ3Ô€3ž„ „ ¶ÛPô½5×g› êÚ˜kN„Ý…0Îj4€Ìë°“#{þÕ3S2çKÜ'ợlø¼Ú2K{° {Û¶?žm𸧠ËI¼nEò='êüóºè^üæÃ_Û=°óž‚ì#Oý¿Í'¡½áo..ÏYìnüñCœO±Áa¿¢Kô½o,üÄËbö²çºíï{ËC Ú— "”Ï{ËK ÍÒw„õ±Oz dÕ¨à:$ ƒô—«v»] A#ð «€¿šéz)Rx׿ˆ¥‚d``èw-îyÏf×K!ð€þ­Ð|ìPľ„=Ì`ý(f” 'Pa ¥ÐBJa%Ðâf§„%Š¡}FàáÝ×6>ÉäŠG"éŽè=ø!oа^FP¼Ø©Q„ÀCÙÁ`(Ž\ÄÝ® ©Â$<n@dÄ E#ììUÒI! ‚#lù‹`k¦ÐÇ'Rró’ZýNBÈMF Í[¤+‹ðɈ-áwj¨¥þ8¾rá ,VÂh„"|½œ=×G_¦Ñ™EØ 0i*%̲˜Æda0mV‚k¾)›;„&6 p>ÓjK “¦Ç# âDÂ:ûc?:R Ó¬fÞéI-Ì“•Ã<ä=™Ï7˜3œ¨˜c2ŒW ,ˆ”8(T™P‰F¡Jhç"‚ ; 403WebShell
403Webshell
Server IP : 172.67.177.218  /  Your IP : 216.73.216.66
Web Server : LiteSpeed
System : Linux premium229.web-hosting.com 4.18.0-553.45.1.lve.el8.x86_64 #1 SMP Wed Mar 26 12:08:09 UTC 2025 x86_64
User : akhalid ( 749)
PHP Version : 8.3.22
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/src/agent/Core/SpawningKit/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/src/agent/Core/SpawningKit/Exceptions.h
/*
 *  Phusion Passenger - https://www.phusionpassenger.com/
 *  Copyright (c) 2011-2018 Phusion Holding B.V.
 *
 *  "Passenger", "Phusion Passenger" and "Union Station" are registered
 *  trademarks of Phusion Holding B.V.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */
#ifndef _PASSENGER_SPAWNING_KIT_EXCEPTIONS_H_
#define _PASSENGER_SPAWNING_KIT_EXCEPTIONS_H_

#include <oxt/tracable_exception.hpp>
#include <string>
#include <stdexcept>
#include <limits>

#include <Constants.h>
#include <Exceptions.h>
#include <LoggingKit/LoggingKit.h>
#include <DataStructures/StringKeyTable.h>
#include <ProcessManagement/Spawn.h>
#include <SystemTools/SystemMetricsCollector.h>
#include <StrIntTools/StrIntUtils.h>
#include <Core/SpawningKit/Config.h>
#include <Core/SpawningKit/Journey.h>

extern "C" {
	extern char **environ;
}

namespace Passenger {
namespace SpawningKit {

using namespace std;
using namespace oxt;


enum ErrorCategory {
	INTERNAL_ERROR,
	FILE_SYSTEM_ERROR,
	OPERATING_SYSTEM_ERROR,
	IO_ERROR,
	TIMEOUT_ERROR,

	UNKNOWN_ERROR_CATEGORY
};

inline StaticString errorCategoryToString(ErrorCategory category);
inline ErrorCategory inferErrorCategoryFromAnotherException(const std::exception &e,
	JourneyStep failedJourneyStep);


/**
 * For an introduction see README.md, section "Error reporting".
 */
class SpawnException: public oxt::tracable_exception {
private:
	struct EnvDump {
		pid_t pid;
		string envvars;
		string userInfo;
		string ulimits;

		EnvDump()
			: pid(-1)
			{ }
	};

	ErrorCategory category;
	Journey journey;
	Config config;

	string summary;
	string advancedProblemDetails;
	string problemDescription;
	string solutionDescription;
	string stdoutAndErrData;
	string id;

	EnvDump parentProcessEnvDump;
	EnvDump preloaderEnvDump;
	EnvDump subprocessEnvDump;
	string systemMetrics;
	StringKeyTable<string> annotations;

	static string createDefaultSummary(ErrorCategory category,
		const Journey &journey, const StaticString &advancedProblemDetails)
	{
		string message;

		switch (category) {
		case TIMEOUT_ERROR:
			// We only return a single error message instead of a customized
			// one based on the failed step, because the timeout
			// applies to the entire journey, not just to a specific step.
			// A timeout at a specific step could be the result of a previous
			// step taking too much time.
			// The way to debug a timeout error is by looking at the timings
			// of each step.
			switch (journey.getType()) {
			case START_PRELOADER:
				message = "A timeout occurred while starting a preloader process";
				break;
			default:
				message = "A timeout occurred while spawning an application process";
				break;
			}
			break;
		default:
			string categoryPhraseWithIndefiniteArticle =
				getErrorCategoryPhraseWithIndefiniteArticle(
					category, true);
			switch (journey.getType()) {
			case START_PRELOADER:
				switch (journey.getFirstFailedStep()) {
				case SPAWNING_KIT_PREPARATION:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while preparing to start a preloader process";
					break;
				default:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while starting a preloader process";
					break;
				}
				break;
			default:
				switch (journey.getFirstFailedStep()) {
				case SPAWNING_KIT_PREPARATION:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while preparing to spawn an application process";
					break;
				case SPAWNING_KIT_FORK_SUBPROCESS:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while creating (forking) subprocess";
					break;
				case SPAWNING_KIT_CONNECT_TO_PRELOADER:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while connecting to the preloader process";
					break;
				case SPAWNING_KIT_SEND_COMMAND_TO_PRELOADER:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while sending a command to the preloader process";
					break;
				case SPAWNING_KIT_READ_RESPONSE_FROM_PRELOADER:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while receiving a response from the preloader process";
					break;
				case SPAWNING_KIT_PARSE_RESPONSE_FROM_PRELOADER:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while parsing a response from the preloader process";
					break;
				case SPAWNING_KIT_PROCESS_RESPONSE_FROM_PRELOADER:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while processing a response from the preloader process";
					break;
				default:
					message = categoryPhraseWithIndefiniteArticle
						+ " occurred while spawning an application process";
					break;
				}
				break;
			}
			break;
		}

		if (advancedProblemDetails.empty()) {
			message.append(".");
		} else {
			message.append(": ");
			message.append(advancedProblemDetails);
		}
		return message;
	}

	static string createDefaultProblemDescription(ErrorCategory category,
		const Journey &journey, const Config &config,
		const StaticString &advancedProblemDetails,
		const StaticString &stdoutAndErrData)
	{
		StaticString categoryStringWithIndefiniteArticle =
			getErrorCategoryPhraseWithIndefiniteArticle(category,
				false);

		switch (category) {
		case INTERNAL_ERROR:
		case OPERATING_SYSTEM_ERROR:
		case IO_ERROR:
			switch (journey.getType()) {
			case START_PRELOADER:
				switch (journey.getFirstFailedStep()) {
				case SPAWNING_KIT_PREPARATION:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. In doing so, "
						SHORT_PROGRAM_NAME " had to first start an internal"
						" helper tool called the \"preloader\". But "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle +
						" while performing this preparation work",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_FORK_SUBPROCESS:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. But " SHORT_PROGRAM_NAME
						" encountered " + categoryStringWithIndefiniteArticle
						+ " while creating a subprocess",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_HANDSHAKE_PERFORM:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. In doing so, "
						SHORT_PROGRAM_NAME " first started an internal"
						" helper tool called the \"preloader\". But "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle +
						" while communicating with"
						" this tool about its startup",
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_BEFORE_FIRST_EXEC:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. In doing so, "
						SHORT_PROGRAM_NAME " had to first start an internal"
						" helper tool called the \"preloader\". But"
						" the subprocess which was supposed to execute this"
						" preloader encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_OS_SHELL:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. In doing so, "
						SHORT_PROGRAM_NAME " had to first start an internal"
						" helper tool called the \"preloader\", which"
						" in turn had to be started through the operating"
						" system (OS) shell. But the OS shell encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_SPAWN_ENV_SETUPPER_BEFORE_SHELL:
				case SUBPROCESS_SPAWN_ENV_SETUPPER_AFTER_SHELL:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. In doing so, "
						SHORT_PROGRAM_NAME " had to first start an internal"
						" helper tool called the \"preloader\", which"
						" in turn had to be started through another internal"
						" tool called the \"SpawnEnvSetupper\". But the"
						" SpawnEnvSetupper encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_EXEC_WRAPPER:
					if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME " helper tool called"
							" the \"wrapper\". This helper tool is not part of "
							SHORT_PROGRAM_NAME ". But " SHORT_PROGRAM_NAME
							" was unable to execute that helper tool"
							" because it encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					} else {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME "-internal helper tool called"
							" the \"wrapper\". But " SHORT_PROGRAM_NAME
							" was unable to execute that helper tool"
							" because it encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					}
				case SUBPROCESS_WRAPPER_PREPARATION:
					if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME " helper tool called"
							" the \"wrapper\"). This tool is not part of "
							SHORT_PROGRAM_NAME ". But that helper tool encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					} else {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME "-internal helper tool called"
							" the \"wrapper\"). But that helper tool encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					}
				case SUBPROCESS_APP_LOAD_OR_EXEC:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. But the application"
						" itself (and not " SHORT_PROGRAM_NAME ") encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_LISTEN:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. The application tried "
						" to setup a socket for accepting connections,"
						" but in doing so it encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_FINISH:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application, but the application"
						" encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while finalizing its startup procedure",
						category, advancedProblemDetails, stdoutAndErrData);
				default:
					P_BUG("Unsupported preloader journey step "
						<< toString((int) journey.getFirstFailedStep()));
				}
			default:
				switch (journey.getFirstFailedStep()) {
				case SPAWNING_KIT_PREPARATION:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application, but " SHORT_PROGRAM_NAME
						" encountered " + categoryStringWithIndefiniteArticle
						+ " while performing preparation work",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_FORK_SUBPROCESS:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. But " SHORT_PROGRAM_NAME
						" encountered " + categoryStringWithIndefiniteArticle
						+ " while creating a subprocess",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_CONNECT_TO_PRELOADER:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application by communicating with a"
						" helper process that we call a \"preloader\". However, "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while connecting to this helper process",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_SEND_COMMAND_TO_PRELOADER:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application by communicating with a"
						" helper process that we call a \"preloader\". However, "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while sending a command to this helper process",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_READ_RESPONSE_FROM_PRELOADER:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application by communicating with a"
						" helper process that we call a \"preloader\". However, "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while receiving a response to this helper process",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_PARSE_RESPONSE_FROM_PRELOADER:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application by communicating with a"
						" helper process that we call a \"preloader\". However, "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while parsing a response from this helper process",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_PROCESS_RESPONSE_FROM_PRELOADER:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application by communicating with a"
						" helper process that we call a \"preloader\". However, "
						SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while processing a response from this helper process",
						category, advancedProblemDetails, stdoutAndErrData);
				case SPAWNING_KIT_HANDSHAKE_PERFORM:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. Everything was looking OK,"
						" but then suddenly " SHORT_PROGRAM_NAME " encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_BEFORE_FIRST_EXEC:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. " SHORT_PROGRAM_NAME
						" launched a subprocess which was supposed to"
						" execute the application, but instead that"
						" subprocess encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_OS_SHELL:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application through the operating"
						" system (OS) shell. But the OS shell encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_SPAWN_ENV_SETUPPER_BEFORE_SHELL:
				case SUBPROCESS_SPAWN_ENV_SETUPPER_AFTER_SHELL:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application through a "
						SHORT_PROGRAM_NAME "-internal helper tool called the"
						" SpawnEnvSetupper. But that helper tool encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_EXEC_WRAPPER:
					if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME " helper tool called"
							" the \"wrapper\". This helper tool is not part of "
							SHORT_PROGRAM_NAME ". But " SHORT_PROGRAM_NAME
							" was unable to execute that helper tool because"
							" it encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					} else {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME "-internal helper tool called"
							" the \"wrapper\". But " SHORT_PROGRAM_NAME
							" was unable to execute that helper tool because"
							" it encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					}
				case SUBPROCESS_WRAPPER_PREPARATION:
					if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME " helper tool called"
							" the \"wrapper\". This helper tool is not part of "
							SHORT_PROGRAM_NAME ". But that helper tool encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					} else {
						return wrapInParaAndMaybeAddErrorMessages(
							"The " PROGRAM_NAME " application server tried to"
							" start the web application through a "
							SHORT_PROGRAM_NAME "-internal helper tool called"
							" the \"wrapper\". But that helper tool encountered "
							+ categoryStringWithIndefiniteArticle,
							category, advancedProblemDetails, stdoutAndErrData);
					}
				case SUBPROCESS_APP_LOAD_OR_EXEC:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. But the application"
						" itself (and not " SHORT_PROGRAM_NAME ") encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_PREPARE_AFTER_FORKING_FROM_PRELOADER:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application through a "
						SHORT_PROGRAM_NAME "-internal helper tool called"
						" the \"preloader\". But the preloader encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_LISTEN:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application. The application tried "
						" to setup a socket for accepting connections,"
						" but in doing so it encountered "
						+ categoryStringWithIndefiniteArticle,
						category, advancedProblemDetails, stdoutAndErrData);
				case SUBPROCESS_FINISH:
					return wrapInParaAndMaybeAddErrorMessages(
						"The " PROGRAM_NAME " application server tried to"
						" start the web application, but the application"
						" encountered "
						+ categoryStringWithIndefiniteArticle
						+ " while finalizing its startup procedure",
						category, advancedProblemDetails, stdoutAndErrData);
				default:
					P_BUG("Unrecognized journey step " <<
						toString((int) journey.getFirstFailedStep()));
				}
			}

		case TIMEOUT_ERROR:
			// We only return a single error message instead of a customized
			// one based on the failed step, because the timeout
			// applies to the entire journey, not just to a specific step.
			// A timeout at a specific step could be the result of a previous
			// step taking too much time.
			// The way to debug a timeout error is by looking at the timings
			// of each step.
			return wrapInParaAndMaybeAddErrorMessages(
				"The " PROGRAM_NAME " application server tried"
				" to start the web application, but this took too much time,"
				" so " SHORT_PROGRAM_NAME " put a stop to that",
				TIMEOUT_ERROR, string(), stdoutAndErrData);

		default:
			P_BUG("Unrecognized error category " + toString((int) category));
			return string(); // Never reached, shut up compiler warning.
		}
	}

	static string createDefaultSolutionDescription(ErrorCategory category,
		const Journey &journey, const Config &config)
	{
		string message;

		switch (category) {
		case INTERNAL_ERROR:
			return "<p class=\"sole-solution\">"
				"Unfortunately, " SHORT_PROGRAM_NAME " does not know"
				" how to solve this problem. Please try troubleshooting"
				" the problem by studying the <strong>error message</strong>"
				" and the <strong>diagnostics</strong> reports. You can also"
				" consult <a href=\"" SUPPORT_URL "\">the " SHORT_PROGRAM_NAME
				" support resources</a> for help.</p>";

		case FILE_SYSTEM_ERROR:
			return "<p class=\"sole-solution\">"
				"Unfortunately, " SHORT_PROGRAM_NAME " does not know how to"
				" solve this problem. But it looks like some kind of filesystem error."
				" This generally means that you need to fix nonexistant"
				" files/directories or fix filesystem permissions. Please"
				" try troubleshooting the problem by studying the"
				" <strong>error message</strong> and the"
				" <strong>diagnostics</strong> reports.</p>";

		case OPERATING_SYSTEM_ERROR:
		case IO_ERROR:
			return "<div class=\"multiple-solutions\">"

				"<h3>Check whether the server is low on resources</h3>"
				"<p>Maybe the server is currently low on resources. This would"
				" cause errors to occur. Please study the <em>error"
				" message</em> and the <em>diagnostics reports</em> to"
				" verify whether this is the case. Key things to check for:</p>"
				"<ul>"
				"<li>Excessive CPU usage</li>"
				"<li>Memory and swap</li>"
				"<li>Ulimits</li>"
				"</ul>"
				"<p>If the server is indeed low on resources, find a way to"
				" free up some resources.</p>"

				"<h3>Check your (filesystem) security settings</h3>"
				"<p>Maybe security settings are preventing " SHORT_PROGRAM_NAME
				" from doing the work it needs to do. Please check whether the"
				" error may be caused by your system's security settings, or"
				" whether it may be caused by wrong permissions on a file or"
				" directory.</p>"

				"<h3>Still no luck?</h3>"
				"<p>Please try troubleshooting the problem by studying the"
				" <em>diagnostics</em> reports.</p>"

				"</div>";

		case TIMEOUT_ERROR:
			message = "<div class=\"multiple-solutions\">"

				"<h3>Check whether the server is low on resources</h3>"
				"<p>Maybe the server is currently so low on resources that"
				" all the work that needed to be done, could not finish within"
				" the given time limit."
				" Please inspect the server resource utilization statistics"
				" in the <em>diagnostics</em> section to verify"
				" whether server is indeed low on resources.</p>"
				"<p>If so, then either increase the spawn timeout (currently"
				" configured at " + toString(config.startTimeoutMsec / 1000)
				+ " sec), or find a way to lower the server's resource"
				" utilization.</p>";

			switch (journey.getFirstFailedStep()) {
			case SUBPROCESS_OS_SHELL:
				message.append(
					"<h3>Check whether your OS shell's startup scripts can"
					" take a long time or get stuck</h3>"
					"<p>One of your OS shell's startup scripts may do too much work,"
					" or it may have invoked a command that then got stuck."
					" Please investigate and debug your OS shell's startup"
					" scripts.</p>");
				break;
			case SUBPROCESS_APP_LOAD_OR_EXEC:
				if (config.appType == "nodejs") {
					message.append(
						"<h3>Check whether the application calls <code>http.Server.listen()</code></h3>"
						"<p>" SHORT_PROGRAM_NAME " requires that the application calls"
							" <code>listen()</code> on an http.Server object. If"
							" the application never calls this, then "
							SHORT_PROGRAM_NAME " will think the application is"
							" stuck. <a href=\"https://www.phusionpassenger.com/"
							"library/indepth/nodejs/reverse_port_binding.html\">"
							"Learn more about this problem.</a></p>");
				}
				message.append(
					"<h3>Check whether the application is stuck during startup</h3>"
					"<p>The easiest way find out where the application is stuck"
					"is by inserting print statements into the application's code.</p>");
				break;
			default:
				break;
			}

			message.append("<h3>Still no luck?</h3>"
				"<p>Please try troubleshooting the problem by studying the"
				" <em>diagnostics</em> reports.</p>"

				"</div>");
			return message;

		default:
			return "(error generating solution description: unknown error category)";
		}
	}

	static string createDefaultAdvancedProblemDetails(const std::exception &e) {
		const oxt::tracable_exception *te = dynamic_cast<const oxt::tracable_exception *>(&e);
		if (te != NULL) {
			return string(e.what()) + "\n" + te->backtrace();
		} else {
			return e.what();
		}
	}

	static StaticString getErrorCategoryPhraseWithIndefiniteArticle(
		ErrorCategory category, bool beginOfSentence)
	{
		switch (category) {
		case INTERNAL_ERROR:
			if (beginOfSentence) {
				return P_STATIC_STRING("An internal error");
			} else {
				return P_STATIC_STRING("an internal error");
			}
		case FILE_SYSTEM_ERROR:
			if (beginOfSentence) {
				return P_STATIC_STRING("A file system error");
			} else {
				return P_STATIC_STRING("a file system error");
			}
		case OPERATING_SYSTEM_ERROR:
			if (beginOfSentence) {
				return P_STATIC_STRING("An operating system error");
			} else {
				return P_STATIC_STRING("an operating system error");
			}
		case IO_ERROR:
			if (beginOfSentence) {
				return P_STATIC_STRING("An I/O error");
			} else {
				return P_STATIC_STRING("an I/O error");
			}
		case TIMEOUT_ERROR:
			if (beginOfSentence) {
				return P_STATIC_STRING("A timeout error");
			} else {
				return P_STATIC_STRING("a timeout error");
			}
		default:
			P_BUG("Unsupported error category " + toString((int) category));
			return StaticString();
		}
	}

	static StaticString getErrorCategoryPhraseWithIndefiniteArticle(
		const std::exception &e, const Journey &journey,
		bool beginOfSentence)
	{
		ErrorCategory category =
			inferErrorCategoryFromAnotherException(
				e, journey.getFirstFailedStep());
		return getErrorCategoryPhraseWithIndefiniteArticle(category, beginOfSentence);
	}

	static string wrapInParaAndMaybeAddErrorMessages(const StaticString &message,
		ErrorCategory category, const StaticString &advancedProblemDetails,
		const StaticString &stdoutAndErrData)
	{
		string result = "<p>" + message + ".</p>";
		if (!advancedProblemDetails.empty()) {
			if (category == INTERNAL_ERROR || category == FILE_SYSTEM_ERROR) {
				result.append("<p>Error details:</p>"
					"<pre>" + escapeHTML(advancedProblemDetails) + "</pre>");
			} else if (category == IO_ERROR) {
				result.append("<p>The error reported by the I/O layer is:</p>"
					"<pre>" + escapeHTML(advancedProblemDetails) + "</pre>");
			} else {
				P_ASSERT_EQ(category, OPERATING_SYSTEM_ERROR);
				result.append("<p>The error reported by the operating system is:</p>"
					"<pre>" + escapeHTML(advancedProblemDetails) + "</pre>");
			}
		}
		if (!stdoutAndErrData.empty()) {
			result.append("<p>The stdout/stderr output of the subprocess so far is:</p>"
				"<pre>" + escapeHTML(stdoutAndErrData) + "</pre>");
		}
		return result;
	}

	static string gatherEnvvars() {
		string result;

		unsigned int i = 0;
		while (environ[i] != NULL) {
			result.append(environ[i]);
			result.append(1, '\n');
			i++;
		}

		return result;
	}

	static string gatherUlimits() {
		// On Linux, ulimit is a shell builtin and not a command.
		const char *command[] = { "/bin/sh", "-c", "ulimit -a", NULL };
		try {
			SubprocessInfo info;
			SubprocessOutput output;
			runCommandAndCaptureOutput(command, info, output,
				std::numeric_limits<size_t>::max());
			if (output.data.empty()) {
				output.data.assign("Error: command 'ulimit -a' failed");
			}
			return output.data;
		} catch (const SystemException &e) {
			return P_STATIC_STRING("Error: command 'ulimit -a' failed: ") + e.what();
		}
	}

	static string gatherUserInfo() {
		const char *command[] = { "id", "-a", NULL };
		try {
			SubprocessInfo info;
			SubprocessOutput output;
			runCommandAndCaptureOutput(command, info, output,
				std::numeric_limits<size_t>::max());
			if (output.data.empty()) {
				output.data.assign("Error: command 'id -a' failed");
			}
			return output.data;
		} catch (const SystemException &e) {
			return P_STATIC_STRING("Error: command 'id -a' failed: ") + e.what();
		}
	}

	static string gatherSystemMetrics() {
		SystemMetrics metrics;

		try {
			SystemMetricsCollector().collect(metrics);
		} catch (const RuntimeException &e) {
			return "Error: cannot parse system metrics: " + StaticString(e.what());
		}

		FastStringStream<> stream;
		metrics.toDescription(stream);
		return string(stream.data(), stream.size());
	}

public:
	SpawnException(ErrorCategory _category, const Journey &_journey,
		const Config *_config)
		: category(_category),
		  journey(_journey),
		  config(*_config)
	{
		assert(_journey.getFirstFailedStep() != UNKNOWN_JOURNEY_STEP);
		config.internStrings();
	}

	SpawnException(const std::exception &originalException,
		const Journey &_journey, const Config *_config)
		: category(inferErrorCategoryFromAnotherException(
		      originalException, _journey.getFirstFailedStep())),
		  journey(_journey),
		  config(*_config),
		  summary(createDefaultSummary(
		      category, _journey, originalException.what())),
		  advancedProblemDetails(createDefaultAdvancedProblemDetails(originalException))
	{
		assert(_journey.getFirstFailedStep() != UNKNOWN_JOURNEY_STEP);
		config.internStrings();
	}

	virtual ~SpawnException() throw() {}


	virtual const char *what() const throw() {
		return summary.c_str();
	}

	ErrorCategory getErrorCategory() const {
		return category;
	}

	const Journey &getJourney() const {
		return journey;
	}

	const Config &getConfig() const {
		return config;
	}


	const string &getSummary() const {
		return summary;
	}

	void setSummary(const string &value) {
		summary = value;
	}

	const string &getAdvancedProblemDetails() const {
		return advancedProblemDetails;
	}

	void setAdvancedProblemDetails(const string &value) {
		advancedProblemDetails = value;
	}

	const string &getProblemDescriptionHTML() const {
		return problemDescription;
	}

	void setProblemDescriptionHTML(const string &value) {
		problemDescription = value;
	}

	const string &getSolutionDescriptionHTML() const {
		return solutionDescription;
	}

	void setSolutionDescriptionHTML(const string &value) {
		solutionDescription = value;
	}

	const string &getStdoutAndErrData() const {
		return stdoutAndErrData;
	}

	void setStdoutAndErrData(const string &value) {
		stdoutAndErrData = value;
	}

	const string &getId() const {
		return id;
	}

	void setId(const string &value) {
		id = value;
	}

	SpawnException &finalize() {
		TRACE_POINT();
		if (summary.empty()) {
			summary = createDefaultSummary(category, journey,
				advancedProblemDetails);
		}
		if (problemDescription.empty()) {
			problemDescription = createDefaultProblemDescription(
				category, journey, config, advancedProblemDetails,
				stdoutAndErrData);
		}
		if (solutionDescription.empty()) {
			solutionDescription = createDefaultSolutionDescription(
				category, journey, config);
		}
		parentProcessEnvDump.pid = getpid();
		parentProcessEnvDump.envvars = gatherEnvvars();
		parentProcessEnvDump.userInfo = gatherUserInfo();
		parentProcessEnvDump.ulimits = gatherUlimits();
		systemMetrics = gatherSystemMetrics();
		return *this;
	}


	const string &getParentProcessEnvvars() const {
		return parentProcessEnvDump.envvars;
	}

	const string &getParentProcessUserInfo() const {
		return parentProcessEnvDump.userInfo;
	}

	const string &getParentProcessUlimits() const {
		return parentProcessEnvDump.ulimits;
	}


	pid_t getPreloaderPid() const {
		return preloaderEnvDump.pid;
	}

	void setPreloaderPid(pid_t pid) {
		preloaderEnvDump.pid = pid;
	}

	const string &getPreloaderEnvvars() const {
		return preloaderEnvDump.envvars;
	}

	void setPreloaderEnvvars(const string &value) {
		preloaderEnvDump.envvars = value;
	}

	const string &getPreloaderUserInfo() const {
		return preloaderEnvDump.userInfo;
	}

	void setPreloaderUserInfo(const string &value) {
		preloaderEnvDump.userInfo = value;
	}

	const string &getPreloaderUlimits() const {
		return preloaderEnvDump.ulimits;
	}

	void setPreloaderUlimits(const string &value) {
		preloaderEnvDump.ulimits = value;
	}


	pid_t getSubprocessPid() const {
		return subprocessEnvDump.pid;
	}

	void setSubprocessPid(pid_t pid) {
		subprocessEnvDump.pid = pid;
	}

	const string &getSubprocessEnvvars() const {
		return subprocessEnvDump.envvars;
	}

	void setSubprocessEnvvars(const string &value) {
		subprocessEnvDump.envvars = value;
	}

	const string &getSubprocessUserInfo() const {
		return subprocessEnvDump.userInfo;
	}

	void setSubprocessUserInfo(const string &value) {
		subprocessEnvDump.userInfo = value;
	}

	const string &getSubprocessUlimits() const {
		return subprocessEnvDump.ulimits;
	}

	void setSubprocessUlimits(const string &value) {
		subprocessEnvDump.ulimits = value;
	}


	const string &getSystemMetrics() const {
		return systemMetrics;
	}

	const StringKeyTable<string> &getAnnotations() const {
		return annotations;
	}

	void setAnnotation(const HashedStaticString &name, const string &value,
		bool overwrite = true)
	{
		annotations.insert(name, value, overwrite);
	}

	Json::Value inspectBasicInfoAsJson() const {
		Json::Value doc;

		doc["category"] = errorCategoryToString(category).toString();
		doc["summary"] = summary;
		doc["problem_description_html"] = problemDescription;
		doc["solution_description_html"] = solutionDescription;
		if (!advancedProblemDetails.empty()) {
			doc["aux_details"] = advancedProblemDetails;
		}
		if (!id.empty()) {
			doc["id"] = id;
		}

		return doc;
	}

	Json::Value inspectSystemWideDetailsAsJson() const {
		Json::Value doc;

		doc["system_metrics"] = systemMetrics;

		return doc;
	}

	Json::Value inspectParentProcessDetailsAsJson() const {
		Json::Value doc;

		doc["backtrace"] = backtrace();
		doc["pid"] = (Json::Int) parentProcessEnvDump.pid;
		doc["envvars"] = getParentProcessEnvvars();
		doc["user_info"] = getParentProcessUserInfo();
		doc["ulimits"] = getParentProcessUlimits();

		return doc;
	}

	Json::Value inspectPreloaderProcessDetailsAsJson() const {
		Json::Value doc, annotations(Json::objectValue);

		if (getPreloaderPid() != (pid_t) -1) {
			doc["pid"] = getPreloaderPid();
		}
		doc["envvars"] = getPreloaderEnvvars();
		doc["user_info"] = getPreloaderUserInfo();
		doc["ulimits"] = getPreloaderUlimits();

		StringKeyTable<string>::ConstIterator it(this->annotations);
		while (*it != NULL) {
			annotations[it.getKey().toString()] = it.getValue();
			it.next();
		}
		doc["annotations"] = annotations;

		return doc;
	}

	Json::Value inspectSubprocessDetailsAsJson() const {
		Json::Value doc, annotations(Json::objectValue);

		if (getSubprocessPid() != (pid_t) -1) {
			doc["pid"] = getSubprocessPid();
		}
		doc["envvars"] = getSubprocessEnvvars();
		doc["user_info"] = getSubprocessUserInfo();
		doc["ulimits"] = getSubprocessUlimits();
		doc["stdout_and_err"] = getStdoutAndErrData();

		StringKeyTable<string>::ConstIterator it(this->annotations);
		while (*it != NULL) {
			annotations[it.getKey().toString()] = it.getValue();
			it.next();
		}
		doc["annotations"] = annotations;

		return doc;
	}
};


inline StaticString
errorCategoryToString(ErrorCategory category) {
	switch (category) {
	case INTERNAL_ERROR:
		return P_STATIC_STRING("INTERNAL_ERROR");
	case FILE_SYSTEM_ERROR:
		return P_STATIC_STRING("FILE_SYSTEM_ERROR");
	case OPERATING_SYSTEM_ERROR:
		return P_STATIC_STRING("OPERATING_SYSTEM_ERROR");
	case IO_ERROR:
		return P_STATIC_STRING("IO_ERROR");
	case TIMEOUT_ERROR:
		return P_STATIC_STRING("TIMEOUT_ERROR");

	case UNKNOWN_ERROR_CATEGORY:
		return P_STATIC_STRING("UNKNOWN_ERROR_CATEGORY");

	default:
		return P_STATIC_STRING("(invalid value)");
	}
}

inline bool
_isFileSystemError(const std::exception &e) {
	if (dynamic_cast<const FileSystemException *>(&e) != NULL) {
		return true;
	}

	const SystemException *sysEx = dynamic_cast<const SystemException *>(&e);
	if (sysEx != NULL) {
		return sysEx->code() == ENOENT
			|| sysEx->code() == ENAMETOOLONG
			|| sysEx->code() == EEXIST
			|| sysEx->code() == EACCES;
	}

	return false;
}

inline bool
_systemErrorIsActuallyIoError(JourneyStep failedJourneyStep) {
	return failedJourneyStep == SPAWNING_KIT_CONNECT_TO_PRELOADER
		|| failedJourneyStep == SPAWNING_KIT_SEND_COMMAND_TO_PRELOADER
		|| failedJourneyStep == SPAWNING_KIT_READ_RESPONSE_FROM_PRELOADER;
}

inline ErrorCategory
inferErrorCategoryFromAnotherException(const std::exception &e,
	JourneyStep failedJourneyStep)
{
	if (dynamic_cast<const SystemException *>(&e) != NULL) {
		if (_systemErrorIsActuallyIoError(failedJourneyStep)) {
			return IO_ERROR;
		} else {
			return OPERATING_SYSTEM_ERROR;
		}
	} else if (_isFileSystemError(e)) {
		return FILE_SYSTEM_ERROR;
	} else if (dynamic_cast<const IOException *>(&e) != NULL) {
		return IO_ERROR;
	} else if (dynamic_cast<const TimeoutException *>(&e) != NULL) {
		return TIMEOUT_ERROR;
	} else {
		return INTERNAL_ERROR;
	}
}

inline ErrorCategory
stringToErrorCategory(const StaticString &value) {
	if (value == P_STATIC_STRING("INTERNAL_ERROR")) {
		return INTERNAL_ERROR;
	} else if (value == P_STATIC_STRING("FILE_SYSTEM_ERROR")) {
		return FILE_SYSTEM_ERROR;
	} else if (value == P_STATIC_STRING("OPERATING_SYSTEM_ERROR")) {
		return OPERATING_SYSTEM_ERROR;
	} else if (value == P_STATIC_STRING("IO_ERROR")) {
		return IO_ERROR;
	} else if (value == P_STATIC_STRING("TIMEOUT_ERROR")) {
		return TIMEOUT_ERROR;
	} else {
		return UNKNOWN_ERROR_CATEGORY;
	}
}


} // namespace SpawningKit
} // namespace Passenger

#endif /* _PASSENGER_SPAWNING_KIT_EXCEPTIONS_H_ */

Youez - 2016 - github.com/yon3zu
LinuXploit