Annotation of 43BSDReno/share/doc/ps2/03.uprog/p5, revision 1.1

1.1     ! root        1: .\"    @(#)p5  6.3 (Berkeley) 5/10/86
        !             2: .\"
        !             3: .NH
        !             4: PROCESSES
        !             5: .PP
        !             6: It is often easier to use a program written
        !             7: by someone else than to invent one's own.
        !             8: This section describes how to
        !             9: execute a program from within another.
        !            10: .NH 2
        !            11: The ``System'' Function
        !            12: .PP
        !            13: The easiest way to execute a program from another
        !            14: is to use
        !            15: the standard library routine
        !            16: .UL system .
        !            17: .UL system
        !            18: takes one argument, a command string exactly as typed
        !            19: at the terminal
        !            20: (except for the newline at the end)
        !            21: and executes it.
        !            22: For instance, to time-stamp the output of a program,
        !            23: .P1
        !            24: main()
        !            25: {
        !            26:        system("date");
        !            27:        /* rest of processing */
        !            28: }
        !            29: .P2
        !            30: If the command string has to be built from pieces,
        !            31: the in-memory formatting capabilities of
        !            32: .UL sprintf
        !            33: may be useful.
        !            34: .PP
        !            35: Remember than
        !            36: .UL getc
        !            37: and
        !            38: .UL putc
        !            39: normally buffer their input;
        !            40: terminal I/O will not be properly synchronized unless
        !            41: this buffering is defeated.
        !            42: For output, use 
        !            43: .UL fflush ;
        !            44: for input, see
        !            45: .UL setbuf 
        !            46: in the appendix.
        !            47: .NH 2
        !            48: Low-Level Process Creation \(em Execl and Execv
        !            49: .PP
        !            50: If you're not using the standard library,
        !            51: or if you need finer control over what
        !            52: happens,
        !            53: you will have to construct calls to other programs
        !            54: using the more primitive routines that the standard
        !            55: library's
        !            56: .UL system
        !            57: routine is based on.
        !            58: .PP
        !            59: The most basic operation is to execute another program
        !            60: .ul
        !            61: without
        !            62: .IT returning ,
        !            63: by using the routine
        !            64: .UL execl  .
        !            65: To print the date as the last action of a running program,
        !            66: use
        !            67: .P1
        !            68: execl("/bin/date", "date", NULL);
        !            69: .P2
        !            70: The first argument to
        !            71: .UL execl
        !            72: is the
        !            73: .ul
        !            74: file name
        !            75: of the command; you have to know where it is found
        !            76: in the file system.
        !            77: The second argument is conventionally
        !            78: the program name
        !            79: (that is, the last component of the file name),
        !            80: but this is seldom used except as a place-holder.
        !            81: If the command takes arguments, they are strung out after
        !            82: this;
        !            83: the end of the list is marked by a 
        !            84: .UL NULL
        !            85: argument.
        !            86: .PP
        !            87: The
        !            88: .UL execl
        !            89: call
        !            90: overlays the existing program with
        !            91: the new one,
        !            92: runs that, then exits.
        !            93: There is
        !            94: .ul
        !            95: no
        !            96: return to the original program.
        !            97: .PP
        !            98: More realistically,
        !            99: a program might fall into two or more phases
        !           100: that communicate only through temporary files.
        !           101: Here it is natural to make the second pass
        !           102: simply an
        !           103: .UL execl
        !           104: call from the first.
        !           105: .PP
        !           106: The one exception to the rule that the original program never gets control
        !           107: back occurs when there is an error, for example if the file can't be found
        !           108: or is not executable.
        !           109: If you don't know where
        !           110: .UL date
        !           111: is located, say
        !           112: .P1
        !           113: execl("/bin/date", "date", NULL);
        !           114: execl("/usr/bin/date", "date", NULL);
        !           115: fprintf(stderr, "Someone stole 'date'\en");
        !           116: .P2
        !           117: .PP
        !           118: A variant of
        !           119: .UL execl
        !           120: called
        !           121: .UL execv
        !           122: is useful when you don't know in advance how many arguments there are going to be.
        !           123: The call is
        !           124: .P1
        !           125: execv(filename, argp);
        !           126: .P2
        !           127: where
        !           128: .UL argp
        !           129: is an array of pointers to the arguments;
        !           130: the last pointer in the array must be 
        !           131: .UL NULL
        !           132: so
        !           133: .UL execv
        !           134: can tell where the list ends.
        !           135: As with
        !           136: .UL execl ,
        !           137: .UL filename
        !           138: is the file in which the program is found, and
        !           139: .UL argp[0]
        !           140: is the name of the program.
        !           141: (This arrangement is identical to the
        !           142: .UL argv
        !           143: array for program arguments.)
        !           144: .PP
        !           145: Neither of these routines provides the niceties of normal command execution.
        !           146: There is no automatic search of multiple directories \(em
        !           147: you have to know precisely where the command is located.
        !           148: Nor do you get the expansion of metacharacters like
        !           149: .UL < ,
        !           150: .UL > ,
        !           151: .UL * ,
        !           152: .UL ? ,
        !           153: and
        !           154: .UL []
        !           155: in the argument list.
        !           156: If you want these, use
        !           157: .UL execl
        !           158: to invoke the shell
        !           159: .UL sh ,
        !           160: which then does all the work.
        !           161: Construct a string
        !           162: .UL commandline
        !           163: that contains the complete command as it would have been typed
        !           164: at the terminal, then say
        !           165: .P1
        !           166: execl("/bin/sh", "sh", "-c", commandline, NULL);
        !           167: .P2
        !           168: The shell is assumed to be at a fixed place,
        !           169: .UL /bin/sh .
        !           170: Its argument
        !           171: .UL -c
        !           172: says to treat the next argument
        !           173: as a whole command line, so it does just what you want.
        !           174: The only problem is in constructing the right information
        !           175: in
        !           176: .UL commandline .
        !           177: .NH 2
        !           178: Control of Processes \(em Fork and Wait
        !           179: .PP
        !           180: So far what we've talked about isn't really all that useful by itself.
        !           181: Now we will show how to regain control after running
        !           182: a program with
        !           183: .UL execl
        !           184: or
        !           185: .UL execv .
        !           186: Since these routines simply overlay the new program on the old one,
        !           187: to save the old one requires that it first be split into
        !           188: two copies;
        !           189: one of these can be overlaid, while the other waits for the new,
        !           190: overlaying program to finish.
        !           191: The splitting is done by a routine called
        !           192: .UL fork :
        !           193: .P1
        !           194: proc_id = fork();
        !           195: .P2
        !           196: splits the program into two copies, both of which continue to run.
        !           197: The only difference between the two is the value of
        !           198: .UL proc_id ,
        !           199: the ``process id.''
        !           200: In one of these processes (the ``child''),
        !           201: .UL proc_id
        !           202: is zero.
        !           203: In the other
        !           204: (the ``parent''),
        !           205: .UL proc_id
        !           206: is non-zero; it is the process number of the child.
        !           207: Thus the basic way to call, and return from,
        !           208: another program is
        !           209: .P1
        !           210: if (fork() == 0)
        !           211:        execl("/bin/sh", "sh", "-c", cmd, NULL);        /* in child */
        !           212: .P2
        !           213: And in fact, except for handling errors, this is sufficient.
        !           214: The
        !           215: .UL fork
        !           216: makes two copies of the program.
        !           217: In the child, the value returned by
        !           218: .UL fork
        !           219: is zero, so it calls
        !           220: .UL execl
        !           221: which does the
        !           222: .UL command
        !           223: and then dies.
        !           224: In the parent,
        !           225: .UL fork
        !           226: returns non-zero
        !           227: so it skips the
        !           228: .UL execl.
        !           229: (If there is any error,
        !           230: .UL fork
        !           231: returns
        !           232: .UL -1 ).
        !           233: .PP
        !           234: More often, the parent wants to wait for the child to terminate
        !           235: before continuing itself.
        !           236: This can be done with
        !           237: the function
        !           238: .UL wait :
        !           239: .P1
        !           240: int status;
        !           241: 
        !           242: if (fork() == 0)
        !           243:        execl(...);
        !           244: wait(&status);
        !           245: .P2
        !           246: This still doesn't handle any abnormal conditions, such as a failure
        !           247: of the
        !           248: .UL execl
        !           249: or
        !           250: .UL fork ,
        !           251: or the possibility that there might be more than one child running simultaneously.
        !           252: (The
        !           253: .UL wait
        !           254: returns the
        !           255: process id
        !           256: of the terminated child, if you want to check it against the value
        !           257: returned by
        !           258: .UL fork .)
        !           259: Finally, this fragment doesn't deal with any
        !           260: funny behavior on the part of the child
        !           261: (which is reported in
        !           262: .UL status ).
        !           263: Still, these three lines
        !           264: are the heart of the standard library's
        !           265: .UL system
        !           266: routine,
        !           267: which we'll show in a moment.
        !           268: .PP
        !           269: The
        !           270: .UL  status 
        !           271: returned by
        !           272: .UL wait
        !           273: encodes in its low-order eight bits
        !           274: the system's idea of the child's termination status;
        !           275: it is 0 for normal termination and non-zero to indicate
        !           276: various kinds of problems.
        !           277: The next higher eight bits are taken from the argument
        !           278: of the call to
        !           279: .UL exit
        !           280: which caused a normal termination of the child process.
        !           281: It is good coding practice
        !           282: for all programs to return meaningful
        !           283: status.
        !           284: .PP
        !           285: When a program is called by the shell,
        !           286: the three file descriptors
        !           287: 0, 1, and 2 are set up pointing at the right files,
        !           288: and all other possible file descriptors
        !           289: are available for use.
        !           290: When this program calls another one,
        !           291: correct etiquette suggests making sure the same conditions
        !           292: hold.
        !           293: Neither
        !           294: .UL fork
        !           295: nor the
        !           296: .UL exec
        !           297: calls affects open files in any way.
        !           298: If the parent is buffering output
        !           299: that must come out before output from the child,
        !           300: the parent must flush its buffers
        !           301: before the
        !           302: .UL execl .
        !           303: Conversely,
        !           304: if a caller buffers an input stream,
        !           305: the called program will lose any information
        !           306: that has been read by the caller.
        !           307: .NH 2
        !           308: Pipes
        !           309: .PP
        !           310: A
        !           311: .ul
        !           312: pipe
        !           313: is an I/O channel intended for use
        !           314: between two cooperating processes:
        !           315: one process writes into the pipe,
        !           316: while the other reads.
        !           317: The system looks after buffering the data and synchronizing
        !           318: the two processes.
        !           319: Most pipes are created by the shell,
        !           320: as in
        !           321: .P1
        !           322: ls | pr
        !           323: .P2
        !           324: which connects the standard output of
        !           325: .UL ls
        !           326: to the standard input of
        !           327: .UL pr .
        !           328: Sometimes, however, it is most convenient
        !           329: for a process to set up its own plumbing;
        !           330: in this section, we will illustrate how
        !           331: the pipe connection is established and used.
        !           332: .PP
        !           333: The system call
        !           334: .UL pipe
        !           335: creates a pipe.
        !           336: Since a pipe is used for both reading and writing,
        !           337: two file descriptors are returned;
        !           338: the actual usage is like this:
        !           339: .P1
        !           340: int    fd[2];
        !           341: 
        !           342: stat = pipe(fd);
        !           343: if (stat == -1)
        !           344:        /* there was an error ... */
        !           345: .P2
        !           346: .UL fd
        !           347: is an array of two file descriptors, where
        !           348: .UL fd[0]
        !           349: is the read side of the pipe and
        !           350: .UL fd[1] 
        !           351: is for writing.
        !           352: These may be used in
        !           353: .UL read ,
        !           354: .UL write
        !           355: and
        !           356: .UL close
        !           357: calls just like any other file descriptors.
        !           358: .PP
        !           359: If a process reads a pipe which is empty,
        !           360: it will wait until data arrives;
        !           361: if a process writes into a pipe which
        !           362: is too full, it will wait until the pipe empties somewhat.
        !           363: If the write side of the pipe is closed,
        !           364: a subsequent
        !           365: .UL  read 
        !           366: will encounter end of file.
        !           367: .PP
        !           368: To illustrate the use of pipes in a realistic setting,
        !           369: let us write a function called
        !           370: .UL popen(cmd,\ mode) ,
        !           371: which creates a process
        !           372: .UL cmd
        !           373: (just as
        !           374: .UL system 
        !           375: does),
        !           376: and returns a file descriptor that will either
        !           377: read or write that process, according to 
        !           378: .UL mode .
        !           379: That is,
        !           380: the call
        !           381: .P1
        !           382: fout = popen("pr", WRITE);
        !           383: .P2
        !           384: creates a process that executes
        !           385: the
        !           386: .UL pr
        !           387: command;
        !           388: subsequent
        !           389: .UL write
        !           390: calls using the file descriptor
        !           391: .UL fout
        !           392: will send their data to that process
        !           393: through the pipe.
        !           394: .PP
        !           395: .UL popen
        !           396: first creates the
        !           397: the pipe with a
        !           398: .UL pipe
        !           399: system call;
        !           400: it then
        !           401: .UL fork s
        !           402: to create two copies of itself.
        !           403: The child decides whether it is supposed to read or write,
        !           404: closes the other side of the pipe,
        !           405: then calls the shell (via
        !           406: .UL execl )
        !           407: to run the desired process.
        !           408: The parent likewise closes the end of the pipe it does not use.
        !           409: These closes are necessary to make end-of-file tests work properly.
        !           410: For example, if a child that intends to read
        !           411: fails to close the write end of the pipe, it will never
        !           412: see the end of the pipe file, just because there is one writer
        !           413: potentially active.
        !           414: .P1
        !           415: #include <stdio.h>
        !           416: 
        !           417: #define        READ    0
        !           418: #define        WRITE   1
        !           419: #define        tst(a, b)       (mode == READ ? (b) : (a))
        !           420: static int     popen_pid;
        !           421: 
        !           422: popen(cmd, mode)
        !           423: char   *cmd;
        !           424: int    mode;
        !           425: {
        !           426:        int p[2];
        !           427: 
        !           428:        if (pipe(p) < 0)
        !           429:                return(NULL);
        !           430:        if ((popen_pid = fork()) == 0) {
        !           431:                close(tst(p[WRITE], p[READ]));
        !           432:                close(tst(0, 1));
        !           433:                dup(tst(p[READ], p[WRITE]));
        !           434:                close(tst(p[READ], p[WRITE]));
        !           435:                execl("/bin/sh", "sh", "-c", cmd, 0);
        !           436:                _exit(1);       /* disaster has occurred if we get here */
        !           437:        }
        !           438:        if (popen_pid == -1)
        !           439:                return(NULL);
        !           440:        close(tst(p[READ], p[WRITE]));
        !           441:        return(tst(p[WRITE], p[READ]));
        !           442: }
        !           443: .P2
        !           444: The sequence of
        !           445: .UL close s
        !           446: in the child
        !           447: is a bit tricky.
        !           448: Suppose
        !           449: that the task is to create a child process that will read data from the parent.
        !           450: Then the first
        !           451: .UL close
        !           452: closes the write side of the pipe,
        !           453: leaving the read side open.
        !           454: The lines
        !           455: .P1
        !           456: close(tst(0, 1));
        !           457: dup(tst(p[READ], p[WRITE]));
        !           458: .P2
        !           459: are the conventional way to associate the pipe descriptor
        !           460: with the standard input of the child.
        !           461: The 
        !           462: .UL close
        !           463: closes file descriptor 0,
        !           464: that is, the standard input.
        !           465: .UL dup
        !           466: is a system call that
        !           467: returns a duplicate of an already open file descriptor.
        !           468: File descriptors are assigned in increasing order
        !           469: and the first available one is returned,
        !           470: so
        !           471: the effect of the
        !           472: .UL dup
        !           473: is to copy the file descriptor for the pipe (read side)
        !           474: to file descriptor 0;
        !           475: thus the read side of the pipe becomes the standard input.
        !           476: (Yes, this is a bit tricky, but it's a standard idiom.)
        !           477: Finally, the old read side of the pipe is closed.
        !           478: .PP
        !           479: A similar sequence of operations takes place
        !           480: when the child process is supposed to write
        !           481: from the parent instead of reading.
        !           482: You may find it a useful exercise to step through that case.
        !           483: .PP
        !           484: The job is not quite done,
        !           485: for we still need a function
        !           486: .UL pclose
        !           487: to close the pipe created by
        !           488: .UL popen .
        !           489: The main reason for using a separate function rather than
        !           490: .UL close
        !           491: is that it is desirable to wait for the termination of the child process.
        !           492: First, the return value from
        !           493: .UL pclose
        !           494: indicates whether the process succeeded.
        !           495: Equally important when a process creates several children
        !           496: is that only a bounded number of unwaited-for children
        !           497: can exist, even if some of them have terminated;
        !           498: performing the
        !           499: .UL wait
        !           500: lays the child to rest.
        !           501: Thus:
        !           502: .P1
        !           503: #include <signal.h>
        !           504: 
        !           505: pclose(fd)     /* close pipe fd */
        !           506: int fd;
        !           507: {
        !           508:        register r, (*hstat)(), (*istat)(), (*qstat)();
        !           509:        int      status;
        !           510:        extern int popen_pid;
        !           511: 
        !           512:        close(fd);
        !           513:        istat = signal(SIGINT, SIG_IGN);
        !           514:        qstat = signal(SIGQUIT, SIG_IGN);
        !           515:        hstat = signal(SIGHUP, SIG_IGN);
        !           516:        while ((r = wait(&status)) != popen_pid && r != -1);
        !           517:        if (r == -1)
        !           518:                status = -1;
        !           519:        signal(SIGINT, istat);
        !           520:        signal(SIGQUIT, qstat);
        !           521:        signal(SIGHUP, hstat);
        !           522:        return(status);
        !           523: }
        !           524: .P2
        !           525: The calls to
        !           526: .UL signal
        !           527: make sure that no interrupts, etc.,
        !           528: interfere with the waiting process;
        !           529: this is the topic of the next section.
        !           530: .PP
        !           531: The routine as written has the limitation that only one pipe may
        !           532: be open at once, because of the single shared variable
        !           533: .UL popen_pid ;
        !           534: it really should be an array indexed by file descriptor.
        !           535: A
        !           536: .UL popen
        !           537: function, with slightly different arguments and return value is available
        !           538: as part of the standard I/O library discussed below.
        !           539: As currently written, it shares the same limitation.

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.