~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/utils/smbget.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   smbget: a wget-like utility with support for recursive downloading and 
 
3
        smb:// urls
 
4
   Copyright (C) 2003-2004 Jelmer Vernooij <jelmer@samba.org>
 
5
 
 
6
   This program is free software; you can redistribute it and/or modify
 
7
   it under the terms of the GNU General Public License as published by
 
8
   the Free Software Foundation; either version 3 of the License, or
 
9
   (at your option) any later version.
 
10
   
 
11
   This program is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
   GNU General Public License for more details.
 
15
   
 
16
   You should have received a copy of the GNU General Public License
 
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
18
 
 
19
#include "includes.h"
 
20
#include "libsmbclient.h"
 
21
 
 
22
#if _FILE_OFFSET_BITS==64
 
23
#define OFF_T_FORMAT "%lld"
 
24
#define OFF_T_FORMAT_CAST long long
 
25
#else
 
26
#define OFF_T_FORMAT "%ld"
 
27
#define OFF_T_FORMAT_CAST long
 
28
#endif
 
29
 
 
30
static int columns = 0;
 
31
 
 
32
static int debuglevel, update;
 
33
static char *outputfile;
 
34
 
 
35
 
 
36
static time_t total_start_time = 0;
 
37
static off_t total_bytes = 0;
 
38
 
 
39
#define SMB_MAXPATHLEN MAXPATHLEN
 
40
 
 
41
/* Number of bytes to read when checking whether local and remote file are really the same file */
 
42
#define RESUME_CHECK_SIZE                               512
 
43
#define RESUME_DOWNLOAD_OFFSET                  1024
 
44
#define RESUME_CHECK_OFFSET                             RESUME_DOWNLOAD_OFFSET+RESUME_CHECK_SIZE
 
45
/* Number of bytes to read at once */
 
46
#define SMB_DEFAULT_BLOCKSIZE                                   64000
 
47
 
 
48
static const char *username = NULL, *password = NULL, *workgroup = NULL;
 
49
static int nonprompt = 0, quiet = 0, dots = 0, keep_permissions = 0, verbose = 0, send_stdout = 0;
 
50
static int blocksize = SMB_DEFAULT_BLOCKSIZE;
 
51
 
 
52
static int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile);
 
53
 
 
54
static int get_num_cols(void)
 
55
{
 
56
#ifdef TIOCGWINSZ
 
57
        struct winsize ws;
 
58
        if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
 
59
                return 0;
 
60
        }
 
61
        return ws.ws_col;
 
62
#else
 
63
#warning No support for TIOCGWINSZ
 
64
        char *cols = getenv("COLUMNS");
 
65
        if(!cols) return 0;
 
66
        return atoi(cols);
 
67
#endif
 
68
}
 
69
 
 
70
static void change_columns(int sig)
 
71
{
 
72
        columns = get_num_cols();
 
73
}
 
74
 
 
75
static void human_readable(off_t s, char *buffer, int l)
 
76
{
 
77
        if(s > 1024 * 1024 * 1024) snprintf(buffer, l, "%.2fGb", 1.0 * s / (1024 * 1024 * 1024));
 
78
        else if(s > 1024 * 1024) snprintf(buffer, l, "%.2fMb", 1.0 * s / (1024 * 1024));
 
79
        else if(s > 1024) snprintf(buffer, l, "%.2fkb", 1.0 * s / 1024);
 
80
        else snprintf(buffer, l, OFF_T_FORMAT"b", (OFF_T_FORMAT_CAST)s);
 
81
}
 
82
 
 
83
static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen)
 
84
{
 
85
        static char hasasked = 0;
 
86
        char *wgtmp, *usertmp;
 
87
        char tmp[128];
 
88
 
 
89
        if(hasasked) return;
 
90
        hasasked = 1;
 
91
 
 
92
        if(!nonprompt && !username) {
 
93
                printf("Username for %s at %s [guest] ", shr, srv);
 
94
                if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
 
95
                        return;
 
96
                }
 
97
                if(tmp[strlen(tmp)-1] == '\n')tmp[strlen(tmp)-1] = '\0';
 
98
                strncpy(un, tmp, unlen-1);
 
99
        } else if(username) strncpy(un, username, unlen-1);
 
100
 
 
101
        if(!nonprompt && !password) {
 
102
                char *prompt, *pass;
 
103
                if (asprintf(&prompt, "Password for %s at %s: ", shr, srv) == -1) {
 
104
                        return;
 
105
                }
 
106
                pass = getpass(prompt);
 
107
                free(prompt);
 
108
                strncpy(pw, pass, pwlen-1);
 
109
        } else if(password) strncpy(pw, password, pwlen-1);
 
110
 
 
111
        if(workgroup)strncpy(wg, workgroup, wglen-1);
 
112
 
 
113
        wgtmp = SMB_STRNDUP(wg, wglen); 
 
114
        usertmp = SMB_STRNDUP(un, unlen);
 
115
        if(!quiet)printf("Using workgroup %s, %s%s\n", wgtmp, *usertmp?"user ":"guest user", usertmp);
 
116
        free(wgtmp); free(usertmp);
 
117
}
 
118
 
 
119
static int smb_download_dir(const char *base, const char *name, int resume)
 
120
{
 
121
        char path[SMB_MAXPATHLEN];
 
122
        int dirhandle;
 
123
        struct smbc_dirent *dirent;
 
124
        const char *relname = name;
 
125
        char *tmpname;
 
126
        struct stat remotestat;
 
127
        snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (base[0] && name[0] && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
 
128
 
 
129
        /* List files in directory and call smb_download_file on them */
 
130
        dirhandle = smbc_opendir(path);
 
131
        if(dirhandle < 1) {
 
132
                if(errno == ENOTDIR) return smb_download_file(base, name, 1, resume, NULL);
 
133
                fprintf(stderr, "Can't open directory %s: %s\n", path, strerror(errno));
 
134
                return 0;
 
135
        }
 
136
 
 
137
        while(*relname == '/')relname++;
 
138
        mkdir(relname, 0755);
 
139
        
 
140
        tmpname = SMB_STRDUP(name);
 
141
 
 
142
        while((dirent = smbc_readdir(dirhandle))) {
 
143
                char *newname;
 
144
                if(!strcmp(dirent->name, ".") || !strcmp(dirent->name, ".."))continue;
 
145
                if (asprintf(&newname, "%s/%s", tmpname, dirent->name) == -1) {
 
146
                        return 0;
 
147
                }
 
148
                switch(dirent->smbc_type) {
 
149
                case SMBC_DIR:
 
150
                        smb_download_dir(base, newname, resume);
 
151
                        break;
 
152
 
 
153
                case SMBC_WORKGROUP:
 
154
                        smb_download_dir("smb://", dirent->name, resume);
 
155
                        break;
 
156
 
 
157
                case SMBC_SERVER:
 
158
                        smb_download_dir("smb://", dirent->name, resume);
 
159
                        break;
 
160
 
 
161
                case SMBC_FILE:
 
162
                        smb_download_file(base, newname, 1, resume, NULL);
 
163
                        break;
 
164
 
 
165
                case SMBC_FILE_SHARE:
 
166
                        smb_download_dir(base, newname, resume);
 
167
                        break;
 
168
 
 
169
                case SMBC_PRINTER_SHARE:
 
170
                        if(!quiet)printf("Ignoring printer share %s\n", dirent->name);
 
171
                        break;
 
172
 
 
173
                case SMBC_COMMS_SHARE:
 
174
                        if(!quiet)printf("Ignoring comms share %s\n", dirent->name);
 
175
                        break;
 
176
                        
 
177
                case SMBC_IPC_SHARE:
 
178
                        if(!quiet)printf("Ignoring ipc$ share %s\n", dirent->name);
 
179
                        break;
 
180
 
 
181
                default:
 
182
                        fprintf(stderr, "Ignoring file '%s' of type '%d'\n", newname, dirent->smbc_type);
 
183
                        break;
 
184
                }
 
185
                free(newname);
 
186
        }
 
187
        free(tmpname);
 
188
 
 
189
        if(keep_permissions) {
 
190
                if(smbc_fstat(dirhandle, &remotestat) < 0) {
 
191
                        fprintf(stderr, "Unable to get stats on %s on remote server\n", path);
 
192
                        smbc_closedir(dirhandle);
 
193
                        return 0;
 
194
                }
 
195
                
 
196
                if(chmod(relname, remotestat.st_mode) < 0) {
 
197
                        fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname,
 
198
                                (unsigned int)remotestat.st_mode);
 
199
                        smbc_closedir(dirhandle);
 
200
                        return 0;
 
201
                }
 
202
        }
 
203
 
 
204
        smbc_closedir(dirhandle);
 
205
        return 1;
 
206
}
 
207
 
 
208
static char *print_time(long t)
 
209
{
 
210
        static char buffer[100];
 
211
        int secs, mins, hours;
 
212
        if(t < -1) {
 
213
                strncpy(buffer, "Unknown", sizeof(buffer));
 
214
                return buffer;
 
215
        }
 
216
 
 
217
        secs = (int)t % 60;
 
218
        mins = (int)t / 60 % 60;
 
219
        hours = (int)t / (60 * 60);
 
220
        snprintf(buffer, sizeof(buffer)-1, "%02d:%02d:%02d", hours, mins, secs);
 
221
        return buffer;
 
222
}
 
223
 
 
224
static void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total)
 
225
{
 
226
        double avg = 0.0;
 
227
        long  eta = -1; 
 
228
        double prcnt = 0.0;
 
229
        char hpos[20], htotal[20], havg[20];
 
230
        char *status, *filename;
 
231
        int len;
 
232
        if(now - start)avg = 1.0 * (pos - start_pos) / (now - start);
 
233
        eta = (total - pos) / avg;
 
234
        if(total)prcnt = 100.0 * pos / total;
 
235
 
 
236
        human_readable(pos, hpos, sizeof(hpos));
 
237
        human_readable(total, htotal, sizeof(htotal));
 
238
        human_readable(avg, havg, sizeof(havg));
 
239
 
 
240
        len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos, htotal, prcnt, havg, print_time(eta));
 
241
        if (len == -1) {
 
242
                return;
 
243
        }
 
244
        
 
245
        if(columns) {
 
246
                int required = strlen(name), available = columns - len - strlen("[] ");
 
247
                if(required > available) {
 
248
                        if (asprintf(&filename, "...%s", name + required - available + 3) == -1) {
 
249
                                return;
 
250
                        }
 
251
                } else {
 
252
                        filename = SMB_STRNDUP(name, available);
 
253
                }
 
254
        } else filename = SMB_STRDUP(name);
 
255
 
 
256
        fprintf(stderr, "\r[%s] %s", filename, status);
 
257
 
 
258
        free(filename); free(status);
 
259
}
 
260
 
 
261
static int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile) {
 
262
        int remotehandle, localhandle;
 
263
        time_t start_time = time(NULL);
 
264
        const char *newpath;
 
265
        char path[SMB_MAXPATHLEN];
 
266
        char checkbuf[2][RESUME_CHECK_SIZE];
 
267
        char *readbuf = NULL;
 
268
        off_t offset_download = 0, offset_check = 0, curpos = 0, start_offset = 0;
 
269
        struct stat localstat, remotestat;
 
270
 
 
271
        snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (*base && *name && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
 
272
        
 
273
        remotehandle = smbc_open(path, O_RDONLY, 0755);
 
274
 
 
275
        if(remotehandle < 0) {
 
276
                switch(errno) {
 
277
                case EISDIR: 
 
278
                        if(!recursive) {
 
279
                                fprintf(stderr, "%s is a directory. Specify -R to download recursively\n", path);
 
280
                                return 0;
 
281
                        }
 
282
                        smb_download_dir(base, name, resume);
 
283
                        return 0;
 
284
 
 
285
                case ENOENT:
 
286
                        fprintf(stderr, "%s can't be found on the remote server\n", path);
 
287
                        return 0;
 
288
 
 
289
                case ENOMEM:
 
290
                        fprintf(stderr, "Not enough memory\n");
 
291
                        exit(1);
 
292
                        return 0;
 
293
 
 
294
                case ENODEV:
 
295
                        fprintf(stderr, "The share name used in %s does not exist\n", path);
 
296
                        return 0;
 
297
 
 
298
                case EACCES:
 
299
                        fprintf(stderr, "You don't have enough permissions to access %s\n", path);
 
300
                        return 0;
 
301
 
 
302
                default:
 
303
                        perror("smbc_open");
 
304
                        return 0;
 
305
                }
 
306
        } 
 
307
 
 
308
        if(smbc_fstat(remotehandle, &remotestat) < 0) {
 
309
                fprintf(stderr, "Can't stat %s: %s\n", path, strerror(errno));
 
310
                return 0;
 
311
        }
 
312
 
 
313
        if(outfile) newpath = outfile;
 
314
        else if(!name[0]) {
 
315
                newpath = strrchr(base, '/');
 
316
                if(newpath)newpath++; else newpath = base;
 
317
        } else newpath = name;
 
318
 
 
319
        if(newpath[0] == '/')newpath++;
 
320
        
 
321
        /* Open local file according to the mode */
 
322
        if(update) {
 
323
                /* if it is up-to-date, skip */
 
324
                if(stat(newpath, &localstat) == 0 &&
 
325
                                localstat.st_mtime >= remotestat.st_mtime) {
 
326
                        if(verbose)
 
327
                                printf("%s is up-to-date, skipping\n", newpath);
 
328
                        smbc_close(remotehandle);
 
329
                        return 0;
 
330
                }
 
331
                /* else open it for writing and truncate if it exists */
 
332
                localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | O_TRUNC, 0775);
 
333
                if(localhandle < 0) {
 
334
                        fprintf(stderr, "Can't open %s : %s\n", newpath,
 
335
                                        strerror(errno));
 
336
                        smbc_close(remotehandle);
 
337
                        return 0;
 
338
                }
 
339
                /* no offset */
 
340
        } else if(!send_stdout) {
 
341
                localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | (!resume?O_EXCL:0), 0755);
 
342
                if(localhandle < 0) {
 
343
                        fprintf(stderr, "Can't open %s: %s\n", newpath, strerror(errno));
 
344
                        smbc_close(remotehandle);
 
345
                        return 0;
 
346
                }
 
347
        
 
348
                if (fstat(localhandle, &localstat) != 0) {
 
349
                        fprintf(stderr, "Can't fstat %s: %s\n", newpath, strerror(errno));
 
350
                        smbc_close(remotehandle);
 
351
                        close(localhandle);
 
352
                        return 0;
 
353
                }
 
354
 
 
355
                start_offset = localstat.st_size;
 
356
 
 
357
                if(localstat.st_size && localstat.st_size == remotestat.st_size) {
 
358
                        if(verbose)fprintf(stderr, "%s is already downloaded completely.\n", path);
 
359
                        else if(!quiet)fprintf(stderr, "%s\n", path);
 
360
                        smbc_close(remotehandle);
 
361
                        close(localhandle);
 
362
                        return 1;
 
363
                }
 
364
 
 
365
                if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) {
 
366
                        offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET;
 
367
                        offset_check = localstat.st_size - RESUME_CHECK_OFFSET;
 
368
                        if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n"
 
369
                                   "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n",
 
370
                                newpath, (OFF_T_FORMAT_CAST)offset_check, 
 
371
                                (OFF_T_FORMAT_CAST)localstat.st_size,
 
372
                                (OFF_T_FORMAT_CAST)remotestat.st_size);
 
373
                }
 
374
 
 
375
                if(offset_check) { 
 
376
                        off_t off1, off2;
 
377
                        /* First, check all bytes from offset_check to offset_download */
 
378
                        off1 = lseek(localhandle, offset_check, SEEK_SET);
 
379
                        if(off1 < 0) {
 
380
                                fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n",
 
381
                                        (OFF_T_FORMAT_CAST)offset_check, newpath);
 
382
                                smbc_close(remotehandle); close(localhandle);
 
383
                                return 0;
 
384
                        }
 
385
 
 
386
                        off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET); 
 
387
                        if(off2 < 0) {
 
388
                                fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n",
 
389
                                        (OFF_T_FORMAT_CAST)offset_check, newpath);
 
390
                                smbc_close(remotehandle); close(localhandle);
 
391
                                return 0;
 
392
                        }
 
393
 
 
394
                        if(off1 != off2) {
 
395
                                fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n",
 
396
                                        (OFF_T_FORMAT_CAST)off1,
 
397
                                        (OFF_T_FORMAT_CAST)off2);
 
398
                                return 0;
 
399
                        }
 
400
 
 
401
                        if(smbc_read(remotehandle, checkbuf[0], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
 
402
                                fprintf(stderr, "Can't read %d bytes from remote file %s\n", RESUME_CHECK_SIZE, path);
 
403
                                smbc_close(remotehandle); close(localhandle);
 
404
                                return 0;
 
405
                        }
 
406
 
 
407
                        if(read(localhandle, checkbuf[1], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
 
408
                                fprintf(stderr, "Can't read %d bytes from local file %s\n", RESUME_CHECK_SIZE, name);
 
409
                                smbc_close(remotehandle); close(localhandle);
 
410
                                return 0;
 
411
                        }
 
412
 
 
413
                        if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) {
 
414
                                if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", (OFF_T_FORMAT_CAST)offset_download);
 
415
                        } else {
 
416
                                fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path);
 
417
                                smbc_close(remotehandle); close(localhandle);
 
418
                                return 0;
 
419
                        }
 
420
                }
 
421
        } else {
 
422
                localhandle = STDOUT_FILENO;
 
423
                start_offset = 0;
 
424
                offset_download = 0;
 
425
                offset_check = 0;
 
426
        }
 
427
 
 
428
        readbuf = (char *)SMB_MALLOC(blocksize);
 
429
 
 
430
        /* Now, download all bytes from offset_download to the end */
 
431
        for(curpos = offset_download; curpos < remotestat.st_size; curpos+=blocksize) {
 
432
                ssize_t bytesread = smbc_read(remotehandle, readbuf, blocksize);
 
433
                if(bytesread < 0) {
 
434
                        fprintf(stderr, "Can't read %u bytes at offset "OFF_T_FORMAT", file %s\n", (unsigned int)blocksize, (OFF_T_FORMAT_CAST)curpos, path);
 
435
                        smbc_close(remotehandle);
 
436
                        if (localhandle != STDOUT_FILENO) close(localhandle);
 
437
                        free(readbuf);
 
438
                        return 0;
 
439
                }
 
440
 
 
441
                total_bytes += bytesread;
 
442
 
 
443
                if(write(localhandle, readbuf, bytesread) < 0) {
 
444
                        fprintf(stderr, "Can't write %u bytes to local file %s at offset "OFF_T_FORMAT"\n", (unsigned int)bytesread, path, (OFF_T_FORMAT_CAST)curpos);
 
445
                        free(readbuf);
 
446
                        smbc_close(remotehandle);
 
447
                        if (localhandle != STDOUT_FILENO) close(localhandle);
 
448
                        return 0;
 
449
                }
 
450
 
 
451
                if(dots)fputc('.', stderr);
 
452
                else if(!quiet) {
 
453
                        print_progress(newpath, start_time, time(NULL), start_offset, curpos, remotestat.st_size);
 
454
                }
 
455
        }
 
456
 
 
457
        free(readbuf);
 
458
 
 
459
        if(dots){
 
460
                fputc('\n', stderr);
 
461
                printf("%s downloaded\n", path);
 
462
        } else if(!quiet) {
 
463
                int i;
 
464
                fprintf(stderr, "\r%s", path);
 
465
                if(columns) {
 
466
                        for(i = strlen(path); i < columns; i++) {
 
467
                                fputc(' ', stderr);
 
468
                        }
 
469
                }
 
470
                fputc('\n', stderr);
 
471
        }
 
472
 
 
473
        if(keep_permissions && !send_stdout) {
 
474
                if(fchmod(localhandle, remotestat.st_mode) < 0) {
 
475
                        fprintf(stderr, "Unable to change mode of local file %s to %o\n", path,
 
476
                                (unsigned int)remotestat.st_mode);
 
477
                        smbc_close(remotehandle);
 
478
                        close(localhandle);
 
479
                        return 0;
 
480
                }
 
481
        }
 
482
 
 
483
        smbc_close(remotehandle);
 
484
        if (localhandle != STDOUT_FILENO) close(localhandle);
 
485
        return 1;
 
486
}
 
487
 
 
488
static void clean_exit(void)
 
489
{
 
490
        char bs[100];
 
491
        human_readable(total_bytes, bs, sizeof(bs));
 
492
        if(!quiet)fprintf(stderr, "Downloaded %s in %lu seconds\n", bs,
 
493
                (unsigned long)(time(NULL) - total_start_time));
 
494
        exit(0);
 
495
}
 
496
 
 
497
static void signal_quit(int v)
 
498
{
 
499
        clean_exit();
 
500
}
 
501
 
 
502
static int readrcfile(const char *name, const struct poptOption long_options[])
 
503
{
 
504
        FILE *fd = fopen(name, "r");
 
505
        int lineno = 0, i;
 
506
        char var[101], val[101];
 
507
        char found;
 
508
        int *intdata; char **stringdata;
 
509
        if(!fd) {
 
510
                fprintf(stderr, "Can't open RC file %s\n", name);
 
511
                return 1;
 
512
        }
 
513
 
 
514
        while(!feof(fd)) {
 
515
                lineno++;
 
516
                if(fscanf(fd, "%100s %100s\n", var, val) < 2) {
 
517
                        fprintf(stderr, "Can't parse line %d of %s, ignoring.\n", lineno, name);
 
518
                        continue;
 
519
                }
 
520
 
 
521
                found = 0;
 
522
 
 
523
                for(i = 0; long_options[i].shortName; i++) {
 
524
                        if(!long_options[i].longName)continue;
 
525
                        if(strcmp(long_options[i].longName, var)) continue;
 
526
                        if(!long_options[i].arg)continue;
 
527
 
 
528
                        switch(long_options[i].argInfo) {
 
529
                        case POPT_ARG_NONE:
 
530
                                intdata = (int *)long_options[i].arg;
 
531
                                if(!strcmp(val, "on")) *intdata = 1;
 
532
                                else if(!strcmp(val, "off")) *intdata = 0;
 
533
                                else fprintf(stderr, "Illegal value %s for %s at line %d in %s\n", val, var, lineno, name);
 
534
                                break;
 
535
                        case POPT_ARG_INT:
 
536
                                intdata = (int *)long_options[i].arg;
 
537
                                *intdata = atoi(val);
 
538
                                break;
 
539
                        case POPT_ARG_STRING:
 
540
                                stringdata = (char **)long_options[i].arg;
 
541
                                *stringdata = SMB_STRDUP(val);
 
542
                                break;
 
543
                        default:
 
544
                                fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
 
545
                                break;
 
546
                        }
 
547
 
 
548
                        found = 1;
 
549
                }
 
550
                if(!found) {
 
551
                        fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
 
552
                }
 
553
        }
 
554
 
 
555
        fclose(fd);
 
556
        return 0;
 
557
}
 
558
 
 
559
int main(int argc, const char **argv)
 
560
{
 
561
        int c = 0;
 
562
        const char *file = NULL;
 
563
        char *rcfile = NULL;
 
564
        bool smb_encrypt = false;
 
565
        int resume = 0, recursive = 0;
 
566
        TALLOC_CTX *frame = talloc_stackframe();
 
567
        struct poptOption long_options[] = {
 
568
                {"guest", 'a', POPT_ARG_NONE, NULL, 'a', "Work as user guest" },        
 
569
                {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },      
 
570
                {"resume", 'r', POPT_ARG_NONE, &resume, 0, "Automatically resume aborted files" },
 
571
                {"update", 'U',  POPT_ARG_NONE, &update, 0, "Download only when remote file is newer than local file or local file is missing"},
 
572
                {"recursive", 'R',  POPT_ARG_NONE, &recursive, 0, "Recursively download files" },
 
573
                {"username", 'u', POPT_ARG_STRING, &username, 'u', "Username to use" },
 
574
                {"password", 'p', POPT_ARG_STRING, &password, 'p', "Password to use" },
 
575
                {"workgroup", 'w', POPT_ARG_STRING, &workgroup, 'w', "Workgroup to use (optional)" },
 
576
                {"nonprompt", 'n', POPT_ARG_NONE, &nonprompt, 'n', "Don't ask anything (non-interactive)" },
 
577
                {"debuglevel", 'd', POPT_ARG_INT, &debuglevel, 'd', "Debuglevel to use" },
 
578
                {"outputfile", 'o', POPT_ARG_STRING, &outputfile, 'o', "Write downloaded data to specified file" },
 
579
                {"stdout", 'O', POPT_ARG_NONE, &send_stdout, 'O', "Write data to stdout" },
 
580
                {"dots", 'D', POPT_ARG_NONE, &dots, 'D', "Show dots as progress indication" },
 
581
                {"quiet", 'q', POPT_ARG_NONE, &quiet, 'q', "Be quiet" },
 
582
                {"verbose", 'v', POPT_ARG_NONE, &verbose, 'v', "Be verbose" },
 
583
                {"keep-permissions", 'P', POPT_ARG_NONE, &keep_permissions, 'P', "Keep permissions" },
 
584
                {"blocksize", 'b', POPT_ARG_INT, &blocksize, 'b', "Change number of bytes in a block"},
 
585
                {"rcfile", 'f', POPT_ARG_STRING, NULL, 'f', "Use specified rc file"},
 
586
                POPT_AUTOHELP
 
587
                POPT_TABLEEND
 
588
        };
 
589
        poptContext pc;
 
590
 
 
591
        load_case_tables();
 
592
 
 
593
        /* only read rcfile if it exists */
 
594
        if (asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME")) == -1) {
 
595
                return 1;
 
596
        }
 
597
        if(access(rcfile, F_OK) == 0) 
 
598
                readrcfile(rcfile, long_options);
 
599
        free(rcfile);
 
600
 
 
601
#ifdef SIGWINCH
 
602
        signal(SIGWINCH, change_columns);
 
603
#endif
 
604
        signal(SIGINT, signal_quit);
 
605
        signal(SIGTERM, signal_quit);
 
606
 
 
607
        pc = poptGetContext(argv[0], argc, argv, long_options, 0);
 
608
 
 
609
        while((c = poptGetNextOpt(pc)) >= 0) {
 
610
                switch(c) {
 
611
                case 'f':
 
612
                        readrcfile(poptGetOptArg(pc), long_options);
 
613
                        break;
 
614
                case 'a':
 
615
                        username = ""; password = "";
 
616
                        break;
 
617
                case 'e':
 
618
                        smb_encrypt = true;
 
619
                        break;
 
620
                }
 
621
        }
 
622
 
 
623
        if((send_stdout || resume || outputfile) && update) {
 
624
                fprintf(stderr, "The -o, -R or -O and -U options can not be used together.\n");
 
625
                return 1;
 
626
        }
 
627
        if((send_stdout || outputfile) && recursive) {
 
628
                fprintf(stderr, "The -o or -O and -R options can not be used together.\n");
 
629
                return 1;
 
630
        }
 
631
 
 
632
        if(outputfile && send_stdout) {
 
633
                fprintf(stderr, "The -o and -O options cannot be used together.\n");
 
634
                return 1;
 
635
        }
 
636
 
 
637
        if(smbc_init(get_auth_data, debuglevel) < 0) {
 
638
                fprintf(stderr, "Unable to initialize libsmbclient\n");
 
639
                return 1;
 
640
        }
 
641
 
 
642
        if (smb_encrypt) {
 
643
                SMBCCTX *smb_ctx = smbc_set_context(NULL);
 
644
                smbc_option_set(smb_ctx,
 
645
                        CONST_DISCARD(char *, "smb_encrypt_level"),
 
646
                        "require");
 
647
        }
 
648
        
 
649
        columns = get_num_cols();
 
650
 
 
651
        total_start_time = time(NULL);
 
652
 
 
653
        while ( (file = poptGetArg(pc)) ) {
 
654
                if (!recursive) 
 
655
                        return smb_download_file(file, "", recursive, resume, outputfile);
 
656
                else 
 
657
                        return smb_download_dir(file, "", resume);
 
658
        }
 
659
 
 
660
        clean_exit();
 
661
        TALLOC_FREE(frame);
 
662
        return 0;
 
663
}