System() question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Bob

    #1

    System() question

    Howdy,

    Why does a call to system() work by passing the command line string
    supplied to sh -c? This is causing problems when running in a chroot
    environment where no sh is available. Wouldn't it be better for C to
    replace the system() call by a fork()-exec() pair? Is there some
    compiler option that can change the behavior of system()?

    Thanks in advance.

  • santosh

    #2
    Re: System() question

    Bob wrote:
    Howdy,
    >
    Why does a call to system() work by passing the command line string
    supplied to sh -c? This is causing problems when running in a chroot
    environment where no sh is available. Wouldn't it be better for C to
    replace the system() call by a fork()-exec() pair? Is there some
    compiler option that can change the behavior of system()?
    >
    Thanks in advance.
    Fork() and exec() are not present on many systems where C is
    implemented. Also they are not as generic as system(). As far as the C
    Standard is concerned, everthing about the argument to system() is
    implementation specific.

    You can always find out if a shell is available by doing:

    int rc = system(NULL);
    if (rc) { /* shell present */ }
    else { /* no shell */ }

    Comment

    • Flash Gordon

      #3
      Re: System() question

      santosh wrote, On 06/12/07 22:20:
      Bob wrote:
      >
      >Howdy,
      >>
      >Why does a call to system() work by passing the command line string
      >supplied to sh -c? This is causing problems when running in a chroot
      >environment where no sh is available. Wouldn't it be better for C to
      >replace the system() call by a fork()-exec() pair? Is there some
      >compiler option that can change the behavior of system()?
      >>
      >Thanks in advance.
      >
      Fork() and exec() are not present on many systems where C is
      implemented. Also they are not as generic as system(). As far as the C
      Standard is concerned, everthing about the argument to system() is
      implementation specific.
      >
      You can always find out if a shell is available by doing:
      >
      int rc = system(NULL);
      if (rc) { /* shell present */ }
      else { /* no shell */ }
      Not quite everything is system specific, and the answer to why system()
      is having a problem if no shell is available is *not* system specific.

      The standard *requires* that the system call pass the parameter to the
      command processor (AKA shell), so if there is no shell available then it
      is required to fail. Whether some other behaviour would be better is
      another matter.

      If you want the behaviour of fork/exec and your implementation provides
      them (or some equivalent) then I recommend using these system specific
      functions. Note that another standard (POSIX) might give the guarantees
      required, if so then for information on using them see
      comp.unix.progr ammer or some other group appropriate to the system(s) of
      interest.
      --
      Flash Gordon

      Comment

      • Richard Tobin

        #4
        Re: System() question

        In article <slrnflgt13.4vm .nospam@nospam. invalid>,
        Bob <nospam@nospam. invalidwrote:
        >Why does a call to system() work by passing the command line string
        >supplied to sh -c? This is causing problems when running in a chroot
        >environment where no sh is available. Wouldn't it be better for C to
        >replace the system() call by a fork()-exec() pair? Is there some
        >compiler option that can change the behavior of system()?
        As far as the C standard is concerned, it could work either way.

        But in practice it's much more useful if commands passed to system()
        are treated the same way as commands typed to the shell. For example,
        I expect system("rm *") to remove all the files in the directory,
        which wouldn't happen if you just executed the "rm" program with with
        argv[1] set to "*".

        If you're writing code to work in a chroot()ed environment you quite
        likely want to take special care with any commands you execute: I
        suggest writing your own system()-like function that uses fork()
        and exec() (and probably wait()) directly.

        -- Richard
        --
        :wq

        Comment

        • Richard Tobin

          #5
          Re: System() question

          In article <0sdm25x8jc.ln2 @news.flash-gordon.me.uk>,
          Flash Gordon <spam@flash-gordon.me.ukwro te:
          >The standard *requires* that the system call pass the parameter to the
          >command processor (AKA shell), so if there is no shell available then it
          >is required to fail. Whether some other behaviour would be better is
          >another matter.
          Unix has several shells available, and no doubt so do many other
          operating systems. The standard doesn't specify which one to use - it
          just refers to "a command processor". If you wrote some code to
          execute commands using fork() and exec(), that would be another
          (trivial) command processor, and using it would satisfy the C
          standard. For most purposes it would be less useful than using
          /bin/sh or $SHELL.

          -- Richard
          --
          :wq

          Comment

          • Flash Gordon

            #6
            Re: System() question

            Richard Tobin wrote, On 07/12/07 00:03:
            In article <0sdm25x8jc.ln2 @news.flash-gordon.me.uk>,
            Flash Gordon <spam@flash-gordon.me.ukwro te:
            >
            >The standard *requires* that the system call pass the parameter to the
            >command processor (AKA shell), so if there is no shell available then it
            >is required to fail. Whether some other behaviour would be better is
            >another matter.
            >
            Unix has several shells available, and no doubt so do many other
            operating systems. The standard doesn't specify which one to use - it
            just refers to "a command processor". If you wrote some code to
            execute commands using fork() and exec(), that would be another
            (trivial) command processor, and using it would satisfy the C
            standard. For most purposes it would be less useful than using
            /bin/sh or $SHELL.
            Yes, that is all true. However the OP was specifically talking about
            running the program in an environment without a command processor.
            --
            Flash Gordon

            Comment

            • Gordon Burditt

              #7
              Re: System() question

              >>The standard *requires* that the system call pass the parameter to the
              >>command processor (AKA shell), so if there is no shell available then it
              >>is required to fail. Whether some other behaviour would be better is
              >>another matter.
              >>
              >Unix has several shells available, and no doubt so do many other
              >operating systems. The standard doesn't specify which one to use - it
              >just refers to "a command processor". If you wrote some code to
              >execute commands using fork() and exec(), that would be another
              >(trivial) command processor, and using it would satisfy the C
              >standard. For most purposes it would be less useful than using
              >/bin/sh or $SHELL.
              >
              >Yes, that is all true. However the OP was specifically talking about
              >running the program in an environment without a command processor.
              The minimum needed under UNIX to run a command line is to parse the
              command line (possibly just splitting at every white-space character,
              with no quoting conventions whatever, and no i/o redirection), form
              argv[], and call fork() and some form of exec*(). That arguably
              *IS* a command processor (for that matter, you can argue that exec()
              alone is a command processor), even if it isn't a separate program.
              It might even take less code than the existing system() function
              does in the C library.

              Comment

              • James Kuyper

                #8
                Re: System() question

                Gordon Burditt wrote:
                ....
                The minimum needed under UNIX to run a command line is to parse the
                command line (possibly just splitting at every white-space character,
                with no quoting conventions whatever, and no i/o redirection), form
                argv[], and call fork() and some form of exec*(). That arguably
                *IS* a command processor
                It could be a command processor. I don't think it is one; because it
                hasn't been written, yet. You could write it pretty easily though.

                Comment

                • Gordon Burditt

                  #9
                  Re: System() question

                  >The minimum needed under UNIX to run a command line is to parse the
                  >command line (possibly just splitting at every white-space character,
                  >with no quoting conventions whatever, and no i/o redirection), form
                  >argv[], and call fork() and some form of exec*(). That arguably
                  >*IS* a command processor
                  >
                  >It could be a command processor. I don't think it is one; because it
                  >hasn't been written, yet. You could write it pretty easily though.
                  I think something like this, although a little more sophisticated
                  (like knowing how to strip quotes off of quoted strings), was written
                  as an optimization. If the command doesn't contain any of certain
                  shell metacharacters (pipe, I/O redirection, $, *, {}, (), ?, \, and
                  ~ at least would force use of a shell), it would use this instead.
                  I believe at least alphanumerics, white space, - and / were safe.
                  Otherwise it would use a shell.

                  I can't recall what used it, though: I'm thinking it was one of
                  sendmail, exim, certain versions of make, or perl. I learned about
                  it because the optimization had some side effect related to environment
                  variables that was tripping me up somehow.


                  exec() itself could be considered as a command procesor which accepts
                  the name of the program to run as the command (no arguments allowed).
                  Very, very crude, but the standard doesn't require much.

                  Comment

                  • Keith Thompson

                    #10
                    Re: System() question

                    Bob <nospam@nospam. invalidwrites:
                    Why does a call to system() work by passing the command line string
                    supplied to sh -c? This is causing problems when running in a chroot
                    environment where no sh is available. Wouldn't it be better for C to
                    replace the system() call by a fork()-exec() pair? Is there some
                    compiler option that can change the behavior of system()?
                    The C standard doesn't specify sh -c; it merely requires the string to
                    be passed to a "command processor". (Also standard C doesn't specify
                    fork or exec.)

                    POSIX specifies "sh -c". You might try asking in
                    comp.unix.progr ammer. (Note that the job of splitting the command's
                    arguments on whitespace, handling wildcards, etc. is passed off to the
                    shell; a function that uses fork/exec directly would have to reproduce
                    that functionality.)

                    --
                    Keith Thompson (The_Other_Keit h) <kst-u@mib.org>
                    Looking for software development work in the San Diego area.
                    "We must do something. This is something. Therefore, we must do this."
                    -- Antony Jay and Jonathan Lynn, "Yes Minister"

                    Comment

                    • Bob

                      #11
                      Re: System() question

                      On 7 Dec 2007 at 7:45, Keith Thompson wrote:
                      Bob <nospam@nospam. invalidwrites:
                      >Why does a call to system() work by passing the command line string
                      >supplied to sh -c? This is causing problems when running in a chroot
                      >environment where no sh is available. Wouldn't it be better for C to
                      >replace the system() call by a fork()-exec() pair? Is there some
                      >compiler option that can change the behavior of system()?
                      >
                      The C standard doesn't specify sh -c; it merely requires the string to
                      be passed to a "command processor". (Also standard C doesn't specify
                      fork or exec.)
                      >
                      POSIX specifies "sh -c". You might try asking in
                      comp.unix.progr ammer. (Note that the job of splitting the command's
                      arguments on whitespace, handling wildcards, etc. is passed off to the
                      shell; a function that uses fork/exec directly would have to reproduce
                      that functionality.)
                      But wouldn't it be better to first try "sh -c" and then if no shell is
                      available fall back to fork-exec, rather than failing the system() call?

                      Comment

                      • Richard Tobin

                        #12
                        Re: System() question

                        In article <slrnfljai2.d0m .nospam@nospam. invalid>,
                        Bob <nospam@nospam. invalidwrote:
                        >But wouldn't it be better to first try "sh -c" and then if no shell is
                        >available fall back to fork-exec, rather than failing the system() call?
                        Only if the fork()/exec() version does exactly the same thing;
                        executing the wrong command could be disastrous.

                        And if it does do exactly the same thing, why not use it in the first
                        place?

                        -- Richard
                        --
                        :wq

                        Comment

                        • Gordon Burditt

                          #13
                          Re: System() question

                          >POSIX specifies "sh -c". You might try asking in
                          >comp.unix.prog rammer. (Note that the job of splitting the command's
                          >arguments on whitespace, handling wildcards, etc. is passed off to the
                          >shell; a function that uses fork/exec directly would have to reproduce
                          >that functionality.)
                          >
                          >But wouldn't it be better to first try "sh -c" and then if no shell is
                          >available fall back to fork-exec, rather than failing the system() call?
                          No, unless you've got a *complete* shell emulation in the library, and if
                          that's the case, why bother loading another program when it's already
                          loaded? Use the emulation all the time.

                          fork-exec is missing a critical piece: turning a command string
                          into a program name and an argv[] array of command arguments. Along
                          with that go a bunch of other (POSIX) features invoked by the
                          parsing: I/O redirection, sequential command execution, pipelines,
                          wildcard expansion, shell variables, argument quoting, etc.

                          You can do a simple-minded implementation, for example, if the
                          command consists entirely of alphanumeric characters, white space,
                          hyphen, and slash, you can get pretty close with a parser that just
                          breaks arguments at white space, then does fork()/execvp().
                          This can go horribly wrong if the command intended to use some
                          of the features not implemented.

                          Example:
                          rm -f foo.o ; cc -c foo.c ; cc -o foo foo.o -lbar ; ./foo
                          when run by the simple-minded parser runs "rm" with lots of arguments
                          and will end up deleting foo.c, along with complaining about some
                          probably-nonexistent files.


                          Comment

                          Working...