bruno@skipper.dfrf.nasa.gov (Bruno Chenet) (02/26/91)
To anybody that understands fork(), system() or popen() I am sending the command "tar tvf /dev/rst0" to list the content of a tape drive. I want to be able to grap each file description that shows up on my screen as soon as possible since I want to display it in my own X-window. I tried to redirect the output to a file but then I cannot read this file as long as information is redirected to it. (And this can take 5 or more minutes when I am listing a full tape or CD). I cannot afford to let the user waits that long. Originally I was sending the command using a "popen()" as follow: ********************** sprintf(cmdline," %s ", "tar tvf /dev/rfd0"); if ((fp = popen(cmdline, "r")) == NULL) printf("popen error"); try #1: /* while ((fgets(line, MAXLINE, fp)) != NULL) { n = strlen(line); if (write(1, line, n) != n) printf("data write error|n"); */ try #2: /* while ((ch = fgetc(fp)) != EOF) { if (ch == '\n') { buf[i++] = ch; fprintf(stderr," %s",buf); i=0; } else buf[i++] = ch; } */ ********************** I should be able to read the stderr stream but I don't know how to do it. I think that I need to use fork processing and read the stderr until a EOL is reached. At this point I should be able to grab this line and put it in some kind of buffer to be able to display it in my window and then give the control to the tar command again and so on... I have also another problem of the same type: What happen if I send a command that is not right. The system will answer with some kind of error message send to stderr. I need to grab this message and display it in in my "report window" (I am trying to build a kind of front end to the UNIX system using the X-Window environment so that UNIX becomes more "user friendly"). Should I use "popen()", "system()", "shell scripts" or just "fork()" ? Please, I would take any ideas that would help me solve these problems. Thank you for your time, Bruno
jik@athena.mit.edu (Jonathan I. Kamens) (02/26/91)
Well, you can't use system() or popen(), because neither of them allow you to do what you want to to, i.e. read the stderr output of the tar process. In the former case, system(), it doesn't allow you to read any output at all. In the latter case, popen(), you can read stdout but not stderr, since stderr automatically goes to whatever the stderr of your process is. Ah, but wait, there's a trick! You can do this: 1. Create a pipe. 2. Fclose(stderr). 3. Fdopen() the write end of the pipe and assign the return value to stderr. At this point, you've got a pipe connected to stderr, and you can find out what goes into the pipe by reading from the read end of the pipe. Then, you can use popen() to start the tar process, and read from the FILE * returned by the popen, or from the read end of the pipe, as appropriate. Since output will be going to both at the same time, you might want to use select() or poll() to watch both at once and read from one of them was there is output available on it. -- Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8085 Home: 617-782-0710
tchrist@convex.COM (Tom Christiansen) (02/26/91)
From the keyboard of jik@athena.mit.edu (Jonathan I. Kamens): : : Well, you can't use system() or popen(), because neither of them allow you :to do what you want to to, i.e. read the stderr output of the tar process. In :the former case, system(), it doesn't allow you to read any output at all. In :the latter case, popen(), you can read stdout but not stderr, since stderr :automatically goes to whatever the stderr of your process is. This isn't strictly true. Remember that you've got the full power of sh descriptor manipulation to help you out. First of all, you can dup stderr to stdout: if (!(fp = popen("cmd 2>&1", "r"))) perror("couldn't popen of cmd"); Then they are read together as one merged stream. If you want to read just stderr, not stdout, you can do this: fp = popen("3>&1 (cmd 2>&1 1>&3 3>&-) 3>&-", "r"); Now when you do your fgets() or whatever on that fp, you'll be reading his stderr instead of his stdout. His old stdout will be left unaffected, that is, will be your program's stdout. You can obviously redirect this easily enough. Now, if you really want to read both stdout and stderr separately, then yes, you do have to more complex contortions, preferably involving select. --tom -- "UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things." -- Doug Gwyn Tom Christiansen tchrist@convex.com convex!tchrist
mike@bria.commodore.com (02/28/91)
In an article, athena.mit.edu!jik (Jonathan I. Kamens) writes: | Ah, but wait, there's a trick! You can do this: |1. Create a pipe. |2. Fclose(stderr). |3. Fdopen() the write end of the pipe and assign the return value to stderr. Why not simply dup the stderr to stdout prior to the popen()? -- Michael Stefanik, MGI Inc., Los Angeles| Opinions stated are not even my own. Title of the week: Systems Engineer | UUCP: ...!uunet!bria!mike ------------------------------------------------------------------------------- Remember folks: If you can't flame MS-DOS, then what _can_ you flame?