2020#include "close_fds.h"
2121#include "seccomp_notify.h"
2222#include "runtime_args.h"
23+ #include "healthcheck.h"
2324
2425#include <sys/stat.h>
2526#include <locale.h>
@@ -46,7 +47,6 @@ int main(int argc, char *argv[])
4647 _cleanup_close_ int dev_null_r_cleanup = -1 ;
4748 _cleanup_close_ int dev_null_w_cleanup = -1 ;
4849 _cleanup_close_ int dummyfd = -1 ;
49-
5050 int initialize_ec = initialize_cli (argc , argv );
5151 if (initialize_ec >= 0 ) {
5252 exit (initialize_ec );
@@ -396,7 +396,6 @@ int main(int argc, char *argv[])
396396 }
397397
398398 container_pid = atoi (contents );
399- ndebugf ("container PID: %d" , container_pid );
400399
401400 g_hash_table_insert (pid_to_handler , (pid_t * )& container_pid , container_exit_cb );
402401
@@ -408,6 +407,87 @@ int main(int argc, char *argv[])
408407 if ((opt_api_version >= 1 || !opt_exec ) && sync_pipe_fd >= 0 )
409408 write_or_close_sync_fd (& sync_pipe_fd , container_pid , NULL );
410409
410+ /* Start healthcheck timers if healthcheck command is provided */
411+ if (opt_healthcheck_cmd != NULL ) {
412+
413+ healthcheck_config_t config ;
414+ memset (& config , 0 , sizeof (config ));
415+
416+ /* Parse healthcheck command and arguments into array */
417+ /* Count total arguments: command + args + NULL terminator */
418+ int argc = 1 ; // At least the command
419+ if (opt_healthcheck_args != NULL ) {
420+ for (int i = 0 ; opt_healthcheck_args [i ] != NULL ; i ++ ) {
421+ argc ++ ;
422+ }
423+ }
424+
425+ /* Allocate array for command and arguments */
426+ config .test = calloc (argc + 1 , sizeof (char * ));
427+ if (config .test == NULL ) {
428+ pexit ("Failed to allocate memory for healthcheck command" );
429+ }
430+
431+ /* Copy command */
432+ config .test [0 ] = strdup (opt_healthcheck_cmd );
433+ if (config .test [0 ] == NULL ) {
434+ pexit ("Failed to duplicate healthcheck command" );
435+ }
436+
437+ /* Copy arguments */
438+ if (opt_healthcheck_args != NULL ) {
439+ for (int i = 0 ; opt_healthcheck_args [i ] != NULL ; i ++ ) {
440+ config .test [i + 1 ] = strdup (opt_healthcheck_args [i ]);
441+ if (config .test [i + 1 ] == NULL ) {
442+ /* Clean up on error */
443+ for (int j = 0 ; j <= i ; j ++ ) {
444+ free (config .test [j ]);
445+ }
446+ free (config .test );
447+ pexit ("Failed to duplicate healthcheck argument" );
448+ }
449+ }
450+ }
451+ config .test [argc ] = NULL ; /* NULL terminator */
452+
453+ /* Set healthcheck parameters from CLI, using defaults for -1 values */
454+ config .enabled = true;
455+ config .interval = opt_healthcheck_interval != -1 ? opt_healthcheck_interval : 30 ;
456+ config .timeout = opt_healthcheck_timeout != -1 ? opt_healthcheck_timeout : 30 ;
457+ config .retries = opt_healthcheck_retries != -1 ? opt_healthcheck_retries : 3 ;
458+ /* First healthcheck runs immediately, then after 'interval' seconds.
459+ * Here we give a default of 10 seconds to allow container to fully initialize.
460+ * If the user knows the container will take less time to initialize, they can set the start_period to a lower value.
461+ */
462+ config .start_period = opt_healthcheck_start_period != -1 ? opt_healthcheck_start_period : 10 ;
463+
464+ /* Validate healthcheck configuration */
465+ if (!healthcheck_validate_config (& config )) {
466+ nwarnf ("Invalid healthcheck configuration for container %s" , opt_cid );
467+ healthcheck_config_free (& config );
468+ return 1 ;
469+ }
470+
471+ healthcheck_timer_t * timer = healthcheck_timer_new (opt_cid , & config );
472+ if (timer != NULL ) {
473+ /* Start healthcheck with a 3-second delay to allow container to fully initialize in
474+ addition to the default of 10 seconds.
475+ */
476+ if (g_timeout_add_seconds (3 , healthcheck_delayed_start_callback , timer )) {
477+ active_healthcheck_timer = timer ;
478+ ninfof ("Scheduled healthcheck for container %s (will start after 3s delay)" , opt_cid );
479+ } else {
480+ nwarnf ("Failed to schedule delayed healthcheck for container %s" , opt_cid );
481+ healthcheck_timer_free (timer );
482+ }
483+ } else {
484+ nwarnf ("Failed to create healthcheck timer for container %s" , opt_cid );
485+ }
486+
487+ /* Always free the config, regardless of success or failure */
488+ healthcheck_config_free (& config );
489+ }
490+
411491#ifdef __linux__
412492 setup_oom_handling (container_pid );
413493#endif
@@ -495,6 +575,9 @@ int main(int argc, char *argv[])
495575 g_source_remove (signal_fd_tag );
496576 close (signal_fd );
497577
578+ /* Cleanup healthcheck timers */
579+ healthcheck_cleanup ();
580+
498581 /*
499582 * Podman injects some fd's into the conmon process so that exposed ports are kept busy while
500583 * the container runs. Close them before we notify the container exited, so that they can be
0 commit comments