0

I'm writing a code, which is supposed to work with child processes, using different ways to send parameters. However, the problem doesn't concern this part. I have a menu with options, which specify the way, a user can deal with child processes. Depending on a selected option, a certain case should be chosen to work. It doesn't work the way it should, here goes the code and output, which will explain the problem better, than I can.

P.S. Sorry for possible mistakes, hopefully someone can help me out.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <locale.h>
#include <string.h>
#include <math.h>

extern char **environ;

int main(int argc, const char *argv[], char *env[])
{
    char **name;
    int x = 0, num;
    pid_t pid;
    
    for(num=0; ; num++)    //counts the number of environment parameters
        if(env[num] == NULL)
            break;
    
    name = (char **) calloc(1, sizeof(char *));
    if(!name)
    {
        printf("\nMemory isn't allocated");
        return -1;
    }
    
        name[0] = (char *) calloc(9, sizeof(char));

    if(!name[0])
    {
        printf("\nMemory isn't allocated");
        return -1;
    }

    for(int i=0; i<num; i++)
        fprintf(stdout, "%s\n", args[i]);
    
    fprintf(stdout, "Parent process's started...\n");
    
    char *temp;
    temp = (char *) calloc(12, sizeof(char));
    if(!temp)
    {
        printf("\nMemory isn't allocated");
        return -1;
    }
    
    while(x < 100)
    {
        sprintf(temp, "%d", x);
        strcpy(name[0], "child_");
        strcat(name[0], temp);
        
        puts("path info: +-using getenv()");
        puts("                           *-scanning array of environment parameters");
        puts("                           &-using environ");
        puts("                           q-end");
        fflush(stdin);
        
        switch(getchar())
        {
            case '+':
                printf("PLUS:\n");
                
                pid = fork();
                
                if(pid == -1)
                {
                    fprintf(stdout, "Error, code - %d\n", errno);
                }
                
                else
                {
                    execve("./child", name, env);
                }
                
                break;
                
            case '*':
                printf("ASTERISK\n");
                
                pid = fork();
                
                if(pid == -1)
                {
                    fprintf(stdout, "Error, code - %d\n", errno);
                }
                
                else
                {
                    execve(findPath(env, num), name, env);
                }
                
                break;
                
            case '&':
                printf("AMPERSAND:\n");
                
                pid = fork();
                
                if(pid == -1)
                {
                    fprintf(stdout, "Error, code - %d\n", errno);
                }
                
                else
                {
                    execve(findPath(environ, num), name, env);
                }
                
                break;
                
            case 'q':
                return 0;
                
            default:
                printf("Wrong parameter\n");
                return -1;
        }
        
        x++;
    }

    exit(0);
}

The output is the following:

Parent process's started...  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
+  
PLUS:  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end 
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
q  
Program ended with exit code: 0  

Meanwhile, it's supposed to be like this:

Parent process's started...  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
+  
PLUS:  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
q  
Program ended with exit code: 0
Nina
  • 1
  • 1
  • Don't do `fflush(stdin);`, it's undefined behaviour. – Sourav Ghosh Apr 03 '23 at 08:31
  • 3
    Can you create a [mre]? Also, the primary language is English around here, so it'd be useful if you can translate some of the native language for better readility. – Sourav Ghosh Apr 03 '23 at 08:32
  • Welcome to SO. "It doesn't work the way it should" How should it work? What does it do instead? Please edit your question to include a detailled description of the misbehaviour – Gerhardh Apr 03 '23 at 08:33
  • Also, you can check [ru.so](https://ru.stackoverflow.com/). – Sourav Ghosh Apr 03 '23 at 08:33
  • 1
    `calloc(strlen(env[i]), sizeof(char));` You forgot to allocate memory for the terminating 0 byte. You also don't copy that 0 byte lateron. The result is that you do not have valid strings. – Gerhardh Apr 03 '23 at 08:34
  • `result = execve(findPath(env, num), name, env);` You call this twice, once for the parent and once for the child. Is that intentional? – Gerhardh Apr 03 '23 at 08:38
  • You should check all your memory allocations. This is also wrong: `name = (char **) calloc(1, sizeof(char *));` You need memory for `num` pointers but only allocate for 1. – Gerhardh Apr 03 '23 at 08:53
  • 1
    @SouravGhosh, yes, I understand that. The root of my problem is that stdin stores '\n' after entering another choice option and uses it during the next iteration. One of the solutions, provided by the Internet, was to use fflush(stdin). Although, yes, it isn't safe and, moreover, it doesn't change a thing. – Nina Apr 03 '23 at 08:54
  • Using `fflush(stdin)` is not a solution but an error. – Gerhardh Apr 03 '23 at 08:55
  • @Gerhardh, this line is confusing, I'm not proud of it) Array of pointers name should store only one string, which is a name for every child process, which is executed. During new iterations I simply change its number and send it to the child. – Nina Apr 03 '23 at 08:57
  • "Array of pointers name should store only one string" Obviously this is not correct. A few lines later you assign multiple pointers: `name[j] =...` where `j` goes from 0 to `num-1` – Gerhardh Apr 03 '23 at 08:59
  • @Gerhardh, that's why I'm here: to find a different way of clearing stdin and making options be processed properly. – Nina Apr 03 '23 at 08:59
  • You never mentioned anything about clearing `stdin` in your question. You only mention incorrect output. (Which is caused by calling `execve` twice as I mentioned above). Your problem with newline is handled here: [scanf() leaves the newline character in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-newline-character-in-the-buffer) – Gerhardh Apr 03 '23 at 09:02
  • @Gerhardh, I'm sorry, I must've misunderstood you. I have three ways of executing a child process. When a user chooses one of them by entering the desired option, the necessary case starts to work, and every case contains execve() for this purpose. Is this not correct? How can I use it just once in my code? – Nina Apr 03 '23 at 09:09
  • As I mentioned, you are executing `execve` twice. Once for the parent process (pid != 0 && pid != -1) and once for the child (pid==0). That is probably not what you want. – Gerhardh Apr 03 '23 at 09:17
  • I get compiler errors and warnings when I try to compile the code. Please [edit] your question and make sure it contains the same code you ran on your system. Fix all errors and warnings. – Bodo Apr 03 '23 at 12:16
  • @Gerhardh, thanks a lot, your comments helped me to go in the right direction. The problem is solved. – Nina Apr 03 '23 at 18:23

0 Answers0