LCOV - code coverage report
Current view: top level - source4/client - cifsdd.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 167 289 57.8 %
Date: 2024-02-28 12:06:22 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /*
       2             :    CIFSDD - dd for SMB.
       3             :    Main program, argument handling and block copying.
       4             : 
       5             :    Copyright (C) James Peach 2005-2006
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "auth/gensec/gensec.h"
      24             : #include "lib/cmdline/cmdline.h"
      25             : #include "libcli/resolve/resolve.h"
      26             : #include "libcli/raw/libcliraw.h"
      27             : #include "lib/events/events.h"
      28             : 
      29             : #include "cifsdd.h"
      30             : #include "param/param.h"
      31             : 
      32             : const char * const PROGNAME = "cifsdd";
      33             : 
      34             : #define SYNTAX_EXIT_CODE         1      /* Invocation syntax or logic error. */
      35             : #define EOM_EXIT_CODE            9      /* Out of memory error. */
      36             : #define FILESYS_EXIT_CODE       10      /* File manipulation error. */
      37             : #define IOERROR_EXIT_CODE       11      /* Error during IO phase. */
      38             : 
      39             : struct  dd_stats_record dd_stats;
      40             : 
      41             : static int dd_sigint;
      42             : static int dd_sigusr1;
      43             : 
      44           0 : static void dd_handle_signal(int sig)
      45             : {
      46           0 :         switch (sig)
      47             :         {
      48           0 :                 case SIGINT:
      49           0 :                         ++dd_sigint;
      50           0 :                         break;
      51           0 :                 case SIGUSR1:
      52           0 :                         ++dd_sigusr1;
      53           0 :                         break;
      54           0 :                 default:
      55           0 :                         break;
      56             :         }
      57           0 : }
      58             : 
      59             : /* ------------------------------------------------------------------------- */
      60             : /* Argument handling.                                                        */
      61             : /* ------------------------------------------------------------------------- */
      62             : 
      63             : static const struct {
      64             :         enum argtype arg_type;
      65             :         const char * arg_name;
      66             : } names [] = {
      67             :         { ARG_NUMERIC, "COUNT" },
      68             :         { ARG_SIZE, "SIZE" },
      69             :         { ARG_PATHNAME, "FILE" },
      70             :         { ARG_BOOL, "BOOLEAN" },
      71             : };
      72             : 
      73           0 : static const char * argtype_str(enum argtype arg_type)
      74             : {
      75             :         int i;
      76             : 
      77           0 :         for (i = 0; i < ARRAY_SIZE(names); ++i) {
      78           0 :                 if (arg_type == names[i].arg_type) {
      79           0 :                         return(names[i].arg_name);
      80             :                 }
      81             :         }
      82             : 
      83           0 :         return("<unknown>");
      84             : }
      85             : 
      86             : static struct argdef args[] =
      87             : {
      88             :         {
      89             :                 .arg_name = "bs",
      90             :                 .arg_type = ARG_SIZE,
      91             :                 .arg_help = "force ibs and obs to SIZE bytes",
      92             :         },
      93             :         {
      94             :                 .arg_name = "ibs",
      95             :                 .arg_type = ARG_SIZE,
      96             :                 .arg_help = "read SIZE bytes at a time",
      97             :         },
      98             :         {
      99             :                 .arg_name = "obs",
     100             :                 .arg_type = ARG_SIZE,
     101             :                 .arg_help = "write SIZE bytes at a time",
     102             :         },
     103             : 
     104             :         {
     105             :                 .arg_name = "count",
     106             :                 .arg_type = ARG_NUMERIC,
     107             :                 .arg_help = "copy COUNT input blocks",
     108             :         },
     109             :         {
     110             :                 .arg_name = "seek",
     111             :                 .arg_type = ARG_NUMERIC,
     112             :                 .arg_help = "skip COUNT blocks at start of output",
     113             :         },
     114             :         {
     115             :                 .arg_name = "skip",
     116             :                 .arg_type = ARG_NUMERIC,
     117             :                 .arg_help = "skip COUNT blocks at start of input",
     118             :         },
     119             : 
     120             :         {
     121             :                 .arg_name = "if",
     122             :                 .arg_type = ARG_PATHNAME,
     123             :                 .arg_help = "read input from FILE",
     124             :         },
     125             :         {
     126             :                 .arg_name = "of",
     127             :                 .arg_type = ARG_PATHNAME,
     128             :                 .arg_help = "write output to FILE",
     129             :         },
     130             : 
     131             :         {
     132             :                 .arg_name = "direct",
     133             :                 .arg_type = ARG_BOOL,
     134             :                 .arg_help = "use direct I/O if non-zero",
     135             :         },
     136             :         {
     137             :                 .arg_name = "sync",
     138             :                 .arg_type = ARG_BOOL,
     139             :                 .arg_help = "use synchronous writes if non-zero",
     140             :         },
     141             :         {
     142             :                 .arg_name = "oplock",
     143             :                 .arg_type = ARG_BOOL,
     144             :                 .arg_help = "take oplocks on the input and output files",
     145             :         },
     146             : 
     147             : /* FIXME: We should support using iflags and oflags for setting oplock and I/O
     148             :  * options. This would make us compatible with GNU dd.
     149             :  */
     150             : };
     151             : 
     152         648 : static struct argdef * find_named_arg(const char * arg)
     153             : {
     154             :         int i;
     155             : 
     156        3744 :         for (i = 0; i < ARRAY_SIZE(args); ++i) {
     157        3744 :                 if (strwicmp(arg, args[i].arg_name) == 0) {
     158         648 :                         return(&args[i]);
     159             :                 }
     160             :         }
     161             : 
     162           0 :         return(NULL);
     163             : }
     164             : 
     165          54 : int set_arg_argv(const char * argv)
     166             : {
     167             :         struct argdef * arg;
     168             : 
     169             :         char *  name;
     170             :         char *  val;
     171             : 
     172          54 :         if ((name = strdup(argv)) == NULL) {
     173           0 :                 return(0);
     174             :         }
     175             : 
     176          54 :         if ((val = strchr(name, '=')) == NULL) {
     177           0 :                 fprintf(stderr, "%s: malformed argument \"%s\"\n",
     178             :                                 PROGNAME, argv);
     179           0 :                 goto fail;
     180             :         }
     181             : 
     182          54 :         *val = '\0';
     183          54 :         val++;
     184             : 
     185          54 :         if ((arg = find_named_arg(name)) == NULL) {
     186           0 :                 fprintf(stderr, "%s: ignoring unknown argument \"%s\"\n",
     187             :                                 PROGNAME, name);
     188           0 :                 goto fail;
     189             :         }
     190             : 
     191             :         /* Found a matching name; convert the variable argument. */
     192          54 :         switch (arg->arg_type) {
     193           0 :                 case ARG_NUMERIC:
     194           0 :                         if (!conv_str_u64(val, &arg->arg_val.nval)) {
     195           0 :                                 goto fail;
     196             :                         }
     197           0 :                         break;
     198          18 :                 case ARG_SIZE:
     199          18 :                         if (!conv_str_size_error(val, &arg->arg_val.nval)) {
     200           0 :                                 goto fail;
     201             :                         }
     202          18 :                         break;
     203           0 :                 case ARG_BOOL:
     204           0 :                         if (!conv_str_bool(val, &arg->arg_val.bval)) {
     205           0 :                                 goto fail;
     206             :                         }
     207           0 :                         break;
     208          36 :                 case ARG_PATHNAME:
     209          36 :                         if (!(arg->arg_val.pval = strdup(val))) {
     210           0 :                                 goto fail;
     211             :                         }
     212          36 :                         break;
     213           0 :                 default:
     214           0 :                         fprintf(stderr, "%s: argument \"%s\" is of "
     215             :                                 "unknown type\n", PROGNAME, name);
     216           0 :                         goto fail;
     217             :         }
     218             : 
     219          54 :         free(name);
     220          54 :         return(1);
     221             : 
     222           0 : fail:
     223           0 :         free(name);
     224           0 :         return(0);
     225             : }
     226             : 
     227         234 : void set_arg_val(const char * name, ...)
     228             : {
     229             :         va_list         ap;
     230             :         struct argdef * arg;
     231             : 
     232         234 :         va_start(ap, name);
     233         234 :         if ((arg = find_named_arg(name)) == NULL) {
     234           0 :                 goto fail;
     235             :         }
     236             : 
     237             :         /* Found a matching name; convert the variable argument. */
     238         234 :         switch (arg->arg_type) {
     239         144 :                 case ARG_NUMERIC:
     240             :                 case ARG_SIZE:
     241         144 :                         arg->arg_val.nval = va_arg(ap, uint64_t);
     242         144 :                         break;
     243          54 :                 case ARG_BOOL:
     244          54 :                         arg->arg_val.bval = va_arg(ap, int);
     245          54 :                         break;
     246          36 :                 case ARG_PATHNAME:
     247          36 :                         arg->arg_val.pval = va_arg(ap, char *);
     248          36 :                         if (arg->arg_val.pval) {
     249           0 :                                 arg->arg_val.pval = strdup(arg->arg_val.pval);
     250             :                         }
     251          36 :                         break;
     252           0 :                 default:
     253           0 :                         fprintf(stderr, "%s: argument \"%s\" is of "
     254             :                                 "unknown type\n", PROGNAME, name);
     255           0 :                         goto fail;
     256             :         }
     257             : 
     258         234 :         va_end(ap);
     259         234 :         return;
     260             : 
     261           0 : fail:
     262           0 :         fprintf(stderr, "%s: ignoring unknown argument \"%s\"\n",
     263             :                         PROGNAME, name);
     264           0 :         va_end(ap);
     265           0 :         return;
     266             : }
     267             : 
     268         108 : bool check_arg_bool(const char * name)
     269             : {
     270             :         struct argdef * arg;
     271             : 
     272         108 :         if ((arg = find_named_arg(name)) &&
     273         108 :             (arg->arg_type == ARG_BOOL)) {
     274         108 :                 return(arg->arg_val.bval);
     275             :         }
     276             : 
     277           0 :         DEBUG(0, ("invalid argument name: %s\n", name));
     278           0 :         SMB_ASSERT(0);
     279             :         return(false);
     280             : }
     281             : 
     282         180 : uint64_t check_arg_numeric(const char * name)
     283             : {
     284             :         struct argdef * arg;
     285             : 
     286         180 :         if ((arg = find_named_arg(name)) &&
     287         180 :             (arg->arg_type == ARG_NUMERIC || arg->arg_type == ARG_SIZE)) {
     288         180 :                 return(arg->arg_val.nval);
     289             :         }
     290             : 
     291           0 :         DEBUG(0, ("invalid argument name: %s\n", name));
     292           0 :         SMB_ASSERT(0);
     293             :         return(-1);
     294             : }
     295             : 
     296          72 : const char * check_arg_pathname(const char * name)
     297             : {
     298             :         struct argdef * arg;
     299             : 
     300          72 :         if ((arg = find_named_arg(name)) &&
     301          72 :             (arg->arg_type == ARG_PATHNAME)) {
     302          72 :                 return(arg->arg_val.pval);
     303             :         }
     304             : 
     305           0 :         DEBUG(0, ("invalid argument name: %s\n", name));
     306           0 :         SMB_ASSERT(0);
     307             :         return(NULL);
     308             : }
     309             : 
     310          18 : static void dump_args(void)
     311             : {
     312             :         int i;
     313             : 
     314          18 :         DEBUG(10, ("dumping argument values:\n"));
     315         216 :         for (i = 0; i < ARRAY_SIZE(args); ++i) {
     316         198 :                 switch (args[i].arg_type) {
     317         108 :                         case ARG_NUMERIC:
     318             :                         case ARG_SIZE:
     319         108 :                                 DEBUG(10, ("\t%s=%llu\n", args[i].arg_name,
     320             :                                         (unsigned long long)args[i].arg_val.nval));
     321         108 :                                 break;
     322          54 :                         case ARG_BOOL:
     323          54 :                                 DEBUG(10, ("\t%s=%s\n", args[i].arg_name,
     324             :                                         args[i].arg_val.bval ? "yes" : "no"));
     325          54 :                                 break;
     326          36 :                         case ARG_PATHNAME:
     327          36 :                                 DEBUG(10, ("\t%s=%s\n", args[i].arg_name,
     328             :                                         args[i].arg_val.pval ?
     329             :                                                 args[i].arg_val.pval :
     330             :                                                 "(NULL)"));
     331          36 :                                 break;
     332           0 :                         default:
     333           0 :                                 SMB_ASSERT(0);
     334             :                 }
     335             :         }
     336          18 : }
     337             : 
     338           0 : static void cifsdd_help_message(poptContext pctx,
     339             :                 enum poptCallbackReason preason,
     340             :                 struct poptOption * poption, 
     341             :                 const char * parg,
     342             :                 void * pdata)
     343             : {
     344             :         static const char notes[] = 
     345             : "FILE can be a local filename or a UNC path of the form //server/share/path.\n";
     346             : 
     347             :         char prefix[24];
     348             :         int i;
     349             : 
     350           0 :         if (poption->shortName != '?') {
     351           0 :                 poptPrintUsage(pctx, stdout, 0);
     352           0 :                 fprintf(stdout, "        [dd options]\n");
     353           0 :                 exit(0);
     354             :         }
     355             : 
     356           0 :         poptPrintHelp(pctx, stdout, 0);
     357           0 :         fprintf(stdout, "\nCIFS dd options:\n");
     358             : 
     359           0 :         for (i = 0; i < ARRAY_SIZE(args); ++i) {
     360           0 :                 if (args[i].arg_name == NULL) {
     361           0 :                         break;
     362             :                 }
     363             : 
     364           0 :                 snprintf(prefix, sizeof(prefix), "%s=%-*s",
     365             :                         args[i].arg_name,
     366           0 :                         (int)(sizeof(prefix) - strlen(args[i].arg_name) - 2),
     367             :                         argtype_str(args[i].arg_type));
     368           0 :                 prefix[sizeof(prefix) - 1] = '\0';
     369           0 :                 fprintf(stdout, "  %s%s\n", prefix, args[i].arg_help);
     370             :         }
     371             : 
     372           0 :         fprintf(stdout, "\n%s\n", notes);
     373           0 :         exit(0);
     374             : }
     375             : 
     376             : /* ------------------------------------------------------------------------- */
     377             : /* Main block copying routine.                                               */
     378             : /* ------------------------------------------------------------------------- */
     379             : 
     380          18 : static void print_transfer_stats(void)
     381             : {
     382          18 :         if (DEBUGLEVEL > 0) {
     383          18 :                 printf("%llu+%llu records in (%llu bytes)\n"
     384             :                         "%llu+%llu records out (%llu bytes)\n",
     385          18 :                         (unsigned long long)dd_stats.in.fblocks,
     386          18 :                         (unsigned long long)dd_stats.in.pblocks,
     387          18 :                         (unsigned long long)dd_stats.in.bytes,
     388          18 :                         (unsigned long long)dd_stats.out.fblocks,
     389          18 :                         (unsigned long long)dd_stats.out.pblocks,
     390          18 :                         (unsigned long long)dd_stats.out.bytes);
     391             :         } else {
     392           0 :                 printf("%llu+%llu records in\n%llu+%llu records out\n",
     393           0 :                                 (unsigned long long)dd_stats.in.fblocks,
     394           0 :                                 (unsigned long long)dd_stats.in.pblocks,
     395           0 :                                 (unsigned long long)dd_stats.out.fblocks,
     396           0 :                                 (unsigned long long)dd_stats.out.pblocks);
     397             :         }
     398          18 : }
     399             : 
     400          36 : static struct dd_iohandle * open_file(struct resolve_context *resolve_ctx, 
     401             :                                       struct tevent_context *ev,
     402             :                                       const char * which, const char **ports,
     403             :                                       struct smbcli_options *smb_options,
     404             :                                       const char *socket_options,
     405             :                                       struct smbcli_session_options *smb_session_options,
     406             :                                       struct gensec_settings *gensec_settings)
     407             : {
     408          36 :         int                     options = 0;
     409          36 :         const char *            path = NULL;
     410          36 :         struct dd_iohandle *    handle = NULL;
     411             : 
     412          36 :         if (check_arg_bool("direct")) {
     413           0 :                 options |= DD_DIRECT_IO;
     414             :         }
     415             : 
     416          36 :         if (check_arg_bool("sync")) {
     417           0 :                 options |= DD_SYNC_IO;
     418             :         }
     419             : 
     420          36 :         if (check_arg_bool("oplock")) {
     421           0 :                 options |= DD_OPLOCK;
     422             :         }
     423             : 
     424          36 :         if (strcmp(which, "if") == 0) {
     425          18 :                 path = check_arg_pathname("if");
     426          18 :                 handle = dd_open_path(resolve_ctx, ev, path, ports,
     427             :                                       check_arg_numeric("ibs"), options,
     428             :                                       socket_options,
     429             :                                       smb_options, smb_session_options,
     430             :                                       gensec_settings);
     431          18 :         } else if (strcmp(which, "of") == 0) {
     432          18 :                 options |= DD_WRITE;
     433          18 :                 path = check_arg_pathname("of");
     434          18 :                 handle = dd_open_path(resolve_ctx, ev, path, ports,
     435             :                                       check_arg_numeric("obs"), options,
     436             :                                       socket_options,
     437             :                                       smb_options, smb_session_options,
     438             :                                       gensec_settings);
     439             :         } else {
     440           0 :                 SMB_ASSERT(0);
     441             :                 return(NULL);
     442             :         }
     443             : 
     444          36 :         if (!handle) {
     445           0 :                 fprintf(stderr, "%s: failed to open %s\n", PROGNAME, path);
     446             :         }
     447             : 
     448          36 :         return(handle);
     449             : }
     450             : 
     451          18 : static int copy_files(struct tevent_context *ev, struct loadparm_context *lp_ctx)
     452             : {
     453             :         uint8_t *       iobuf;  /* IO buffer. */
     454             :         uint64_t        iomax;  /* Size of the IO buffer. */
     455             :         uint64_t        data_size; /* Amount of data in the IO buffer. */
     456             : 
     457             :         uint64_t        ibs;
     458             :         uint64_t        obs;
     459             :         uint64_t        count;
     460             : 
     461             :         struct dd_iohandle *    ifile;
     462             :         struct dd_iohandle *    ofile;
     463             : 
     464             :         struct smbcli_options options;
     465             :         struct smbcli_session_options session_options;
     466             : 
     467          18 :         ibs = check_arg_numeric("ibs");
     468          18 :         obs = check_arg_numeric("obs");
     469          18 :         count = check_arg_numeric("count");
     470             : 
     471          18 :         lpcfg_smbcli_options(lp_ctx, &options);
     472          18 :         lpcfg_smbcli_session_options(lp_ctx, &session_options);
     473             : 
     474             :         /* Allocate IO buffer. We need more than the max IO size because we
     475             :          * could accumulate a remainder if ibs and obs don't match.
     476             :          */
     477          18 :         iomax = 2 * MAX(ibs, obs);
     478          18 :         if ((iobuf = malloc_array_p(uint8_t, iomax)) == NULL) {
     479           0 :                 fprintf(stderr,
     480             :                         "%s: failed to allocate IO buffer of %llu bytes\n",
     481             :                         PROGNAME, (unsigned long long)iomax);
     482           0 :                 return(EOM_EXIT_CODE);
     483             :         }
     484             : 
     485          18 :         options.max_xmit = MAX(ibs, obs);
     486             : 
     487          18 :         DEBUG(4, ("IO buffer size is %llu, max xmit is %d\n",
     488             :                         (unsigned long long)iomax, options.max_xmit));
     489             : 
     490          18 :         if (!(ifile = open_file(lpcfg_resolve_context(lp_ctx), ev, "if",
     491             :                                 lpcfg_smb_ports(lp_ctx), &options,
     492             :                                 lpcfg_socket_options(lp_ctx),
     493             :                                 &session_options, 
     494             :                                 lpcfg_gensec_settings(lp_ctx, lp_ctx)))) {
     495           0 :                 SAFE_FREE(iobuf);
     496           0 :                 return(FILESYS_EXIT_CODE);
     497             :         }
     498             : 
     499          18 :         if (!(ofile = open_file(lpcfg_resolve_context(lp_ctx), ev, "of",
     500             :                                 lpcfg_smb_ports(lp_ctx), &options,
     501             :                                 lpcfg_socket_options(lp_ctx),
     502             :                                 &session_options,
     503             :                                 lpcfg_gensec_settings(lp_ctx, lp_ctx)))) {
     504           0 :                 SAFE_FREE(iobuf);
     505           0 :                 return(FILESYS_EXIT_CODE);
     506             :         }
     507             : 
     508             :         /* Seek the files to their respective starting points. */
     509          18 :         ifile->io_seek(ifile, check_arg_numeric("skip") * ibs);
     510          18 :         ofile->io_seek(ofile, check_arg_numeric("seek") * obs);
     511             : 
     512          18 :         DEBUG(4, ("max xmit was negotiated to be %d\n", options.max_xmit));
     513             : 
     514          18 :         for (data_size = 0;;) {
     515             : 
     516             :                 /* Handle signals. We are somewhat compatible with GNU dd.
     517             :                  * SIGINT makes us stop, but still print transfer statistics.
     518             :                  * SIGUSR1 makes us print transfer statistics but we continue
     519             :                  * copying.
     520             :                  */
     521         714 :                 if (dd_sigint) {
     522           0 :                         break;
     523             :                 }
     524             : 
     525         714 :                 if (dd_sigusr1) {
     526           0 :                         print_transfer_stats();
     527           0 :                         dd_sigusr1 = 0;
     528             :                 }
     529             : 
     530         714 :                 if (ifile->io_flags & DD_END_OF_FILE) {
     531          18 :                         DEBUG(4, ("flushing %llu bytes at EOF\n",
     532             :                                         (unsigned long long)data_size));
     533          18 :                         while (data_size > 0) {
     534           0 :                                 if (!dd_flush_block(ofile, iobuf,
     535             :                                                         &data_size, obs)) {
     536           0 :                                         SAFE_FREE(iobuf);
     537           0 :                                         return(IOERROR_EXIT_CODE);
     538             :                                 }
     539             :                         }
     540          18 :                         goto done;
     541             :                 }
     542             : 
     543             :                 /* Try and read enough blocks of ibs bytes to be able write
     544             :                  * out one of obs bytes.
     545             :                  */
     546         696 :                 if (!dd_fill_block(ifile, iobuf, &data_size, obs, ibs)) {
     547           0 :                         SAFE_FREE(iobuf);
     548           0 :                         return(IOERROR_EXIT_CODE);
     549             :                 }
     550             : 
     551         696 :                 if (data_size == 0) {
     552             :                         /* Done. */
     553           6 :                         SMB_ASSERT(ifile->io_flags & DD_END_OF_FILE);
     554             :                 }
     555             : 
     556             :                 /* Stop reading when we hit the block count. */
     557         696 :                 if (dd_stats.in.bytes >= (ibs * count)) {
     558           0 :                         ifile->io_flags |= DD_END_OF_FILE;
     559             :                 }
     560             : 
     561             :                 /* If we wanted to be a legitimate dd, we would do character
     562             :                  * conversions and other shenanigans here.
     563             :                  */
     564             : 
     565             :                 /* Flush what we read in units of obs bytes. We want to have
     566             :                  * at least obs bytes in the IO buffer but might not if the
     567             :                  * file is too small.
     568             :                  */
     569         696 :                 if (data_size && 
     570         690 :                     !dd_flush_block(ofile, iobuf, &data_size, obs)) {
     571           0 :                         SAFE_FREE(iobuf);
     572           0 :                         return(IOERROR_EXIT_CODE);
     573             :                 }
     574             :         }
     575             : 
     576          18 : done:
     577          18 :         SAFE_FREE(iobuf);
     578          18 :         print_transfer_stats();
     579          18 :         return(0);
     580             : }
     581             : 
     582             : /* ------------------------------------------------------------------------- */
     583             : /* Main.                                                                     */
     584             : /* ------------------------------------------------------------------------- */
     585             : 
     586             : struct poptOption cifsddHelpOptions[] = {
     587             :         {
     588             :                 .longName   = NULL,
     589             :                 .shortName  = '\0',
     590             :                 .argInfo    = POPT_ARG_CALLBACK,
     591             :                 .arg        = (void *)&cifsdd_help_message,
     592             :                 .val        = '\0',
     593             :         },
     594             :         {
     595             :                 .longName   = "help",
     596             :                 .shortName  = '?',
     597             :                 .val        = '?',
     598             :                 .descrip    = "Show this help message",
     599             :         },
     600             :         {
     601             :                 .longName   = "usage",
     602             :                 .shortName  = '\0',
     603             :                 .val        = 'u',
     604             :                 .descrip    = "Display brief usage message",
     605             :         },
     606             :         POPT_TABLEEND
     607             : };
     608             : 
     609          18 : int main(int argc, char *argv[])
     610             : {
     611          18 :         const char **const_argv = discard_const_p(const char *, argv);
     612             :         int i;
     613             :         const char ** dd_args;
     614          18 :         TALLOC_CTX *mem_ctx = NULL;
     615          18 :         struct loadparm_context *lp_ctx = NULL;
     616             :         struct tevent_context *ev;
     617             :         bool ok;
     618             :         int rc;
     619             : 
     620             :         poptContext pctx;
     621         108 :         struct poptOption poptions[] = {
     622             :                 /* POPT_AUTOHELP */
     623             :                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, cifsddHelpOptions,
     624             :                         0, "Help options:", NULL },
     625          18 :                 POPT_COMMON_SAMBA
     626          18 :                 POPT_COMMON_CONNECTION
     627          18 :                 POPT_COMMON_CREDENTIALS
     628          18 :                 POPT_LEGACY_S4
     629          18 :                 POPT_COMMON_VERSION
     630             :                 POPT_TABLEEND
     631             :         };
     632             : 
     633             :         /* Block sizes. */
     634          18 :         set_arg_val("bs", (uint64_t)4096);
     635          18 :         set_arg_val("ibs", (uint64_t)4096);
     636          18 :         set_arg_val("obs", (uint64_t)4096);
     637             :         /* Block counts. */
     638          18 :         set_arg_val("count", (uint64_t)-1);
     639          18 :         set_arg_val("seek", (uint64_t)0);
     640          18 :         set_arg_val("skip", (uint64_t)0);
     641             :         /* Files. */
     642          18 :         set_arg_val("if", NULL);
     643          18 :         set_arg_val("of", NULL);
     644             :         /* Options. */
     645          18 :         set_arg_val("direct", false);
     646          18 :         set_arg_val("sync", false);
     647          18 :         set_arg_val("oplock", false);
     648             : 
     649          18 :         mem_ctx = talloc_init("cifsdd.c/main");
     650          18 :         if (mem_ctx == NULL) {
     651           0 :                 d_printf("Not enough memory\n");
     652           0 :                 exit(1);
     653             :         }
     654             : 
     655          18 :         ok = samba_cmdline_init(mem_ctx,
     656             :                                 SAMBA_CMDLINE_CONFIG_CLIENT,
     657             :                                 false /* require_smbconf */);
     658          18 :         if (!ok) {
     659           0 :                 DBG_ERR("Failed to init cmdline parser!\n");
     660           0 :                 TALLOC_FREE(mem_ctx);
     661           0 :                 exit(1);
     662             :         }
     663             : 
     664          18 :         pctx = samba_popt_get_context(getprogname(), argc, const_argv, poptions, 0);
     665          18 :         if (pctx == NULL) {
     666           0 :                 DBG_ERR("Failed to setup popt context!\n");
     667           0 :                 TALLOC_FREE(mem_ctx);
     668           0 :                 exit(1);
     669             :         }
     670             : 
     671          18 :         while ((i = poptGetNextOpt(pctx)) != -1) {
     672           0 :                 switch (i) {
     673           0 :                 case POPT_ERROR_BADOPT:
     674           0 :                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
     675             :                                 poptBadOption(pctx, 0), poptStrerror(i));
     676           0 :                         poptPrintUsage(pctx, stderr, 0);
     677           0 :                         exit(1);
     678             :                 }
     679             :         }
     680             : 
     681          72 :         for (dd_args = poptGetArgs(pctx); dd_args && *dd_args; ++dd_args) {
     682             : 
     683          54 :                 if (!set_arg_argv(*dd_args)) {
     684           0 :                         fprintf(stderr, "%s: invalid option: %s\n",
     685             :                                         PROGNAME, *dd_args);
     686           0 :                         exit(SYNTAX_EXIT_CODE);
     687             :                 }
     688             : 
     689             :                 /* "bs" has the side-effect of setting "ibs" and "obs". */
     690          54 :                 if (strncmp(*dd_args, "bs=", 3) == 0) {
     691          18 :                         uint64_t bs = check_arg_numeric("bs");
     692          18 :                         set_arg_val("ibs", bs);
     693          18 :                         set_arg_val("obs", bs);
     694             :                 }
     695             :         }
     696             : 
     697          18 :         poptFreeContext(pctx);
     698          18 :         samba_cmdline_burn(argc, argv);
     699             : 
     700          18 :         ev = s4_event_context_init(mem_ctx);
     701          18 :         lp_ctx = samba_cmdline_get_lp_ctx();
     702             : 
     703          18 :         gensec_init();
     704          18 :         dump_args();
     705             : 
     706          18 :         if (check_arg_numeric("ibs") == 0 || check_arg_numeric("obs") == 0) {
     707           0 :                 fprintf(stderr, "%s: block sizes must be greater that zero\n",
     708             :                                 PROGNAME);
     709           0 :                 talloc_free(mem_ctx);
     710           0 :                 exit(SYNTAX_EXIT_CODE);
     711             :         }
     712             : 
     713          18 :         if (check_arg_pathname("if") == NULL) {
     714           0 :                 fprintf(stderr, "%s: missing input filename\n", PROGNAME);
     715           0 :                 talloc_free(mem_ctx);
     716           0 :                 exit(SYNTAX_EXIT_CODE);
     717             :         }
     718             : 
     719          18 :         if (check_arg_pathname("of") == NULL) {
     720           0 :                 fprintf(stderr, "%s: missing output filename\n", PROGNAME);
     721           0 :                 talloc_free(mem_ctx);
     722           0 :                 exit(SYNTAX_EXIT_CODE);
     723             :         }
     724             : 
     725          18 :         CatchSignal(SIGINT, dd_handle_signal);
     726          18 :         CatchSignal(SIGUSR1, dd_handle_signal);
     727          18 :         rc = copy_files(ev, lp_ctx);
     728             : 
     729          18 :         talloc_free(mem_ctx);
     730          18 :         return rc;
     731             : }
     732             : 
     733             : /* vim: set sw=8 sts=8 ts=8 tw=79 : */

Generated by: LCOV version 1.14