158 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			158 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* tee - duplicate standard input */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* See Makefile for compilation details. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "config.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "bashtypes.h"
							 | 
						||
| 
								 | 
							
								#include "posixstat.h"
							 | 
						||
| 
								 | 
							
								#include "filecntl.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <signal.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined (HAVE_UNISTD_H)
							 | 
						||
| 
								 | 
							
								#  include <unistd.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "bashansi.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "builtins.h"
							 | 
						||
| 
								 | 
							
								#include "shell.h"
							 | 
						||
| 
								 | 
							
								#include "bashgetopt.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if !defined (errno)
							 | 
						||
| 
								 | 
							
								extern int errno;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct flist {
							 | 
						||
| 
								 | 
							
								  struct flist *next;
							 | 
						||
| 
								 | 
							
								  int fd;
							 | 
						||
| 
								 | 
							
								  char *fname;
							 | 
						||
| 
								 | 
							
								} FLIST;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static FLIST *tee_flist;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define TEE_BUFSIZE	8192
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern int interrupt_immediately;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern char *strerror ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								tee_builtin (list)
							 | 
						||
| 
								 | 
							
								     WORD_LIST *list;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int opt, append, nointr, rval, fd, fflags;
							 | 
						||
| 
								 | 
							
								  int n, nr, nw;
							 | 
						||
| 
								 | 
							
								  FLIST *fl;
							 | 
						||
| 
								 | 
							
								  char *buf, *bp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  char *t;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  reset_internal_getopt ();
							 | 
						||
| 
								 | 
							
								  append = nointr = 0;
							 | 
						||
| 
								 | 
							
								  tee_flist = (FLIST *)NULL;
							 | 
						||
| 
								 | 
							
								  while ((opt = internal_getopt (list, "ai")) != -1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      switch (opt)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									case 'a':
							 | 
						||
| 
								 | 
							
									  append = 1;
							 | 
						||
| 
								 | 
							
									  break;
							 | 
						||
| 
								 | 
							
									case 'i':
							 | 
						||
| 
								 | 
							
									  nointr = 1;
							 | 
						||
| 
								 | 
							
									  break;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
									  builtin_usage ();
							 | 
						||
| 
								 | 
							
									  return (EX_USAGE);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  list = loptend;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (nointr == 0)
							 | 
						||
| 
								 | 
							
								    interrupt_immediately++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  buf = xmalloc (TEE_BUFSIZE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Initialize output file list. */
							 | 
						||
| 
								 | 
							
								  fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
							 | 
						||
| 
								 | 
							
								  tee_flist->fd = 1;
							 | 
						||
| 
								 | 
							
								  tee_flist->fname = "stdout";
							 | 
						||
| 
								 | 
							
								  tee_flist->next = (FLIST *)NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Add file arguments to list of output files. */
							 | 
						||
| 
								 | 
							
								  fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
							 | 
						||
| 
								 | 
							
								  for (rval = EXECUTION_SUCCESS; list; list = list->next)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      fd = open (list->word->word, fflags, 0666);
							 | 
						||
| 
								 | 
							
								      if (fd < 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
							 | 
						||
| 
								 | 
							
								          rval = EXECUTION_FAILURE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								          fl->next = (FLIST *)xmalloc (sizeof(FLIST));
							 | 
						||
| 
								 | 
							
								          fl->next->fd = fd;
							 | 
						||
| 
								 | 
							
								          fl->next->fname = list->word->word;
							 | 
						||
| 
								 | 
							
								          fl = fl->next;
							 | 
						||
| 
								 | 
							
								          fl->next = (FLIST *)NULL;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
							 | 
						||
| 
								 | 
							
								    for (fl = tee_flist; fl; fl = fl->next)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
									n = nr;
							 | 
						||
| 
								 | 
							
									bp = buf;
							 | 
						||
| 
								 | 
							
									do
							 | 
						||
| 
								 | 
							
									  {
							 | 
						||
| 
								 | 
							
									    if ((nw = write (fl->fd, bp, n)) == -1)
							 | 
						||
| 
								 | 
							
									      {
							 | 
						||
| 
								 | 
							
										builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
							 | 
						||
| 
								 | 
							
										rval = EXECUTION_FAILURE;
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									      }
							 | 
						||
| 
								 | 
							
								            bp += nw;
							 | 
						||
| 
								 | 
							
									  }
							 | 
						||
| 
								 | 
							
									while (n -= nw);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								  if (nr < 0)
							 | 
						||
| 
								 | 
							
								    builtin_error ("read error: %s", strerror (errno));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Deallocate resources -- this is a builtin command. */
							 | 
						||
| 
								 | 
							
								  tee_flist = tee_flist->next;		/* skip bogus close of stdout */
							 | 
						||
| 
								 | 
							
								  while (tee_flist)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      fl = tee_flist;
							 | 
						||
| 
								 | 
							
								      if (close (fl->fd) < 0)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									  builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
							 | 
						||
| 
								 | 
							
									  rval = EXECUTION_FAILURE;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								      tee_flist = tee_flist->next;
							 | 
						||
| 
								 | 
							
								      free (fl);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  return (rval);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								char *tee_doc[] = {
							 | 
						||
| 
								 | 
							
									"Copy standard input to standard output, making a copy in each",
							 | 
						||
| 
								 | 
							
									"filename argument.  If the `-a' option is gived, the specified",
							 | 
						||
| 
								 | 
							
									"files are appended to, otherwise they are overwritten.  If the",
							 | 
						||
| 
								 | 
							
									"`-i' option is supplied, tee ignores interrupts.",
							 | 
						||
| 
								 | 
							
									(char *)NULL
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct builtin tee_struct = {
							 | 
						||
| 
								 | 
							
									"tee",			/* builtin name */
							 | 
						||
| 
								 | 
							
									tee_builtin,		/* function implementing the builtin */
							 | 
						||
| 
								 | 
							
									BUILTIN_ENABLED,	/* initial flags for builtin */
							 | 
						||
| 
								 | 
							
									tee_doc,		/* array of long documentation strings. */
							 | 
						||
| 
								 | 
							
									"tee [-ai] [file ...]",	/* usage synopsis; becomes short_doc */
							 | 
						||
| 
								 | 
							
									0			/* reserved for internal use */
							 | 
						||
| 
								 | 
							
								};
							 |