source: tools/repeat.c @ 50e04cc

Last change on this file since 50e04cc was 967e3c9, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Repeat tool can now redirect output

  • Property mode set to 100644
File size: 3.7 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <stdbool.h>
5#include <string.h>
6
7#include <getopt.h>
8#include <unistd.h>
9
10#include <sys/types.h>
11#include <sys/wait.h>
12
13int repetitions = 0;
14bool stop_on_error = false;
15char * this_cmd = NULL;
16bool print_iterations = false;
17
18void parse_args(int argc, char * argv[]);
19void setup();
20int run();
21
22int main(int argc, char * argv[]) {
23        parse_args(argc, argv);
24        setup();
25        for(int i = 0; i < repetitions; i++) {
26                if(print_iterations) {
27                        printf("\r%d / %d", i, repetitions);
28                        fflush(stdout);
29                }
30                int retcode = run();
31                if( !WIFEXITED(retcode) ) {
32                        printf("FAILURE: %d @ %d\n", retcode, i + 1);
33                }
34                if( !WIFEXITED(retcode) && stop_on_error ) {
35                        return retcode;
36                }
37        }
38
39        if(print_iterations) {
40                printf("\r%d / %d\n", repetitions, repetitions);
41        }
42
43        return 0;
44}
45
46void usage( FILE * out, int code ) {
47        fprintf(out, "%s [OPTION] [--] N CMD\n", this_cmd);
48        fprintf(out, "Repeat CMD N times\n\n");
49        fprintf(out, "\t-h,--help\tprint this usage message\n");
50        fprintf(out, "\t-s\t\tstop on error\n");
51        fprintf(out, "\t-i\t\toutput iterations instead of CMD stdout\n");
52        fprintf(out, "\t-x\t\tprint CMD before running it\n");
53        fprintf(out, "\t-a FILE\t\tredirect output of command to append to FILE\n");
54        fprintf(out, "\t-r FILE\t\tredirect output of command to FILE\n");
55        exit(code);
56}
57
58char ** cmd_to_run = NULL;
59bool print_cmd = false;
60bool redirect = false;
61bool redirect_append = false;
62char * redirect_to = "/dev/null";
63pid_t child_pid = 0;
64
65void error() {
66        fprintf(stderr,"\n");
67        usage(stderr, 1);
68}
69
70void parse_args(int argc, char * argv[]) {
71        this_cmd = argv[0];
72
73        enum { Help, };
74        static struct option long_opts[] = {
75                { "help", no_argument, 0, Help },
76                { 0, 0, 0, 0 }
77        }; // long_opts
78        int long_index;
79
80        int c;
81        while ( (c = getopt_long( argc, argv, "ahirsx", long_opts, &long_index)) != -1 ) {
82                switch ( c ) {
83                        case Help:
84                        case 'h':
85                                usage(stdout, 0);
86                                break;
87                        case 's':
88                                stop_on_error = true;
89                                break;
90                        case 'x':
91                                print_cmd = true;
92                                break;
93                        case 'i':
94                                print_iterations = true;
95                                break;
96                        case 'a':
97                                if(redirect) { fprintf(stderr, "Cannot have -a and -r\n"); error(); }
98                                redirect_append = true;
99                                redirect_to = argv[optind];
100                                optind++;
101                                break;
102                        case 'r':
103                                if(redirect_append) { fprintf(stderr, "Cannot have -a and -r\n"); error(); }
104                                redirect = true;
105                                redirect_to = argv[optind];
106                                optind++;
107                                break;
108                        default:
109                                error("");
110                                break;
111                } // switch
112        } // while
113
114        if( argc < optind + 2 ) {
115                fprintf(stderr, "Too few arguments\n");
116                error();
117        }
118
119        char * pEnd;
120        char * repeats_c = argv[optind];
121        repetitions = strtol(repeats_c, &pEnd, 10);
122
123        bool is_number = (size_t)(pEnd - repeats_c) == strlen(repeats_c);
124        bool in_range  = repetitions > 0;
125        if( !is_number || !in_range ) {
126                fprintf(
127                        stderr,
128                        "repetitions option : %s not an number greater than 0\n",
129                        repeats_c
130                );
131                error();
132        }
133
134        cmd_to_run = argv + optind + 1;
135}
136
137void setup() {
138
139}
140
141int run() {
142        /* Duplicate this process. */
143        child_pid = fork();
144        if (child_pid != 0) {
145
146                /* This is the parent process. */
147                int status;
148                waitpid(child_pid, &status, 0);
149                child_pid = 0;
150                return status;
151        }
152        else {
153                /* Now execute PROGRAM, searching for it in the path.  */
154                if( print_cmd ) {
155                        char ** cmd = cmd_to_run;
156                        while (*cmd) {
157                                printf("%s ", *cmd);
158                                cmd++;
159                        }
160                        printf("\n");
161                }
162                if(print_iterations || redirect || redirect_append) {
163                        __attribute__((unused)) FILE * ignore =
164                                freopen(redirect_to, redirect_append ? "a" : "w" , stdout);
165                }
166                execvp ( *cmd_to_run, cmd_to_run);
167                /* The execvp  function returns only if an error occurs.  */
168                fprintf(stderr, "an error occurred in execvp\n");
169                abort ();
170        }
171
172        return 0;
173}
Note: See TracBrowser for help on using the repository browser.