c4648804283ad1d83e6a8990ddb1db6f58320a6a
[runfinite.git] / src / main.cpp
1 /**
2 * shuber, 2008-04-24
3 *
4 * Little hack to let a process run only a specific amount of time. If process
5 * has not finished until that amount of time it is killed.
6 *
7 */
8
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <time.h>
14 #include <unistd.h>
15
16 #include <sys/wait.h>
17 #include <sys/types.h>
18
19
20
21 #define ERR_WRONGARGS -1
22 #define ERR_EXECVE -2
23 #define ERR_FORK -3
24 #define ERR_WAITPID -4
25 #define ERR_KILL -5
26
27
28
29 void printUsage(FILE* out, int argc, char** argv)
30 {
31 fprintf(out, "Run command <command> for at least a specific time. Kill\n");
32 fprintf(out, "process executing <command> if time is over. \n");
33 fprintf(out, "\n");
34 fprintf(out, "Usage: %s [options] <command>\n", argv[0]);
35 fprintf(out, "\n");
36 fprintf(out, "Options:\n");
37 fprintf(out, " -h Print this help.\n");
38 fprintf(out, " -t <sec> Number of seconds.\n");
39 fprintf(out, " -v Be verbose.\n");
40 }
41
42
43 int main(int argc, char** argv)
44 {
45 bool argHelp=false;
46 bool argTime=false;
47 bool argVerbose=false;
48 float maxtime=0;
49
50 //Wrong arguments
51 if( argc<=1 )
52 {
53 printUsage(stderr, argc, argv);
54 return ERR_WRONGARGS;
55 }
56
57
58 //Get the argument index of the head of <command>
59 int fiarg=1;
60
61 //Aha, argument -- skip it
62 while( fiarg<argc && strncmp(argv[fiarg], "-", 1)==0 )
63 {
64 //Help option
65 if( strncmp(argv[fiarg], "-h", 2) == 0 )
66 {
67 argHelp = true;
68 }
69
70 //Parse time
71 else if( strncmp(argv[fiarg], "-t", 2) == 0 )
72 {
73 //Time is given -- goto next argument
74 argTime=true;
75 fiarg++;
76 if( fiarg >= argc)
77 {
78 fprintf(stderr, "Missing time.\n");
79 fprintf(stderr, "\n");
80 printUsage(stderr, argc, argv);
81 return ERR_WRONGARGS;
82 }
83
84 //Convert the time given in seconds to float
85 char* endptr;
86 maxtime = strtof( argv[fiarg], &endptr);
87 if( endptr != argv[fiarg] + strlen(argv[fiarg]) ||
88 maxtime<0.0)
89 {
90 fprintf(stderr, "Invalid time.\n");
91 fprintf(stderr, "\n");
92 printUsage(stderr, argc, argv);
93 return ERR_WRONGARGS;
94 }
95 }
96
97 //Help option
98 else if( strncmp(argv[fiarg], "-v", 2) == 0 )
99 {
100 argVerbose = true;
101 }
102
103
104 //Unknown option
105 else
106 {
107 fprintf(stderr, "Invalid argument: %s\n", argv[fiarg]);
108 fprintf(stderr, "\n");
109 printUsage(stderr, argc, argv);
110 return ERR_WRONGARGS;
111 }
112
113 //Goto next argument
114 fiarg++;
115 }
116
117
118 //Print help
119 if( argHelp )
120 {
121 printUsage(stdout, argc, argv);
122 return 0;
123 }
124
125
126 //No time given...
127 if( !argTime )
128 {
129 fprintf(stderr, "No time given!\n");
130 fprintf(stderr, "\n");
131 printUsage(stderr, argc, argv);
132 return ERR_WRONGARGS;
133 }
134
135 //No command left
136 if( fiarg>=argc )
137 {
138 fprintf(stderr, "No command given!\n");
139 fprintf(stderr, "\n");
140 printUsage(stderr, argc, argv);
141 return ERR_WRONGARGS;
142 }
143
144
145
146 //Fork process
147 pid_t pid = fork();
148
149
150 //Childrens code...
151 if( pid == 0)
152 {
153 char** newargv = (char**) malloc( sizeof(char*)*(argc-fiarg+1) );
154 char* newenv[] = {NULL};
155
156 //Copy arguments
157 for( int i=fiarg; i<argc; i++)
158 {
159 newargv[i-fiarg] = (char*)malloc(strlen(argv[i])+1);
160 strcpy(newargv[i-fiarg], argv[i]);
161 }
162 newargv[argc-fiarg] = NULL;
163
164
165 //Execute child process
166 execve(newargv[0], newargv, newenv);
167 perror("execve");
168 return ERR_EXECVE;
169 }
170 //Parents code...
171 else
172 {
173 //Failure
174 if(pid==-1)
175 {
176 perror("fork");
177 return ERR_FORK;
178 }
179
180
181 //Nmb of loops=seconds
182 float loops=0;
183 //Status flags of child process
184 int status;
185 //granularity
186 const int ussleep=25000;
187
188 while(true)
189 {
190 //Kill the child
191 if( loops*ussleep/1e6 >= maxtime )
192 {
193 if( argVerbose )
194 printf("Kill child...\n");
195
196 if( kill(pid, SIGTERM ) < 0)
197 break;
198 }
199
200 //Test for child
201 if( waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED) < 0 )
202 break;
203
204 if( WIFEXITED(status) )
205 break;
206
207 //Sleep a round
208 usleep(ussleep);
209 loops++;
210
211 }
212 }
213
214
215 if( argVerbose)
216 printf("Finished\n");
217
218 return 0;
219 }
220
221