1

I'm fairly new to C, so I apologize if this is a simple question. I'm writing a C program, part of which is below. The goal of the overall program is to copy a file from one location to another (files are passed as arguments, with the final argument being the destination). main(), below, uses fork() to create one child process for each file passed, and I need to print out the file name (just the input argument) along with a message that may include the PID for each copy attempt after all child processes have run.

I can obviously get and use the PID, that's not a problem, but how can I get the right file name/argument that's tied to that process? The method I have in there now is obviously wrong; simply iterating through each argument in order won't be correct. This will be run on Minix 2.0.4, but I don't know if that matters.

int
main(int argc, char *argv[])
{
   int i, pid, rem, status;
   int pids[argc];
   char cfstatus[];

   rem = argc;

   for(i = 1; i < argc; i++) {
      if((pids[i] = fork()) < 0) {
         fprintf(stderr, "Error while forking");
      }
      else if(pids[i] == 0) {
         if(copyfile(argv[i], argv[argc - 1]) == 1)
            exit(4);
         else
            exit(0);
      }
   }

   i = 0;

   while(rem > 1) {
      pid = wait(&status);
      cfstatus = getcfstatus(status, pid);
      printf("%-20s: %s", argv[i], cfstatus);
      rem--;
      i++;
   }
}
vaindil
  • 7,536
  • 21
  • 68
  • 127
  • the code should check that argc is (at least) 3 and if that test fails, output a error message indicating the correct format and then exit – user3629249 Feb 16 '15 at 02:20
  • 1
    argc include a count for the name of the program (that name is found at argv[0])) so the code needs to be modified to take those two details into account – user3629249 Feb 16 '15 at 02:21
  • Ah, okay. It does check for the number of arguments and fails if too few are passed, but I removed that check in the interest of keeping the code snippet to the point. – vaindil Feb 16 '15 at 02:21

2 Answers2

1

As currently written, the child process whose PID is stored in pids[i] will operate on the file named by argv[i]. There's no uncertainty whatsoever about that. i is duplicated along with everything else by the fork operation, and not modified thereafter.

However, because all the children run in parallel, they may complete in any order. That is, each call to wait might return any of the PIDs in the array (that hasn't already been returned). So what you need to do in your wait loop is map back from the pid value returned by wait, to its index in the pids array, and then you know the right index in argv to print out. For a program like this, a linear search through the array is probably good enough.

zwol
  • 135,547
  • 38
  • 252
  • 361
0

this line (other than 'i' must not be 0) has a few problems

"if(copyfile(argv[i], argv[argc - 1]) == 1)'

if the command line is: programname srcFile desFile

then argc = 3 then argv[argc-1] = srcFile, which is not what is wanted

suggest:

'if(copyfile(argv[i], argv[argc]) == 1)'

then, to avoid race conditions in the writing to the output/desFile

only one process can be writing to that file at any one time.

so forking a number of processes to be writing to the same file is an error

this line:

'for(i = 0; i < argc; i++) {'

needs a couple of modifications to (amongst other things) avoid trying to copy the executable file to the desFile and avoid trying to copy the desFile to itself

suggest:

'for(i = 1; i < (argc-1); i++) {'
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • `argv[]` is 0-indexed, so using your example `argc = 3` and therefore `argv[argc - 1] = argv[2] = desFile`. The rest of it makes sense. Thank you! – vaindil Feb 16 '15 at 02:39