|
|
/*
* --- 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 - 2004 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; }
|