Revision: 23892 http://trac.macosforge.org/projects/launchd/changeset/23892 Author: dsorresso@apple.com Date: 2009-04-10 15:06:38 -0700 (Fri, 10 Apr 2009) Log Message: ----------- <rdar://problem/6757199> ResetAtClose should handle the case of a failed exec(2) Modified Paths: -------------- trunk/launchd/src/launch.h trunk/launchd/src/launch_priv.h trunk/launchd/src/launchd_core_logic.c Modified: trunk/launchd/src/launch.h =================================================================== --- trunk/launchd/src/launch.h 2009-04-10 07:43:38 UTC (rev 23891) +++ trunk/launchd/src/launch.h 2009-04-10 22:06:38 UTC (rev 23892) @@ -110,6 +110,7 @@ #define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose" #define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn" +#define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash" #define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit" #define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState" Modified: trunk/launchd/src/launch_priv.h =================================================================== --- trunk/launchd/src/launch_priv.h 2009-04-10 07:43:38 UTC (rev 23891) +++ trunk/launchd/src/launch_priv.h 2009-04-10 22:06:38 UTC (rev 23892) @@ -75,7 +75,6 @@ #define LAUNCH_JOBKEY_MACH_TASKSPECIALPORT "TaskSpecialPort" #define LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT "HostSpecialPort" #define LAUNCH_JOBKEY_MACH_ENTERKERNELDEBUGGERONCLOSE "EnterKernelDebuggerOnClose" -#define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash" typedef struct _launch *launch_t; Modified: trunk/launchd/src/launchd_core_logic.c =================================================================== --- trunk/launchd/src/launchd_core_logic.c 2009-04-10 07:43:38 UTC (rev 23891) +++ trunk/launchd/src/launchd_core_logic.c 2009-04-10 22:06:38 UTC (rev 23892) @@ -168,18 +168,21 @@ job_t job; unsigned int gen_num; mach_port_name_t port; - unsigned int isActive :1, - reset :1, - recv :1, - hide :1, - kUNCServer :1, - per_user_hack :1, - debug_on_close :1, - per_pid :1, - delete_on_destruction :1, - drain_one :1, - drain_all :1, - special_port_num :22; + unsigned int isActive :1, + reset :1, + recv :1, + hide :1, + kUNCServer :1, + per_user_hack :1, + debug_on_close :1, + per_pid :1, + delete_on_destruction :1, + drain_one_on_crash :1, + drain_all_on_crash :1, + /* Don't let the size of this field to get too small. It has to be large enough + * to represent the reasonable range of special port numbers. + */ + special_port_num :20; const char name[0]; }; @@ -534,6 +537,7 @@ has_console :1, /* The job owns the console. */ clean_exit_timer_expired :1, /* The job was clean, received SIGKILL and failed to exit after LAUNCHD_CLEAN_KILL_TIMER seconds. */ embedded_special_privileges :1, /* The job runs as a non-root user on embedded but has select privileges of the root user. */ + did_exec :1, /* The job exec(2)ed successfully. */ migratory :1; /* The (anonymous) job called vprocmgr_switch_to_session(). */ mode_t mask; pid_t tracing_pid; @@ -2728,14 +2732,18 @@ j->reaped = true; struct machservice *msi = NULL; - if( j->crashed ) { + if( j->crashed || !(j->did_exec || j->anonymous) ) { SLIST_FOREACH( msi, &j->machservices, sle ) { - if( !msi->isActive && (msi->drain_one || msi->drain_all) ) { + if( j->crashed && !msi->isActive && (msi->drain_one_on_crash || msi->drain_all_on_crash) ) { machservice_drain_port(msi); } + + if( !j->did_exec && msi->reset && job_assumes(j, !msi->isActive) ) { + machservice_resetport(j, msi); + } } } - + struct suspended_peruser *spi = NULL; while( (spi = LIST_FIRST(&j->suspended_perusers)) ) { job_log(j, LOG_ERR, "Job exited before resuming per-user launchd for UID %u. Will forcibly resume.", spi->j->mach_uid); @@ -3270,6 +3278,7 @@ LIST_INSERT_HEAD(&label_hash[hash_label(j->label)], j, label_hash_sle); } } else { + j->did_exec = true; job_log(j, LOG_DEBUG, "Program changed"); } } @@ -3627,6 +3636,7 @@ job_log(j, LOG_DEBUG, "Started as PID: %u", c); + j->did_exec = false; j->checkedin = false; j->start_pending = false; j->reaped = false; @@ -3677,7 +3687,7 @@ SLIST_REMOVE(&j->env, ei, envitem, sle); } } - + if (likely(!j->stall_before_exec)) { job_uncork_fork(j); } @@ -3778,7 +3788,7 @@ errno = psf(NULL, file2exec, NULL, &spattr, (char *const*)argv, environ); job_log_error(j, LOG_ERR, "posix_spawn(\"%s\", ...)", file2exec); - + #if HAVE_SANDBOX out_bad: #endif @@ -5464,9 +5474,9 @@ if( strcasecmp(key, LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH) == 0 ) { const char *option = launch_data_get_string(obj); if( strcasecmp(option, "One") == 0 ) { - ms->drain_one = true; + ms->drain_one_on_crash = true; } else if( strcasecmp(option, "All") == 0 ) { - ms->drain_all = true; + ms->drain_all_on_crash = true; } } break; @@ -6061,14 +6071,13 @@ void machservice_drain_port(struct machservice *ms) { - if (!job_assumes(ms->job, ms->job->crashed == true)) { - return; - } + bool drain_one = ms->drain_one_on_crash; + bool drain_all = ms->drain_all_on_crash; - if( ms->drain_one == false && ms->drain_all == false ) { + if( !job_assumes(ms->job, (drain_one || drain_all) == true) ) { return; } - + job_log(ms->job, LOG_INFO, "Draining %s...", ms->name); char req_buff[sizeof(union __RequestUnion__catch_mach_exc_subsystem) * 2]; @@ -6103,7 +6112,7 @@ break; } } - } while( ms->drain_all && mr != MACH_RCV_TIMED_OUT ); + } while( drain_all && mr != MACH_RCV_TIMED_OUT ); } void @@ -6257,7 +6266,7 @@ * ReceiveRight(N - 1)Returned */ - if( ms->drain_one || ms->drain_all ) { + if( ms->drain_one_on_crash || ms->drain_all_on_crash ) { if( j->crashed && j->reaped ) { job_log(j, LOG_DEBUG, "Job has crashed. Draining port..."); machservice_drain_port(ms); @@ -6267,7 +6276,6 @@ } ms->isActive = false; - if (ms->delete_on_destruction) { machservice_delete(j, ms, false); } else if (ms->reset) { @@ -7588,6 +7596,7 @@ } } + return BOOTSTRAP_SUCCESS; }