1

Iam trying to call system to save a buffer to an output, i have to do this with system call, or with execve and pipes(it's a university project).

The buffer is read for a part of a file, and then i have to run a sh on it, and then i can save it to file. I was trying to just save it to file with the system(), when i replace the buffer with a shorter string it works perfectly, but not with the large buffer.

I use this function to create the command:

char* command = string_new();
string_append_with_format(&command, "(printf '%s') > %s", buffer, outputName);

Here is the link to the functions iam using if you wanna see them, it's a university library. https://github.com/sisoputnfrba/so-commons-library/blob/master/src/commons/string.c

Is there a limit to the characters you can output with printf command on sh?

What do you recommend me to do? to change this to execve approach?

Thanks, i will add code/information if you need it.

Gaunt
  • 649
  • 8
  • 20
  • 3
    yes the maximum length of a command line may be limited, depends on the OS – Ingo Leonhardt Dec 06 '17 at 16:42
  • 1
    See https://stackoverflow.com/questions/19354870/bash-command-line-and-input-limit and https://stackoverflow.com/questions/3205027/maximum-length-of-command-line-string depending on your OS. – cdarke Dec 06 '17 at 16:45
  • 4
    That's a very strange way of writing data to a file. Not only will you run into the command line length limit, but there will also be issues if the data contains special characters such as `'`. – interjay Dec 06 '17 at 16:45
  • 1
    `string_append_with_format(&command...` should be `string_append_with_format(command...` which implies not all warnings are enabled. Save time - Enable them. – chux - Reinstate Monica Dec 06 '17 at 16:52
  • 2
    Given your options, I would suggest setting up a system call to "cat > output.txt" and a pipe to feed the data to the above program. You could use the `popen` function to perform the system call and create the pipe in one go, or emulate the functionality of the `popen` function in your own code. – Ian Abbott Dec 06 '17 at 17:00
  • @interjay not only characters special to shell, but also format specifiers special to `printf` such as `%%`... – el.pescado - нет войне Dec 06 '17 at 17:33
  • "*What do you recommend me to do?*" Use `fopen()/fwrite()/fclose()` or `open()/write()/close()`! – alk Dec 06 '17 at 18:11

1 Answers1

3

What do you recommend me to do? to change this to execve approach?

The alternatives of system() vs. execve() are choices for how to run another process. The latter would be combined with fork(). Given that you must use one of these, it is apparent that you are supposed to use an external command to perform the I/O to the eventual destination. An essential question to answer, then, is which external command to use.

As you have discovered, there are limits to the size of a shell command, and if you pursued a direct conversion to using execve() instead of system() then you would likely discover that there are corresponding limits at that level. Therefore, your basic approach of passing the data to be printed as an argument to the command is not viable if the possible size of the data is not suitably bounded. Thus a second, related, essential question is how the data to write are to be conveyed to the external command.

Allow me to suggest using the cat command in place of printf. With no arguments, cat simply copies its standard input to its standard output. This solves the problem of providing the data to write to the file: you will arrange for cat to read it from its standard input. To arrange for the data to go to the destination file, you will need to connect cat's standard output to that file.

As far as the standard input goes, it looks like you would want to establish a pipe() between the main process and its fork()ed child, and to dup2() the read end of that pipe onto the child's standard input. The child would close the write end of the pipe (important), and the parent would close the read end.

The clean way to handle the output would be for the child to open() the destination file, and to dup2() its file descriptor on to its standard output.

Having performed those redirections, the child would then execve() /usr/bin/cat with no arguments, and the parent would write() or fwrite() the data to the write end of the pipe, then close() the pipe and wait()s for the child to finish.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157