/*
|
|
* --- ROCK-COPYRIGHT-NOTE-BEGIN ---
|
|
*
|
|
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
|
|
* Please add additional copyright information _after_ the line containing
|
|
* the ROCK-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by
|
|
* the ./scripts/Create-CopyPatch script. Do not edit this copyright text!
|
|
*
|
|
* ROCK Linux: rock-src/misc/tools-source/cmd_wrapper.c
|
|
* ROCK Linux is Copyright (C) 1998 - 2006 Clifford Wolf
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version. A copy of the GNU General Public
|
|
* License can be found at Documentation/COPYING.
|
|
*
|
|
* Many people helped and are helping developing ROCK Linux. Please
|
|
* have a look at http://www.rocklinux.org/ and the Documentation/TEAM
|
|
* file for details.
|
|
*
|
|
* --- ROCK-COPYRIGHT-NOTE-END ---
|
|
*
|
|
* Generic command wrapper.
|
|
*
|
|
* Recognised Variables:
|
|
*
|
|
* prefix_WRAPPER_MYPATH "/path/to/binary"
|
|
* prefix_WRAPPER_LOGFILE ".cmd_wrapper_log"
|
|
*
|
|
* prefix_WRAPPER_DEBUG 0
|
|
* prefix_WRAPPER_BYPASS 0
|
|
*
|
|
* prefix_WRAPPER_APPEND_PO "-1st-opt -2nd-opt"
|
|
*
|
|
* prefix_WRAPPER_OTHERS "wrapper1:wrapper2:..."
|
|
*
|
|
* prefix_WRAPPER_INSERT "-1st-opt -2nd-opt"
|
|
* prefix_WRAPPER_REMOVE "-del-this-opt -this-also [!-]*"
|
|
* prefix_WRAPPER_APPEND "-last-opt"
|
|
*
|
|
* prefix_WRAPPER_FILTER "sed '...' | awk '...' | foobar"
|
|
*
|
|
* prefix_WRAPPER_NOLOOP Internal use only.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <sys/wait.h>
|
|
#include <libgen.h>
|
|
#include <fnmatch.h>
|
|
|
|
#ifndef ENVPREFIX
|
|
# error You must use -DENVPREFIX=".." when compiling this tool.
|
|
#endif
|
|
|
|
#ifndef MYNAME
|
|
# error You must use -DMYNAME=".." when compiling this tool.
|
|
#endif
|
|
|
|
#define VERBOSE_DEBUG 1
|
|
int debug=1;
|
|
|
|
/*
|
|
* Clean config vars before using them (ugh!)
|
|
*/
|
|
void cleanenv(const char * name, const char ch) {
|
|
int pos1=0, pos2=0, delim=1;
|
|
char *tmp1, *tmp2;
|
|
|
|
setenv(name, "", 0);
|
|
tmp1 = getenv(name);
|
|
tmp2 = malloc(strlen(tmp1)+1);
|
|
|
|
while ( tmp1[pos1] ) {
|
|
if ( tmp1[pos1] == ch ) {
|
|
if ( ! delim ) {
|
|
tmp2[pos2++] = ch;
|
|
delim = 1;
|
|
}
|
|
} else {
|
|
tmp2[pos2++] = tmp1[pos1];
|
|
delim = 0;
|
|
}
|
|
pos1++;
|
|
}
|
|
if (pos2 > 0 && tmp2[pos2-1] == ch) pos2--;
|
|
tmp2[pos2] = 0; setenv(name, tmp2, 1);
|
|
}
|
|
|
|
/*
|
|
* Main function.
|
|
*/
|
|
int main(int argc, char ** argv) {
|
|
char **newargv;
|
|
int c1,c2,c3;
|
|
char *delim, *delim1, *optbuf, *wrdir;
|
|
FILE *logfile = NULL;
|
|
|
|
/* Calling the wrapper with an absolute path results in an
|
|
endless-loop. Use basename only to force a $PATH lookup. */
|
|
argv[0] = basename(argv[0]);
|
|
if ( !strcmp(argv[0], MYNAME) ) {
|
|
if ( argc > 1 ) {
|
|
argv++; argc--;
|
|
argv[0] = basename(argv[0]);
|
|
} else {
|
|
fprintf(stderr, "Usage: %s command\n", argv[0]);
|
|
exit(250);
|
|
}
|
|
}
|
|
|
|
/* Open logfile (if any) */
|
|
delim = getenv(ENVPREFIX "_WRAPPER_LOGFILE");
|
|
if (delim && delim[0]) {
|
|
logfile = fopen(delim, "a");
|
|
}
|
|
if (logfile) {
|
|
delim = malloc(FILENAME_MAX);
|
|
if ( getcwd(delim, FILENAME_MAX) == NULL ) delim[0]=0;
|
|
fprintf(logfile, "\n%s:\n-", delim);
|
|
for (c3=0; c3<argc; c3++) fprintf(logfile, " %s", argv[c3]);
|
|
fprintf(logfile, "\n");
|
|
free(delim);
|
|
}
|
|
|
|
/* Others loop */
|
|
if ( (delim = getenv(ENVPREFIX "_WRAPPER_OTHERS_TMP")) != NULL )
|
|
setenv(ENVPREFIX "_WRAPPER_OTHERS", delim, 1);
|
|
|
|
/* Has to be solved that way ... do not ask my why >_< */
|
|
if ( (delim = getenv(ENVPREFIX "_WRAPPER_APPEND_PO_CLEAR")) != NULL )
|
|
setenv(ENVPREFIX "_WRAPPER_APPEND_PO", "", 1);
|
|
|
|
/*
|
|
* Read prefix_WRAPPER_DEBUG and prefix_WRAPPER_BYPASS
|
|
*/
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_DEBUG")) != NULL &&
|
|
delim[0] ) debug = atoi(delim);
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_BYPASS")) != NULL &&
|
|
delim[0] && atoi(delim)) {
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr, "Bypassing cmd_wrapper by "
|
|
"clearing all config variables.\n");
|
|
#endif
|
|
setenv(ENVPREFIX "_WRAPPER_APPEND_PO", "", 1);
|
|
setenv(ENVPREFIX "_WRAPPER_OTHERS", "", 1);
|
|
setenv(ENVPREFIX "_WRAPPER_INSERT", "", 1);
|
|
setenv(ENVPREFIX "_WRAPPER_REMOVE", "", 1);
|
|
setenv(ENVPREFIX "_WRAPPER_APPEND", "", 1);
|
|
setenv(ENVPREFIX "_WRAPPER_FILTER", "", 1);
|
|
}
|
|
|
|
cleanenv(ENVPREFIX "_WRAPPER_APPEND_PO", ' ');
|
|
cleanenv(ENVPREFIX "_WRAPPER_OTHERS", ':');
|
|
cleanenv(ENVPREFIX "_WRAPPER_INSERT", ' ');
|
|
cleanenv(ENVPREFIX "_WRAPPER_REMOVE", ' ');
|
|
cleanenv(ENVPREFIX "_WRAPPER_APPEND", ' ');
|
|
cleanenv(ENVPREFIX "_WRAPPER_FILTER", '|');
|
|
|
|
#if VERBOSE_DEBUG
|
|
if (debug) {
|
|
fprintf(stderr, "Old Command:");
|
|
for (c3=0; c3<argc; c3++) fprintf(stderr, " %s", argv[c3]);
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "ENVPREFIX = '%s'\n", ENVPREFIX);
|
|
fprintf(stderr, "APPEND_PO = '%s'\n",
|
|
getenv(ENVPREFIX "_WRAPPER_APPEND_PO"));
|
|
fprintf(stderr, "OTHERS = '%s'\n",
|
|
getenv(ENVPREFIX "_WRAPPER_OTHERS"));
|
|
fprintf(stderr, "INSERT = '%s'\n",
|
|
getenv(ENVPREFIX "_WRAPPER_INSERT"));
|
|
fprintf(stderr, "REMOVE = '%s'\n",
|
|
getenv(ENVPREFIX "_WRAPPER_REMOVE"));
|
|
fprintf(stderr, "APPEND = '%s'\n",
|
|
getenv(ENVPREFIX "_WRAPPER_APPEND"));
|
|
fprintf(stderr, "FILTER = '%s'\n",
|
|
getenv(ENVPREFIX "_WRAPPER_FILTER"));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Run other wrappers first. They will re-start us.
|
|
*/
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_OTHERS")) != NULL &&
|
|
delim[0] ) {
|
|
|
|
c1=argc;
|
|
|
|
/*
|
|
* If prefix__WRAPPER_APPEND_PO we need to add the count of
|
|
* spaces in that variable
|
|
*/
|
|
|
|
if ( (delim1=getenv(ENVPREFIX "_WRAPPER_APPEND_PO")) != NULL &&
|
|
delim1[0] ) {
|
|
while (*delim1) { if (*delim1==' ') c1++; delim1++; }
|
|
}
|
|
|
|
newargv=malloc( sizeof(char*) * (c1+10) );
|
|
|
|
newargv[0] = malloc(strlen(delim) + 1);
|
|
strcpy(newargv[0], delim);
|
|
delim = strchr(newargv[0], ':');
|
|
if ( delim == NULL ) delim = "";
|
|
else { *delim = 0; delim++; }
|
|
setenv(ENVPREFIX "_WRAPPER_OTHERS_TMP", delim, 1);
|
|
|
|
for (c1=0; c1 < argc; c1++)
|
|
newargv[c1+1] = argv[c1];
|
|
|
|
/*
|
|
* Append prefix_WRAPPER_APPEND_PO contents
|
|
*/
|
|
|
|
if ( (delim1=getenv(ENVPREFIX "_WRAPPER_APPEND_PO")) != NULL &&
|
|
delim1[0] ) {
|
|
optbuf = malloc( strlen(delim1) + 1 );
|
|
strcpy(optbuf, delim1);
|
|
|
|
delim1 = strtok(optbuf, " ");
|
|
c1=argc+1;
|
|
while (delim1 != NULL) {
|
|
if (delim1[0]) {
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr,
|
|
"Append PreOthers: %s\n",
|
|
delim1);
|
|
#endif
|
|
newargv[c1++] = delim1;
|
|
}
|
|
delim1 = strtok(NULL, " ");
|
|
}
|
|
/* Telling next instance of the wrapper to clean
|
|
* prefix_WRAPPER_APPEND_PO_RUN (argh!)
|
|
*/
|
|
setenv(ENVPREFIX "_WRAPPER_APPEND_PO_CLEAR", "1", 1);
|
|
}
|
|
|
|
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr,
|
|
"Running external wrapper: %s\n", newargv[0]);
|
|
#endif
|
|
|
|
if (logfile) {
|
|
fprintf(logfile, "+");
|
|
for (c3=0; c3<=c1; c3++)
|
|
fprintf(logfile, " %s", newargv[c3]);
|
|
fprintf(logfile, "\n");
|
|
fclose(logfile);
|
|
}
|
|
|
|
execvp(newargv[0], newargv);
|
|
fprintf(stderr, ENVPREFIX "_WRAPPER: Can't execute "
|
|
"'%s' -> abort.\n", newargv[0]);
|
|
return 250;
|
|
}
|
|
|
|
|
|
/*
|
|
* Detect loops
|
|
*/
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_NOLOOP")) != NULL &&
|
|
delim[0] && delim[0] != '0') {
|
|
fprintf(stderr, ENVPREFIX
|
|
"_WRAPPER: Detected loop! -> abort.\n");
|
|
return 250;
|
|
}
|
|
setenv(ENVPREFIX "_WRAPPER_NOLOOP", "1", 1);
|
|
|
|
|
|
/*
|
|
* Remove the wrapper dir from PATH
|
|
*/
|
|
|
|
if ( (delim=getenv("PATH")) != NULL && delim[0] &&
|
|
(wrdir=getenv(ENVPREFIX "_WRAPPER_MYPATH")) != NULL &&
|
|
wrdir[0] ) {
|
|
optbuf = malloc( strlen(delim) + 1 );
|
|
optbuf[0] = 0;
|
|
|
|
#if VERBOSE_DEBUG
|
|
if (debug)
|
|
fprintf(stderr, "Old PATH: %s\n", delim);
|
|
#endif
|
|
|
|
delim = strtok(delim, ":");
|
|
while ( delim != NULL ) {
|
|
if (strcmp(delim, wrdir)) {
|
|
if (optbuf[0]) strcat(optbuf, ":");
|
|
strcat(optbuf, delim);
|
|
}
|
|
delim = strtok(NULL, ":");
|
|
}
|
|
setenv("PATH", optbuf, 1);
|
|
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr, "New PATH: %s\n", optbuf);
|
|
#endif
|
|
} else {
|
|
fprintf(stderr, ENVPREFIX "_WRAPPER: $PATH or $" ENVPREFIX
|
|
"_WRAPPER_MYPATH is not set! -> abort.\n");
|
|
return 250;
|
|
}
|
|
|
|
/*
|
|
* Make sure that newargv[] is big enough
|
|
*/
|
|
|
|
/* start with argc */
|
|
c1 = argc;
|
|
|
|
/* add numbers of blanks in prefix_WRAPPER_INSERT */
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_INSERT")) != NULL )
|
|
while (*delim) { if (*delim==' ') c1++; delim++; }
|
|
|
|
/* add numbers of blanks in prefix_WRAPPER_APPEND */
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_APPEND")) != NULL )
|
|
while (*delim) { if (*delim==' ') c1++; delim++; }
|
|
|
|
/* add 10 to be sure (3 should be enough) */
|
|
newargv=malloc( sizeof(char*) * (c1+10) );
|
|
|
|
/* init newargv[], c1 and c2 */
|
|
newargv[0]=argv[0]; c1=1; c2=1;
|
|
|
|
/*
|
|
* Copy options from prefix_WRAPPER_INSERT to newargv[]
|
|
*/
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_INSERT")) != NULL ) {
|
|
optbuf = malloc( strlen(delim) + 1 );
|
|
strcpy(optbuf, delim);
|
|
|
|
delim = strtok(optbuf, " ");
|
|
while (delim != NULL) {
|
|
if (delim[0]) {
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr, "Insert: %s\n", delim);
|
|
#endif
|
|
newargv[c1++] = delim;
|
|
}
|
|
delim = strtok(NULL, " ");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Copy options from argv[] to newargv[] if they are not listed
|
|
* in prefix_WRAPPER_REMOVE
|
|
*/
|
|
|
|
for (; c2<argc; c2++) {
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_REMOVE")) != NULL ) {
|
|
optbuf = malloc( strlen(delim) + 1 );
|
|
strcpy(optbuf, delim);
|
|
|
|
delim = strtok(optbuf, " ");
|
|
while (delim != NULL) {
|
|
if ( delim[0] &&
|
|
!fnmatch(delim, argv[c2], 0) ) break;
|
|
delim = strtok(NULL, " ");
|
|
}
|
|
free(optbuf);
|
|
}
|
|
if (delim == NULL) {
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr, "Copy: %s\n", argv[c2]);
|
|
#endif
|
|
newargv[c1++] = argv[c2];
|
|
#if VERBOSE_DEBUG
|
|
} else {
|
|
if (debug) fprintf(stderr, "Remove: %s\n", argv[c2]);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Copy options from prefix_WRAPPER_APPEND to newargv[]
|
|
*/
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_APPEND")) != NULL ) {
|
|
optbuf = malloc( strlen(delim) + 1 );
|
|
strcpy(optbuf, delim);
|
|
|
|
delim = strtok(optbuf, " ");
|
|
while (delim != NULL) {
|
|
if (delim[0]) {
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr, "Append: %s\n", delim);
|
|
#endif
|
|
newargv[c1++] = delim;
|
|
}
|
|
delim = strtok(NULL, " ");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Use prefix_WRAPPER_FILTER if set and not ""
|
|
*
|
|
* (Maybe we make a nice re-write of this code-block later.)
|
|
*/
|
|
|
|
if ( (delim=getenv(ENVPREFIX "_WRAPPER_FILTER")) != NULL && delim[0] ) {
|
|
|
|
/* Open temp files. */
|
|
char outfn[] = "/tmp/gccfilter_out.XXXXXX";
|
|
char infn[] = "/tmp/gccfilter_in.XXXXXX";
|
|
int outfd = mkstemp(outfn);
|
|
int infd = mkstemp(infn);
|
|
|
|
/* Create content of input file */
|
|
for (c3=0; c3<c1; c3++) {
|
|
write(infd, newargv[c3], strlen(newargv[c3]));
|
|
write(infd, "\n", 1);
|
|
}
|
|
lseek(infd, 0, SEEK_SET);
|
|
|
|
/* Run filter command with shell (sh -c xxx) */
|
|
#if VERBOSE_DEBUG
|
|
if (debug) fprintf(stderr, "Run Filter: %s\n", delim);
|
|
#endif
|
|
if (!fork()) {
|
|
dup2(infd, 0); close(infd);
|
|
dup2(outfd, 1); close(outfd);
|
|
execlp("sh", "sh", "-c", delim, NULL);
|
|
fprintf(stderr, ENVPREFIX "_WRAPPER: Can't execute "
|
|
"'%s' with shell!\n", delim);
|
|
return 1;
|
|
}
|
|
wait(NULL); /* We don't expect any signals and have no */
|
|
/* other child processes. */
|
|
|
|
/* Re-read parameter list. Don't free old stuff, we do an
|
|
exec() anyway ... */
|
|
lseek(outfd, 0, SEEK_SET);
|
|
/* Maximum on 1023 parameters, 1023 chars each. */
|
|
newargv = malloc( sizeof(char*) * 1024 );
|
|
for (c1=0; c1<1023; c1++) {
|
|
newargv[c1] = malloc(1024);
|
|
for (c2=0; c2<1023; c2++) {
|
|
if (read(outfd, newargv[c1]+c2, 1) != 1)
|
|
goto reread_file_finished;
|
|
if (newargv[c1][c2] == '\n')
|
|
{ newargv[c1][c2] = 0; break; }
|
|
}
|
|
newargv[c1] = realloc(newargv[c1],
|
|
strlen(newargv[c1])+1);
|
|
}
|
|
reread_file_finished:
|
|
|
|
/* Close and remove temp files */
|
|
close(outfd); unlink(outfn);
|
|
close(infd); unlink(infn);
|
|
}
|
|
|
|
|
|
/*
|
|
* Run the new command
|
|
*/
|
|
|
|
if (debug) {
|
|
fprintf(stderr, "New Command:");
|
|
for (c3=0; c3<c1; c3++) fprintf(stderr, " %s", newargv[c3]);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if (logfile) {
|
|
fprintf(logfile, "+");
|
|
for (c3=0; c3<c1; c3++) fprintf(logfile, " %s", newargv[c3]);
|
|
fprintf(logfile, "\n");
|
|
fclose(logfile);
|
|
}
|
|
|
|
newargv[c1]=NULL;
|
|
execvp(newargv[0], newargv);
|
|
|
|
fprintf(stderr, ENVPREFIX "_WRAPPER: Can't execute "
|
|
"'%s' -> abort.\n", newargv[0]);
|
|
return 250;
|
|
}
|