4

A regular C program, an implementation of some shell program, which uses standard input to get commands and executes them, in which main() is declared as: int main(int argc, char *argv[]), works normally. It's a small shell program that prints a prompt and waits for user input in a loop, and executes the command entered. However I want to make the commandline parameters invisible when invoked, as follows:

  • rename the main() function to old_main().
  • create a new main() function that:
    • Copies the argv[] string array to a new array, and then
    • Erases the original argv[] structure.
    • Forks itself and in the child calls old_main with the saved commandline parameters, and exits the parent process.

This works as 'ps -ef' now shows the command run without the commandline arguments displayed. However, the program now behaves different, and does not wait for user-input, but keeps printing the prompt. Even Ctrl-C does not work anymore.

If, however, I call the program as:

$ echo quit | ./newprog 

The command 'quit' is executed (causing the program to exit), so the program still works when the stdin is redirected, but does not work in interactive mode.

Below the new program that forks itself and in the child calls the old main with the saved commandline parameters.

/* newprog.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAX_NARGS   40

extern int old_main(int nargc, char *nargv[]);    

int main(int argc, char *argv[])
{
    int i; pid_t pid;
    int nargc=argc;
    char *nargv[];
    nargv[0]=argv[0];

    for (i = 1; i < argc; i++)
    {
        nargv[i]=strdup(argv[i]);
        memset(argv[i],0,strlen(argv[i]));
    }
    nargv[i]=NULL;

    pid=fork();

    if (pid == 0)   return old_main(nargc, nargv); /* child calls old_main() */
    else if (pid == -1) printf("error: fork()\n");
    exit(0);  /* exit parent */
}
Rob Heusdens
  • 155
  • 5
  • I found out incidently that for my original problem (not display the commandline arguments in process list), I don't have to do a fork, the method explained here to copy the old commandline arguments to new variables and then erase the old commandline args works in the original main function. But this question adresses just the problem that after fork() in the child the standard input seems no longer functional as in the original program. Still interested to know what the cause of that is. – Rob Heusdens Mar 04 '17 at 12:09
  • The parent process is a child of your shell. Before executing your command, the shell most likely sets up a redirection to the parents stdin. When you exit the parent, that redirection is terminated. The stdin of the child no longer listens on anything. This is a relevant read on the matter, and possibly a worthy duplicate http://stackoverflow.com/questions/37064172/replace-parent-process-with-child-process-after-death – StoryTeller - Unslander Monica Mar 04 '17 at 12:11
  • @StoryTeller: I assume (documented feature of fork() - see man 2 fork) the child inherits the parents file descriptors of openfiles, which normally includes stdin,stdout and stderr, so even when parent exits, child should be able to read stdin and write stdout as usual. In my case I found that the input from fgets() called by the child after the parent exits, does not wait for user input, however, if I use redirection by the shell, that input does get through the child's fgets, and works normally. Why this difference in behaviour? – Rob Heusdens Mar 04 '17 at 14:24
  • man 2 fork: "The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two descriptors share open file status flags, current file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in fcntl(2))." – Rob Heusdens Mar 04 '17 at 14:28
  • The issue isn't with copying file descriptors. The issue is with having someone write into the stream both parent and child listen. When you pipe commands, then the child's pipe descriptor is enough to keep the pipe open. But it's not the same with the shell's forwarding input from the terminal. It will only forward as long as the parent is alive, since that's the only PID it waits on. – StoryTeller - Unslander Monica Mar 04 '17 at 15:51
  • @StoryTeller So what resolution is there for that situation? Postpone exit of parent until child dies, or can the child somehow take over the stdin from parent, so that parent can exit and child can read from terminal? – Rob Heusdens Mar 04 '17 at 16:34
  • The first is the simplest solution. Have the parent wait on the PID of the child, and return the same return status. Not sure how it will affect your goal of keeping the command line arguments hidden. For a more complex solution that substitutes the child for the parent completely, I'm afraid I can't give much help. Since I'm not well versed enough to do it. – StoryTeller - Unslander Monica Mar 04 '17 at 16:37
  • Having the parent wait till child dies is in this case not a solution, I would rather find a way in which the child could inherit the stdin file handle from parent, so the child can read from stdin, like the parent. (btw. the issue of keeping the commandline hidden is no longer relevant, as I figured out I would not need a fork() to establish that, this question is purely about reading stdin (not redirected by shell) from the child, and letting the parent exit soon after fork(). – Rob Heusdens Mar 05 '17 at 13:10
  • @Rob Heusdens Can you provide me all the program code? – Abhijit Pritam Dutta Oct 11 '17 at 17:01

0 Answers0