Thread: Can I use C system() to replace bash script?

  1. #1
    Registered User
    Join Date
    Sep 2014
    Posts
    121

    Can I use C system() to replace bash script?

    Hello,
    I am wondering if I can write a C program with strings and to pass it to the system to avoid the ugly bash syntax? A simple example would be:
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    
    /* start a virtual image with qemu-kvm */
    
    static char command_name[2040] = {0};
    int main(int argc, char** argv) {
        
        if ( argc != 2 ) {
            fprintf(stderr, "Provide command line argument for virtual image \n");
            exit(1);
        } else {
                sprintf(command_name, "qemu-kvm -m 1024 %s -netdev user,id=user.0 -device rtl8139,netdev=user.0",
                    argv[1]);
                
        }
        
        return system(command_name);
    }
    I don`t need big scripts just for few commands.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,855
    Give it a try and find out. You probably want to try with something trivial though.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Sep 2014
    Posts
    121
    It works for now. With the flexibility of macro replacement, a good script logic can be written, however it`s not maintainable as a script due to compile procedure.

  4. #4
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    733
    Both Bash and C were written for different purposes. Bash was designed to run C based compiled applications, especially chaining them together with pipes. C, however, was not really designed to run bash scripts or commands, although you certainly could.

    I could eat peas with a knife, or write a letter with Lotus 123 or Excel, and I know people who have done both, but should you? ;^)

  5. #5
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    In a POSIX environment, system() just passes the string to /bin/sh, so you still have to worry about shell issues (what if the image name has a space in it, for example?).

    If you want to safely execute programs from C (again, for POSIX), you'll probably want to look at the exec family of functions (execl(), execv(), and so on), as well as fork(). These completely avoid the shell and will help prevent aginst unexpected shell interactions.

  6. #6
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    726
    I don't see how this script can be called particularly "ugly":
    Code:
    #! /bin/sh
    
    if [ $# -ne 1 ]; then
      echo >&2 Provide command line argument for virtual image
      exit 1
    fi
    
    exec qemu-kvm -m 1024 "$1" -netdev user,id=user.0 -device rtl8139,netdev=user.0
    It has a few advantages over your simple C version:
    • It supports an argument with spaces in it
    • It supports arbitrarily-long arguments (longer than 2040 characters)
    • It doesn't leave a process waiting around doing nothing while qemu-kvm is running
    • It handles exit status and signals properly

    The system() function returns a status code that cannot meaningfully be returned directly from main() as you are doing. You can pass that status code to WEXITSTATUS() if WIFEXITED() is non-zero. If WIFEXITED() is zero (WIFSIGNALED() is probably non-zero in that case), WTERMSIG() will give you the termination signal, but it doesn't make sense to return that value either. It might make sense to kill your own process with that signal in order to propagate the termination condition.

    As you can see, it's somewhat more complicated to handle arguments and executing child processes properly from a C program. The Bourne shell (including Bash) makes it much easier.

  7. #7
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by christop View Post
    I don't see how this script can be called particularly "ugly":
    Code:
    #! /bin/sh
    
    if [ $# -ne 1 ]; then
      echo >&2 Provide command line argument for virtual image
      exit 1
    fi
    
    exec qemu-kvm -m 1024 "$1" -netdev user,id=user.0 -device rtl8139,netdev=user.0
    It has a few advantages over your simple C version:
    • It supports an argument with spaces in it
    • It supports arbitrarily-long arguments (longer than 2040 characters)
    • It doesn't leave a process waiting around doing nothing while qemu-kvm is running
    • It handles exit status and signals properly

    The system() function returns a status code that cannot meaningfully be returned directly from main() as you are doing. You can pass that status code to WEXITSTATUS() if WIFEXITED() is non-zero. If WIFEXITED() is zero (WIFSIGNALED() is probably non-zero in that case), WTERMSIG() will give you the termination signal, but it doesn't make sense to return that value either. It might make sense to kill your own process with that signal in order to propagate the termination condition.

    As you can see, it's somewhat more complicated to handle arguments and executing child processes properly from a C program. The Bourne shell (including Bash) makes it much easier.
    Yeah, I was thinking why not just write a small bash script file, then I thought, maybe the OP didn't know they could or didn't know how? Although they asked if it could be done in C, I personally believe a small bash script like the one you wrote there would be much nicer. It wouldn't be hard to expand on that script either, so if they didn't provide a command argument to the script, it asks for it instead of passing control back to the OS via the exit 1 call...

  8. #8
    Registered User
    Join Date
    Sep 2014
    Posts
    121
    I agree with all of you. It`s a bit offtopic, however I was able to detach the parent from the qemu window with atexit(fcn) function:
    Code:
    void execute1(void) {
        pid_t pid = fork();
        if ( pid == 0 ) {
            system(command_name);
        } else if ( pid > 0 ) {  } 
          else { }    
    }
    In main function, I`ve just registered the function with atexit(). Now I can close the terminal, and the qemu-kvm remains working.

  9. #9
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    If you want to detach some command from the terminal, just use the standard setsid-to-background-in-a-subshell approach. Adjusting christop's script,
    Code:
    #!/bin/sh
    if [ $# -ne 1 ]; then
      printf '\nUsage: %s QEMU-KVM-IMAGE\n\n' "$0" >&2
      exit 1
    fi
    ( exec </dev/null >/dev/null 2>/dev/null
      setsid qemu-kvm -m 1024 "$1" -netdev user,id=user.0 -device rtl8139,netdev=user.0 & )
    Because detaching severs all connections to the terminal used to execute the command (if any), this won't tell you whether the command succeeded or not.

    However, qemu-kvm does provide a perfect option for this: -daemonize. It will do initialization as normal (so you should get error messages if there is a problem with the image an so on), but then daemonize (detach from the terminal). So, you really should just use
    Code:
    #!/bin/sh
    if [ $# -ne 1 ]; then
      printf '\nUsage: %s QEMU-KVM-IMAGE\n\n' "$0" >&2
      exit 1
    fi
    exec qemu-kvm -m 1024 "$1" -netdev user,id=user.0 -device rtl8139,netdev=user.0 -daemonize
    instead.

  10. #10
    Registered User
    Join Date
    Sep 2014
    Posts
    121
    Quote Originally Posted by Nominal Animal View Post
    If you want to detach some command from the terminal, just use the standard setsid-to-background-in-a-subshell approach. Adjusting christop's script,
    Code:
    #!/bin/sh
    if [ $# -ne 1 ]; then
      printf '\nUsage: %s QEMU-KVM-IMAGE\n\n' "$0" >&2
      exit 1
    fi
    ( exec </dev/null >/dev/null 2>/dev/null
      setsid qemu-kvm -m 1024 "$1" -netdev user,id=user.0 -device rtl8139,netdev=user.0 & )
    Because detaching severs all connections to the terminal used to execute the command (if any), this won't tell you whether the command succeeded or not.

    However, qemu-kvm does provide a perfect option for this: -daemonize. It will do initialization as normal (so you should get error messages if there is a problem with the image an so on), but then daemonize (detach from the terminal). So, you really should just use
    Code:
    #!/bin/sh
    if [ $# -ne 1 ]; then
      printf '\nUsage: %s QEMU-KVM-IMAGE\n\n' "$0" >&2
      exit 1
    fi
    exec qemu-kvm -m 1024 "$1" -netdev user,id=user.0 -device rtl8139,netdev=user.0 -daemonize
    instead.

    Cool feature, never knew of it. Thanks.

  11. #11
    Registered User FourAngels's Avatar
    Join Date
    Aug 2015
    Location
    Canada
    Posts
    130
    A system call used to cause the kernel mode to interrupt the applications that were running in the normal operation mode, it was like hitting ctr-alt-delete in Windows. The shell is invoked after the system call is made, I think someone said. Just maybe the c++ error handling using try and catch statements might allow someone to get some information to the shell but still be able to return to the program where the exception took place? It might contain the answer.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bash script in c
    By programmerc in forum C Programming
    Replies: 1
    Last Post: 10-02-2014, 08:47 PM
  2. exec a bash script
    By quo in forum Linux Programming
    Replies: 17
    Last Post: 06-02-2012, 06:01 AM
  3. Awk and sed bash script help
    By Annonymous in forum Linux Programming
    Replies: 19
    Last Post: 05-10-2012, 12:40 AM
  4. ssh/bash script question
    By Overworked_PhD in forum Tech Board
    Replies: 2
    Last Post: 03-30-2009, 07:48 PM
  5. Bash Script Q
    By QuestionC in forum Tech Board
    Replies: 1
    Last Post: 04-19-2007, 10:16 AM