int main(int argc, char **argv) { size_t i, r; FILE **pipes; char buf[BUFSIZ]; pipes = malloc(((argc - 1) * sizeof *pipes)); if (!pipes) exit(EXIT_FAILURE); for (i = 1; i < argc; i++) { pipes[i - 1] = popen(argv[i], "w"); if (!pipes[i - 1]) { fprintf(stderr, "Can not open pipe to '%s\'\n", argv[i]); close_pipes(pipes, i); exit(EXIT_FAILURE); } } argc--; while(!feof(stdin) && (!ferror(stdin))) { r = fread(buf, sizeof(char), BUFSIZ, stdin); for(i = 0; i < argc; i++) { if (fwrite(buf, sizeof(char), r, pipes[i]) != r) { fprintf(stderr, "Write error to `%s\'\n", argv[i + 1]); close_pipes(pipes, i); exit(EXIT_FAILURE); } } } close_pipes(pipes, argc); exit(EXIT_SUCCESS); }
/* Programme principal * ------------------- * * On crée les pipes, puis les n processus fils correspondant aux stations. La * fonction station(i), invoquée par chaque fils, établit les connexions et * exécute le programme station.exe. */ int main(int argc, char *argv[]) { int i; /* Extraction du nombre de stations (passé en argument) */ if (argc <= 1) { fprintf(stderr, "Usage : ring.exe n_stations\n"); exit(1); } n_stations = atoi(argv[1]); if (n_stations <= 2 || n_stations >= MAX_STATIONS) { fprintf(stderr, "Vous voulez %d stations ? Soyez raisonnable! \n" "\t(Nombre maximum possible de stations : %d)\n", n_stations, MAX_STATIONS ); exit(1); } /* Création de tous les pipes */ for (i = 0; i < n_stations; i++) { if (pipe(fd_pipes[i]) < 0) perror("création des tubes"); } /* Création des processus des stations * ----------------------------------- * Le processus Si lit sur le pipe i et écrit sur le pipe i+1. La structure * est circulaire: les calculs d'indice ont donc lieu modulo n_stations * (c'est pourquoi il vaut mieux éviter les valeurs négatives de i) */ for (i = 0; i < n_stations; ++i) { switch(fork()) { case -1: perror("fork"); break; case 0: /* Le fils appelle la mise en place de la station i */ station(i); /*NOTREACHED*/ break; default: /* Le père passe à l'itèration suivante */ break; } } /* On peut maintenant fermer tous les descripteurs de pipes */ close_pipes(); /* Le père se met en attente de tous ses fils */ for (i = 0; i < n_stations; i++) wait(NULL); /* Fin du programme */ exit(0); }
/* Connect pipe read end to stdin. * @pipes: array of pipe file descriptors * @idx: the pipe index we are dup-ing * @n_of_th: number of threads/processes in the pipeline * @return: the return value of dup2 system call */ int dup_pipe_read(int (*pipes)[2], int idx, int n_of_th) { int rel; if (-1 == (rel = dup2(pipes[idx][0], STDIN_FILENO))) perror("dup2"); close_pipes(pipes, n_of_th); return rel; }
/* Connect pipe write end to stdout. * @pipes: array of pipe file descriptors * @idx: the pipe index we are dup-ing * @n_of_th: number of threads/processes in the pipeline * @return: the return value of dup2 system call */ int dup_pipe_write(int (*pipes)[2], int idx, int n_of_th) { int rel; if (-1 == (rel = dup2(pipes[idx][1], STDOUT_FILENO))) perror("dup2"); close_pipes(pipes, n_of_th); return rel; }
/* * Cleanup single user: close all pipes, kill user's child process, kill user * xterm process, free-up slot. * Remember to wait for the appropriate processes here! */ void cleanup_user(int idx, user_chat_box_t *users) { /***** Insert YOUR code *******/ close_pipes(idx, users); kill(users[idx].child_pid, SIGKILL); kill(users[idx].pid, SIGKILL); users[idx].status = SLOT_EMPTY; }
/* Executes a set of commands that are piped together. * If it's a single command, it simply calls `exec_command`. */ int exec_commands(struct commands *cmds) { int exec_ret; /* single command? run it */ if (cmds->cmd_count == 1) { cmds->cmds[0]->fds[STDIN_FILENO] = STDIN_FILENO; cmds->cmds[0]->fds[STDOUT_FILENO] = STDOUT_FILENO; exec_ret = exec(cmds, cmds->cmds[0], NULL); wait(NULL); } else { /* execute a pipeline */ int pipe_count = cmds->cmd_count - 1; /* if any command in the pipeline is a built-in, raise error */ int i; for (i = 0; i < cmds->cmd_count; i++) { if (check_built_in(cmds->cmds[i])) { fprintf(stderr, "error: no builtins in pipe\n"); return 0; } } /* allocate an array of pipes. Each member is array[2] */ int (*pipes)[2] = calloc(pipe_count * sizeof(int[2]), 1); if (pipes == NULL) { fprintf(stderr, "error: memory alloc error\n"); return 0; } /* create pipes and set file descriptors on commands */ cmds->cmds[0]->fds[STDIN_FILENO] = STDIN_FILENO; for (i = 1; i < cmds->cmd_count; i++) { pipe(pipes[i-1]); cmds->cmds[i-1]->fds[STDOUT_FILENO] = pipes[i-1][1]; cmds->cmds[i]->fds[STDIN_FILENO] = pipes[i-1][0]; } cmds->cmds[pipe_count]->fds[STDOUT_FILENO] = STDOUT_FILENO; /* execute the commands */ for (i = 0; i < cmds->cmd_count; i++) exec_ret = exec(cmds, cmds->cmds[i], pipes); close_pipes(pipes, pipe_count); /* wait for children to finish */ for (i = 0; i < cmds->cmd_count; ++i) wait(NULL); free(pipes); } return exec_ret; }
int exec(struct commands *cmds, struct command *cmd, int (*pipes)[2]) { if (check_built_in(cmd) == 1) return handle_built_in(cmds, cmd); pid_t child_pid = fork(); if (child_pid == -1) { fprintf(stderr, "error: fork error\n"); return 0; } /* in the child */ if (child_pid == 0) { int input_fd = cmd->fds[0]; int output_fd = cmd->fds[1]; // change input/output file descriptors if they aren't standard if (input_fd != -1 && input_fd != STDIN_FILENO) dup2(input_fd, STDIN_FILENO); if (output_fd != -1 && output_fd != STDOUT_FILENO) dup2(output_fd, STDOUT_FILENO); if (pipes != NULL) { int pipe_count = cmds->cmd_count - 1; close_pipes(pipes, pipe_count); } /* execute the command */ execv(cmd->name, cmd->argv); /* execv returns only if an error occurs */ fprintf(stderr, "error: %s\n", strerror(errno)); /* cleanup in the child to avoid memory leaks */ clear(); free(history); free(pipes); free(input); cleanup_commands(cmds); if (parent_cmd != NULL) { free(parent_cmd); free(temp_line); free(parent_cmds); } /* exit from child so that the parent can handle the scenario*/ _exit(EXIT_FAILURE); } /* parent continues here */ return child_pid; }
/* Connect pipe write end to stdout and pipe read end to stdin. * @pipes: array of pipe file descriptors * @idx: the process index * @n_of_th: number of threads/processes in the pipeline * @return: the return value of dup2 system call */ int dup_pipe_read_write(int (*pipes)[2], int idx, int n_of_th) { int rel; if (-1 == (rel = dup2(pipes[n_of_th-1-idx][0], STDIN_FILENO)) || -1 == (rel = dup2(pipes[n_of_th-2-idx][1], STDOUT_FILENO))) perror("dup2 read write"); close_pipes(pipes, n_of_th); return rel; }
//----------------------------------------------------------------------------- void shutdown( void ) { // unlock memory. do before any other shutdown operations munlockall(); printf( "shutting down\n" ); // send notifications to clients msgbuffer.close(); close_pipes(); }
int exec_cmd(t_parser *parser, t_env *envs) { t_command *cmd; close_pipes(parser->father); cmd = parser->command; if (check_for_exec(cmd->new_argv, envs->env) == -1 || (envs->path && check_path_exec(cmd->new_argv, envs->env, envs->path) == -1)) return (-1); return (0); }
static int start_gps_client(void) { LOG_ENTRY; int rc = -1; if (pipe(pipe_gps) < 0) { RPC_ERROR("failed to create GPS pipe"); goto fail; } if (pipe(pipe_ni) < 0) { RPC_ERROR("fail to create NI pipe"); goto fail; } if (pipe(pipe_agps) < 0) { RPC_ERROR("failed to create AGPS pipe"); goto fail; } if (pipe(pipe_xtra) < 0) { RPC_ERROR("failed to create XTRA pipe"); goto fail; } if (pipe(pipe_ril) < 0) { RPC_ERROR("fail to create RIL pipe"); goto fail; } pthread_create(&gps_rpc_thread, NULL, gps_client, NULL); pthread_mutex_lock(&gps_mutex); pthread_cond_wait(&gps_cond, &gps_mutex); pthread_mutex_unlock(&gps_mutex); if (!gps_rpc) { goto fail; } rc = 0; goto done; fail: close_pipes(); done: LOG_EXIT; return rc; }
/* Setup pipes for a single process run the process in the pipeline. * @n_of_th: number of threads in the line * @i: index of loop; index of threads in arr_ps_infos */ void run_piped_process(int n_of_th, int i, int (*pipes)[], pid_t pid) { if (i == n_of_th) { /* parent of all processes */ close_pipes(pipes, n_of_th); usleep(50000); wait_first_child(pid); } else if (i == n_of_th - 1) { /* first child in the chain */ if (-1 == dup_pipe_read(pipes, 0, n_of_th)) _exit(EXIT_FAILURE); piped_single_threaded_cmd(&arr_ps_infos[i].argc, arr_ps_infos[i].argv); } else if (i == 0) { /* last child in the chain gets here */ if (-1 == dup_pipe_write(pipes, n_of_th-2, n_of_th)) _exit(EXIT_FAILURE); piped_single_threaded_cmd(&arr_ps_infos[i].argc, arr_ps_infos[i].argv); } else { /* processes in the middle of the chain get here */ if (-1 == dup_pipe_read_write(pipes, i, n_of_th)) _exit(EXIT_FAILURE); piped_single_threaded_cmd(&arr_ps_infos[i].argc, arr_ps_infos[i].argv); } }
/* Mise en place d'une station * --------------------------- */ void station(int i) { char ctab[5]; char *arg[] = {STATION_EXE, NULL, NULL}; /* Argument de execvp */ /* On redirige entree et sortie standard */ dup2(fd_pipes[i][0], 0); dup2(fd_pipes[(i + 1) % n_stations][1], 1); /* On peut maintenant fermer tous les descripteurs de pipes */ close_pipes(); /* On exécute la station en passant i en argument */ int nw = snprintf(ctab, 5, "%d", i); /* encodage de i sous forme d'une chaine */ assert(nw < 5); /* voir manuel de snprintf() */ arg[1] = ctab; execvp(STATION_EXE, arg); perror("exécution de la station"); exit(1); /* surtout pas return ! */ }
//----------------------------------------------------------------------------- void init( int argc, char* argv[] ) { // * set variables from constants * cpu = DEFAULT_CPU; // * open error logs * std::string log_name = "info.log"; info = log_c( log_name ); log_c::error_e log_err; log_err = info.allocate( LOG_CAPACITY ); if( log_err != log_c::ERROR_NONE ) { sprintf( errstr, "(coordinator.cpp) init() failed calling log_c::allocate(...).\nExiting\n" ); printf( "%s", errstr ); exit( 1 ); } // * get the process identifier * coordinator_pid = getpid( ); printf( "coordinator pid: %d\n", coordinator_pid ); // * bind the process to a single cpu * if( cpu_c::bind( coordinator_pid, cpu ) != cpu_c::ERROR_NONE ) { sprintf( errstr, "(coordinator.cpp) init() failed calling cpu_c::bind(coordinator_pid,DEFAULT_CPU).\nExiting\n" ); //error_log.write( errstr ); printf( "%s", errstr ); //error_log.close( ); exit( 1 ); } // * set the process to be scheduled with realtime policy and max priority * if( scheduler_c::set_realtime_policy( coordinator_pid, coordinator_priority ) != scheduler_c::ERROR_NONE ) { sprintf( errstr, "(coordinator.cpp) init() failed calling schedule_set_realtime_max(coordinator_pid,coordinator_priority).\nExiting\n" ); //error_log.write( errstr ); printf( "%s", errstr ); //error_log.close( ); exit( 1 ); } printf( "coordinator process priority: %d\n", coordinator_priority ); // * determine if the OS supports high resolution timers * struct timespec res; clock_getres( CLOCK_MONOTONIC, &res ); double clock_res = timespec_to_real( res ); printf( "Clock resolution (secs): %10.9f\n", clock_res ); if( res.tv_sec != 0 && res.tv_nsec != 1 ) { sprintf( errstr, "(coordinator.cpp) init() failed. The host operating system does not support high resolution timers. Consult your system documentation on enabling this feature.\nExiting\n" ); //error_log.write( errstr ); printf( "%s", errstr ); //error_log.close( ); exit( 1 ); } // * get the cpu speed * if( cpu_c::get_speed( cpu_speed, cpu ) != cpu_c::ERROR_NONE ) { sprintf( errstr, "(coordinator.cpp) init() failed calling cpu_c::get_frequency(cpu_speed,cpu)\nExiting\n" ); //error_log.write( errstr ); printf( "%s", errstr ); //error_log.close( ); exit( 1 ); } // * initialize pipes * if( !init_pipes() ) { sprintf( errstr, "(coordinator.cpp) init() failed calling init_pipes()\nExiting\n" ); //error_log.write( errstr ); printf( "%s", errstr ); //error_log.close( ); exit( 1 ); } // * initialize shared memory * msgbuffer = client_message_buffer_c( CLIENT_MESSAGE_BUFFER_NAME, CLIENT_MESSAGE_BUFFER_MUTEX_NAME, true ); if( msgbuffer.open( ) != client_message_buffer_c::ERROR_NONE ) { sprintf( errstr, "(coordinator.cpp) init() failed calling actuator_msg_buffer_c.open(...,true)\n" ); //error_log.write( errstr ); printf( "%s", errstr ); close_pipes( ); //error_log.close( ); exit( 1 ); } // * initialize clients * /* CLIENT_MAX_PRIORITY = coordinator_priority - 1; CLIENT_MIN_PRIORITY = coordinator_priority - 3; int client_priority_step = CLIENT_MAX_PRIORITY - CLIENT_MIN_PRIORITY; processor = boost::shared_ptr<processor_c>( new processor_c() ); processor->name = "processor"; dynamics = boost::shared_ptr<dynamics_c>( new dynamics_c() ); dynamics->name = "dynamics"; prey = boost::shared_ptr<timesink_c>( new timesink_c( scheduler_c::PROGRESS) ); prey->name = "prey_timesink"; prey_controller = boost::shared_ptr<osthread_c>( new osthread_c(&select, &read_notifications) ); prey_controller->name = "prey_controller"; prey_controller->_max_priority = CLIENT_MAX_PRIORITY; prey_controller->_min_priority = CLIENT_MIN_PRIORITY; prey_controller->_priority_step = client_priority_step; pred = boost::shared_ptr<timesink_c>( new timesink_c(scheduler_c::PRIORITY) ); pred->name = "pred_timesink"; pred_controller = boost::shared_ptr<osthread_c>( new osthread_c(&select, &read_notifications) ); pred_controller->name = "pred_controller"; pred_controller->_max_priority = CLIENT_MAX_PRIORITY; pred_controller->_min_priority = CLIENT_MIN_PRIORITY; pred_controller->_priority_step = client_priority_step; pred_planner = boost::shared_ptr<osthread_c>( new osthread_c(&select, &read_notifications) ); pred_planner->name = "pred_planner"; pred_planner->_max_priority = CLIENT_MAX_PRIORITY; pred_planner->_min_priority = CLIENT_MIN_PRIORITY; pred_planner->_priority_step = client_priority_step; processor->run_queue.push_back( dynamics ); processor->run_queue.push_back( prey ); processor->run_queue.push_back( pred ); std::make_heap(processor->run_queue.begin(),processor->run_queue.end(),compare_thread_p_t()); prey->run_queue.push_back( prey_controller ); std::make_heap(prey->run_queue.begin(),prey->run_queue.end(),compare_thread_p_t()); pred->run_queue.push_back( pred_planner ); pred->run_queue.push_back( pred_controller ); std::make_heap(pred->run_queue.begin(),pred->run_queue.end(),compare_thread_p_t()); */ // * initialize block detection, i.e. wakeup * wakeup_priority = coordinator_priority - 2; if( scheduler_c::create( wakeup_thread, wakeup_priority, wakeup ) != scheduler_c::ERROR_NONE ) { msgbuffer.close( ); close_pipes( ); //error_log.close( ); printf( "(coordinator.cpp) init() failed calling wakeup_thread.create(...,wakeup)\nExiting\n" ); exit( 1 ); } // * initialize timer * if( timer.create( timer_sighandler, RTTIMER_SIGNAL ) != timer_c::ERROR_NONE ) { sprintf( errstr, "(coordinator.cpp) init() failed calling timer.create(timer_sighandler,RTTIMER_SIGNAL)\nExiting\n" ); //error_log.write( errstr ); printf( "%s", errstr ); msgbuffer.close( ); close_pipes( ); //error_log.close( ); exit( 1 ); } // * initialize other resources * // lock into memory to prevent pagefaults. do last before main loop mlockall( MCL_CURRENT ); }
int execute( const List_t* list) { Node_t* curr = list->head->next; int files = -1; int** pipes = make_pipes( list->count - 1); if( !pipes) return 0; int outPipe[2] = {}; pipe( outPipe); if( outPipe[0] < 0 || outPipe[1] < 0) { warn( "Error while creating outPipe"); return 0; } char* argv[ARGUMENTS_NUMBER] = {}; int i = 0; pid_t pid = 0; int status = -1; while( curr) { make_argv( curr->program, argv); files = open_files( curr->program); if( (pid = fork()) == 0) { if( curr->program->input >= 0) { if( dup2( curr->program->input, 0) < 0) warn( "Error while getting input from file %s", curr->program->input_name); } else if( i > 0) { if( dup2( pipes[i - 1][0], 0) < 0) warn( "Error while piping input for program %d", i); } if( curr->program->output >= 0) if( dup2( curr->program->output, 1) < 0) warn( "Error while sending output to file %s", curr->program->output_name); if( curr->type == last && curr->program->output < 0) if( dup2( outPipe[1], 1) < 0) warn( "Error while sending output to final pipe"); if( curr->type != last && curr->program->output < 0) if( dup2( pipes[i][1], 1) < 0) warn( "Error while piping output for program %d", i); close_pipes( pipes, list->count - 1); if( outPipe[0] > 0) close( outPipe[0]); if( outPipe[1] > 0) close( outPipe[1]); free_pipes( pipes, list->count - 1); if( files != close_files( curr->program)) warn( "Error while closing files in child"); if( execvp( curr->program->name, argv) < 0) { warn( "Error while executing %s", curr->program->name); exit( -1); } } if( curr->type == last) { close_pipes( pipes, list->count - 1); if( outPipe[1] > 0) close( outPipe[1]); print_output( outPipe[0]); if( outPipe[0] > 0) close( outPipe[0]); waitpid( pid, &status, 0); printf("Process exited with status %d\n", status); } if( files != close_files( curr->program)) warn( "Error while closing files in parrent"); curr = curr->next; ++i; } free_pipes( pipes, list->count - 1); return 1; }
static int start_mbrola(const char *voice_path) { int error, p_stdin[2], p_stdout[2], p_stderr[2]; ssize_t written; char charbuf[20]; if (mbr_state != MBR_INACTIVE) { err("mbrola init request when already initialized"); return -1; } error = create_pipes(p_stdin, p_stdout, p_stderr); if (error) return -1; mbr_pid = fork(); if (mbr_pid == -1) { error = errno; close_pipes(p_stdin, p_stdout, p_stderr); err("fork(): %s", strerror(error)); return -1; } if (mbr_pid == 0) { int i; if (dup2(p_stdin[0], 0) == -1 || dup2(p_stdout[1], 1) == -1 || dup2(p_stderr[1], 2) == -1) { snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "dup2(): %s\n", strerror(errno)); written = write(p_stderr[1], mbr_errorbuf, strlen(mbr_errorbuf)); (void)written; // suppress 'variable not used' warning _exit(1); } for (i = p_stderr[1]; i > 2; i--) close(i); signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); snprintf(charbuf, sizeof(charbuf), "%g", mbr_volume); execlp("mbrola", "mbrola", "-e", "-v", charbuf, voice_path, "-", "-.wav", (char *)NULL); /* if execution reaches this point then the exec() failed */ snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "mbrola: %s\n", strerror(errno)); written = write(2, mbr_errorbuf, strlen(mbr_errorbuf)); (void)written; // suppress 'variable not used' warning _exit(1); } snprintf(charbuf, sizeof(charbuf), "/proc/%d/stat", mbr_pid); mbr_proc_stat = open(charbuf, O_RDONLY); if (mbr_proc_stat == -1) { error = errno; close_pipes(p_stdin, p_stdout, p_stderr); waitpid(mbr_pid, NULL, 0); mbr_pid = 0; err("/proc is unaccessible: %s", strerror(error)); return -1; } signal(SIGPIPE, SIG_IGN); if (fcntl(p_stdin[1], F_SETFL, O_NONBLOCK) == -1 || fcntl(p_stdout[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(p_stderr[0], F_SETFL, O_NONBLOCK) == -1) { error = errno; close_pipes(p_stdin, p_stdout, p_stderr); waitpid(mbr_pid, NULL, 0); mbr_pid = 0; err("fcntl(): %s", strerror(error)); return -1; } mbr_cmd_fd = p_stdin[1]; mbr_audio_fd = p_stdout[0]; mbr_error_fd = p_stderr[0]; close(p_stdin[0]); close(p_stdout[1]); close(p_stderr[1]); mbr_state = MBR_IDLE; return 0; }
//----------------------------------------------------------------------------- void shutdown( void ) { // unlock memory. do before any other shutdown operations munlockall(); ///* // kill the wakeup thread pthread_cancel( wakeup_thread ); //sleep( 1 ); //*/ /* // delete the timer timer.block(); timer.destroy(); */ // wait for close messages from all clients /* bool clients_shutdown = false; while( !clients_shutdown ) { select(); sleep( 5 ); } */ // wait for close messages from all clients int status; ///* /* if( pred_controller ) { kill( pred_controller->pid, SIGTERM ); waitpid( pred_controller->pid, &status, 0 ); } */ if( prey_controller ) { kill( prey_controller->pid, SIGTERM ); waitpid( prey_controller->pid, &status, 0 ); } //*/ /* // kill the clients for( unsigned i = 0; i < clients.size(); i++ ) { kill( clients[i]->pid, SIGTERM ); waitpid( clients[i]->pid, &status, 0 ); } */ /* while( !prey_controller->invalidated ) { // send notifications to clients select(); //sleep( 1 ); waitpid( prey_controller->pid, &status, 0 ); //wait( &status ); } */ // close the shared buffer msgbuffer.close(); // close the pipes close_pipes(); // write any last statistics sprintf( spstr, "timer events: actual[%d], caught[%u]\n", actual_timer_events, caught_timer_events ); if( info ) info->write( spstr ); printf( spstr ); sprintf( spstr, "coordinator shutdown\n" ); if( info ) info->write( spstr ); printf( spstr ); // ensure the log gets written then destroyed if( info ) info->flush(); if( info ) info->deallocate(); }
int main(int argc, const char* argv[]) { int status, bg_pipes[2], num_pipes, flags; struct sigaction act_bg_term, act_int_old, act_int_new; /* Define handler for SIGINT (ignore) */ act_int_new.sa_handler = SIG_IGN; act_int_new.sa_flags = 0; if (sigaction(SIGINT, &act_int_new, &act_int_old)) perror("Failed to change handler for SIGINT"); /* Define handler for detecting background process termination */ if (SIGNAL_DETECTION == 1) { if (sigaction(SIGUSR1, NULL, &act_bg_term)) perror("Failed to get handler for SIGUSR1"); act_bg_term.sa_handler = sig_bg_handler; act_bg_term.sa_flags = SA_RESTART; if (sigaction(SIGUSR1, &act_bg_term, NULL)) perror("Failed to set handler for SIGUSR1"); } /* Create pipe for printing background process info */ num_pipes = 1; create_pipes(bg_pipes, num_pipes); /* Configure pipe to be non-blocking on read end */ flags = fcntl(bg_pipes[0], F_GETFL, 0); fcntl(bg_pipes[0], F_SETFL, flags | O_NONBLOCK); while (1) { char input[80], cmd[80]; int i; /* Wait for all defunct children */ /* Continue even if no child has exited */ if (!(SIGNAL_DETECTION == 1)) while (waitpid(-1, &status, WNOHANG | WUNTRACED) > 0); /* Print prompt */ if (!print_prompt()) continue; /* Exit if error occurs */ if (!fgets(input, 80, stdin)) { perror("Failed to get input"); continue; } /* Remove newline, if present */ i = strlen(input) - 1; if (input[i] == '\n') input[i] = '\0'; /* Read given commands */ i = 0; /* Input index */ i = read_cmd(cmd, input, i); if (strcmp(cmd, "exit") == 0) break; else if (strcmp(cmd, "cd") == 0) cd(input, cmd, i); else if (strcmp(cmd, "checkEnv") == 0) check_env(input, i); else if (cmd[0] == '\0') {} /* Just print process info */ else general_cmd(input, &act_int_old, bg_pipes); /* Print accumulated process information */ print_process_info(bg_pipes); } /* Close pipe for printing background process info */ close_pipes(bg_pipes, num_pipes); exit_shell(); return 0; }
int general_cmd(char* input, const struct sigaction* act_int_old, const int* bg_pipes) { int pipes[2]; /* File descriptors from piping */ int fds[4]; /* File descriptors to dupe */ int background_process; /* Whether to run in the background */ int status; /* Wait status */ int i; /* Command index */ int j = 1; /* Loop index */ int num_pipes = 1; /* Number of pipes to create */ char* args[80]; /* All arguments to the command */ char arg[80]; /* One argument to command */ char cmd[80]; /* The command to be executed */ unsigned long exec_time; /* Execution time */ pid_t pid; /* PID of child */ struct timeval time_before; /* Time before execution of command */ struct timeval time_after; /* Time after execution of command */ create_pipes(pipes, num_pipes); fds[0] = -1; fds[1] = -1; fds[2] = -1; fds[3] = -1; /* Read the entire command string */ background_process = 0; for (i = 0; ; ++i) { /* Check if the process should run in the background */ if (input[i] == '&') { background_process = 1; input[i] = '\0'; break; } else if (input[i] == '\0') { break; } } /* Read the command */ i = read_cmd(cmd, input, 0); /* First argument in list must be file name */ args[0] = cmd; /* Read arguments to the command */ while (input[i] != '\0') { i = read_cmd(arg, input, i); args[j] = arg; ++j; } /* Argument list to execvp is NULL terminated */ args[j] = (char*) NULL; pid = fork(); /* Create new child process that handles execution */ /* Child process */ if (pid == 0) { /* Save current stdout file descriptor */ if (background_process) { /* Write termination info to process info pipe */ if (dup2(bg_pipes[1], WRITE) < 0) { perror("Failed to duplicate file descriptor for writing"); return 0; } /* Write err info to process info process pipe */ if (dup2(bg_pipes[1], ERROR) < 0) { perror("Failed to duplicate file descriptor for errors"); return 0; } /* Close file descriptor */ if (close(bg_pipes[1])) { perror("Failed to delete file descriptor"); return 0; } } /* Restore normal interrupt behaviour */ if (sigaction(SIGINT, act_int_old, NULL)) perror("Failed to change handler for SIGINT in child"); /* Measure execution time */ gettimeofday(&time_before, NULL); if (!fork_exec_cmd(cmd, pipes, fds, args, num_pipes, 0)) { perror(cmd); return 0; } if ((pid = wait(&status)) < 0) { perror("Failed to wait for executing process"); return 0; } /* Calculate execution time */ gettimeofday(&time_after, NULL); exec_time = 1000 * (time_after.tv_sec - time_before.tv_sec) + (time_after.tv_usec - time_before.tv_usec) / 1000; printf("(pid: %d) %s finished executing in %lu ms.\n", pid, cmd, exec_time); /* Notify parent of termination */ if (SIGNAL_DETECTION == 1 && background_process) { if (kill(getppid(), SIGUSR1)) { perror("Failed to notify parent of termination"); return 0; } } _exit(0); /* exit() unreliable */ } /* Error */ else if (pid < 0) { perror("Failed to fork child process"); exit(1); } /* Parent process */ else { /* The parent process comes here after forking */ if (!background_process) { if (waitpid(pid, &status, 0) < 0) { perror("Failed to wait for process"); return 0; } } } /* Let the parent processes close all pipes */ close_pipes(pipes, num_pipes); return 1; }
//----------------------------------------------------------------------------- void init( int argc, char* argv[] ) { //quit = false; quit = 0; //quit.store( 0, std::memory_order_seq_cst ); //quit.store( 0, std::memory_order_relaxed ); actual_timer_events = 0; caught_timer_events = 0; // * set variables from constants * cpu = DEFAULT_CPU; // * install SIGTERM signal handler * struct sigaction action; memset( &action, 0, sizeof(struct sigaction) ); action.sa_handler = term_sighandler; sigaction( SIGTERM, &action, NULL ); // * open log * #ifdef DO_LOGGING info = log_p( new log_c( "info.log", true ) ); log_c::error_e log_err = info->allocate( LOG_CAPACITY ); if( log_err != log_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling log_c::allocate(...).\nExiting\n" ); printf( spstr ); exit( 1 ); } #endif // * get the process identifier * coordinator_pid = getpid( ); sprintf( spstr, "coordinator pid: %d\n", coordinator_pid ); if( info ) info->write( spstr ); printf( "%s", spstr ); // * bind the process to a single cpu * if( cpu_c::bind( coordinator_pid, cpu ) != cpu_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling cpu_c::_bind(coordinator_pid,DEFAULT_CPU).\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); exit( 1 ); } // * set the process to be scheduled with realtime policy and max priority * if( scheduler_c::set_realtime_policy( coordinator_pid, coordinator_os_priority ) != scheduler_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling schedule_set_realtime_max(coordinator_pid,coordinator_priority).\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); exit( 1 ); } sprintf( spstr, "coordinator os priority: %d\n", coordinator_os_priority ); if( info ) info->write( spstr ); printf( "%s", spstr ); // * determine if the OS supports high resolution timers * struct timespec res; clock_getres( CLOCK_MONOTONIC, &res ); double clock_res = timespec_to_real( res ); sprintf( spstr, "clock resolution (secs): %10.9f\n", clock_res ); if( info ) info->write( spstr ); printf( "%s", spstr ); if( res.tv_sec != 0 && res.tv_nsec != 1 ) { sprintf( spstr, "(coordinator.cpp) init() failed. The host operating system does not support high resolution timers. Consult your system documentation on enabling this feature.\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); exit( 1 ); } // * get the cpu speed * if( cpu_c::get_speed( cpu_speed, cpu ) != cpu_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling cpu_c::get_frequency(cpu_speed,cpu)\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); exit( 1 ); } sprintf( spstr, "cpu speed(hz): %llu\n", cpu_speed ); if( info ) info->write( spstr ); printf( "%s", spstr ); // * initialize pipes * if( !init_pipes() ) { sprintf( spstr, "(coordinator.cpp) init() failed calling init_pipes()\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); exit( 1 ); } // * initialize shared memory * msgbuffer = client_message_buffer_c( CLIENT_MESSAGE_BUFFER_NAME, CLIENT_MESSAGE_BUFFER_MUTEX_NAME, true ); if( msgbuffer.open( ) != client_message_buffer_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling actuator_msg_buffer_c.open(...,true)\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); close_pipes( ); exit( 1 ); } // * initialize block detection, i.e. wakeup * wakeup_os_priority = coordinator_os_priority - 2; wakeup_enabled.store( 1 ); // set up the wakeup overhead to minimize what changes inside wakeup_note.source = notification_t::WAKEUP; wakeup_write_fd = FD_WAKEUP_TO_COORDINATOR_WRITE_CHANNEL; if( info ) info->flush(); // lock into memory to prevent pagefaults. do last before main loop mlockall( MCL_CURRENT ); /* if( scheduler_c::create( wakeup_thread, wakeup_os_priority, wakeup ) != scheduler_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling wakeup_thread.create(...,wakeup)\nExiting\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); msgbuffer.close( ); close_pipes( ); exit( 1 ); } */ /* if( scheduler_c::get_priority( wakeup_thread, wakeup_os_priority ) != scheduler_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling get_priority(wakeup_thread,...)\nExiting\n" ); info.write( spstr ); msgbuffer.close( ); close_pipes( ); // kill the wakeup thread? exit(1); } */ sprintf( spstr, "wakeup thread created... priority:%d\n", wakeup_os_priority ); if( info ) info->write( spstr ); printf( "%s", spstr ); // * initialize clients * sprintf( spstr, "initializing clients\n" ); if( info ) info->write( spstr ); printf( "%s", spstr ); scheduler_c::error_e schedulererr; double controller_floor_seconds = 0.001; double controller_ceiling_seconds = 0.01; double planner_floor_seconds = 0.01; double planner_ceiling_seconds = 0.5; std::string controller_seed = "1"; char numbuf[16]; sprintf(numbuf,"%llu",seconds_to_cycles(controller_floor_seconds, cpu_speed)); std::string controller_floor = numbuf; sprintf(numbuf,"%llu",seconds_to_cycles(controller_ceiling_seconds, cpu_speed)); std::string controller_ceiling = numbuf; sprintf(numbuf,"%llu",seconds_to_cycles(planner_floor_seconds, cpu_speed)); std::string planner_floor = numbuf; sprintf(numbuf,"%llu",seconds_to_cycles(planner_ceiling_seconds, cpu_speed)); std::string planner_ceiling = numbuf; CLIENT_OS_MAX_PRIORITY = coordinator_os_priority - 1; CLIENT_OS_MIN_PRIORITY = coordinator_os_priority - 3; int client_os_priority_step = CLIENT_OS_MAX_PRIORITY - CLIENT_OS_MIN_PRIORITY; log_c* pinfo = NULL; if( info ) pinfo = info.get(); /* // - create a processor - processor = boost::shared_ptr<processor_c>( new processor_c( "processor_0" ) ); timesink_p processor_timesink = boost::dynamic_pointer_cast<timesink_c>( processor ); processor_thread = boost::dynamic_pointer_cast<thread_c>( processor ); processor->info = pinfo; // - create dynamics process - dynamics = boost::shared_ptr<dynamics_c>( new dynamics_c( "dynamics", processor_timesink, cpu_speed ) ); dynamics->info = pinfo; processor->run_queue.push( dynamics ); // - create prey processes - prey = boost::shared_ptr<timesink_c>( new timesink_c( "prey", processor_timesink, scheduler_c::PROGRESS) ); prey->info = pinfo; //prey->priority = 0; processor->run_queue.push( prey ); prey_thread = boost::dynamic_pointer_cast<thread_c>(prey); */ prey_controller = boost::shared_ptr<osthread_c>( new osthread_c( "prey_controller", prey, &select, &read_notifications, &process_notifications, pinfo ) ); prey_controller->_max_os_priority = CLIENT_OS_MAX_PRIORITY; prey_controller->_min_os_priority = CLIENT_OS_MIN_PRIORITY; prey_controller->_os_priority_step = client_os_priority_step; prey_controller->_cpu_speed = cpu_speed; prey_controller->priority = 0; prey_controller->desired_period = seconds_to_cycles( controller_ceiling_seconds, cpu_speed ); //prey->run_queue.push( prey_controller ); schedulererr = scheduler_c::create( prey_controller, 3, DEFAULT_CPU, "client-process", "prey-controller", controller_seed.c_str(), controller_floor.c_str(), controller_ceiling.c_str() ); //prey_controller->block(); sprintf( spstr, "created prey-controller: pid[%d], _os_priority[%d], _os_priority_step[%d], _max_os_priority[%d], _min_os_priority[%d]\n", prey_controller->pid, prey_controller->_os_priority, prey_controller->_os_priority_step, prey_controller->_max_os_priority, prey_controller->_min_os_priority ); if( info ) info->write( spstr ); /* // - create predator processes - pred = boost::shared_ptr<timesink_c>( new timesink_c( "pred", processor_timesink, scheduler_c::PROGRESS) ); pred->info = pinfo; //prey->priority = 0; processor->run_queue.push( pred ); pred_thread = boost::dynamic_pointer_cast<thread_c>(pred); pred_controller = boost::shared_ptr<osthread_c>( new osthread_c( "pred_controller", pred, &select, &read_notifications, &process_notifications, pinfo ) ); pred_controller->_max_os_priority = CLIENT_OS_MAX_PRIORITY; pred_controller->_min_os_priority = CLIENT_OS_MIN_PRIORITY; pred_controller->_os_priority_step = client_os_priority_step; pred_controller->_cpu_speed = cpu_speed; pred_controller->priority = 0; pred_controller->desired_period = seconds_to_cycles( controller_ceiling_seconds, cpu_speed ); pred->run_queue.push( pred_controller ); schedulererr = scheduler_c::create( pred_controller, 3, DEFAULT_CPU, "client-process", "pred-controller", controller_seed.c_str(), controller_floor.c_str(), controller_ceiling.c_str() ); //prey_controller->block(); sprintf( spstr, "created pred-controller: pid[%d], _os_priority[%d], _os_priority_step[%d], _max_os_priority[%d], _min_os_priority[%d]\n", pred_controller->pid, pred_controller->_os_priority, pred_controller->_os_priority_step, pred_controller->_max_os_priority, pred_controller->_min_os_priority ); if( info ) info->write( spstr ); */ // * initialize timer * // set up the timer handler overhead to minimize what changes inside timer_note.source = notification_t::TIMER; timer_write_fd = FD_TIMER_TO_COORDINATOR_WRITE_CHANNEL; // create the timer if( timer.create( timer_sighandler, RTTIMER_SIGNAL ) != timer_c::ERROR_NONE ) { sprintf( spstr, "(coordinator.cpp) init() failed calling timer.create(timer_sighandler,RTTIMER_SIGNAL)\nExiting\n" ); pthread_cancel( wakeup_thread ); int status; if( pred_controller ) { kill( pred_controller->pid, SIGTERM ); waitpid( pred_controller->pid, &status, 0 ); } if( prey_controller ) { kill( prey_controller->pid, SIGTERM ); waitpid( prey_controller->pid, &status, 0 ); } if( info ) info->write( spstr ); printf( "%s", spstr ); msgbuffer.close( ); close_pipes( ); exit( 1 ); } // * initialize other resources * //clients.push_back( prey_controller ); //clients.push_back( pred_controller ); //clients.push_back( pred_planner ); }
int main(int argc, char **argv, char **envp) { /* Pager 1 = less, 2 = more */ char* pager = "less"; int i; /* Letar igenom miljövariablerna efter PAGER. Finns den, använd less om den finns, om den finns men inte innehåller less används more.*/ for(i = 0; envp[i] != NULL; i++) { if(strcmp_lim(envp[i], "PAGER", 5)) { if(!strcmp_lim(envp[i]+6,"less",4)) pager = "more"; } } /* Pipes */ int pipe_filedesc[3][2]; /* Skapa så många pipes som behövs, beror på om vi fick parametrar eller inte */ int child_count = (argc > 1)?4:3; for(i = 0; i< child_count-1; i++) { return_value = pipe(pipe_filedesc[i]); check_return_value_pipe(); } /* Håller koll på vilken pipe som skall användas. */ int current_pipe = 0; childpid = fork(); /* skapa första child-processen (för printenv) */ if(0 == childpid) { /* Bind om stdout till pipe. */ return_value = dup2( pipe_filedesc[current_pipe][ PIPE_WRITE_SIDE ], STDOUT_FILENO ); /* STDOUT_FILENO == 1 */ /* Kolla om allt gick bra */ check_return_value_pipe(); /* Stäng alla pipes */ close_pipes(child_count-1, pipe_filedesc); (void) execlp( "printenv", "printenv", (char *) 0 ); } current_pipe++; /* Skriv ut processens childpid */ fprintf(stderr, "printenv: %d\n",childpid ); /* Om vi har fått en parameterlista skall vi utföra grep här. */ if(argc > 1) { childpid = fork(); if( 0 == childpid ) { /* Bind om stdin till pipe. */ return_value = dup2( pipe_filedesc[current_pipe-1][ PIPE_READ_SIDE ], STDIN_FILENO ); /* STDIN_FILENO == 0 */ /* Kolla om allt gick bra */ check_return_value_pipe(); /* Bind om stdout till pipe. */ return_value = dup2( pipe_filedesc[current_pipe][ PIPE_WRITE_SIDE ], STDOUT_FILENO ); /* STDOUT_FILENO == 1 */ /* Kolla om allt gick bra */ check_return_value_pipe(); /* Stäng alla pipes */ close_pipes(child_count-1, pipe_filedesc); argv[0] = "grep"; execvp( "grep", argv); fprintf(stderr, "Error in grep\n"); } current_pipe++; /* Skriv ut processens childpid */ fprintf(stderr, "grep: %d\n",childpid ); } childpid = fork(); /* skapa andra child-processen (för sort) */ if (0 == childpid ) { /* Bind om stdin */ return_value = dup2( pipe_filedesc[current_pipe-1][ PIPE_READ_SIDE ], STDIN_FILENO ); /* STDIN_FILENO == 0 */ /* Kolla om allt gick bra */ check_return_value_pipe(); /* Bind om stdout */ return_value = dup2( pipe_filedesc[current_pipe][ PIPE_WRITE_SIDE ], STDOUT_FILENO ); /* STOUT_FILENO == 1 */ /* Kolla om allt gick bra */ check_return_value_pipe(); /* Stäng alla pipes */ close_pipes(child_count-1, pipe_filedesc); (void) execlp( "sort", "sort", (char *) 0 ); } /* Skriv ut processens childpid */ fprintf(stderr, "sort: %d\n",childpid ); current_pipe++; childpid = fork(); if( 0 == childpid ) { /* bind om stdin */ return_value = dup2( pipe_filedesc[current_pipe-1][ PIPE_READ_SIDE ], STDIN_FILENO ); /* STDIN_FILENO == 0 */ /* Kolla om allt gick bra */ check_return_value_pipe(); /* Stäng alla pipes */ close_pipes(child_count-1, pipe_filedesc); (void) execlp( pager, pager, (char *) 0 ); } /* Skriv ut processens childpid */ fprintf(stderr, "less: %d\n",childpid ); /* Stäng alla pipes */ close_pipes(child_count-1, pipe_filedesc); /* Vänta på alla barn */ for(i = 0; i<child_count; i++) { waitForChild(); } exit( 0 ); /* Avsluta parent-processen på normalt sätt */ }
int run_pipe(int pipefd[], int pipes_num, char ***cmd_list) { int fd_cntr, cmd_cntr, cmd_list_len, pipe_fd_total, final_cmd_pos; int cpid1, cpid2, cpid3; cmd_list_len = three_d_array_len(cmd_list); // Need at least 1 command. if( cmd_list[0] == NULL ) return -1; // Handle just 1 command passed if(pipes_num == 0) { cpid1 = fork(); if(cpid1 == 0) { if(execvp(cmd_list[0][0], cmd_list[0]) < 0) printErrorMessage(cmd_list[0], errno); _exit(EXIT_SUCCESS); } } else // Handle piping { // First child, always executes first command regardless of // number of pipes cpid1 = fork(); if(cpid1 == 0) { printf("Child 0 launched with command %s\n", cmd_list[0][0]); if(dup2(pipefd[1], STDOUT_FILENO) < 0) printStdErrMessage(__func__, __LINE__, "CHILD 0: Dup failed!", errno); close_pipes(pipefd, pipes_num); if( execvp(cmd_list[0][0], cmd_list[0]) < 0) printErrorMessage(cmd_list[0], errno); _exit(EXIT_SUCCESS); } // Middle child[ren] // If cmd_list > 2, then multiple pipes are in order. if(cmd_list_len > 2) { fd_cntr = 0; cmd_cntr = 1; while(cmd_cntr < (cmd_list_len - 1)) { //printf("%s %d: cmd_cntr = %d, cmd_list_len = %d\n", // __func__, __LINE__, cmd_cntr, cmd_list_len); cpid2 = fork(); if(cpid2 == 0) { printf("Child %d launched with command %s\n", cmd_cntr + 1, cmd_list[cmd_cntr][0]); if(dup2(pipefd[fd_cntr], STDIN_FILENO) < 0) printStdErrMessage(__func__, __LINE__, "CHILD 2: Dup STDIN failed!", errno); if(dup2(pipefd[fd_cntr+3], STDOUT_FILENO) < 0) printStdErrMessage(__func__, __LINE__, "CHILD 2: Dup STDOUT failed!", errno); close_pipes(pipefd, pipes_num); if( execvp(cmd_list[cmd_cntr][0], cmd_list[cmd_cntr]) < 0) printErrorMessage(cmd_list[cmd_cntr], errno); _exit(EXIT_SUCCESS); } // Increase command counter cmd_cntr++; // Move file descriptor position to the stdin of the next // pipe in the array fd_cntr += 2; } } // Last child, executed regardless of num of pipes cpid3 = fork(); if(cpid3 == 0) { final_cmd_pos = cmd_list_len - 1; printf("Child 1 launched with command %s\n", cmd_list[final_cmd_pos][0]); pipe_fd_total = (pipes_num*2); if(dup2(pipefd[pipe_fd_total - 2], STDIN_FILENO) < 0) printStdErrMessage(__func__, __LINE__, "CHILD 1: Dup STDIN failed!", errno); close_pipes(pipefd, pipes_num); if( execvp(cmd_list[final_cmd_pos][0], cmd_list[final_cmd_pos]) < 0) printErrorMessage(cmd_list[final_cmd_pos], errno); _exit(EXIT_SUCCESS); } } close_pipes(pipefd, pipes_num); return 0; }
int check_env(const char* input, int i) { int pipes[6]; /* File descriptors from piping */ int fds[4]; /* File descriptors to dupe */ int status; /* Wait status */ int j = 1; /* Loop index */ int num_pipes = 2; /* Number of pipes to create */ char* args[80]; /* All arguments to grep */ char* pager = getenv("PAGER"); /* PAGER enviroment variable */ char cmd[80]; /* One grep parameter */ /* Read arguments to grep */ while (input[i] != '\0') { i = read_cmd(cmd, input, i); args[j] = cmd; ++j; } /* If arguments were given, one pipe is needed for grep */ if (j > 1) num_pipes = 3; /* Create all pipes beforehand */ create_pipes(pipes, num_pipes); /* Argument list to execvp is NULL terminated */ args[j] = (char*) NULL; /* First argument in list must be file name */ args[0] = cmd; /* pipe fds: (0, 1) [2, 3, 4, 5, 6, 7] */ /* PIPE READ WRITE */ /* 1 2 3 */ /* 2 4 5 */ /* 3 6 7 */ /* PROC READ WRITE */ /* 1 0 3 */ /* 2 2 5 */ /* 3 4 7 */ /* 4 6 1 */ /* Pipe and execute printenv */ fds[0] = -1; fds[1] = -1; fds[2] = 1; fds[3] = WRITE; if (!fork_exec_cmd("printenv", pipes, fds, NULL, num_pipes, 0)) { perror("Failed to execute printenv"); return 0; } /* Only pipe and excute grep if arguments were given */ fds[0] = 0; fds[1] = READ; fds[2] = 3; fds[3] = WRITE; if (num_pipes == 3) { if (!fork_exec_cmd("grep", pipes, fds, args, num_pipes, 0)) { perror("Failed to to execute grep"); return 0; } } /* Pipe and execute sort */ if (num_pipes == 3) { fds[0] = 2; fds[1] = READ; fds[2] = 5; fds[3] = WRITE; } if (!fork_exec_cmd("sort", pipes, fds, NULL, num_pipes, 0)) { perror("Failed to to execute sort"); return 0; } /* Try to pipe and execute with PAGER environment variable */ fds[0] = (num_pipes == 3) ? 4 : 2; fds[1] = READ; fds[2] = -1; fds[3] = -1; if (pager) { if (!fork_exec_cmd(pager, pipes, fds, NULL, num_pipes, 0)) { perror("Failed to to execute checkEnv with environment pager"); return 0; } } /* Try to pipe and execute with pager `less`, then `more` */ else { if (!fork_exec_cmd("more", pipes, fds, NULL, num_pipes, 1)) { perror("Failed to to execute checkEnv with default pagers"); return 0; } } /* Let the parent processes close all pipes */ close_pipes(pipes, num_pipes); /* Let the parent processes wait for all children */ for (j = 0; j < num_pipes + 1; ++j) { /* Wait for the processes to finish */ if (wait(&status) < 0) { perror("Failed to wait for process"); return 0; } } return 1; }