2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by scripts/Create-CopyPatch.
5 * T2 SDE: misc/tools-source/cmd_wrapper.c
6 * Copyright (C) 2004 - 2021 The T2 SDE Project
7 * Copyright (C) 1998 - 2003 ROCK Linux Project
8 * Copyright (C) 2006 - 2010 Rene Rebe <rene@exactcode.de>
10 * More information can be found in the files COPYING and README.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2 of the License. A copy of the
15 * GNU General Public License can be found in the file COPYING.
16 * --- T2-COPYRIGHT-NOTE-END ---
18 * Generic command wrapper.
20 * Recognised Variables:
22 * prefix_WRAPPER_MYPATH "/path/to/binary"
23 * prefix_WRAPPER_LOGFILE ".cmd_wrapper_log"
25 * prefix_WRAPPER_DEBUG 0
26 * prefix_WRAPPER_BYPASS 0
28 * prefix_WRAPPER_OTHERS "other_cmd"
30 * prefix_WRAPPER_INSERT "-1st-opt -2nd-opt"
31 * prefix_WRAPPER_REMOVE "-del-this-opt -this-also [!-]*"
32 * prefix_WRAPPER_APPEND "-last-opt"
34 * prefix_WRAPPER_FILTER "sed '...' | awk '...' | foobar"
36 * prefix_WRAPPER_NOLOOP Internal use only.
37 * prefix_WRAPPER_OTHERS_DONE Internal use only.
52 # error You must use -DENVPREFIX=".." when compiling this tool.
56 # error You must use -DMYNAME=".." when compiling this tool.
59 #define VERBOSE_DEBUG 1
63 * Clean config vars before using them
65 void cleanenv(const char * name
, const char ch
) {
66 int pos1
=0, pos2
=0, delim
=1;
69 setenv(name
, "", 0); /* no overwrite - make sure it is defined */
71 tmp2
= malloc(strlen(tmp1
)+1);
73 while ( tmp1
[pos1
] ) {
74 if ( tmp1
[pos1
] == ch
) {
80 tmp2
[pos2
++] = tmp1
[pos1
];
85 if (pos2
> 0 && tmp2
[pos2
-1] == ch
) pos2
--;
86 tmp2
[pos2
] = 0; setenv(name
, tmp2
, 1);
90 * Evaluate conditional argument in the form:
91 * "condition?matched-value:unmatched-value"
93 char* eval_cond_arg (char * arg
, int argc
, char ** argv
) {
95 char * lhs
= NULL
, * rhs
= NULL
;
98 while (*c
&& *c
!= '?') c
++;
104 if (debug
) fprintf(stderr
, "Conditonal arg: '%s'\n", arg
);
107 /* split conditional (arg), left hand and right hand statement */
112 while (*c
&& *c
!= ':') c
++;
117 if (debug
) fprintf(stderr
, "Conditonal: '%s', lhs: '%s', rhs: '%s'\n", arg
, lhs
, rhs
);
119 /* match arguments against conditional */
122 if (!fnmatch(arg
, *argv
, 0)) {
124 if (debug
) fprintf(stderr
, "Conditonal: '%s', matched: '%s'\n", arg
, *argv
);
134 /* newargv memory management, realloc if newargv is filled */
135 static inline char** realloc_if_needed(int c1
, int* newargc
, char** newargv
) {
136 if (c1
+ 1 >= *newargc
) { /* +1 for NULL-sentinel */
138 newargv
= realloc (newargv
, sizeof(char*) * *newargc
);
146 int main(int argc
, char ** argv
) {
147 int newargc
= 64; /* initial newargv size, anyhting >3 (name, other, NULL) */
149 char *other
, *other_done
;
151 char *delim
, *optbuf
, *wrdir
;
152 FILE *logfile
= NULL
;
154 /* Calling the wrapper with an absolute path results in an
155 endless-loop. Use basename only to force a $PATH lookup. */
156 argv
[0] = basename(argv
[0]);
157 if ( !strcmp(argv
[0], MYNAME
) ) {
160 argv
[0] = basename(argv
[0]);
166 /* Open logfile (if any) */
167 delim
= getenv(ENVPREFIX
"_WRAPPER_LOGFILE");
168 if (delim
&& delim
[0]) {
169 logfile
= fopen(delim
, "a");
172 delim
= malloc(FILENAME_MAX
);
173 if ( getcwd(delim
, FILENAME_MAX
) == NULL
) delim
[0]=0;
174 fprintf(logfile
, "\n%s:\n-", delim
);
175 for (c3
=0; c3
<argc
; c3
++) fprintf(logfile
, " %s", argv
[c3
]);
176 fprintf(logfile
, "\n");
181 * Read prefix_WRAPPER_DEBUG and prefix_WRAPPER_BYPASS
184 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_DEBUG")) != NULL
&&
185 delim
[0] ) debug
= atoi(delim
);
187 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_BYPASS")) != NULL
&&
188 delim
[0] && atoi(delim
)) {
190 if (debug
) fprintf(stderr
, "Bypassing cmd_wrapper by "
191 "clearing all config variables.\n");
193 setenv(ENVPREFIX
"_WRAPPER_OTHERS", "", 1);
194 setenv(ENVPREFIX
"_WRAPPER_INSERT", "", 1);
195 setenv(ENVPREFIX
"_WRAPPER_REMOVE", "", 1);
196 setenv(ENVPREFIX
"_WRAPPER_APPEND", "", 1);
197 setenv(ENVPREFIX
"_WRAPPER_FILTER", "", 1);
200 cleanenv(ENVPREFIX
"_WRAPPER_OTHERS", ':');
201 cleanenv(ENVPREFIX
"_WRAPPER_INSERT", ' ');
202 cleanenv(ENVPREFIX
"_WRAPPER_REMOVE", ' ');
203 cleanenv(ENVPREFIX
"_WRAPPER_APPEND", ' ');
204 cleanenv(ENVPREFIX
"_WRAPPER_FILTER", '|');
208 fprintf(stderr
, "Old Command:");
209 for (c3
=0; c3
<argc
; c3
++) fprintf(stderr
, " %s", argv
[c3
]);
210 fprintf(stderr
, "\n");
211 fprintf(stderr
, "ENVPREFIX = '%s'\n", ENVPREFIX
);
212 fprintf(stderr
, "OTHERS = '%s'\n",
213 getenv(ENVPREFIX
"_WRAPPER_OTHERS"));
214 if (getenv(ENVPREFIX
"_WRAPPER_OTHERS_DONE"))
215 fprintf(stderr
, "OTHERS DONE = '%s'\n",
216 getenv(ENVPREFIX
"_WRAPPER_OTHERS_DONE"));
217 fprintf(stderr
, "INSERT = '%s'\n",
218 getenv(ENVPREFIX
"_WRAPPER_INSERT"));
219 fprintf(stderr
, "REMOVE = '%s'\n",
220 getenv(ENVPREFIX
"_WRAPPER_REMOVE"));
221 fprintf(stderr
, "APPEND = '%s'\n",
222 getenv(ENVPREFIX
"_WRAPPER_APPEND"));
223 fprintf(stderr
, "FILTER = '%s'\n",
224 getenv(ENVPREFIX
"_WRAPPER_FILTER"));
228 /* extract the next other wrapper */
229 other
= getenv(ENVPREFIX
"_WRAPPER_OTHERS");
230 other_done
= getenv(ENVPREFIX
"_WRAPPER_OTHERS_DONE");
232 if (other
&& strlen(other
) > 0) {
233 other
= strdup(other
);
237 char *str
= strstr(other
, other_done
);
239 fprintf(stderr
, "OTHERS_DONE set but does not match.\n");
243 other
+= strlen(other_done
);
251 newother_done
= (char *) malloc(strlen(getenv(ENVPREFIX
"_WRAPPER_OTHERS")));
252 strcpy(newother_done
, other_done
);
253 strcat(newother_done
, ":");
254 strcat(newother_done
, other
);
256 setenv(ENVPREFIX
"_WRAPPER_OTHERS_DONE", newother_done
, 1);
260 other
= strtok(other
, ":");
261 setenv(ENVPREFIX
"_WRAPPER_OTHERS_DONE", other
, 1);
269 newargv
= malloc( sizeof(char*) * newargc
);
271 /* init newargv[], c1 and c2 */
273 if (other
&& strlen(other
) > 0)
274 newargv
[c1
++] = other
;
275 newargv
[c1
++] = argv
[c2
++];
278 * Copy options from prefix_WRAPPER_INSERT to newargv[]
281 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_INSERT")) != NULL
) {
282 optbuf
= malloc( strlen(delim
) + 1 );
283 strcpy(optbuf
, delim
);
285 delim
= strtok(optbuf
, " ");
286 while (delim
!= NULL
) {
287 delim
= eval_cond_arg (delim
, argc
, argv
);
291 if (debug
) fprintf(stderr
, "Insert: %s\n", delim
);
293 newargv
= realloc_if_needed(c1
, &newargc
, newargv
);
294 newargv
[c1
++] = delim
;
296 delim
= strtok(NULL
, " ");
302 * Copy options from argv[] to newargv[] if they are not listed
303 * in prefix_WRAPPER_REMOVE
306 for (; c2
<argc
; c2
++) {
307 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_REMOVE")) != NULL
) {
308 optbuf
= malloc( strlen(delim
) + 1 );
309 strcpy(optbuf
, delim
);
311 delim
= strtok(optbuf
, " ");
312 while (delim
!= NULL
) {
313 delim
= eval_cond_arg (delim
, argc
, argv
);
315 !fnmatch(delim
, argv
[c2
], 0) ) break;
316 delim
= strtok(NULL
, " ");
322 if (debug
) fprintf(stderr
, "Copy: %s\n", argv
[c2
]);
325 newargv
= realloc_if_needed(c1
, &newargc
, newargv
);
326 newargv
[c1
++] = argv
[c2
];
329 if (debug
) fprintf(stderr
, "Remove: %s\n", argv
[c2
]);
336 * Copy options from prefix_WRAPPER_APPEND to newargv[]
339 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_APPEND")) != NULL
) {
340 optbuf
= malloc( strlen(delim
) + 1 );
341 strcpy(optbuf
, delim
);
343 delim
= strtok(optbuf
, " ");
344 while (delim
!= NULL
) {
345 delim
= eval_cond_arg (delim
, argc
, argv
);
348 if (debug
) fprintf(stderr
, "Append: %s\n", delim
);
351 newargv
= realloc_if_needed(c1
, &newargc
, newargv
);
352 newargv
[c1
++] = delim
;
354 delim
= strtok(NULL
, " ");
360 * Use prefix_WRAPPER_FILTER if set and not ""
362 * (Maybe we make a nice re-write of this code-block later.)
365 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_FILTER")) != NULL
&& delim
[0] ) {
367 /* Open temp files. */
368 char outfn
[] = "/tmp/gccfilter_out.XXXXXX";
369 char infn
[] = "/tmp/gccfilter_in.XXXXXX";
370 int outfd
= mkstemp(outfn
);
371 int infd
= mkstemp(infn
);
374 /* Create content of input file */
375 for (c3
=0; c3
<c1
; c3
++) {
376 write(infd
, newargv
[c3
], strlen(newargv
[c3
]));
377 write(infd
, "\n", 1);
379 lseek(infd
, 0, SEEK_SET
);
381 /* Run filter command with shell (sh -c xxx) */
383 if (debug
) fprintf(stderr
, "Run Filter: %s\n", delim
);
387 dup2(infd
, 0); close(infd
);
388 dup2(outfd
, 1); close(outfd
);
389 execlp("sh", "sh", "-c", delim
, NULL
);
391 } else if (pid
== -1) {
392 fprintf(stderr
, "Fork failed: %d: %s\n", errno
, strerror(errno
));
394 /* We don't expect any signals and have no other child processes. */
396 if (WEXITSTATUS(status
) != 0) {
397 fprintf(stderr
, "Filter failed: %d\n", WEXITSTATUS(status
));
401 /* Re-read parameter list. */
403 size_t argvsize
= lseek(outfd
, 0, SEEK_END
);
404 char* argvmem
= malloc (argvsize
+ 1); /* might not have trailing \n */
405 lseek(outfd
, 0, SEEK_SET
);
406 read(outfd
, argvmem
, argvsize
);
409 fprintf(stderr
, "Filter produced no output!\n");
413 for (c1
= c2
= 0; c2
< argvsize
; ++c2
) {
414 newargv
= realloc_if_needed(c1
, &newargc
, newargv
);
415 newargv
[c1
++] = argvmem
+ c2
;
417 /* scan for newlines, terminate, next */
418 while (c2
< argvsize
&& argvmem
[c2
] != '\n')
424 /* Close and remove temp files */
425 close(outfd
); unlink(outfn
);
426 close(infd
); unlink(infn
);
430 * Run other wrappers first. They will re-start us.
433 if (other
&& strlen(other
) > 0) {
437 fprintf(stderr
, "Running external wrapper: %s\n", newargv
[0]);
438 for (c3
=0; c3
<c1
; c3
++)
439 fprintf(stderr
, " %s", newargv
[c3
]);
440 fprintf(stderr
, "\n");
445 fprintf(logfile
, "+");
446 for (c3
=0; c3
<c1
; c3
++)
447 fprintf(logfile
, " %s", newargv
[c3
]);
448 fprintf(logfile
, "\n");
453 execvp(newargv
[0], newargv
);
454 fprintf(stderr
, "cmd_wrapper: execvp(%s,...) - %s\n",
455 newargv
[0], strerror(errno
));
461 * Remove the wrapper dir from PATH
464 if ( (delim
=getenv("PATH")) != NULL
&& delim
[0] &&
465 (wrdir
=getenv(ENVPREFIX
"_WRAPPER_MYPATH")) != NULL
&&
467 optbuf
= malloc( strlen(delim
) + 1 );
472 fprintf(stderr
, "Old PATH: %s\n", delim
);
475 delim
= strtok(delim
, ":");
476 while ( delim
!= NULL
) {
477 if (strcmp(delim
, wrdir
)) {
478 if (optbuf
[0]) strcat(optbuf
, ":");
479 strcat(optbuf
, delim
);
481 delim
= strtok(NULL
, ":");
483 setenv("PATH", optbuf
, 1);
486 if (debug
) fprintf(stderr
, "New PATH: %s\n", optbuf
);
496 if ( (delim
=getenv(ENVPREFIX
"_WRAPPER_NOLOOP")) != NULL
&&
497 delim
[0] && delim
[0] != '0') {
500 setenv(ENVPREFIX
"_WRAPPER_NOLOOP", "1", 1);
503 * Run the new command
508 fprintf(stderr
, "New Command:");
509 for (c3
=0; c3
<c1
; c3
++) fprintf(stderr
, " %s", newargv
[c3
]);
510 fprintf(stderr
, "\n");
515 fprintf(logfile
, "+");
516 for (c3
=0; c3
<c1
; c3
++) fprintf(logfile
, " %s", newargv
[c3
]);
517 fprintf(logfile
, "\n");
522 execvp(newargv
[0], newargv
);
523 fprintf(stderr
, "cmd_wrapper: execvp(%s,...) - %s\n",
524 newargv
[0], strerror(errno
));