Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there downsides to using calls to system() instead of your programming language's functions?

I'm programming in C to create some API for an embedded device. This embedded device runs a variant of Linux. I'm not very familiar with C - I'm more familiar with shell scripting/bash.

With that in mind, when it comes to things like checking whether a directory exists, or getting disk usage, I find it easier to just make a call to system or popen and execute my command, then parse the output. It's faster for me as a developer.

Are there downsides to making these system and popen calls instead of finding out how to do each of these things in C and then making use of C's functions?

like image 228
Pimgd Avatar asked Jul 02 '15 12:07

Pimgd


3 Answers

Cons:

  1. it is insecure if there are user input
  2. it is difficult to parse the output
  3. it will relies on something external, such shell script.
  4. heavy process - system fork() and start the other program in parallel

Pros:

  1. easy to implement
  2. depends of program output parse could be very easy. example system("ls -1");

Summarize -

It depends what you need to do, but in general case there more negatives than positives.

like image 98
Nick Avatar answered Oct 21 '22 17:10

Nick


Even if it is going to work on Linux, you can't rely on the availability of all the commands you intend to use, so the downside is straight forward: you can't rely on a given tool being available.

One more thing to consider is that parsing the output of shell commands from c is terribly difficult.

And finally, you can't make your program randomly call a system utility or shell script simply because it's unsafe.

like image 4
Iharob Al Asimi Avatar answered Oct 21 '22 18:10

Iharob Al Asimi


At the end of the day, on a Linux system, pretty much everything is calling C functions at some point.

To touch on some of the arguments in comments as well as my own thoughts:

  1. Executing shell commands from a c program, especially when using user arguments, is a potential vulnerability. Example would be if you allowed the user to call your program with the argument "foo; rm -rf *"; depending on how you invoke the shell, there's the potential you could effectively call "mkdir foo; rm -rf *" if you wanted to make the directory the user provided. This may or may not be a big deal depending on how you trust your users etc.
  2. Executing shell commands leads to potential race conditions that you can't avoid that might be more easily dealt with using straight system calls that you chain together
  3. Parsing output of commands means dealing with more string operations in C, which is less than fun.
  4. If you really prefer bash, your best bet is to probably implement small programs which wrap discrete portions of your target library's C API. This is the UNIX way(tm) anyways.

EDIT to address Pimgd's comment: Note that race conditions are a pain in the neck and a lot of them aren't necessarily an issue for your particular use case, but are at least worth considering when weighing pro's/con's. Anyways, the specific race-condition instances I was thinking about include (and there are likely other classes):

  1. Security type race conditions. If you create a temp file containing a set of commands and then execute it, there is the possibility that between creation and execution, someone goes in and modifies the file. (There are actually a variety of variations on this theme for things like setting/resetting sym links etc.). Based on your above comments, this is pretty much outside the scope of your project, but is something to be aware of for other applications.
  2. Multi-process race conditions. The simplest example I can think of is what happens if two instances of your program want to set a configuration file and are running at the same time. There are certain OS calls which have certain levels of guarantee on atomicity, but you lose a lot of that if you call a series of shell commands to write to the file. (note that even if you do it from a monolithic C application versus a series of shell commands, you still would need to do something extra to prevent instance 1 from overwriting instance 2's change, but you're at least not likely to run into the case that you end up having changes intermixed. As an example consider:

    FILE *fp = fopen("config.txt","wt");

    fprintf(fp,"Config value 1: %s",config[0]);

    fprintf(fp,"Config value 2: %s",config[1]);

    fflush(fp);

    fclose(fp);

vs.

system("echo Config value 1: `df | awk '{print $1}'` > config.txt");
system("echo Config value 2: `ps | grep foo | awk '{print $2}'` >> config.txt");

Where, if two instances of the program run at close to the exact time, you can end up with e.g. 2 instances of Config value 2 in the config file in the latter case.

like image 2
Foon Avatar answered Oct 21 '22 18:10

Foon