LCOV - code coverage report
Current view: top level - openssh-6.6p1 - scp.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 385 694 55.5 %
Date: 2014-08-01 Functions: 14 20 70.0 %
Branches: 211 508 41.5 %

           Branch data     Line data    Source code
       1                 :            : /* $OpenBSD: scp.c,v 1.179 2013/11/20 20:53:10 deraadt Exp $ */
       2                 :            : /*
       3                 :            :  * scp - secure remote copy.  This is basically patched BSD rcp which
       4                 :            :  * uses ssh to do the data transfer (instead of using rcmd).
       5                 :            :  *
       6                 :            :  * NOTE: This version should NOT be suid root.  (This uses ssh to
       7                 :            :  * do the transfer and ssh has the necessary privileges.)
       8                 :            :  *
       9                 :            :  * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
      10                 :            :  *
      11                 :            :  * As far as I am concerned, the code I have written for this software
      12                 :            :  * can be used freely for any purpose.  Any derived versions of this
      13                 :            :  * software must be clearly marked as such, and if the derived work is
      14                 :            :  * incompatible with the protocol description in the RFC file, it must be
      15                 :            :  * called by a name other than "ssh" or "Secure Shell".
      16                 :            :  */
      17                 :            : /*
      18                 :            :  * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
      19                 :            :  * Copyright (c) 1999 Aaron Campbell.  All rights reserved.
      20                 :            :  *
      21                 :            :  * Redistribution and use in source and binary forms, with or without
      22                 :            :  * modification, are permitted provided that the following conditions
      23                 :            :  * are met:
      24                 :            :  * 1. Redistributions of source code must retain the above copyright
      25                 :            :  *    notice, this list of conditions and the following disclaimer.
      26                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      27                 :            :  *    notice, this list of conditions and the following disclaimer in the
      28                 :            :  *    documentation and/or other materials provided with the distribution.
      29                 :            :  *
      30                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      31                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      32                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      33                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      34                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      35                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      36                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      37                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      38                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      39                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      40                 :            :  */
      41                 :            : 
      42                 :            : /*
      43                 :            :  * Parts from:
      44                 :            :  *
      45                 :            :  * Copyright (c) 1983, 1990, 1992, 1993, 1995
      46                 :            :  *      The Regents of the University of California.  All rights reserved.
      47                 :            :  *
      48                 :            :  * Redistribution and use in source and binary forms, with or without
      49                 :            :  * modification, are permitted provided that the following conditions
      50                 :            :  * are met:
      51                 :            :  * 1. Redistributions of source code must retain the above copyright
      52                 :            :  *    notice, this list of conditions and the following disclaimer.
      53                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      54                 :            :  *    notice, this list of conditions and the following disclaimer in the
      55                 :            :  *    documentation and/or other materials provided with the distribution.
      56                 :            :  * 3. Neither the name of the University nor the names of its contributors
      57                 :            :  *    may be used to endorse or promote products derived from this software
      58                 :            :  *    without specific prior written permission.
      59                 :            :  *
      60                 :            :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      61                 :            :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      62                 :            :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      63                 :            :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      64                 :            :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      65                 :            :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      66                 :            :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      67                 :            :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      68                 :            :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      69                 :            :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      70                 :            :  * SUCH DAMAGE.
      71                 :            :  *
      72                 :            :  */
      73                 :            : 
      74                 :            : #include "includes.h"
      75                 :            : 
      76                 :            : #include <sys/types.h>
      77                 :            : #include <sys/param.h>
      78                 :            : #ifdef HAVE_SYS_STAT_H
      79                 :            : # include <sys/stat.h>
      80                 :            : #endif
      81                 :            : #ifdef HAVE_POLL_H
      82                 :            : #include <poll.h>
      83                 :            : #else
      84                 :            : # ifdef HAVE_SYS_POLL_H
      85                 :            : #  include <sys/poll.h>
      86                 :            : # endif
      87                 :            : #endif
      88                 :            : #ifdef HAVE_SYS_TIME_H
      89                 :            : # include <sys/time.h>
      90                 :            : #endif
      91                 :            : #include <sys/wait.h>
      92                 :            : #include <sys/uio.h>
      93                 :            : 
      94                 :            : #include <ctype.h>
      95                 :            : #include <dirent.h>
      96                 :            : #include <errno.h>
      97                 :            : #include <fcntl.h>
      98                 :            : #include <pwd.h>
      99                 :            : #include <signal.h>
     100                 :            : #include <stdarg.h>
     101                 :            : #include <stdio.h>
     102                 :            : #include <stdlib.h>
     103                 :            : #include <string.h>
     104                 :            : #include <time.h>
     105                 :            : #include <unistd.h>
     106                 :            : #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
     107                 :            : #include <vis.h>
     108                 :            : #endif
     109                 :            : 
     110                 :            : #include "xmalloc.h"
     111                 :            : #include "atomicio.h"
     112                 :            : #include "pathnames.h"
     113                 :            : #include "log.h"
     114                 :            : #include "misc.h"
     115                 :            : #include "progressmeter.h"
     116                 :            : 
     117                 :            : extern char *__progname;
     118                 :            : 
     119                 :            : #define COPY_BUFLEN     16384
     120                 :            : 
     121                 :            : int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
     122                 :            : int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout);
     123                 :            : 
     124                 :            : /* Struct for addargs */
     125                 :            : arglist args;
     126                 :            : arglist remote_remote_args;
     127                 :            : 
     128                 :            : /* Bandwidth limit */
     129                 :            : long long limit_kbps = 0;
     130                 :            : struct bwlimit bwlimit;
     131                 :            : 
     132                 :            : /* Name of current file being transferred. */
     133                 :            : char *curfile;
     134                 :            : 
     135                 :            : /* This is set to non-zero to enable verbose mode. */
     136                 :            : int verbose_mode = 0;
     137                 :            : 
     138                 :            : /* This is set to zero if the progressmeter is not desired. */
     139                 :            : int showprogress = 1;
     140                 :            : 
     141                 :            : /*
     142                 :            :  * This is set to non-zero if remote-remote copy should be piped
     143                 :            :  * through this process.
     144                 :            :  */
     145                 :            : int throughlocal = 0;
     146                 :            : 
     147                 :            : /* This is the program to execute for the secured connection. ("ssh" or -S) */
     148                 :            : char *ssh_program = _PATH_SSH_PROGRAM;
     149                 :            : 
     150                 :            : /* This is used to store the pid of ssh_program */
     151                 :            : pid_t do_cmd_pid = -1;
     152                 :            : 
     153                 :            : static void
     154                 :          1 : killchild(int signo)
     155                 :            : {
     156         [ -  + ]:          1 :         if (do_cmd_pid > 1) {
     157         [ #  # ]:          0 :                 kill(do_cmd_pid, signo ? signo : SIGTERM);
     158                 :          0 :                 waitpid(do_cmd_pid, NULL, 0);
     159                 :            :         }
     160                 :            : 
     161         [ -  + ]:          1 :         if (signo)
     162                 :          0 :                 _exit(1);
     163                 :          1 :         exit(1);
     164                 :            : }
     165                 :            : 
     166                 :            : static void
     167                 :          0 : suspchild(int signo)
     168                 :            : {
     169                 :            :         int status;
     170                 :            : 
     171         [ #  # ]:          0 :         if (do_cmd_pid > 1) {
     172                 :          0 :                 kill(do_cmd_pid, signo);
     173   [ #  #  #  # ]:          0 :                 while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 &&
     174                 :          0 :                     errno == EINTR)
     175                 :            :                         ;
     176                 :          0 :                 kill(getpid(), SIGSTOP);
     177                 :            :         }
     178                 :          0 : }
     179                 :            : 
     180                 :            : static int
     181                 :          4 : do_local_cmd(arglist *a)
     182                 :            : {
     183                 :            :         u_int i;
     184                 :            :         int status;
     185                 :            :         pid_t pid;
     186                 :            : 
     187         [ -  + ]:          4 :         if (a->num == 0)
     188                 :          0 :                 fatal("do_local_cmd: no arguments");
     189                 :            : 
     190         [ -  + ]:          4 :         if (verbose_mode) {
     191                 :          0 :                 fprintf(stderr, "Executing:");
     192         [ #  # ]:          0 :                 for (i = 0; i < a->num; i++)
     193                 :          0 :                         fprintf(stderr, " %s", a->list[i]);
     194                 :          0 :                 fprintf(stderr, "\n");
     195                 :            :         }
     196         [ -  + ]:          4 :         if ((pid = fork()) == -1)
     197                 :          0 :                 fatal("do_local_cmd: fork: %s", strerror(errno));
     198                 :            : 
     199         [ +  + ]:          8 :         if (pid == 0) {
     200                 :          4 :                 execvp(a->list[0], a->list);
     201                 :          4 :                 perror(a->list[0]);
     202                 :          0 :                 exit(1);
     203                 :            :         }
     204                 :            : 
     205                 :          4 :         do_cmd_pid = pid;
     206                 :          4 :         signal(SIGTERM, killchild);
     207                 :          4 :         signal(SIGINT, killchild);
     208                 :          4 :         signal(SIGHUP, killchild);
     209                 :            : 
     210         [ -  + ]:          4 :         while (waitpid(pid, &status, 0) == -1)
     211         [ #  # ]:          0 :                 if (errno != EINTR)
     212                 :          0 :                         fatal("do_local_cmd: waitpid: %s", strerror(errno));
     213                 :            : 
     214                 :          4 :         do_cmd_pid = -1;
     215                 :            : 
     216 [ +  - ][ -  + ]:          4 :         if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
     217                 :            :                 return (-1);
     218                 :            : 
     219                 :            :         return (0);
     220                 :            : }
     221                 :            : 
     222                 :            : /*
     223                 :            :  * This function executes the given command as the specified user on the
     224                 :            :  * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
     225                 :            :  * assigns the input and output file descriptors on success.
     226                 :            :  */
     227                 :            : 
     228                 :            : int
     229                 :         17 : do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
     230                 :            : {
     231                 :            :         int pin[2], pout[2], reserved[2];
     232                 :            : 
     233         [ -  + ]:         17 :         if (verbose_mode)
     234         [ #  # ]:          0 :                 fprintf(stderr,
     235                 :            :                     "Executing: program %s host %s, user %s, command %s\n",
     236                 :            :                     ssh_program, host,
     237                 :            :                     remuser ? remuser : "(unspecified)", cmd);
     238                 :            : 
     239                 :            :         /*
     240                 :            :          * Reserve two descriptors so that the real pipes won't get
     241                 :            :          * descriptors 0 and 1 because that will screw up dup2 below.
     242                 :            :          */
     243         [ -  + ]:         17 :         if (pipe(reserved) < 0)
     244                 :          0 :                 fatal("pipe: %s", strerror(errno));
     245                 :            : 
     246                 :            :         /* Create a socket pair for communicating with ssh. */
     247         [ -  + ]:         17 :         if (pipe(pin) < 0)
     248                 :          0 :                 fatal("pipe: %s", strerror(errno));
     249         [ -  + ]:         17 :         if (pipe(pout) < 0)
     250                 :          0 :                 fatal("pipe: %s", strerror(errno));
     251                 :            : 
     252                 :            :         /* Free the reserved descriptors. */
     253                 :         17 :         close(reserved[0]);
     254                 :         17 :         close(reserved[1]);
     255                 :            : 
     256                 :         17 :         signal(SIGTSTP, suspchild);
     257                 :         17 :         signal(SIGTTIN, suspchild);
     258                 :         17 :         signal(SIGTTOU, suspchild);
     259                 :            : 
     260                 :            :         /* Fork a child to execute the command on the remote host using ssh. */
     261                 :         17 :         do_cmd_pid = fork();
     262         [ +  + ]:         30 :         if (do_cmd_pid == 0) {
     263                 :            :                 /* Child. */
     264                 :         17 :                 close(pin[1]);
     265                 :         17 :                 close(pout[0]);
     266                 :         17 :                 dup2(pin[0], 0);
     267                 :         17 :                 dup2(pout[1], 1);
     268                 :         17 :                 close(pin[0]);
     269                 :         17 :                 close(pout[1]);
     270                 :            : 
     271                 :         17 :                 replacearg(&args, 0, "%s", ssh_program);
     272         [ -  + ]:         17 :                 if (remuser != NULL) {
     273                 :          0 :                         addargs(&args, "-l");
     274                 :          0 :                         addargs(&args, "%s", remuser);
     275                 :            :                 }
     276                 :         17 :                 addargs(&args, "--");
     277                 :         17 :                 addargs(&args, "%s", host);
     278                 :         17 :                 addargs(&args, "%s", cmd);
     279                 :            : 
     280                 :         17 :                 execvp(ssh_program, args.list);
     281                 :         17 :                 perror(ssh_program);
     282                 :          0 :                 exit(1);
     283         [ -  + ]:         13 :         } else if (do_cmd_pid == -1) {
     284                 :          0 :                 fatal("fork: %s", strerror(errno));
     285                 :            :         }
     286                 :            :         /* Parent.  Close the other side, and return the local side. */
     287                 :         13 :         close(pin[0]);
     288                 :         13 :         *fdout = pin[1];
     289                 :         13 :         close(pout[1]);
     290                 :         13 :         *fdin = pout[0];
     291                 :         13 :         signal(SIGTERM, killchild);
     292                 :         13 :         signal(SIGINT, killchild);
     293                 :         13 :         signal(SIGHUP, killchild);
     294                 :         13 :         return 0;
     295                 :            : }
     296                 :            : 
     297                 :            : /*
     298                 :            :  * This functions executes a command simlar to do_cmd(), but expects the
     299                 :            :  * input and output descriptors to be setup by a previous call to do_cmd().
     300                 :            :  * This way the input and output of two commands can be connected.
     301                 :            :  */
     302                 :            : int
     303                 :          0 : do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
     304                 :            : {
     305                 :            :         pid_t pid;
     306                 :            :         int status;
     307                 :            : 
     308         [ #  # ]:          0 :         if (verbose_mode)
     309         [ #  # ]:          0 :                 fprintf(stderr,
     310                 :            :                     "Executing: 2nd program %s host %s, user %s, command %s\n",
     311                 :            :                     ssh_program, host,
     312                 :            :                     remuser ? remuser : "(unspecified)", cmd);
     313                 :            : 
     314                 :            :         /* Fork a child to execute the command on the remote host using ssh. */
     315                 :          0 :         pid = fork();
     316         [ #  # ]:          0 :         if (pid == 0) {
     317                 :          0 :                 dup2(fdin, 0);
     318                 :          0 :                 dup2(fdout, 1);
     319                 :            : 
     320                 :          0 :                 replacearg(&args, 0, "%s", ssh_program);
     321         [ #  # ]:          0 :                 if (remuser != NULL) {
     322                 :          0 :                         addargs(&args, "-l");
     323                 :          0 :                         addargs(&args, "%s", remuser);
     324                 :            :                 }
     325                 :          0 :                 addargs(&args, "--");
     326                 :          0 :                 addargs(&args, "%s", host);
     327                 :          0 :                 addargs(&args, "%s", cmd);
     328                 :            : 
     329                 :          0 :                 execvp(ssh_program, args.list);
     330                 :          0 :                 perror(ssh_program);
     331                 :          0 :                 exit(1);
     332         [ #  # ]:          0 :         } else if (pid == -1) {
     333                 :          0 :                 fatal("fork: %s", strerror(errno));
     334                 :            :         }
     335         [ #  # ]:          0 :         while (waitpid(pid, &status, 0) == -1)
     336         [ #  # ]:          0 :                 if (errno != EINTR)
     337                 :          0 :                         fatal("do_cmd2: waitpid: %s", strerror(errno));
     338                 :          0 :         return 0;
     339                 :            : }
     340                 :            : 
     341                 :            : typedef struct {
     342                 :            :         size_t cnt;
     343                 :            :         char *buf;
     344                 :            : } BUF;
     345                 :            : 
     346                 :            : BUF *allocbuf(BUF *, int, int);
     347                 :            : void lostconn(int);
     348                 :            : int okname(char *);
     349                 :            : void run_err(const char *,...);
     350                 :            : void verifydir(char *);
     351                 :            : 
     352                 :            : struct passwd *pwd;
     353                 :            : uid_t userid;
     354                 :            : int errs, remin, remout;
     355                 :            : int pflag, iamremote, iamrecursive, targetshouldbedirectory;
     356                 :            : 
     357                 :            : #define CMDNEEDS        64
     358                 :            : char cmd[CMDNEEDS];             /* must hold "rcp -r -p -d\0" */
     359                 :            : 
     360                 :            : int response(void);
     361                 :            : void rsource(char *, struct stat *);
     362                 :            : void sink(int, char *[]);
     363                 :            : void source(int, char *[]);
     364                 :            : void tolocal(int, char *[]);
     365                 :            : void toremote(char *, int, char *[]);
     366                 :            : void usage(void);
     367                 :            : 
     368                 :            : int
     369                 :         28 : main(int argc, char **argv)
     370                 :            : {
     371                 :            :         int ch, fflag, tflag, status, n;
     372                 :            :         char *targ, **newargv;
     373                 :            :         const char *errstr;
     374                 :            :         extern char *optarg;
     375                 :            :         extern int optind;
     376                 :            : 
     377                 :            :         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
     378                 :         28 :         sanitise_stdfd();
     379                 :            : 
     380                 :            :         /* Copy argv, because we modify it */
     381                 :         28 :         newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv));
     382         [ +  + ]:        191 :         for (n = 0; n < argc; n++)
     383                 :        163 :                 newargv[n] = xstrdup(argv[n]);
     384                 :         28 :         argv = newargv;
     385                 :            : 
     386                 :         28 :         __progname = ssh_get_progname(argv[0]);
     387                 :            : 
     388                 :            :         memset(&args, '\0', sizeof(args));
     389                 :            :         memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
     390                 :            :         args.list = remote_remote_args.list = NULL;
     391                 :         28 :         addargs(&args, "%s", ssh_program);
     392                 :         28 :         addargs(&args, "-x");
     393                 :         28 :         addargs(&args, "-oForwardAgent=no");
     394                 :         28 :         addargs(&args, "-oPermitLocalCommand=no");
     395                 :         28 :         addargs(&args, "-oClearAllForwardings=yes");
     396                 :            : 
     397                 :         28 :         fflag = tflag = 0;
     398         [ +  + ]:         89 :         while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
     399   [ -  -  +  -  :         61 :                 switch (ch) {
          -  -  -  +  +  
          -  +  -  +  +  
                      - ]
     400                 :            :                 /* User-visible flags. */
     401                 :            :                 case '1':
     402                 :            :                 case '2':
     403                 :            :                 case '4':
     404                 :            :                 case '6':
     405                 :            :                 case 'C':
     406                 :          0 :                         addargs(&args, "-%c", ch);
     407                 :          0 :                         addargs(&remote_remote_args, "-%c", ch);
     408                 :         61 :                         break;
     409                 :            :                 case '3':
     410                 :          0 :                         throughlocal = 1;
     411                 :          0 :                         break;
     412                 :            :                 case 'o':
     413                 :            :                 case 'c':
     414                 :            :                 case 'i':
     415                 :            :                 case 'F':
     416                 :          2 :                         addargs(&remote_remote_args, "-%c", ch);
     417                 :          2 :                         addargs(&remote_remote_args, "%s", optarg);
     418                 :          2 :                         addargs(&args, "-%c", ch);
     419                 :          2 :                         addargs(&args, "%s", optarg);
     420                 :          2 :                         break;
     421                 :            :                 case 'P':
     422                 :          0 :                         addargs(&remote_remote_args, "-p");
     423                 :          0 :                         addargs(&remote_remote_args, "%s", optarg);
     424                 :          0 :                         addargs(&args, "-p");
     425                 :          0 :                         addargs(&args, "%s", optarg);
     426                 :          0 :                         break;
     427                 :            :                 case 'B':
     428                 :          0 :                         addargs(&remote_remote_args, "-oBatchmode=yes");
     429                 :          0 :                         addargs(&args, "-oBatchmode=yes");
     430                 :          0 :                         break;
     431                 :            :                 case 'l':
     432                 :          0 :                         limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
     433                 :            :                             &errstr);
     434         [ #  # ]:          0 :                         if (errstr != NULL)
     435                 :          0 :                                 usage();
     436                 :          0 :                         limit_kbps *= 1024; /* kbps */
     437                 :          0 :                         bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
     438                 :          0 :                         break;
     439                 :            :                 case 'p':
     440                 :          0 :                         pflag = 1;
     441                 :          0 :                         break;
     442                 :            :                 case 'r':
     443                 :         10 :                         iamrecursive = 1;
     444                 :         10 :                         break;
     445                 :            :                 case 'S':
     446                 :         22 :                         ssh_program = xstrdup(optarg);
     447                 :         22 :                         break;
     448                 :            :                 case 'v':
     449                 :          0 :                         addargs(&args, "-v");
     450                 :          0 :                         addargs(&remote_remote_args, "-v");
     451                 :          0 :                         verbose_mode = 1;
     452                 :          0 :                         break;
     453                 :            :                 case 'q':
     454                 :         21 :                         addargs(&args, "-q");
     455                 :         21 :                         addargs(&remote_remote_args, "-q");
     456                 :         21 :                         showprogress = 0;
     457                 :         21 :                         break;
     458                 :            : 
     459                 :            :                 /* Server options. */
     460                 :            :                 case 'd':
     461                 :          0 :                         targetshouldbedirectory = 1;
     462                 :          0 :                         break;
     463                 :            :                 case 'f':       /* "from" */
     464                 :          3 :                         iamremote = 1;
     465                 :          3 :                         fflag = 1;
     466                 :          3 :                         break;
     467                 :            :                 case 't':       /* "to" */
     468                 :          3 :                         iamremote = 1;
     469                 :          3 :                         tflag = 1;
     470                 :            : #ifdef HAVE_CYGWIN
     471                 :            :                         setmode(0, O_BINARY);
     472                 :            : #endif
     473                 :          3 :                         break;
     474                 :            :                 default:
     475                 :          0 :                         usage();
     476                 :            :                 }
     477                 :         28 :         argc -= optind;
     478                 :         28 :         argv += optind;
     479                 :            : 
     480         [ -  + ]:         28 :         if ((pwd = getpwuid(userid = getuid())) == NULL)
     481                 :          0 :                 fatal("unknown user %u", (u_int) userid);
     482                 :            : 
     483         [ +  + ]:         28 :         if (!isatty(STDOUT_FILENO))
     484                 :         17 :                 showprogress = 0;
     485                 :            : 
     486                 :         28 :         remin = STDIN_FILENO;
     487                 :         28 :         remout = STDOUT_FILENO;
     488                 :            : 
     489         [ +  + ]:         28 :         if (fflag) {
     490                 :            :                 /* Follow "protocol", send data. */
     491                 :          3 :                 (void) response();
     492                 :          3 :                 source(argc, argv);
     493                 :          3 :                 exit(errs != 0);
     494                 :            :         }
     495         [ +  + ]:         25 :         if (tflag) {
     496                 :            :                 /* Receive data. */
     497                 :          3 :                 sink(argc, argv);
     498                 :          3 :                 exit(errs != 0);
     499                 :            :         }
     500         [ -  + ]:         22 :         if (argc < 2)
     501                 :          0 :                 usage();
     502         [ +  + ]:         22 :         if (argc > 2)
     503                 :          1 :                 targetshouldbedirectory = 1;
     504                 :            : 
     505                 :         22 :         remin = remout = -1;
     506                 :         22 :         do_cmd_pid = -1;
     507                 :            :         /* Command to be executed on remote system using "ssh". */
     508 [ +  + ][ +  - ]:         22 :         (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
         [ +  + ][ +  - ]
     509                 :         22 :             verbose_mode ? " -v" : "",
     510                 :         44 :             iamrecursive ? " -r" : "", pflag ? " -p" : "",
     511                 :         22 :             targetshouldbedirectory ? " -d" : "");
     512                 :            : 
     513                 :         22 :         (void) signal(SIGPIPE, lostconn);
     514                 :            : 
     515         [ +  + ]:         22 :         if ((targ = colon(argv[argc - 1])))     /* Dest is remote host. */
     516                 :          3 :                 toremote(targ, argc, argv);
     517                 :            :         else {
     518         [ +  + ]:         19 :                 if (targetshouldbedirectory)
     519                 :          1 :                         verifydir(argv[argc - 1]);
     520                 :         18 :                 tolocal(argc, argv);    /* Dest is local host. */
     521                 :            :         }
     522                 :            :         /*
     523                 :            :          * Finally check the exit status of the ssh process, if one was forked
     524                 :            :          * and no error has occurred yet
     525                 :            :          */
     526 [ +  + ][ +  - ]:         11 :         if (do_cmd_pid != -1 && errs == 0) {
     527         [ +  + ]:          7 :                 if (remin != -1)
     528                 :          3 :                     (void) close(remin);
     529         [ +  + ]:          7 :                 if (remout != -1)
     530                 :          3 :                     (void) close(remout);
     531         [ -  + ]:          7 :                 if (waitpid(do_cmd_pid, &status, 0) == -1)
     532                 :          0 :                         errs = 1;
     533                 :            :                 else {
     534 [ +  - ][ -  + ]:          7 :                         if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
     535                 :          0 :                                 errs = 1;
     536                 :            :                 }
     537                 :            :         }
     538                 :         11 :         exit(errs != 0);
     539                 :            : }
     540                 :            : 
     541                 :            : /* Callback from atomicio6 to update progress meter and limit bandwidth */
     542                 :            : static int
     543                 :        936 : scpio(void *_cnt, size_t s)
     544                 :            : {
     545                 :        936 :         off_t *cnt = (off_t *)_cnt;
     546                 :            : 
     547                 :        936 :         *cnt += s;
     548         [ -  + ]:        936 :         if (limit_kbps > 0)
     549                 :          0 :                 bandwidth_limit(&bwlimit, s);
     550                 :        936 :         return 0;
     551                 :            : }
     552                 :            : 
     553                 :            : static int
     554                 :          0 : do_times(int fd, int verb, const struct stat *sb)
     555                 :            : {
     556                 :            :         /* strlen(2^64) == 20; strlen(10^6) == 7 */
     557                 :            :         char buf[(20 + 7 + 2) * 2 + 2];
     558                 :            : 
     559                 :          0 :         (void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
     560                 :          0 :             (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
     561                 :          0 :             (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
     562         [ #  # ]:          0 :         if (verb) {
     563                 :          0 :                 fprintf(stderr, "File mtime %lld atime %lld\n",
     564                 :          0 :                     (long long)sb->st_mtime, (long long)sb->st_atime);
     565                 :          0 :                 fprintf(stderr, "Sending file timestamps: %s", buf);
     566                 :            :         }
     567                 :          0 :         (void) atomicio(vwrite, fd, buf, strlen(buf));
     568                 :          0 :         return (response());
     569                 :            : }
     570                 :            : 
     571                 :            : void
     572                 :          3 : toremote(char *targ, int argc, char **argv)
     573                 :            : {
     574                 :            :         char *bp, *host, *src, *suser, *thost, *tuser, *arg;
     575                 :            :         arglist alist;
     576                 :            :         int i;
     577                 :            :         u_int j;
     578                 :            : 
     579                 :            :         memset(&alist, '\0', sizeof(alist));
     580                 :            :         alist.list = NULL;
     581                 :            : 
     582                 :          3 :         *targ++ = 0;
     583         [ -  + ]:          3 :         if (*targ == 0)
     584                 :          0 :                 targ = ".";
     585                 :            : 
     586                 :          3 :         arg = xstrdup(argv[argc - 1]);
     587         [ -  + ]:          3 :         if ((thost = strrchr(arg, '@'))) {
     588                 :            :                 /* user@host */
     589                 :          0 :                 *thost++ = 0;
     590                 :          0 :                 tuser = arg;
     591         [ #  # ]:          0 :                 if (*tuser == '\0')
     592                 :          0 :                         tuser = NULL;
     593                 :            :         } else {
     594                 :            :                 thost = arg;
     595                 :            :                 tuser = NULL;
     596                 :            :         }
     597                 :            : 
     598 [ -  + ][ #  # ]:          3 :         if (tuser != NULL && !okname(tuser)) {
     599                 :          0 :                 free(arg);
     600                 :          0 :                 return;
     601                 :            :         }
     602                 :            : 
     603         [ +  + ]:          6 :         for (i = 0; i < argc - 1; i++) {
     604                 :          3 :                 src = colon(argv[i]);
     605 [ -  + ][ #  # ]:          3 :                 if (src && throughlocal) {      /* extended remote to remote */
     606                 :          0 :                         *src++ = 0;
     607         [ #  # ]:          0 :                         if (*src == 0)
     608                 :          0 :                                 src = ".";
     609                 :          0 :                         host = strrchr(argv[i], '@');
     610         [ #  # ]:          0 :                         if (host) {
     611                 :          0 :                                 *host++ = 0;
     612                 :          0 :                                 host = cleanhostname(host);
     613                 :          0 :                                 suser = argv[i];
     614         [ #  # ]:          0 :                                 if (*suser == '\0')
     615                 :          0 :                                         suser = pwd->pw_name;
     616         [ #  # ]:          0 :                                 else if (!okname(suser))
     617                 :          0 :                                         continue;
     618                 :            :                         } else {
     619                 :          0 :                                 host = cleanhostname(argv[i]);
     620                 :          0 :                                 suser = NULL;
     621                 :            :                         }
     622         [ #  # ]:          0 :                         xasprintf(&bp, "%s -f %s%s", cmd,
     623                 :          0 :                             *src == '-' ? "-- " : "", src);
     624         [ #  # ]:          0 :                         if (do_cmd(host, suser, bp, &remin, &remout) < 0)
     625                 :          0 :                                 exit(1);
     626                 :          0 :                         free(bp);
     627                 :          0 :                         host = cleanhostname(thost);
     628         [ #  # ]:          0 :                         xasprintf(&bp, "%s -t %s%s", cmd,
     629                 :          0 :                             *targ == '-' ? "-- " : "", targ);
     630         [ #  # ]:          0 :                         if (do_cmd2(host, tuser, bp, remin, remout) < 0)
     631                 :          0 :                                 exit(1);
     632                 :          0 :                         free(bp);
     633                 :          0 :                         (void) close(remin);
     634                 :          0 :                         (void) close(remout);
     635                 :          0 :                         remin = remout = -1;
     636         [ -  + ]:          3 :                 } else if (src) {       /* standard remote to remote */
     637                 :          0 :                         freeargs(&alist);
     638                 :          0 :                         addargs(&alist, "%s", ssh_program);
     639                 :          0 :                         addargs(&alist, "-x");
     640                 :          0 :                         addargs(&alist, "-oClearAllForwardings=yes");
     641                 :          0 :                         addargs(&alist, "-n");
     642         [ #  # ]:          0 :                         for (j = 0; j < remote_remote_args.num; j++) {
     643                 :          0 :                                 addargs(&alist, "%s",
     644                 :          0 :                                     remote_remote_args.list[j]);
     645                 :            :                         }
     646                 :          0 :                         *src++ = 0;
     647         [ #  # ]:          0 :                         if (*src == 0)
     648                 :          0 :                                 src = ".";
     649                 :          0 :                         host = strrchr(argv[i], '@');
     650                 :            : 
     651         [ #  # ]:          0 :                         if (host) {
     652                 :          0 :                                 *host++ = 0;
     653                 :          0 :                                 host = cleanhostname(host);
     654                 :          0 :                                 suser = argv[i];
     655         [ #  # ]:          0 :                                 if (*suser == '\0')
     656                 :          0 :                                         suser = pwd->pw_name;
     657         [ #  # ]:          0 :                                 else if (!okname(suser))
     658                 :          0 :                                         continue;
     659                 :          0 :                                 addargs(&alist, "-l");
     660                 :          0 :                                 addargs(&alist, "%s", suser);
     661                 :            :                         } else {
     662                 :          0 :                                 host = cleanhostname(argv[i]);
     663                 :            :                         }
     664                 :          0 :                         addargs(&alist, "--");
     665                 :          0 :                         addargs(&alist, "%s", host);
     666                 :          0 :                         addargs(&alist, "%s", cmd);
     667                 :          0 :                         addargs(&alist, "%s", src);
     668 [ #  # ][ #  # ]:          0 :                         addargs(&alist, "%s%s%s:%s",
     669                 :            :                             tuser ? tuser : "", tuser ? "@" : "",
     670                 :            :                             thost, targ);
     671         [ #  # ]:          0 :                         if (do_local_cmd(&alist) != 0)
     672                 :          0 :                                 errs = 1;
     673                 :            :                 } else {        /* local to remote */
     674         [ +  - ]:          3 :                         if (remin == -1) {
     675         [ +  - ]:          3 :                                 xasprintf(&bp, "%s -t %s%s", cmd,
     676                 :          3 :                                     *targ == '-' ? "-- " : "", targ);
     677                 :          3 :                                 host = cleanhostname(thost);
     678         [ -  + ]:          3 :                                 if (do_cmd(host, tuser, bp, &remin,
     679                 :            :                                     &remout) < 0)
     680                 :          0 :                                         exit(1);
     681         [ -  + ]:          3 :                                 if (response() < 0)
     682                 :          0 :                                         exit(1);
     683                 :          3 :                                 free(bp);
     684                 :            :                         }
     685                 :          3 :                         source(1, argv + i);
     686                 :            :                 }
     687                 :            :         }
     688                 :          3 :         free(arg);
     689                 :            : }
     690                 :            : 
     691                 :            : void
     692                 :         18 : tolocal(int argc, char **argv)
     693                 :            : {
     694                 :            :         char *bp, *host, *src, *suser;
     695                 :            :         arglist alist;
     696                 :            :         int i;
     697                 :            : 
     698                 :            :         memset(&alist, '\0', sizeof(alist));
     699                 :            :         alist.list = NULL;
     700                 :            : 
     701         [ +  + ]:         26 :         for (i = 0; i < argc - 1; i++) {
     702         [ +  + ]:         18 :                 if (!(src = colon(argv[i]))) {  /* Local to local. */
     703                 :          4 :                         freeargs(&alist);
     704                 :          4 :                         addargs(&alist, "%s", _PATH_CP);
     705         [ +  + ]:          4 :                         if (iamrecursive)
     706                 :          1 :                                 addargs(&alist, "-r");
     707         [ -  + ]:          4 :                         if (pflag)
     708                 :          0 :                                 addargs(&alist, "-p");
     709                 :          4 :                         addargs(&alist, "--");
     710                 :          4 :                         addargs(&alist, "%s", argv[i]);
     711                 :          4 :                         addargs(&alist, "%s", argv[argc-1]);
     712         [ -  + ]:          4 :                         if (do_local_cmd(&alist))
     713                 :          0 :                                 ++errs;
     714                 :          4 :                         continue;
     715                 :            :                 }
     716                 :         14 :                 *src++ = 0;
     717         [ -  + ]:         14 :                 if (*src == 0)
     718                 :          0 :                         src = ".";
     719         [ -  + ]:         14 :                 if ((host = strrchr(argv[i], '@')) == NULL) {
     720                 :            :                         host = argv[i];
     721                 :            :                         suser = NULL;
     722                 :            :                 } else {
     723                 :          0 :                         *host++ = 0;
     724                 :          0 :                         suser = argv[i];
     725         [ #  # ]:          0 :                         if (*suser == '\0')
     726                 :          0 :                                 suser = pwd->pw_name;
     727                 :            :                 }
     728                 :         14 :                 host = cleanhostname(host);
     729         [ +  - ]:         14 :                 xasprintf(&bp, "%s -f %s%s",
     730                 :         14 :                     cmd, *src == '-' ? "-- " : "", src);
     731         [ -  + ]:         14 :                 if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
     732                 :          0 :                         free(bp);
     733                 :          0 :                         ++errs;
     734                 :          0 :                         continue;
     735                 :            :                 }
     736                 :         10 :                 free(bp);
     737                 :         10 :                 sink(1, argv + argc - 1);
     738                 :          4 :                 (void) close(remin);
     739                 :          4 :                 remin = remout = -1;
     740                 :            :         }
     741                 :          8 : }
     742                 :            : 
     743                 :            : void
     744                 :          8 : source(int argc, char **argv)
     745                 :            : {
     746                 :            :         struct stat stb;
     747                 :            :         static BUF buffer;
     748                 :            :         BUF *bp;
     749                 :            :         off_t i, statbytes;
     750                 :            :         size_t amt;
     751                 :          8 :         int fd = -1, haderr, indx;
     752                 :            :         char *last, *name, buf[2048], encname[MAXPATHLEN];
     753                 :            :         int len;
     754                 :            : 
     755         [ +  + ]:         16 :         for (indx = 0; indx < argc; ++indx) {
     756                 :          8 :                 name = argv[indx];
     757                 :          8 :                 statbytes = 0;
     758                 :          8 :                 len = strlen(name);
     759 [ +  - ][ -  + ]:          8 :                 while (len > 1 && name[len-1] == '/')
     760                 :          0 :                         name[--len] = '\0';
     761         [ +  - ]:          8 :                 if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0)
     762                 :            :                         goto syserr;
     763         [ -  + ]:          8 :                 if (strchr(name, '\n') != NULL) {
     764                 :          0 :                         strnvis(encname, name, sizeof(encname), VIS_NL);
     765                 :          0 :                         name = encname;
     766                 :            :                 }
     767         [ -  + ]:          8 :                 if (fstat(fd, &stb) < 0) {
     768                 :          0 : syserr:                 run_err("%s: %s", name, strerror(errno));
     769                 :          0 :                         goto next;
     770                 :            :                 }
     771         [ -  + ]:          8 :                 if (stb.st_size < 0) {
     772                 :          0 :                         run_err("%s: %s", name, "Negative file size");
     773                 :          0 :                         goto next;
     774                 :            :                 }
     775                 :          8 :                 unset_nonblock(fd);
     776      [ +  -  + ]:          8 :                 switch (stb.st_mode & S_IFMT) {
     777                 :            :                 case S_IFREG:
     778                 :            :                         break;
     779                 :            :                 case S_IFDIR:
     780         [ +  - ]:          2 :                         if (iamrecursive) {
     781                 :          2 :                                 rsource(name, &stb);
     782                 :          2 :                                 goto next;
     783                 :            :                         }
     784                 :            :                         /* FALLTHROUGH */
     785                 :            :                 default:
     786                 :          0 :                         run_err("%s: not a regular file", name);
     787                 :          0 :                         goto next;
     788                 :            :                 }
     789         [ +  - ]:          6 :                 if ((last = strrchr(name, '/')) == NULL)
     790                 :            :                         last = name;
     791                 :            :                 else
     792                 :          6 :                         ++last;
     793                 :          6 :                 curfile = last;
     794         [ -  + ]:          6 :                 if (pflag) {
     795         [ #  # ]:          0 :                         if (do_times(remout, verbose_mode, &stb) < 0)
     796                 :            :                                 goto next;
     797                 :            :                 }
     798                 :            : #define FILEMODEMASK    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
     799                 :          6 :                 snprintf(buf, sizeof buf, "C%04o %lld %s\n",
     800                 :          6 :                     (u_int) (stb.st_mode & FILEMODEMASK),
     801                 :          6 :                     (long long)stb.st_size, last);
     802         [ -  + ]:          6 :                 if (verbose_mode) {
     803                 :          0 :                         fprintf(stderr, "Sending file modes: %s", buf);
     804                 :            :                 }
     805                 :          6 :                 (void) atomicio(vwrite, remout, buf, strlen(buf));
     806         [ +  - ]:          6 :                 if (response() < 0)
     807                 :            :                         goto next;
     808         [ -  + ]:          6 :                 if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
     809         [ +  - ]:          2 : next:                   if (fd != -1) {
     810                 :          2 :                                 (void) close(fd);
     811                 :          2 :                                 fd = -1;
     812                 :            :                         }
     813                 :          2 :                         continue;
     814                 :            :                 }
     815         [ -  + ]:          6 :                 if (showprogress)
     816                 :          0 :                         start_progress_meter(curfile, stb.st_size, &statbytes);
     817                 :          6 :                 set_nonblock(remout);
     818         [ +  + ]:        438 :                 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
     819                 :        432 :                         amt = bp->cnt;
     820         [ +  + ]:        432 :                         if (i + (off_t)amt > stb.st_size)
     821                 :          6 :                                 amt = stb.st_size - i;
     822         [ +  - ]:        432 :                         if (!haderr) {
     823         [ -  + ]:        432 :                                 if (atomicio(read, fd, bp->buf, amt) != amt)
     824                 :          0 :                                         haderr = errno;
     825                 :            :                         }
     826                 :            :                         /* Keep writing after error to retain sync */
     827         [ -  + ]:        432 :                         if (haderr) {
     828                 :          0 :                                 (void)atomicio(vwrite, remout, bp->buf, amt);
     829                 :          0 :                                 continue;
     830                 :            :                         }
     831         [ -  + ]:        432 :                         if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
     832                 :            :                             &statbytes) != amt)
     833                 :          0 :                                 haderr = errno;
     834                 :            :                 }
     835                 :          6 :                 unset_nonblock(remout);
     836         [ -  + ]:          6 :                 if (showprogress)
     837                 :          0 :                         stop_progress_meter();
     838                 :            : 
     839         [ +  - ]:          6 :                 if (fd != -1) {
     840 [ -  + ][ #  # ]:          6 :                         if (close(fd) < 0 && !haderr)
     841                 :          0 :                                 haderr = errno;
     842                 :            :                         fd = -1;
     843                 :            :                 }
     844         [ +  - ]:          6 :                 if (!haderr)
     845                 :          6 :                         (void) atomicio(vwrite, remout, "", 1);
     846                 :            :                 else
     847                 :          0 :                         run_err("%s: %s", name, strerror(haderr));
     848                 :          6 :                 (void) response();
     849                 :            :         }
     850                 :          8 : }
     851                 :            : 
     852                 :            : void
     853                 :          2 : rsource(char *name, struct stat *statp)
     854                 :            : {
     855                 :            :         DIR *dirp;
     856                 :            :         struct dirent *dp;
     857                 :            :         char *last, *vect[1], path[MAXPATHLEN];
     858                 :            : 
     859         [ -  + ]:          2 :         if (!(dirp = opendir(name))) {
     860                 :          0 :                 run_err("%s: %s", name, strerror(errno));
     861                 :          0 :                 return;
     862                 :            :         }
     863                 :          2 :         last = strrchr(name, '/');
     864         [ +  - ]:          2 :         if (last == 0)
     865                 :            :                 last = name;
     866                 :            :         else
     867                 :          2 :                 last++;
     868         [ -  + ]:          2 :         if (pflag) {
     869         [ #  # ]:          0 :                 if (do_times(remout, verbose_mode, statp) < 0) {
     870                 :          0 :                         closedir(dirp);
     871                 :          0 :                         return;
     872                 :            :                 }
     873                 :            :         }
     874                 :          2 :         (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
     875                 :          2 :             (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
     876         [ -  + ]:          2 :         if (verbose_mode)
     877                 :          0 :                 fprintf(stderr, "Entering directory: %s", path);
     878                 :          2 :         (void) atomicio(vwrite, remout, path, strlen(path));
     879         [ +  - ]:          2 :         if (response() < 0) {
     880                 :          0 :                 closedir(dirp);
     881                 :          0 :                 return;
     882                 :            :         }
     883         [ +  + ]:          8 :         while ((dp = readdir(dirp)) != NULL) {
     884         [ -  + ]:          6 :                 if (dp->d_ino == 0)
     885                 :          0 :                         continue;
     886 [ +  + ][ +  + ]:          6 :                 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
         [ +  + ][ +  - ]
                 [ +  + ]
     887                 :          4 :                         continue;
     888         [ -  + ]:          2 :                 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
     889                 :          0 :                         run_err("%s/%s: name too long", name, dp->d_name);
     890                 :          0 :                         continue;
     891                 :            :                 }
     892                 :          2 :                 (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
     893                 :          2 :                 vect[0] = path;
     894                 :          6 :                 source(1, vect);
     895                 :            :         }
     896                 :          2 :         (void) closedir(dirp);
     897                 :          2 :         (void) atomicio(vwrite, remout, "E\n", 2);
     898                 :          2 :         (void) response();
     899                 :            : }
     900                 :            : 
     901                 :            : void
     902                 :         15 : sink(int argc, char **argv)
     903                 :            : {
     904                 :            :         static BUF buffer;
     905                 :            :         struct stat stb;
     906                 :            :         enum {
     907                 :            :                 YES, NO, DISPLAYED
     908                 :            :         } wrerr;
     909                 :            :         BUF *bp;
     910                 :            :         off_t i;
     911                 :            :         size_t j, count;
     912                 :            :         int amt, exists, first, ofd;
     913                 :            :         mode_t mode, omode, mask;
     914                 :            :         off_t size, statbytes;
     915                 :            :         unsigned long long ull;
     916                 :         15 :         int setimes, targisdir, wrerrno = 0;
     917                 :            :         char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
     918                 :            :         struct timeval tv[2];
     919                 :            : 
     920                 :            : #define atime   tv[0]
     921                 :            : #define mtime   tv[1]
     922                 :            : #define SCREWUP(str)    { why = str; goto screwup; }
     923                 :            : 
     924                 :         15 :         setimes = targisdir = 0;
     925                 :         15 :         mask = umask(0);
     926         [ +  - ]:         15 :         if (!pflag)
     927                 :         15 :                 (void) umask(mask);
     928         [ -  + ]:         15 :         if (argc != 1) {
     929                 :          0 :                 run_err("ambiguous target");
     930                 :          0 :                 exit(1);
     931                 :            :         }
     932                 :         15 :         targ = *argv;
     933         [ -  + ]:         15 :         if (targetshouldbedirectory)
     934                 :          0 :                 verifydir(targ);
     935                 :            : 
     936                 :         15 :         (void) atomicio(vwrite, remout, "", 1);
     937 [ +  + ][ +  - ]:         15 :         if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
     938                 :         10 :                 targisdir = 1;
     939                 :         15 :         for (first = 1;; first = 0) {
     940                 :         24 :                 cp = buf;
     941         [ +  + ]:         24 :                 if (atomicio(read, remin, cp, 1) != 1)
     942                 :            :                         return;
     943         [ +  - ]:         17 :                 if (*cp++ == '\n')
     944                 :            :                         SCREWUP("unexpected <newline>");
     945                 :            :                 do {
     946         [ +  - ]:        690 :                         if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
     947                 :            :                                 SCREWUP("lost connection");
     948                 :        690 :                         *cp++ = ch;
     949 [ +  - ][ +  + ]:        690 :                 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
     950                 :         17 :                 *cp = 0;
     951         [ -  + ]:         17 :                 if (verbose_mode)
     952                 :          0 :                         fprintf(stderr, "Sink: %s", buf);
     953                 :            : 
     954         [ -  + ]:         17 :                 if (buf[0] == '\01' || buf[0] == '\02') {
     955         [ #  # ]:          0 :                         if (iamremote == 0)
     956                 :          0 :                                 (void) atomicio(vwrite, STDERR_FILENO,
     957                 :            :                                     buf + 1, strlen(buf + 1));
     958         [ #  # ]:          0 :                         if (buf[0] == '\02')
     959                 :          0 :                                 exit(1);
     960                 :          0 :                         ++errs;
     961                 :          0 :                         continue;
     962                 :            :                 }
     963         [ +  + ]:         17 :                 if (buf[0] == 'E') {
     964                 :          2 :                         (void) atomicio(vwrite, remout, "", 1);
     965                 :          2 :                         return;
     966                 :            :                 }
     967         [ +  - ]:         15 :                 if (ch == '\n')
     968                 :         15 :                         *--cp = 0;
     969                 :            : 
     970                 :         15 :                 cp = buf;
     971         [ -  + ]:         15 :                 if (*cp == 'T') {
     972                 :          0 :                         setimes++;
     973                 :          0 :                         cp++;
     974         [ #  # ]:          0 :                         if (!isdigit((unsigned char)*cp))
     975                 :            :                                 SCREWUP("mtime.sec not present");
     976                 :          0 :                         ull = strtoull(cp, &cp, 10);
     977 [ #  # ][ #  # ]:          0 :                         if (!cp || *cp++ != ' ')
     978                 :            :                                 SCREWUP("mtime.sec not delimited");
     979         [ #  # ]:          0 :                         if ((time_t)ull < 0 ||
     980                 :            :                             (unsigned long long)(time_t)ull != ull)
     981                 :          0 :                                 setimes = 0;    /* out of range */
     982                 :          0 :                         mtime.tv_sec = ull;
     983                 :          0 :                         mtime.tv_usec = strtol(cp, &cp, 10);
     984 [ #  # ][ #  # ]:          0 :                         if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 ||
         [ #  # ][ #  # ]
     985                 :            :                             mtime.tv_usec > 999999)
     986                 :            :                                 SCREWUP("mtime.usec not delimited");
     987         [ #  # ]:          0 :                         if (!isdigit((unsigned char)*cp))
     988                 :            :                                 SCREWUP("atime.sec not present");
     989                 :          0 :                         ull = strtoull(cp, &cp, 10);
     990 [ #  # ][ #  # ]:          0 :                         if (!cp || *cp++ != ' ')
     991                 :            :                                 SCREWUP("atime.sec not delimited");
     992         [ #  # ]:          0 :                         if ((time_t)ull < 0 ||
     993                 :            :                             (unsigned long long)(time_t)ull != ull)
     994                 :          0 :                                 setimes = 0;    /* out of range */
     995                 :          0 :                         atime.tv_sec = ull;
     996                 :          0 :                         atime.tv_usec = strtol(cp, &cp, 10);
     997 [ #  # ][ #  # ]:          0 :                         if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
         [ #  # ][ #  # ]
     998                 :            :                             atime.tv_usec > 999999)
     999                 :            :                                 SCREWUP("atime.usec not delimited");
    1000                 :          0 :                         (void) atomicio(vwrite, remout, "", 1);
    1001                 :          0 :                         continue;
    1002                 :            :                 }
    1003         [ -  + ]:         15 :                 if (*cp != 'C' && *cp != 'D') {
    1004                 :            :                         /*
    1005                 :            :                          * Check for the case "rcp remote:foo\* local:bar".
    1006                 :            :                          * In this case, the line "No match." can be returned
    1007                 :            :                          * by the shell before the rcp command on the remote is
    1008                 :            :                          * executed so the ^Aerror_message convention isn't
    1009                 :            :                          * followed.
    1010                 :            :                          */
    1011         [ #  # ]:          0 :                         if (first) {
    1012                 :          0 :                                 run_err("%s", cp);
    1013                 :          0 :                                 exit(1);
    1014                 :            :                         }
    1015                 :            :                         SCREWUP("expected control record");
    1016                 :            :                 }
    1017                 :         15 :                 mode = 0;
    1018         [ +  + ]:         75 :                 for (++cp; cp < buf + 5; cp++) {
    1019         [ +  - ]:         60 :                         if (*cp < '0' || *cp > '7')
    1020                 :            :                                 SCREWUP("bad mode");
    1021                 :         60 :                         mode = (mode << 3) | (*cp - '0');
    1022                 :            :                 }
    1023         [ +  - ]:         15 :                 if (*cp++ != ' ')
    1024                 :            :                         SCREWUP("mode not delimited");
    1025                 :            : 
    1026         [ +  + ]:         72 :                 for (size = 0; isdigit((unsigned char)*cp);)
    1027                 :         57 :                         size = size * 10 + (*cp++ - '0');
    1028         [ +  - ]:         15 :                 if (*cp++ != ' ')
    1029                 :            :                         SCREWUP("size not delimited");
    1030 [ +  + ][ -  + ]:         15 :                 if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
         [ #  # ][ -  + ]
    1031                 :          6 :                         run_err("error: unexpected filename: %s", cp);
    1032                 :          6 :                         exit(1);
    1033                 :            :                 }
    1034         [ +  + ]:          9 :                 if (targisdir) {
    1035                 :            :                         static char *namebuf;
    1036                 :            :                         static size_t cursize;
    1037                 :            :                         size_t need;
    1038                 :            : 
    1039                 :          4 :                         need = strlen(targ) + strlen(cp) + 250;
    1040         [ +  - ]:          4 :                         if (need > cursize) {
    1041                 :          4 :                                 free(namebuf);
    1042                 :          4 :                                 namebuf = xmalloc(need);
    1043                 :          4 :                                 cursize = need;
    1044                 :            :                         }
    1045         [ -  + ]:          4 :                         (void) snprintf(namebuf, need, "%s%s%s", targ,
    1046         [ +  - ]:          4 :                             strcmp(targ, "/") ? "/" : "", cp);
    1047                 :          4 :                         np = namebuf;
    1048                 :            :                 } else
    1049                 :            :                         np = targ;
    1050                 :          9 :                 curfile = cp;
    1051                 :          9 :                 exists = stat(np, &stb) == 0;
    1052         [ +  + ]:          9 :                 if (buf[0] == 'D') {
    1053                 :          2 :                         int mod_flag = pflag;
    1054         [ +  - ]:          2 :                         if (!iamrecursive)
    1055                 :            :                                 SCREWUP("received directory without -r");
    1056         [ -  + ]:          2 :                         if (exists) {
    1057         [ #  # ]:          0 :                                 if (!S_ISDIR(stb.st_mode)) {
    1058                 :          0 :                                         errno = ENOTDIR;
    1059                 :          0 :                                         goto bad;
    1060                 :            :                                 }
    1061         [ #  # ]:          0 :                                 if (pflag)
    1062                 :          0 :                                         (void) chmod(np, mode);
    1063                 :            :                         } else {
    1064                 :            :                                 /* Handle copying from a read-only
    1065                 :            :                                    directory */
    1066                 :          2 :                                 mod_flag = 1;
    1067         [ +  - ]:          2 :                                 if (mkdir(np, mode | S_IRWXU) < 0)
    1068                 :            :                                         goto bad;
    1069                 :            :                         }
    1070                 :          2 :                         vect[0] = xstrdup(np);
    1071                 :          2 :                         sink(1, vect);
    1072         [ -  + ]:          2 :                         if (setimes) {
    1073                 :          0 :                                 setimes = 0;
    1074         [ #  # ]:          0 :                                 if (utimes(vect[0], tv) < 0)
    1075                 :          0 :                                         run_err("%s: set times: %s",
    1076                 :          0 :                                             vect[0], strerror(errno));
    1077                 :            :                         }
    1078         [ +  - ]:          2 :                         if (mod_flag)
    1079                 :          2 :                                 (void) chmod(vect[0], mode);
    1080                 :          2 :                         free(vect[0]);
    1081                 :          2 :                         continue;
    1082                 :            :                 }
    1083                 :          7 :                 omode = mode;
    1084                 :          7 :                 mode |= S_IWUSR;
    1085         [ -  + ]:          7 :                 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
    1086                 :          0 : bad:                    run_err("%s: %s", np, strerror(errno));
    1087                 :          0 :                         continue;
    1088                 :            :                 }
    1089                 :          7 :                 (void) atomicio(vwrite, remout, "", 1);
    1090         [ -  + ]:          7 :                 if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
    1091                 :          0 :                         (void) close(ofd);
    1092                 :          0 :                         continue;
    1093                 :            :                 }
    1094                 :          7 :                 cp = bp->buf;
    1095                 :          7 :                 wrerr = NO;
    1096                 :            : 
    1097                 :          7 :                 statbytes = 0;
    1098         [ -  + ]:          7 :                 if (showprogress)
    1099                 :          0 :                         start_progress_meter(curfile, size, &statbytes);
    1100                 :          7 :                 set_nonblock(remin);
    1101         [ +  + ]:        511 :                 for (count = i = 0; i < size; i += bp->cnt) {
    1102                 :        504 :                         amt = bp->cnt;
    1103         [ +  + ]:        504 :                         if (i + amt > size)
    1104                 :          7 :                                 amt = size - i;
    1105                 :        504 :                         count += amt;
    1106                 :            :                         do {
    1107                 :        504 :                                 j = atomicio6(read, remin, cp, amt,
    1108                 :            :                                     scpio, &statbytes);
    1109         [ -  + ]:        504 :                                 if (j == 0) {
    1110         [ #  # ]:          0 :                                         run_err("%s", j != EPIPE ?
    1111                 :          0 :                                             strerror(errno) :
    1112                 :            :                                             "dropped connection");
    1113                 :          0 :                                         exit(1);
    1114                 :            :                                 }
    1115                 :        504 :                                 amt -= j;
    1116                 :        504 :                                 cp += j;
    1117         [ -  + ]:        504 :                         } while (amt > 0);
    1118                 :            : 
    1119         [ +  + ]:        504 :                         if (count == bp->cnt) {
    1120                 :            :                                 /* Keep reading so we stay sync'd up. */
    1121         [ +  - ]:        497 :                                 if (wrerr == NO) {
    1122         [ -  + ]:        497 :                                         if (atomicio(vwrite, ofd, bp->buf,
    1123                 :            :                                             count) != count) {
    1124                 :          0 :                                                 wrerr = YES;
    1125                 :          0 :                                                 wrerrno = errno;
    1126                 :            :                                         }
    1127                 :            :                                 }
    1128                 :        497 :                                 count = 0;
    1129                 :        497 :                                 cp = bp->buf;
    1130                 :            :                         }
    1131                 :            :                 }
    1132                 :          7 :                 unset_nonblock(remin);
    1133         [ -  + ]:          7 :                 if (showprogress)
    1134                 :          0 :                         stop_progress_meter();
    1135   [ +  -  -  + ]:         14 :                 if (count != 0 && wrerr == NO &&
    1136                 :          7 :                     atomicio(vwrite, ofd, bp->buf, count) != count) {
    1137                 :          0 :                         wrerr = YES;
    1138                 :          0 :                         wrerrno = errno;
    1139                 :            :                 }
    1140 [ +  - ][ -  + ]:         14 :                 if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
           [ #  #  -  + ]
    1141                 :          7 :                     ftruncate(ofd, size) != 0) {
    1142                 :          0 :                         run_err("%s: truncate: %s", np, strerror(errno));
    1143                 :          0 :                         wrerr = DISPLAYED;
    1144                 :            :                 }
    1145         [ -  + ]:          7 :                 if (pflag) {
    1146         [ #  # ]:          0 :                         if (exists || omode != mode)
    1147                 :            : #ifdef HAVE_FCHMOD
    1148         [ #  # ]:          0 :                                 if (fchmod(ofd, omode)) {
    1149                 :            : #else /* HAVE_FCHMOD */
    1150                 :            :                                 if (chmod(np, omode)) {
    1151                 :            : #endif /* HAVE_FCHMOD */
    1152                 :          0 :                                         run_err("%s: set mode: %s",
    1153                 :          0 :                                             np, strerror(errno));
    1154                 :          0 :                                         wrerr = DISPLAYED;
    1155                 :            :                                 }
    1156                 :            :                 } else {
    1157         [ -  + ]:          7 :                         if (!exists && omode != mode)
    1158                 :            : #ifdef HAVE_FCHMOD
    1159         [ #  # ]:          0 :                                 if (fchmod(ofd, omode & ~mask)) {
    1160                 :            : #else /* HAVE_FCHMOD */
    1161                 :            :                                 if (chmod(np, omode & ~mask)) {
    1162                 :            : #endif /* HAVE_FCHMOD */
    1163                 :          0 :                                         run_err("%s: set mode: %s",
    1164                 :          0 :                                             np, strerror(errno));
    1165                 :          0 :                                         wrerr = DISPLAYED;
    1166                 :            :                                 }
    1167                 :            :                 }
    1168         [ -  + ]:          7 :                 if (close(ofd) == -1) {
    1169                 :          0 :                         wrerr = YES;
    1170                 :          0 :                         wrerrno = errno;
    1171                 :            :                 }
    1172                 :          7 :                 (void) response();
    1173         [ -  + ]:          7 :                 if (setimes && wrerr == NO) {
    1174                 :          0 :                         setimes = 0;
    1175         [ #  # ]:          0 :                         if (utimes(np, tv) < 0) {
    1176                 :          0 :                                 run_err("%s: set times: %s",
    1177                 :          0 :                                     np, strerror(errno));
    1178                 :          0 :                                 wrerr = DISPLAYED;
    1179                 :            :                         }
    1180                 :            :                 }
    1181      [ -  -  + ]:          7 :                 switch (wrerr) {
    1182                 :            :                 case YES:
    1183                 :          0 :                         run_err("%s: %s", np, strerror(wrerrno));
    1184                 :          9 :                         break;
    1185                 :            :                 case NO:
    1186                 :          7 :                         (void) atomicio(vwrite, remout, "", 1);
    1187                 :          7 :                         break;
    1188                 :            :                 case DISPLAYED:
    1189                 :            :                         break;
    1190                 :            :                 }
    1191                 :            :         }
    1192                 :            : screwup:
    1193                 :          0 :         run_err("protocol error: %s", why);
    1194                 :          0 :         exit(1);
    1195                 :            : }
    1196                 :            : 
    1197                 :            : int
    1198                 :         29 : response(void)
    1199                 :            : {
    1200                 :            :         char ch, *cp, resp, rbuf[2048];
    1201                 :            : 
    1202         [ -  + ]:         29 :         if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
    1203                 :          0 :                 lostconn(0);
    1204                 :            : 
    1205                 :         29 :         cp = rbuf;
    1206      [ -  -  + ]:         29 :         switch (resp) {
    1207                 :            :         case 0:         /* ok */
    1208                 :            :                 return (0);
    1209                 :            :         default:
    1210                 :          0 :                 *cp++ = resp;
    1211                 :            :                 /* FALLTHROUGH */
    1212                 :            :         case 1:         /* error, followed by error msg */
    1213                 :            :         case 2:         /* fatal error, "" */
    1214                 :            :                 do {
    1215         [ #  # ]:          0 :                         if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
    1216                 :          0 :                                 lostconn(0);
    1217                 :          0 :                         *cp++ = ch;
    1218 [ #  # ][ #  # ]:          0 :                 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
    1219                 :            : 
    1220         [ #  # ]:          0 :                 if (!iamremote)
    1221                 :          0 :                         (void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf);
    1222                 :          0 :                 ++errs;
    1223         [ #  # ]:          0 :                 if (resp == 1)
    1224                 :            :                         return (-1);
    1225                 :          0 :                 exit(1);
    1226                 :            :         }
    1227                 :            :         /* NOTREACHED */
    1228                 :            : }
    1229                 :            : 
    1230                 :            : void
    1231                 :          0 : usage(void)
    1232                 :            : {
    1233                 :          0 :         (void) fprintf(stderr,
    1234                 :            :             "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
    1235                 :            :             "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
    1236                 :            :             "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
    1237                 :          0 :         exit(1);
    1238                 :            : }
    1239                 :            : 
    1240                 :            : void
    1241                 :          7 : run_err(const char *fmt,...)
    1242                 :            : {
    1243                 :            :         static FILE *fp;
    1244                 :            :         va_list ap;
    1245                 :            : 
    1246                 :          7 :         ++errs;
    1247 [ +  - ][ +  + ]:          7 :         if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
                 [ +  - ]
    1248                 :          6 :                 (void) fprintf(fp, "%c", 0x01);
    1249                 :          6 :                 (void) fprintf(fp, "scp: ");
    1250                 :          6 :                 va_start(ap, fmt);
    1251                 :          6 :                 (void) vfprintf(fp, fmt, ap);
    1252                 :          6 :                 va_end(ap);
    1253                 :          6 :                 (void) fprintf(fp, "\n");
    1254                 :          6 :                 (void) fflush(fp);
    1255                 :            :         }
    1256                 :            : 
    1257         [ +  - ]:          7 :         if (!iamremote) {
    1258                 :          7 :                 va_start(ap, fmt);
    1259                 :          7 :                 vfprintf(stderr, fmt, ap);
    1260                 :          7 :                 va_end(ap);
    1261                 :          7 :                 fprintf(stderr, "\n");
    1262                 :            :         }
    1263                 :          7 : }
    1264                 :            : 
    1265                 :            : void
    1266                 :          1 : verifydir(char *cp)
    1267                 :            : {
    1268                 :            :         struct stat stb;
    1269                 :            : 
    1270         [ +  - ]:          1 :         if (!stat(cp, &stb)) {
    1271         [ +  - ]:          1 :                 if (S_ISDIR(stb.st_mode))
    1272                 :          0 :                         return;
    1273                 :          1 :                 errno = ENOTDIR;
    1274                 :            :         }
    1275                 :          1 :         run_err("%s: %s", cp, strerror(errno));
    1276                 :          1 :         killchild(0);
    1277                 :            : }
    1278                 :            : 
    1279                 :            : int
    1280                 :          0 : okname(char *cp0)
    1281                 :            : {
    1282                 :            :         int c;
    1283                 :            :         char *cp;
    1284                 :            : 
    1285                 :          0 :         cp = cp0;
    1286                 :            :         do {
    1287                 :          0 :                 c = (int)*cp;
    1288         [ #  # ]:          0 :                 if (c & 0200)
    1289                 :            :                         goto bad;
    1290 [ #  # ][ #  # ]:          0 :                 if (!isalpha(c) && !isdigit((unsigned char)c)) {
    1291         [ #  # ]:          0 :                         switch (c) {
    1292                 :            :                         case '\'':
    1293                 :            :                         case '"':
    1294                 :            :                         case '`':
    1295                 :            :                         case ' ':
    1296                 :            :                         case '#':
    1297                 :            :                                 goto bad;
    1298                 :            :                         default:
    1299                 :            :                                 break;
    1300                 :            :                         }
    1301                 :            :                 }
    1302         [ #  # ]:          0 :         } while (*++cp);
    1303                 :            :         return (1);
    1304                 :            : 
    1305                 :          0 : bad:    fprintf(stderr, "%s: invalid user name\n", cp0);
    1306                 :          0 :         return (0);
    1307                 :            : }
    1308                 :            : 
    1309                 :            : BUF *
    1310                 :         13 : allocbuf(BUF *bp, int fd, int blksize)
    1311                 :            : {
    1312                 :            :         size_t size;
    1313                 :            : #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
    1314                 :            :         struct stat stb;
    1315                 :            : 
    1316         [ -  + ]:         13 :         if (fstat(fd, &stb) < 0) {
    1317                 :          0 :                 run_err("fstat: %s", strerror(errno));
    1318                 :          0 :                 return (0);
    1319                 :            :         }
    1320 [ -  + ][ #  # ]:         13 :         size = roundup(stb.st_blksize, blksize);
    1321         [ -  + ]:         13 :         if (size == 0)
    1322                 :          0 :                 size = blksize;
    1323                 :            : #else /* HAVE_STRUCT_STAT_ST_BLKSIZE */
    1324                 :            :         size = blksize;
    1325                 :            : #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
    1326         [ +  - ]:         13 :         if (bp->cnt >= size)
    1327                 :            :                 return (bp);
    1328         [ +  - ]:         13 :         if (bp->buf == NULL)
    1329                 :         13 :                 bp->buf = xmalloc(size);
    1330                 :            :         else
    1331                 :          0 :                 bp->buf = xrealloc(bp->buf, 1, size);
    1332                 :         13 :         memset(bp->buf, 0, size);
    1333                 :         13 :         bp->cnt = size;
    1334                 :         13 :         return (bp);
    1335                 :            : }
    1336                 :            : 
    1337                 :            : void
    1338                 :          0 : lostconn(int signo)
    1339                 :            : {
    1340         [ #  # ]:          0 :         if (!iamremote)
    1341                 :          0 :                 (void)write(STDERR_FILENO, "lost connection\n", 16);
    1342         [ #  # ]:          0 :         if (signo)
    1343                 :          0 :                 _exit(1);
    1344                 :            :         else
    1345                 :          0 :                 exit(1);
    1346                 :            : }

Generated by: LCOV version 1.9