execute.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:12k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * Utility routines to assist with the running of sub-commands
  3.  */
  4. #include <net-snmp/net-snmp-config.h>
  5. #if HAVE_IO_H
  6. #include <io.h>
  7. #endif
  8. #include <stdio.h>
  9. #if HAVE_STDLIB_H
  10. #include <stdlib.h>
  11. #endif
  12. #if HAVE_UNISTD_H
  13. #include <unistd.h>
  14. #endif
  15. #if HAVE_MALLOC_H
  16. #include <malloc.h>
  17. #endif
  18. #include <sys/types.h>
  19. #include <ctype.h>
  20. #if HAVE_FCNTL_H
  21. #include <fcntl.h>
  22. #endif
  23. #if HAVE_SYS_WAIT_H
  24. #include <sys/wait.h>
  25. #endif
  26. #if HAVE_SYS_SELECT_H
  27. #include <sys/select.h>
  28. #endif
  29. #include <errno.h>
  30. #include <net-snmp/net-snmp-includes.h>
  31. #include <net-snmp/agent/net-snmp-agent-includes.h>
  32. #include <ucd-snmp/errormib.h>
  33. #include "util_funcs.h"
  34. #define setPerrorstatus(x) snmp_log_perror(x)
  35. int
  36. run_shell_command( char *command, char *input,
  37.                    char *output,  int *out_len) /* Or realloc style ? */
  38. {
  39. #if HAVE_SYSTEM
  40.     const char *ifname;    /* Filename for input  redirection */
  41.     const char *ofname;    /* Filename for output redirection */
  42.     char        shellline[STRMAX];   /* The full command to run */
  43.     int         result;    /* and the return value of the command */
  44.     if (!command)
  45.         return -1;
  46.     DEBUGMSGTL(("run_shell_command", "running %sn", command));
  47.     DEBUGMSGTL(("run:shell", "running '%s'n", command));
  48.     /*
  49.      * Set up the command to run....
  50.      */
  51.     if (input) {
  52.         FILE       *file;
  53.         ifname = make_tempfile();
  54.         if(NULL == ifname)
  55.             return -1;
  56.         file = fopen(ifname, "w");
  57.         if(NULL == file) {
  58.             snmp_log(LOG_ERR,"couldn't open temporary file %sn", ifname);
  59.             unlink(ifname);
  60.             return -1;
  61.         }
  62. fprintf(file, "%s", input);
  63.         fclose( file );
  64.         if (output) {
  65.             ofname = make_tempfile();
  66.             if(NULL == ofname) {
  67.                 if(ifname)
  68.                     unlink(ifname);
  69.                 return -1;
  70.             }
  71.             snprintf( shellline, sizeof(shellline), "(%s) < "%s" > "%s"",
  72.                       command, ifname, ofname );
  73.         } else {
  74.             ofname = NULL;   /* Just to shut the compiler up! */
  75.             snprintf( shellline, sizeof(shellline), "(%s) < "%s"",
  76.                       command, ifname );
  77.         }
  78.     } else {
  79.         ifname = NULL;   /* Just to shut the compiler up! */
  80.         if (output) {
  81.             ofname = make_tempfile();
  82.             if(NULL == ofname)
  83.                 return -1;
  84.             snprintf( shellline, sizeof(shellline), "(%s) > "%s"",
  85.                       command, ofname );
  86.         } else {
  87.             ofname = NULL;   /* Just to shut the compiler up! */
  88.             snprintf( shellline, sizeof(shellline), "%s",
  89.                       command );
  90.         }
  91.     }
  92.     /*
  93.      * ... and run it
  94.      */
  95.     result = system(shellline);
  96.     /*
  97.      * If output was requested, then retrieve & return it.
  98.      * Tidy up, and return the result of the command.
  99.      */
  100.     if ( output && out_len && (*out_len != 0) ) {
  101.         int         fd;        /* For processing any output */
  102.         int         len = 0;
  103.         fd = open(ofname, O_RDONLY);
  104.         if(fd >= 0)
  105.             len  = read( fd, output, *out_len-1 );
  106. *out_len = len;
  107. if (len >= 0) output[len] = 0;
  108. else output[0] = 0;
  109. if (fd >= 0) close(fd);
  110.         unlink(ofname);
  111.     }
  112.     if ( input ) {
  113.         unlink(ifname);
  114.     }
  115.     return result;
  116. #else
  117.     return -1;
  118. #endif
  119. }
  120. /*
  121.  * Split the given command up into separate tokens,
  122.  * ready to be passed to 'execv'
  123.  */
  124. static char **
  125. tokenize_exec_command( char *command, int *argc )
  126. {
  127.     char ctmp[STRMAX];
  128.     char *cptr1, *cptr2;
  129.     char **argv;
  130.     int  count, i;
  131.     if (!command)
  132.         return NULL;
  133.     memset( ctmp, 0, STRMAX );
  134.     /*
  135.      * Make a copy of the command into the 'ctmp' buffer,
  136.      *    splitting it into separate tokens
  137.      *    (but still all in the one buffer).
  138.      */
  139.     count = 1;
  140.     for (cptr1 = command, cptr2 = ctmp;
  141.             cptr1 && *cptr1;
  142.             cptr1++, cptr2++) {
  143.         *cptr2 = *cptr1;
  144. if (isspace(*cptr1)) {
  145.             /*
  146.              * We've reached the end of a token, so increase
  147.              * the count, and mark this in the command copy.
  148.              * Then get ready for the next word.
  149.              */
  150.             count++;
  151.             *cptr2 = 0;    /* End of token */
  152.     cptr1 = skip_white(cptr1);
  153.     if (!cptr1)
  154.         break;
  155.     cptr1--; /* Back up one, ready for the next loop */
  156. }
  157.     }
  158.     /*
  159.      * Now set up the 'argv' array,
  160.      *   copying tokens out of the 'cptr' buffer
  161.      */
  162.     argv = (char **) calloc((count + 2), sizeof(char *));
  163.     if (argv == NULL)
  164.         return NULL;
  165.     cptr2 = ctmp;
  166.     for (i = 0; i < count; i++) {
  167.         argv[i] = strdup( cptr2 );
  168.         cptr2  += strlen( cptr2 )+1;
  169.     }
  170.     argv[count] = 0;
  171.     *argc       = count;
  172.         
  173.     return argv;
  174. }
  175. int
  176. run_exec_command( char *command, char *input,
  177.                   char *output,  int  *out_len) /* Or realloc style ? */
  178. {
  179. #if HAVE_EXECV
  180.     int ipipe[2];
  181.     int opipe[2];
  182.     int i;
  183.     int pid;
  184.     int result;
  185.     char **argv;
  186.     int argc;
  187.     DEBUGMSGTL(("run:exec", "running '%s'n", command));
  188.     pipe(ipipe);
  189.     pipe(opipe);
  190.     if ((pid = fork()) == 0) {
  191.         /*
  192.          * Child process
  193.          */
  194.         /*
  195.          * Set stdin/out/err to use the pipe
  196.          *   and close everything else
  197.          */
  198.         close(0);
  199.         dup(  ipipe[0]);
  200. close(ipipe[1]);
  201.         close(1);
  202.         dup(  opipe[1]);
  203.         close(opipe[0]);
  204.         close(2);
  205.         dup(1);
  206.         for (i = getdtablesize()-1; i>2; i--)
  207.             close(i);
  208.         /*
  209.          * Set up the argv array and execute it
  210.          * This is being run in the child process,
  211.          *   so will release resources when it terminates.
  212.          */
  213.         argv = tokenize_exec_command( command, &argc );
  214.         execv( argv[0], argv );
  215.         perror( argv[0] );
  216.         exit(1); /* End of child */
  217.     } else if (pid > 0) {
  218.         char            cache[MAXCACHESIZE];
  219.         char           *cache_ptr;
  220.         ssize_t         count, cache_size, offset = 0;
  221.         int             waited = 0, numfds;
  222.         fd_set          readfds;
  223.         struct timeval  timeout;
  224.         /*
  225.          * Parent process
  226.          */
  227.         /*
  228.  * Pass the input message (if any) to the child,
  229.          * wait for the child to finish executing, and read
  230.          *    any output into the output buffer (if provided)
  231.          */
  232. close(ipipe[0]);
  233. close(opipe[1]);
  234. if (input) {
  235.    write(ipipe[1], input, strlen(input));
  236.    close(ipipe[1]); /* or flush? */
  237.         }
  238. else close(ipipe[1]);
  239.         /*
  240.          * child will block if it writes a lot of data and
  241.          * fills up the pipe before exiting, so we read data
  242.          * to keep the pipe empty.
  243.          */
  244.         if (output && ((NULL == out_len) || (0 == *out_len))) {
  245.             DEBUGMSGTL(("run:exec",
  246.                         "invalid params; no output will be returnedn"));
  247.             output = NULL;
  248.         }
  249.         if (output) {
  250.             cache_ptr = output;
  251.             cache_size = *out_len - 1;
  252.         } else {
  253.             cache_ptr = cache;
  254.             cache_size = sizeof(cache);
  255.         }
  256.         /*
  257.          * xxx: some of this code was lifted from get_exec_output
  258.          * in util_funcs.c. Probably should be moved to a common
  259.          * routine for both to use.
  260.          */
  261.         DEBUGMSGTL(("verbose:run:exec","  waiting for child %d...n", pid));
  262.         numfds = opipe[0] + 1;
  263.         i = MAXREADCOUNT;
  264.         for (; i; --i) {
  265.             /*
  266.              * set up data for select
  267.              */
  268.             FD_ZERO(&readfds);
  269.             FD_SET(opipe[0],&readfds);
  270.             timeout.tv_sec = 1;
  271.             timeout.tv_usec = 0;
  272.             DEBUGMSGTL(("verbose:run:exec", "    calling selectn"));
  273.             count = select(numfds, &readfds, NULL, NULL, &timeout);
  274.             if (count == -1) {
  275.                 if (EAGAIN == errno)
  276.                     continue;
  277.                 else {
  278.                     DEBUGMSGTL(("verbose:run:exec", "      errno %dn",
  279.                                 errno));
  280.                     setPerrorstatus("read");
  281.                     break;
  282.                 }
  283.             } else if (0 == count) {
  284.                 DEBUGMSGTL(("verbose:run:exec", "      timeoutn"));
  285.                 continue;
  286.             }
  287.             if (! FD_ISSET(opipe[0], &readfds)) {
  288.                 DEBUGMSGTL(("verbose:run:exec", "    fd not ready!n"));
  289.                 continue;
  290.             }
  291.             /*
  292.              * read data from the pipe, optionally saving to output buffer
  293.              */
  294.             count = read(opipe[0], &cache_ptr[offset], cache_size);
  295.             DEBUGMSGTL(("verbose:run:exec",
  296.                         "    read %d bytesn", count));
  297.             if (0 == count) {
  298.                 int rc;
  299.                 /*
  300.                  * we shouldn't get no data, because select should
  301.                  * wait til the fd is ready. before we go back around,
  302.                  * check to see if the child exited.
  303.                  */
  304.                 DEBUGMSGTL(("verbose:run:exec", "    no data!n"));
  305.                 if ((rc = waitpid(pid, &result, WNOHANG)) <= 0) {
  306.                     if (rc < 0) {
  307.                         snmp_log_perror("waitpid");
  308.                         break;
  309.                     } else
  310.                         DEBUGMSGTL(("verbose:run:exec",
  311.                                     "      child not done!?!n"));;
  312.                 } else {
  313.                     DEBUGMSGTL(("verbose:run:exec", "      child donen"));
  314.                     waited = 1; /* don't wait again */
  315.                     break;
  316.                 }
  317.             }
  318.             else if (count > 0) {
  319.                 /*
  320.                  * got some data. fix up offset, if needed.
  321.                  */
  322.                 if(output) {
  323.                     offset += count;
  324.                     cache_size -= count;
  325.                     if (cache_size <= 0) {
  326.                         DEBUGMSGTL(("verbose:run:exec",
  327.                                     "      output fulln"));
  328.                         break;
  329.                     }
  330.                     DEBUGMSGTL(("verbose:run:exec",
  331.                                 "    %d left in buffern", cache_size));
  332.                 }
  333.             }
  334.             else if ((count == -1) && (EAGAIN != errno)) {
  335.                 /*
  336.                  * if error, break
  337.                  */
  338.                 DEBUGMSGTL(("verbose:run:exec", "      errno %dn",
  339.                             errno));
  340.                 setPerrorstatus("read");
  341.                 break;
  342.             }
  343.         }
  344.         DEBUGMSGTL(("verbose:run:exec", "  done readingn"));
  345.         if (output)
  346.             DEBUGMSGTL(("run:exec", "  got %d bytesn", *out_len));
  347.             
  348.         /*
  349.          * close pipe to signal that we aren't listenting any more.
  350.          */
  351.         close(opipe[0]);
  352.         /*
  353.          * if we didn't wait successfully above, wait now.
  354.          * xxx-rks: seems like this is a waste of the agent's
  355.          * time. maybe start a time to wait(WNOHANG) once a second,
  356.          * and late the agent continue?
  357.          */
  358.         if ((!waited) && (waitpid(pid, &result, 0) < 0 )) {
  359.             snmp_log_perror("waitpid");
  360.             return -1;
  361.         }
  362.         /*
  363.          * null terminate any output
  364.          */
  365.         if (output) {
  366.     output[offset] = 0;
  367.     *out_len = offset;
  368.         }
  369.         DEBUGMSGTL(("run:exec","  child %d finished. result=%dn",
  370.                     pid,result));
  371. return WEXITSTATUS(result);
  372.     } else {
  373.         /*
  374.          * Parent process - fork failed
  375.          */
  376.         snmp_log_perror("fork");
  377. close(ipipe[0]);
  378. close(ipipe[1]);
  379. close(opipe[0]);
  380. close(opipe[1]);
  381. return -1;
  382.     }
  383.     
  384. #else
  385.     /*
  386.      * If necessary, fall back to using 'system'
  387.      */
  388.     return run_shell_command( command, input, output, out_len );
  389. #endif
  390. }