0

My program accepts many options.
And I have to write a shell script to test my program.

The shell script must run my program multiple times and every time it must pass different options and different arguments for an option.

For example:

    #!/bin/bash
echo "CS111 " > testing.txt
echo "is " >> testing.txt
echo "intersting " >> testing.txt
echo "even " >> testing.txt
echo "though " >> testing.txt
echo "it " >> testing.txt
echo "is " >> testing.txt
echo "time " >> testing.txt
echo "consuming " >> testting.txt
echo "and " >> testing.txt
echo "hard " >> testing.txt

./simpsh \
--verbose \
--rdonly in.txt \
--append --wronly out.txt \
--wronly err.txt \
--command 0 1 2 sort testing

./simpsh \
--verbose\ 
--rdonly in.txt \
--append --wronly out.txt \
--wronly err.txt \
--command 0 1 2 sort

The first test will be executed, but then there is an error 127.

This is my code:

#include <stdio.h>     
#include <stdlib.h>    
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

int main(int argc, char **argv)
{
  int c;
  int oflag = 0;
  int *fd;
  int fdCount = 0;
  int pipefd[2];
  int p;
  int verbose = 0;
  while (1) {
    static struct option long_options[] = {
      {"append",no_argument,0,'a'},
      {"cloexec",no_argument,0,'b'},
      {"creat",  no_argument,0,'c'},
      {"directory",no_argument,0,'d'},
      {"dsync",no_argument,0,'e'},
      {"excl",no_argument,0,'f'},
      {"nofollow",no_argument,0,'g'},
      {"nonblock",no_argument, 0,'h'},
      {"rsync",no_argument,0,'i'},
      {"sync",no_argument,0,'j'},
      {"trunc",no_argument,0,'k'},
      {"rdonly",required_argument,0,'l'},
      {"rdwr",required_argument,0,'m'},
      {"wronly",required_argument,0,'n'},
      {"pipe",no_argument,0,'o'},
      {"command",required_argument,0,'p'},
      {"wait",no_argument,0,'q'},
      {"close",required_argument,0,'r'},
      {"verbose",no_argument,0,'s'},
      {"profile",no_argument,0,'t'},
      {"abort",no_argument,0,'u'},
      {"catch",required_argument,0,'v'},
      {"ignore",required_argument,0,'w'},
      {"default",required_argument,0,'x'},
      {"pause",no_argument,0,'y'},
      };
    c = getopt_long(argc, argv, "abcdefghijkl:m:n:op:qr:stuv:w:x:y", long_options, NULL);
    if (c == -1)
      break;
    switch (c) {
    case 'a':
      if(verbose)
    printf("O_APPEND\n");
      oflag = oflag | O_APPEND;
      break;
    case 'b':
      if(verbose)
    printf("O_CLOEXEC\n");
      oflag = oflag | O_CLOEXEC;
      break;
    case 'c':
      if(verbose)
    printf("O_CREAT\n");
      oflag = oflag | O_CREAT;
      break;
    case 'd':
      if(verbose)
    printf("O_DIRECTORY\n");
      oflag = oflag | O_DIRECTORY;
      break;
    case 'e':
      if(verbose)
    printf("O_DSYNC\n");
      oflag = oflag | O_DSYNC;
      break;
    case 'f':
      if(verbose)
    printf("O_EXCL\n");
      oflag = oflag | O_EXCL;
      break;
    case 'g':
      if(verbose)
    printf("O_NOFOLLOW\n");
      oflag = oflag | O_NOFOLLOW;
      break;
    case 'h':
      if(verbose)
    printf("O_NONBLOCK\n");
      oflag = oflag | O_NONBLOCK;
      break;
    case 'i':
      if(verbose)
    printf("O_RSYNC\n");
      oflag = oflag | O_RSYNC;
      break;
    case 'j':
      if(verbose)
    printf("O_SYNC\n");
      oflag = oflag | O_SYNC;
      break;
    case 'k':
      if(verbose)
    printf("O_TRUNC\n");
      oflag = oflag | O_TRUNC;
      break;
    case 'l':
      if(optarg){
    if(fdCount == 0)
      fd = (int *)malloc(sizeof(int));
    else
      fd = (int *)realloc(fd, (fdCount  + 1)* sizeof(int));
    if(verbose)
      printf("O_RDONLY %s\n", optarg);
    fd[fdCount] = open(optarg, oflag | O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
    oflag = 0;
    if(fd[fdCount] == -1){
      fprintf(stderr, "%s cannot be opened/created", optarg);
      exit(1);
    }
    else
      fdCount++;
      }
      break;
    case 'm':
       if(optarg){
    if(fdCount == 0)
      fd = (int *)malloc(sizeof(int));
    else
      fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
    if(verbose)
      printf("O_RDWR %s\n", optarg);
    fd[fdCount] = open(optarg, oflag | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
    oflag = 0;
    if(fd[fdCount] == -1){
      fprintf(stderr, "%s cannot be opened/created", optarg);
      exit(2);
    }
    else
      fdCount++;
       }
      break;
    case 'n':
      if(optarg){
    if(fdCount == 0)
      fd = (int *)malloc(sizeof(int));
    else
      fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
    if(verbose)
      printf("O_WRONLY %s\n", optarg);
    fd[fdCount] = open(optarg, oflag | O_WRONLY, S_IRWXU | S_IRWXG | S_IRWXO);
    oflag = 0;
    if(fd[fdCount] == -1){
      fprintf(stderr, "%s cannot be opened/created", optarg);
      exit(3);
    }
    else
      fdCount++;
       }
      break;
    case 'o':
      if(verbose)
    printf("pipe\n");
      p = pipe(pipefd);
      if(p == -1){
    fprintf(stderr, "The pipe wasn't made.\n");
    exit(5);
      }
      else{
    if(fdCount == 0)
      fd = (int *)malloc(2 * sizeof(int));
    else
      fd = (int *)realloc(fd, (fdCount + 2) * sizeof(int));
    fdCount = fdCount + 2;
    fd[fdCount - 2] = pipefd[0];
    fd[fdCount - 1] = pipefd[1];
      }
      break;
    case 'p':
      if(optarg){
    if(verbose){
      printf("command ");
      int vi = optind -1;
      for( vi = optind - 1; vi < argc && *argv[vi] != '-'; vi++)
        printf("%s ", argv[vi]);
      printf("\n");
    }
    pid_t pid = fork();
    if(pid == 0){
      int fdin;
      int fdout;
      int fderr;
      int i = 0;
      char **arg;
      int index;
      for(index = optind-1; index < argc && *argv[index] != '-'; index++, i++){
        switch(i){
        case 0:
          fdin = atoi(argv[index]);
          break;
        case 1:
          fdout = atoi(argv[index]);
          break;
        case 2:
          fderr = atoi(argv[index]);
          break;
        default:
          if(i - 3 == 0)
        arg = (char**)malloc(sizeof(char));
          else
        arg = (char**)realloc(arg, ((i - 3) + 1)* sizeof(char));
          arg[i - 3] = strdup(argv[index]);
        }
      }
      dup2(fd[fdin],0);
      close(fd[fdin]);
      dup2(fd[fdout],1);
      close(fd[fdout]);
      dup2(fd[fderr],2);
      close(fd[fderr]);
      execvp(arg[0], arg);
    }
    else if(pid == -1){
      fprintf(stderr, "The new proccess isn't created by fork()\n");
      exit(6);
    }
      }
      break;
    case 'q':
      break;
    case 'r':
      break;
    case 's':
      verbose = 1;
      break;
    case 't':
      break;
    case 'u':
      break;
    case 'v':
      break;
    case 'w':
      break;
    case 'x':
      break;
    case 'y':
      break;
    default:
      fprintf(stderr, "An option is misstyped or has no argument\n");
      exit(4);
    }
  }
  exit(0);
}
user3050866
  • 33
  • 1
  • 5

1 Answers1

1

Return code 127 indicates the command was not found.

It is likely myprogram is not found inside the current directory you execute your test script from.

Try changing to the directory where your program is located, or calling it with a full path.

Also, remember bash ignores commands that fail unless you activate the "-e" flag or trap errors and handle them explicitly. When building a test script (or any script for that matter), allowing silent failure could lead to bad surprises down the road.

Fred
  • 6,590
  • 9
  • 20
  • it runs the first ./myprogram --a --b --c file.txt --d but then it gives error 127. so the first run is fine and no issue with the myprogram. – user3050866 Jan 17 '17 at 03:25
  • If you execute "myprogram" manually with the same arguments as those that cause the 127 return code, do you get a 127 return code also? – Fred Jan 17 '17 at 03:32
  • if I use ubuntu terminal directly without using shell script file to run myprogram no error. by the way, in terminal I run them separately. I mean like: $ ./myprogram ... then I press enter after the program returns then I do the second test and third test and so on. – user3050866 Jan 17 '17 at 03:55
  • If you change the order in which the commands are executed, is it always the same one failing? – Fred Jan 17 '17 at 03:57
  • if I commented out the other tests, and leave only one test case no matter which one, then no error. – user3050866 Jan 17 '17 at 04:06
  • I am note sure how executing the command from inside a script would yield a different result from running it from the command line, at least if you are using the same terminal to both launch manually and with the test script. I am afraid I cannot think of any explanation at this time. – Fred Jan 17 '17 at 04:07
  • I posted before I could see your comment. Your last test does not make things any easier, as it seems to imply that your tests somehow interact, which they should not as they are each executed in separate processes (therefore unable to affect each other's environment variables). – Fred Jan 17 '17 at 04:09
  • I see, in fact, my program use fork() and then runs part of it on child process and the rest on parent. – user3050866 Jan 17 '17 at 04:32
  • My understanding is forking inside your program should not change anything, as neither the parent nor child will be the same process as the shell executing your test script. I will not be of much use debugging C code, but irrespective of what your program does, the symptoms do not fit with my mental model of how the OS isolates a parent process from its child. – Fred Jan 17 '17 at 04:37
  • and add my shell script on the queestion – user3050866 Jan 17 '17 at 04:39
  • I assume myprogram is your C program above. You are losing me here... What is that new script? Seeing it without the newlines makes it impossible to read. – Fred Jan 17 '17 at 04:44
  • I just posted my real script and my real code. previously I just put an example to give what is my issue. this is homework and we are restricted not to disclose our code online. that was the reason I didn't post everything. now you can see my code and the shell script that I have issue with. simpsh is the executable for my code. – user3050866 Jan 17 '17 at 04:47
  • Are your sure your program does not delete the "testing.txt" file? I see your two invocations of the `simpsh` command are identical except for the last "testing". Is that intended? – Fred Jan 17 '17 at 04:50
  • everything works perfect I will post the link for spec so you will find out what does my program do. – user3050866 Jan 17 '17 at 04:55
  • Have you tried adding echo "$PWD" in between your simpsh invocations to make sure the current directory has not changed? Have you tried using a full path to call the simpsh program? – Fred Jan 17 '17 at 05:00
  • no I haven't, but I will do. However, I don't think that is the issue. – user3050866 Jan 17 '17 at 05:05
  • I just tested ./test.sh O_RDONLY in.txt O_APPEND O_WRONLY out.txt O_WRONLY err.txt command 0 1 2 sort testing ./test.sh: line 20: /u/cs/ugrad/teodik: is a directory ./test.sh: line 22: 22693 Segmentation fault ./simpsh --verbose\ ./test.sh: line 23: --rdonly: command not found make: *** [check] Error 127 – user3050866 Jan 17 '17 at 05:06
  • Segmentation fault... This is not a "command not found" in the bash sense, I suppose. This is your program crashing, and I cannot help you with that part. It is getting late here, I have to get a bit of sleep... Best of luck! – Fred Jan 17 '17 at 05:10