178 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* tee - duplicate standard input */
 | |
| 
 | |
| /* See Makefile for compilation details. */
 | |
| 
 | |
| /*
 | |
|    Copyright (C) 1999-2009 Free Software Foundation, Inc.
 | |
| 
 | |
|    This file is part of GNU Bash.
 | |
|    Bash is free software: you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation, either version 3 of the License, or
 | |
|    (at your option) any later version.
 | |
| 
 | |
|    Bash is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| 
 | |
| #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"
 | |
| #include "common.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[] = {
 | |
| 	"Duplicate standard output.",
 | |
| 	"",
 | |
| 	"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 */
 | |
| };
 | 
