int main(int argc, const char *argv[]) { if (argc == 1) { print_help_text(); return 1; } argc--; argv++; // The command name is now the first argument return run_command(argc, argv); }
int main (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; const gchar *simulation_filename, *introspection_filename; gchar *simulation_code, *introspection_xml; GPtrArray/*<DfsmObject>*/ *simulated_objects; guint i; gboolean found_unreachable_states = FALSE; /* Set up localisation. */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif g_set_application_name (_("D-Bus Simulator Lint")); /* Parse command line options */ context = g_option_context_new (_("[simulation code file] [introspection XML file]")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); g_option_context_set_summary (context, _("Checks the FSM simulation code for a D-Bus client–server conversation simulation.")); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_printerr (_("Error parsing command line options: %s"), error->message); g_printerr ("\n"); print_help_text (context); g_error_free (error); g_option_context_free (context); exit (STATUS_INVALID_OPTIONS); } /* Extract the simulation and the introspection filenames. */ if (argc < 3) { g_printerr (_("Error parsing command line options: %s"), _("Simulation and introspection filenames must be provided")); g_printerr ("\n"); print_help_text (context); g_option_context_free (context); exit (STATUS_INVALID_OPTIONS); } simulation_filename = argv[1]; introspection_filename = argv[2]; g_option_context_free (context); /* Load the files. */ g_file_get_contents (simulation_filename, &simulation_code, NULL, &error); if (error != NULL) { g_printerr (_("Error loading simulation code from file ‘%s’: %s"), simulation_filename, error->message); g_printerr ("\n"); g_error_free (error); exit (STATUS_UNREADABLE_FILE); } g_file_get_contents (introspection_filename, &introspection_xml, NULL, &error); if (error != NULL) { g_printerr (_("Error loading introspection XML from file ‘%s’: %s"), introspection_filename, error->message); g_printerr ("\n"); g_error_free (error); g_free (simulation_code); exit (STATUS_UNREADABLE_FILE); } /* Build the DfsmObjects and thus check the simulation code. */ simulated_objects = dfsm_object_factory_from_data (simulation_code, introspection_xml, &error); g_free (introspection_xml); g_free (simulation_code); if (error != NULL) { g_printerr (_("Error creating simulated DFSMs: %s"), error->message); g_printerr ("\n"); g_error_free (error); exit (STATUS_INVALID_CODE); } /* Check the reachability of all of the states in each object. */ for (i = 0; i < simulated_objects->len; i++) { DfsmObject *simulated_object; DfsmMachine *machine; GArray/*<DfsmStateReachability>*/ *reachability; DfsmMachineStateNumber state; simulated_object = DFSM_OBJECT (g_ptr_array_index (simulated_objects, i)); machine = dfsm_object_get_machine (simulated_object); reachability = dfsm_machine_calculate_state_reachability (machine); for (state = 0; state < reachability->len; state++) { switch (g_array_index (reachability, DfsmStateReachability, state)) { case DFSM_STATE_UNREACHABLE: g_printerr (_("State ‘%s’ of object ‘%s’ is unreachable."), dfsm_machine_get_state_name (machine, state), dfsm_object_get_object_path (simulated_object)); g_printerr ("\n"); /* Note the error, but continue so that we detect any other unreachable states. */ found_unreachable_states = TRUE; break; case DFSM_STATE_POSSIBLY_REACHABLE: case DFSM_STATE_REACHABLE: /* Nothing to do. */ break; default: g_assert_not_reached (); } } g_array_unref (reachability); } g_ptr_array_unref (simulated_objects); /* Did we find at least one unreachable state? Yes? Shame. */ if (found_unreachable_states == TRUE) { return STATUS_UNREACHABLE_STATES; } return STATUS_SUCCESS; }
int main (int argc, char *argv[]) { GError *error = NULL; GOptionGroup *option_group; GOptionContext *context; const gchar *simulation_filename, *introspection_filename; gchar *simulation_code, *introspection_xml; MainData data; GPtrArray/*<DfsmObject>*/ *simulated_objects; const gchar *test_program_name; GPtrArray/*<string>*/ *test_program_argv; guint i; gchar *time_str, *command_line, *log_header, *seed_str; GDateTime *date_time; GFile *working_directory_file, *dbus_daemon_config_file; /* Set up localisation. */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif g_set_application_name (_("D-Bus Simulator")); /* Take a copy of the command line, for use in printing the log headers later. */ command_line = g_strjoinv (" ", argv); /* Parse command line options */ context = g_option_context_new (_("[simulation code file] [introspection XML file] -- [executable-file] [arguments]")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); g_option_context_set_summary (context, _("Simulates the server in a D-Bus client–server conversation.")); g_option_context_add_main_entries (context, main_entries, GETTEXT_PACKAGE); /* Logging option group */ option_group = g_option_group_new ("logging", _("Logging Options:"), _("Show help options for output logging"), NULL, NULL); g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE); g_option_group_add_entries (option_group, logging_entries); g_option_context_add_group (context, option_group); /* Testing option group */ option_group = g_option_group_new ("testing", _("Testing Options:"), _("Show help options for test runs and timeouts"), NULL, NULL); g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE); g_option_group_add_entries (option_group, testing_entries); g_option_context_add_group (context, option_group); /* Test program option group */ option_group = g_option_group_new ("test-program", _("Test Program Options:"), _("Show help options for the program under test"), NULL, NULL); g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE); g_option_group_add_entries (option_group, test_program_entries); g_option_context_add_group (context, option_group); /* dbus-daemon option group */ option_group = g_option_group_new ("dbus-daemon", _("D-Bus Daemon Options:"), _("Show help options for the dbus-daemon"), NULL, NULL); g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE); g_option_group_add_entries (option_group, dbus_daemon_entries); g_option_context_add_group (context, option_group); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_printerr (_("Error parsing command line options: %s"), error->message); g_printerr ("\n"); print_help_text (context); g_error_free (error); g_option_context_free (context); g_free (command_line); exit (STATUS_INVALID_OPTIONS); } /* Extract the simulation and the introspection filenames. */ if (argc < 3) { g_printerr (_("Error parsing command line options: %s"), _("Simulation and introspection filenames must be provided")); g_printerr ("\n"); print_help_text (context); g_option_context_free (context); g_free (command_line); exit (STATUS_INVALID_OPTIONS); } simulation_filename = argv[1]; introspection_filename = argv[2]; /* Extract the remaining arguments */ if (argc < 4) { g_printerr (_("Error parsing command line options: %s"), _("Test program must be provided")); g_printerr ("\n"); print_help_text (context); g_option_context_free (context); g_free (command_line); exit (STATUS_INVALID_OPTIONS); } /* Work out where the test program's command line starts. g_option_context_parse() sometimes leaves the ‘--’ in argv. */ if (strcmp (argv[3], "--") == 0) { i = 4; } else { i = 3; } test_program_name = argv[i++]; test_program_argv = g_ptr_array_new_with_free_func (g_free); for (; i < (guint) argc; i++) { g_ptr_array_add (test_program_argv, g_strdup (argv[i])); } g_option_context_free (context); /* Set up logging. */ dsim_logging_init (test_program_log_file, test_program_log_fd, dbus_daemon_log_file, dbus_daemon_log_fd, simulator_log_file, simulator_log_fd, &error); if (error != NULL) { g_printerr (_("Error setting up logging: %s"), error->message); g_printerr ("\n"); g_error_free (error); g_free (command_line); exit (STATUS_LOGGING_PROBLEM); } /* Output a log header to each of the log streams. */ date_time = g_date_time_new_now_utc (); time_str = g_date_time_format (date_time, "%F %TZ"); g_date_time_unref (date_time); log_header = g_strdup_printf (_("Bendy Bus (number %s) left the depot at %s using command line: %s"), PACKAGE_VERSION, time_str, command_line); g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "%s", log_header); g_log (dsim_logging_get_domain_name (DSIM_LOG_DBUS_DAEMON), G_LOG_LEVEL_MESSAGE, "%s", log_header); g_log (dsim_logging_get_domain_name (DSIM_LOG_TEST_PROGRAM), G_LOG_LEVEL_MESSAGE, "%s", log_header); g_free (log_header); g_free (time_str); g_free (command_line); /* Set up the random number generator. */ if (random_seed == 0) { random_seed = g_get_real_time (); } seed_str = g_strdup_printf ("%" G_GINT64_FORMAT, random_seed); g_message (_("Note: Setting random number generator seed to %s."), seed_str); g_free (seed_str); g_random_set_seed ((guint32) random_seed); /* Load the files. */ g_file_get_contents (simulation_filename, &simulation_code, NULL, &error); if (error != NULL) { g_printerr (_("Error loading simulation code from file ‘%s’: %s"), simulation_filename, error->message); g_printerr ("\n"); g_error_free (error); exit (STATUS_UNREADABLE_FILE); } g_file_get_contents (introspection_filename, &introspection_xml, NULL, &error); if (error != NULL) { g_printerr (_("Error loading introspection XML from file ‘%s’: %s"), introspection_filename, error->message); g_printerr ("\n"); g_error_free (error); g_free (simulation_code); exit (STATUS_UNREADABLE_FILE); } /* Build the DfsmObjects. */ simulated_objects = dfsm_object_factory_from_data (simulation_code, introspection_xml, &error); g_free (introspection_xml); g_free (simulation_code); if (error != NULL) { g_printerr (_("Error creating simulated DFSMs: %s"), error->message); g_printerr ("\n"); g_error_free (error); exit (STATUS_INVALID_CODE); } /* Prepare the main data struct, which will last for the lifetime of the program. */ data.main_loop = g_main_loop_new (NULL, FALSE); data.exit_status = STATUS_SUCCESS; data.exit_signal = EXIT_SIGNAL_INVALID; data.test_program = NULL; data.connection = NULL; data.simulated_objects = g_ptr_array_ref (simulated_objects); data.outstanding_registration_callbacks = 0; data.test_run_inactivity_timeout_id = 0; data.test_program_spawn_end_signal = 0; data.test_program_process_died_signal = 0; data.test_program_sigkill_timeout_id = 0; if (run_infinitely == TRUE || (run_iters == 0 && run_time == 0)) { data.num_test_runs_remaining = -1; } else { data.num_test_runs_remaining = run_iters; } g_ptr_array_unref (simulated_objects); /* Store the test program name and argv, since we can only spawn it once we know the bus address. */ data.test_program_name = g_strdup (test_program_name); data.test_program_argv = g_ptr_array_ref (test_program_argv); g_ptr_array_unref (test_program_argv); /* Set up signal handlers for SIGINT and SIGTERM so that we can close gracefully. */ g_unix_signal_add (SIGINT, (GSourceFunc) sigint_handler_cb, &data); g_unix_signal_add (SIGTERM, (GSourceFunc) sigterm_handler_cb, &data); /* Create a working directory. */ prepare_dbus_daemon_working_directory (&(data.working_directory_file), &working_directory_file, &dbus_daemon_config_file, &error); if (error != NULL) { g_printerr (_("Error creating dbus-daemon working directory: %s"), error->message); g_printerr ("\n"); g_error_free (error); main_data_clear (&data); dsim_logging_finalise (); exit (STATUS_TMP_DIR_ERROR); } /* Start up our own private dbus-daemon instance. */ data.dbus_daemon = dsim_dbus_daemon_new (working_directory_file, dbus_daemon_config_file); data.dbus_address = NULL; g_object_unref (dbus_daemon_config_file); g_object_unref (working_directory_file); g_signal_connect (data.dbus_daemon, "process-died", (GCallback) dbus_daemon_died_cb, &data); g_signal_connect (data.dbus_daemon, "notify::bus-address", (GCallback) dbus_daemon_notify_bus_address_cb, &data); dsim_program_wrapper_spawn (DSIM_PROGRAM_WRAPPER (data.dbus_daemon), &error); if (error != NULL) { g_printerr (_("Error spawning private dbus-daemon instance: %s"), error->message); g_printerr ("\n"); g_error_free (error); main_data_clear (&data); dsim_logging_finalise (); exit (STATUS_DAEMON_SPAWN_ERROR); } /* Start the main loop and wait for the dbus-daemon to send us its address. */ g_main_loop_run (data.main_loop); /* Free the main data struct. */ main_data_clear (&data); dsim_logging_finalise (); if (data.exit_signal != EXIT_SIGNAL_INVALID) { struct sigaction action; /* Propagate the signal to the default handler. */ action.sa_handler = SIG_DFL; sigemptyset (&action.sa_mask); action.sa_flags = 0; sigaction (data.exit_signal, &action, NULL); kill (getpid (), data.exit_signal); } return data.exit_status; }
int entry_point( int argc , char* argv[] ) { if( ! ( 1 < argc ) ){ /* オプションが足りない */ print_help_text(argv[0]); return EXIT_SUCCESS; } /* まず一段階目のfork では SIGCHLD を 無視する */ { struct sigaction sa = {{0}}; sa.sa_handler = SIG_IGN; sa.sa_flags = SA_NOCLDWAIT; if (sigaction(SIGCHLD, &sa, NULL) == -1) { return EXIT_FAILURE; } } { const pid_t pid = fork(); if( pid < 0 ){ // fork fail. perror( "fork faild" ); return EXIT_FAILURE; } if( 0 != pid ){ return EXIT_SUCCESS; } /* セッショングループを作り直して端末グループから外れる */ assert( 0 == pid && "the process is child process."); if( -1 == setsid() ){ perror("create new session"); } } /* パイプを作成する */ int logger_pipes[2] = {-1,-1}; if( pipe( logger_pipes ) ){ perror( "pipe()" ); return EXIT_FAILURE; } assert( 0 <=logger_pipes[0] ); assert( 0 <=logger_pipes[1] ); /* ログを書きだす先の プロセスを作成する */ const pid_t logger_pid = fork(); if( -1 == logger_pid ){ perror( "fork() faild"); VERIFY( 0 == close( logger_pipes[WRITE_SIDE] )); VERIFY( 0 == close( logger_pipes[READ_SIDE] )); abort(); } if( 0 == logger_pid){ VERIFY( 0 == close( logger_pipes[WRITE_SIDE] )); exec_logger_process( logger_pipes[READ_SIDE] ); return EXIT_FAILURE; }else{ VERIFY( 0 == close( logger_pipes[READ_SIDE] )); /* 標準入力を /dev/null に置き換える */ { int null_in = open( "/dev/null" , O_RDONLY ); if( -1 == null_in ){ return EXIT_FAILURE; } int null_out = open( "/dev/null" , O_WRONLY ); if( -1 == null_out ){ return EXIT_FAILURE; } int stdin_dup = dup( STDIN_FILENO ); int stdout_dup = dup( STDOUT_FILENO ); int stderr_dup = dup( STDERR_FILENO ); VERIFY( dup2( null_in , STDIN_FILENO ) == STDIN_FILENO ); VERIFY( dup2( null_out , STDOUT_FILENO ) == STDOUT_FILENO); VERIFY( dup2( null_out , STDERR_FILENO ) == STDERR_FILENO ); VERIFY( 0 == close( stdin_dup ) ); VERIFY( 0 == close( stdout_dup ) ); VERIFY( 0 == close( stderr_dup ) ); VERIFY( 0 == close( null_in )); VERIFY( 0 == close( null_out )); } struct process_param param = { logger_pipes[WRITE_SIDE] ,NULL}; char* pid_file_path = malloc( sizeof(char) * PATH_MAX ); if( pid_file_path ){ // TODO ここの PID_FILE_PATH の作り方、もうちょっと注意が必要 char *p = strrchr( argv[0] , '/' ); if( p ){ p++; p = (('\0' == *p) ? NULL : p); }else{ p = argv[0]; } VERIFY( 0 < snprintf( pid_file_path, sizeof( char ) * PATH_MAX , "/tmp/%s.pid" , (p)?(p): argv[0] ) ); param.pid_file_path = pid_file_path; const size_t params_len = argc; char**params = malloc( sizeof(char*) * params_len ); if( params ){ // params に strdup で引数を積んでいく for( size_t i = 0 ; i < (params_len -1); ++i ){ params[i] = strdup( argv[ i + 1] ); } params[params_len - 1] = NULL; if( EXIT_SUCCESS != start_process(param, params[0], params ) ){ // TODO spawn 失敗した } for( size_t i = 0; i < params_len ; ++i ){ if( params[i] ){ free( params[i] ); } } free( params ); } free( pid_file_path ); } VERIFY( 0 == close( logger_pipes[WRITE_SIDE] )); } return EXIT_SUCCESS; }