r6303: Setting up for 3.0.15pre1
[Samba.git] / source / client / client.c
blob604bf0989a8f5cec5045bc36214bfab1af3126d5
1 /*
2 Unix SMB/CIFS implementation.
3 SMB client
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Simo Sorce 2001-2002
6 Copyright (C) Jelmer Vernooij 2003
7 Copyright (C) Gerald (Jerry) Carter 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #define NO_SYSLOG
26 #include "includes.h"
27 #include "client/client_proto.h"
28 #ifndef REGISTER
29 #define REGISTER 0
30 #endif
32 extern BOOL AllowDebugChange;
33 extern BOOL override_logfile;
34 extern char tar_type;
35 extern BOOL in_client;
36 static int port = 0;
37 pstring cur_dir = "\\";
38 static pstring cd_path = "";
39 static pstring service;
40 static pstring desthost;
41 static pstring username;
42 static pstring calling_name;
43 static BOOL grepable=False;
44 static char *cmdstr = NULL;
46 static int io_bufsize = 64512;
48 static int name_type = 0x20;
49 extern int max_protocol;
51 static int process_tok(pstring tok);
52 static int cmd_help(void);
54 /* 30 second timeout on most commands */
55 #define CLIENT_TIMEOUT (30*1000)
56 #define SHORT_TIMEOUT (5*1000)
58 /* value for unused fid field in trans2 secondary request */
59 #define FID_UNUSED (0xFFFF)
61 time_t newer_than = 0;
62 static int archive_level = 0;
64 static BOOL translation = False;
65 static BOOL have_ip;
67 /* clitar bits insert */
68 extern int blocksize;
69 extern BOOL tar_inc;
70 extern BOOL tar_reset;
71 /* clitar bits end */
74 static BOOL prompt = True;
76 static int printmode = 1;
78 static BOOL recurse = False;
79 BOOL lowercase = False;
81 static struct in_addr dest_ip;
83 #define SEPARATORS " \t\n\r"
85 static BOOL abort_mget = True;
87 static pstring fileselection = "";
89 extern file_info def_finfo;
91 /* timing globals */
92 SMB_BIG_UINT get_total_size = 0;
93 unsigned int get_total_time_ms = 0;
94 static SMB_BIG_UINT put_total_size = 0;
95 static unsigned int put_total_time_ms = 0;
97 /* totals globals */
98 static double dir_total;
100 /* root cli_state connection */
102 struct cli_state *cli;
106 /****************************************************************************
107 Write to a local file with CR/LF->LF translation if appropriate. Return the
108 number taken from the buffer. This may not equal the number written.
109 ****************************************************************************/
111 static int writefile(int f, char *b, int n)
113 int i;
115 if (!translation) {
116 return write(f,b,n);
119 i = 0;
120 while (i < n) {
121 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
122 b++;i++;
124 if (write(f, b, 1) != 1) {
125 break;
127 b++;
128 i++;
131 return(i);
134 /****************************************************************************
135 Read from a file with LF->CR/LF translation if appropriate. Return the
136 number read. read approx n bytes.
137 ****************************************************************************/
139 static int readfile(char *b, int n, XFILE *f)
141 int i;
142 int c;
144 if (!translation)
145 return x_fread(b,1,n,f);
147 i = 0;
148 while (i < (n - 1) && (i < BUFFER_SIZE)) {
149 if ((c = x_getc(f)) == EOF) {
150 break;
153 if (c == '\n') { /* change all LFs to CR/LF */
154 b[i++] = '\r';
157 b[i++] = c;
160 return(i);
163 /****************************************************************************
164 Send a message.
165 ****************************************************************************/
167 static void send_message(void)
169 int total_len = 0;
170 int grp_id;
172 if (!cli_message_start(cli, desthost, username, &grp_id)) {
173 d_printf("message start: %s\n", cli_errstr(cli));
174 return;
178 d_printf("Connected. Type your message, ending it with a Control-D\n");
180 while (!feof(stdin) && total_len < 1600) {
181 int maxlen = MIN(1600 - total_len,127);
182 pstring msg;
183 int l=0;
184 int c;
186 ZERO_ARRAY(msg);
188 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
189 if (c == '\n')
190 msg[l++] = '\r';
191 msg[l] = c;
194 if (!cli_message_text(cli, msg, l, grp_id)) {
195 d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
196 return;
199 total_len += l;
202 if (total_len >= 1600)
203 d_printf("the message was truncated to 1600 bytes\n");
204 else
205 d_printf("sent %d bytes\n",total_len);
207 if (!cli_message_end(cli, grp_id)) {
208 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
209 return;
213 /****************************************************************************
214 Check the space on a device.
215 ****************************************************************************/
217 static int do_dskattr(void)
219 int total, bsize, avail;
220 struct cli_state *targetcli;
221 pstring targetpath;
223 if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
224 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
225 return 1;
228 if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
229 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
230 return 1;
233 d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
234 total, bsize, avail);
236 return 0;
239 /****************************************************************************
240 Show cd/pwd.
241 ****************************************************************************/
243 static int cmd_pwd(void)
245 d_printf("Current directory is %s",service);
246 d_printf("%s\n",cur_dir);
247 return 0;
250 /****************************************************************************
251 Change directory - inner section.
252 ****************************************************************************/
254 static int do_cd(char *newdir)
256 char *p = newdir;
257 pstring saved_dir;
258 pstring dname;
259 pstring targetpath;
260 struct cli_state *targetcli;
261 SMB_STRUCT_STAT sbuf;
262 uint32 attributes;
264 dos_format(newdir);
266 /* Save the current directory in case the new directory is invalid */
268 pstrcpy(saved_dir, cur_dir);
270 if (*p == '\\')
271 pstrcpy(cur_dir,p);
272 else
273 pstrcat(cur_dir,p);
275 if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
276 pstrcat(cur_dir, "\\");
279 dos_clean_name(cur_dir);
280 pstrcpy( dname, cur_dir );
281 pstrcat(cur_dir,"\\");
282 dos_clean_name(cur_dir);
284 if ( !cli_resolve_path( "", cli, dname, &targetcli, targetpath ) ) {
285 d_printf("cd %s: %s\n", dname, cli_errstr(cli));
286 pstrcpy(cur_dir,saved_dir);
287 goto out;
291 if ( strequal(targetpath,"\\" ) )
292 return 0;
294 /* use a trans2_qpathinfo to test directories for modern servers */
296 if ( targetcli->protocol >= PROTOCOL_LANMAN2 ) {
297 if ( !cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
298 d_printf("cd %s: %s\n", dname, cli_errstr(targetcli));
299 pstrcpy(cur_dir,saved_dir);
300 goto out;
303 if ( !(attributes&FILE_ATTRIBUTE_DIRECTORY) ) {
304 d_printf("cd %s: not a directory\n", dname);
305 pstrcpy(cur_dir,saved_dir);
306 goto out;
309 else {
310 pstrcat( targetpath, "\\" );
311 dos_clean_name( targetpath );
313 if ( !cli_chkpath(targetcli, targetpath) ) {
314 d_printf("cd %s: %s\n", dname, cli_errstr(targetcli));
315 pstrcpy(cur_dir,saved_dir);
319 out:
320 pstrcpy(cd_path,cur_dir);
322 return 0;
325 /****************************************************************************
326 Change directory.
327 ****************************************************************************/
329 static int cmd_cd(void)
331 pstring buf;
332 int rc = 0;
334 if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
335 rc = do_cd(buf);
336 else
337 d_printf("Current directory is %s\n",cur_dir);
339 return rc;
342 /*******************************************************************
343 Decide if a file should be operated on.
344 ********************************************************************/
346 static BOOL do_this_one(file_info *finfo)
348 if (finfo->mode & aDIR)
349 return(True);
351 if (*fileselection &&
352 !mask_match(finfo->name,fileselection,False)) {
353 DEBUG(3,("mask_match %s failed\n", finfo->name));
354 return False;
357 if (newer_than && finfo->mtime < newer_than) {
358 DEBUG(3,("newer_than %s failed\n", finfo->name));
359 return(False);
362 if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
363 DEBUG(3,("archive %s failed\n", finfo->name));
364 return(False);
367 return(True);
370 /****************************************************************************
371 Display info about a file.
372 ****************************************************************************/
374 static void display_finfo(file_info *finfo)
376 if (do_this_one(finfo)) {
377 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
378 d_printf(" %-30s%7.7s %8.0f %s",
379 finfo->name,
380 attrib_string(finfo->mode),
381 (double)finfo->size,
382 asctime(LocalTime(&t)));
383 dir_total += finfo->size;
387 /****************************************************************************
388 Accumulate size of a file.
389 ****************************************************************************/
391 static void do_du(file_info *finfo)
393 if (do_this_one(finfo)) {
394 dir_total += finfo->size;
398 static BOOL do_list_recurse;
399 static BOOL do_list_dirs;
400 static char *do_list_queue = 0;
401 static long do_list_queue_size = 0;
402 static long do_list_queue_start = 0;
403 static long do_list_queue_end = 0;
404 static void (*do_list_fn)(file_info *);
406 /****************************************************************************
407 Functions for do_list_queue.
408 ****************************************************************************/
411 * The do_list_queue is a NUL-separated list of strings stored in a
412 * char*. Since this is a FIFO, we keep track of the beginning and
413 * ending locations of the data in the queue. When we overflow, we
414 * double the size of the char*. When the start of the data passes
415 * the midpoint, we move everything back. This is logically more
416 * complex than a linked list, but easier from a memory management
417 * angle. In any memory error condition, do_list_queue is reset.
418 * Functions check to ensure that do_list_queue is non-NULL before
419 * accessing it.
422 static void reset_do_list_queue(void)
424 SAFE_FREE(do_list_queue);
425 do_list_queue_size = 0;
426 do_list_queue_start = 0;
427 do_list_queue_end = 0;
430 static void init_do_list_queue(void)
432 reset_do_list_queue();
433 do_list_queue_size = 1024;
434 do_list_queue = SMB_MALLOC(do_list_queue_size);
435 if (do_list_queue == 0) {
436 d_printf("malloc fail for size %d\n",
437 (int)do_list_queue_size);
438 reset_do_list_queue();
439 } else {
440 memset(do_list_queue, 0, do_list_queue_size);
444 static void adjust_do_list_queue(void)
447 * If the starting point of the queue is more than half way through,
448 * move everything toward the beginning.
450 if (do_list_queue && (do_list_queue_start == do_list_queue_end)) {
451 DEBUG(4,("do_list_queue is empty\n"));
452 do_list_queue_start = do_list_queue_end = 0;
453 *do_list_queue = '\0';
454 } else if (do_list_queue_start > (do_list_queue_size / 2)) {
455 DEBUG(4,("sliding do_list_queue backward\n"));
456 memmove(do_list_queue,
457 do_list_queue + do_list_queue_start,
458 do_list_queue_end - do_list_queue_start);
459 do_list_queue_end -= do_list_queue_start;
460 do_list_queue_start = 0;
464 static void add_to_do_list_queue(const char* entry)
466 char *dlq;
467 long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
468 while (new_end > do_list_queue_size) {
469 do_list_queue_size *= 2;
470 DEBUG(4,("enlarging do_list_queue to %d\n",
471 (int)do_list_queue_size));
472 dlq = SMB_REALLOC(do_list_queue, do_list_queue_size);
473 if (! dlq) {
474 d_printf("failure enlarging do_list_queue to %d bytes\n",
475 (int)do_list_queue_size);
476 reset_do_list_queue();
477 } else {
478 do_list_queue = dlq;
479 memset(do_list_queue + do_list_queue_size / 2,
480 0, do_list_queue_size / 2);
483 if (do_list_queue) {
484 safe_strcpy_base(do_list_queue + do_list_queue_end,
485 entry, do_list_queue, do_list_queue_size);
486 do_list_queue_end = new_end;
487 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
488 entry, (int)do_list_queue_start, (int)do_list_queue_end));
492 static char *do_list_queue_head(void)
494 return do_list_queue + do_list_queue_start;
497 static void remove_do_list_queue_head(void)
499 if (do_list_queue_end > do_list_queue_start) {
500 do_list_queue_start += strlen(do_list_queue_head()) + 1;
501 adjust_do_list_queue();
502 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
503 (int)do_list_queue_start, (int)do_list_queue_end));
507 static int do_list_queue_empty(void)
509 return (! (do_list_queue && *do_list_queue));
512 /****************************************************************************
513 A helper for do_list.
514 ****************************************************************************/
516 static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
518 if (f->mode & aDIR) {
519 if (do_list_dirs && do_this_one(f)) {
520 do_list_fn(f);
522 if (do_list_recurse &&
523 !strequal(f->name,".") &&
524 !strequal(f->name,"..")) {
525 pstring mask2;
526 char *p;
528 if (!f->name[0]) {
529 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
530 return;
533 pstrcpy(mask2, mntpoint);
534 pstrcat(mask2, mask);
535 p = strrchr_m(mask2,'\\');
536 if (!p)
537 return;
538 p[1] = 0;
539 pstrcat(mask2, f->name);
540 pstrcat(mask2,"\\*");
541 add_to_do_list_queue(mask2);
543 return;
546 if (do_this_one(f)) {
547 do_list_fn(f);
551 /****************************************************************************
552 A wrapper around cli_list that adds recursion.
553 ****************************************************************************/
555 void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs)
557 static int in_do_list = 0;
558 struct cli_state *targetcli;
559 pstring targetpath;
561 if (in_do_list && rec) {
562 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
563 exit(1);
566 in_do_list = 1;
568 do_list_recurse = rec;
569 do_list_dirs = dirs;
570 do_list_fn = fn;
572 if (rec) {
573 init_do_list_queue();
574 add_to_do_list_queue(mask);
576 while (! do_list_queue_empty()) {
578 * Need to copy head so that it doesn't become
579 * invalid inside the call to cli_list. This
580 * would happen if the list were expanded
581 * during the call.
582 * Fix from E. Jay Berkenbilt (ejb@ql.org)
584 pstring head;
585 pstrcpy(head, do_list_queue_head());
587 /* check for dfs */
589 if ( !cli_resolve_path( "", cli, head, &targetcli, targetpath ) ) {
590 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
591 remove_do_list_queue_head();
592 continue;
595 cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
596 remove_do_list_queue_head();
597 if ((! do_list_queue_empty()) && (fn == display_finfo)) {
598 char* next_file = do_list_queue_head();
599 char* save_ch = 0;
600 if ((strlen(next_file) >= 2) &&
601 (next_file[strlen(next_file) - 1] == '*') &&
602 (next_file[strlen(next_file) - 2] == '\\')) {
603 save_ch = next_file +
604 strlen(next_file) - 2;
605 *save_ch = '\0';
607 d_printf("\n%s\n",next_file);
608 if (save_ch) {
609 *save_ch = '\\';
613 } else {
614 /* check for dfs */
616 if ( cli_resolve_path( "", cli, mask, &targetcli, targetpath ) ) {
617 if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1)
618 d_printf("%s listing %s\n", cli_errstr(targetcli), targetpath);
620 else
621 d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
625 in_do_list = 0;
626 reset_do_list_queue();
629 /****************************************************************************
630 Get a directory listing.
631 ****************************************************************************/
633 static int cmd_dir(void)
635 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
636 pstring mask;
637 pstring buf;
638 char *p=buf;
639 int rc;
641 dir_total = 0;
642 if (strcmp(cur_dir, "\\") != 0) {
643 pstrcpy(mask,cur_dir);
644 if(mask[strlen(mask)-1]!='\\')
645 pstrcat(mask,"\\");
646 } else {
647 pstrcpy(mask, "\\");
650 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
651 dos_format(p);
652 if (*p == '\\')
653 pstrcpy(mask,p + 1);
654 else
655 pstrcat(mask,p);
656 } else {
657 pstrcat(mask,"*");
660 do_list(mask, attribute, display_finfo, recurse, True);
662 rc = do_dskattr();
664 DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
666 return rc;
669 /****************************************************************************
670 Get a directory listing.
671 ****************************************************************************/
673 static int cmd_du(void)
675 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
676 pstring mask;
677 pstring buf;
678 char *p=buf;
679 int rc;
681 dir_total = 0;
682 pstrcpy(mask,cur_dir);
683 if(mask[strlen(mask)-1]!='\\')
684 pstrcat(mask,"\\");
686 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
687 dos_format(p);
688 if (*p == '\\')
689 pstrcpy(mask,p);
690 else
691 pstrcat(mask,p);
692 } else {
693 pstrcat(mask,"*");
696 do_list(mask, attribute, do_du, recurse, True);
698 rc = do_dskattr();
700 d_printf("Total number of bytes: %.0f\n", dir_total);
702 return rc;
705 /****************************************************************************
706 Get a file from rname to lname
707 ****************************************************************************/
709 static int do_get(char *rname, char *lname, BOOL reget)
711 int handle = 0, fnum;
712 BOOL newhandle = False;
713 char *data;
714 struct timeval tp_start;
715 int read_size = io_bufsize;
716 uint16 attr;
717 SMB_OFF_T size;
718 off_t start = 0;
719 off_t nread = 0;
720 int rc = 0;
721 struct cli_state *targetcli;
722 pstring targetname;
725 if (lowercase) {
726 strlower_m(lname);
729 if ( !cli_resolve_path( "", cli, rname, &targetcli, targetname ) ) {
730 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
731 return 1;
735 GetTimeOfDay(&tp_start);
737 fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
739 if (fnum == -1) {
740 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
741 return 1;
744 if(!strcmp(lname,"-")) {
745 handle = fileno(stdout);
746 } else {
747 if (reget) {
748 handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
749 if (handle >= 0) {
750 start = sys_lseek(handle, 0, SEEK_END);
751 if (start == -1) {
752 d_printf("Error seeking local file\n");
753 return 1;
756 } else {
757 handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
759 newhandle = True;
761 if (handle < 0) {
762 d_printf("Error opening local file %s\n",lname);
763 return 1;
767 if (!cli_qfileinfo(targetcli, fnum,
768 &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
769 !cli_getattrE(targetcli, fnum,
770 &attr, &size, NULL, NULL, NULL)) {
771 d_printf("getattrib: %s\n",cli_errstr(targetcli));
772 return 1;
775 DEBUG(1,("getting file %s of size %.0f as %s ",
776 rname, (double)size, lname));
778 if(!(data = (char *)SMB_MALLOC(read_size))) {
779 d_printf("malloc fail for size %d\n", read_size);
780 cli_close(targetcli, fnum);
781 return 1;
784 while (1) {
785 int n = cli_read(targetcli, fnum, data, nread + start, read_size);
787 if (n <= 0)
788 break;
790 if (writefile(handle,data, n) != n) {
791 d_printf("Error writing local file\n");
792 rc = 1;
793 break;
796 nread += n;
799 if (nread + start < size) {
800 DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
801 rname, (long)nread));
803 rc = 1;
806 SAFE_FREE(data);
808 if (!cli_close(targetcli, fnum)) {
809 d_printf("Error %s closing remote file\n",cli_errstr(cli));
810 rc = 1;
813 if (newhandle) {
814 close(handle);
817 if (archive_level >= 2 && (attr & aARCH)) {
818 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
822 struct timeval tp_end;
823 int this_time;
825 GetTimeOfDay(&tp_end);
826 this_time =
827 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
828 (tp_end.tv_usec - tp_start.tv_usec)/1000;
829 get_total_time_ms += this_time;
830 get_total_size += nread;
832 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
833 nread / (1.024*this_time + 1.0e-4),
834 get_total_size / (1.024*get_total_time_ms)));
837 return rc;
840 /****************************************************************************
841 Get a file.
842 ****************************************************************************/
844 static int cmd_get(void)
846 pstring lname;
847 pstring rname;
848 char *p;
850 pstrcpy(rname,cur_dir);
851 pstrcat(rname,"\\");
853 p = rname + strlen(rname);
855 if (!next_token_nr(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
856 d_printf("get <filename>\n");
857 return 1;
859 pstrcpy(lname,p);
860 dos_clean_name(rname);
862 next_token_nr(NULL,lname,NULL,sizeof(lname));
864 return do_get(rname, lname, False);
867 /****************************************************************************
868 Do an mget operation on one file.
869 ****************************************************************************/
871 static void do_mget(file_info *finfo)
873 pstring rname;
874 pstring quest;
875 pstring saved_curdir;
876 pstring mget_mask;
878 if (strequal(finfo->name,".") || strequal(finfo->name,".."))
879 return;
881 if (abort_mget) {
882 d_printf("mget aborted\n");
883 return;
886 if (finfo->mode & aDIR)
887 slprintf(quest,sizeof(pstring)-1,
888 "Get directory %s? ",finfo->name);
889 else
890 slprintf(quest,sizeof(pstring)-1,
891 "Get file %s? ",finfo->name);
893 if (prompt && !yesno(quest))
894 return;
896 if (!(finfo->mode & aDIR)) {
897 pstrcpy(rname,cur_dir);
898 pstrcat(rname,finfo->name);
899 do_get(rname, finfo->name, False);
900 return;
903 /* handle directories */
904 pstrcpy(saved_curdir,cur_dir);
906 pstrcat(cur_dir,finfo->name);
907 pstrcat(cur_dir,"\\");
909 unix_format(finfo->name);
910 if (lowercase)
911 strlower_m(finfo->name);
913 if (!directory_exist(finfo->name,NULL) &&
914 mkdir(finfo->name,0777) != 0) {
915 d_printf("failed to create directory %s\n",finfo->name);
916 pstrcpy(cur_dir,saved_curdir);
917 return;
920 if (chdir(finfo->name) != 0) {
921 d_printf("failed to chdir to directory %s\n",finfo->name);
922 pstrcpy(cur_dir,saved_curdir);
923 return;
926 pstrcpy(mget_mask,cur_dir);
927 pstrcat(mget_mask,"*");
929 do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,False, True);
930 chdir("..");
931 pstrcpy(cur_dir,saved_curdir);
934 /****************************************************************************
935 View the file using the pager.
936 ****************************************************************************/
938 static int cmd_more(void)
940 pstring rname,lname,pager_cmd;
941 char *pager;
942 int fd;
943 int rc = 0;
945 pstrcpy(rname,cur_dir);
946 pstrcat(rname,"\\");
948 slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir());
949 fd = smb_mkstemp(lname);
950 if (fd == -1) {
951 d_printf("failed to create temporary file for more\n");
952 return 1;
954 close(fd);
956 if (!next_token_nr(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
957 d_printf("more <filename>\n");
958 unlink(lname);
959 return 1;
961 dos_clean_name(rname);
963 rc = do_get(rname, lname, False);
965 pager=getenv("PAGER");
967 slprintf(pager_cmd,sizeof(pager_cmd)-1,
968 "%s %s",(pager? pager:PAGER), lname);
969 system(pager_cmd);
970 unlink(lname);
972 return rc;
975 /****************************************************************************
976 Do a mget command.
977 ****************************************************************************/
979 static int cmd_mget(void)
981 uint16 attribute = aSYSTEM | aHIDDEN;
982 pstring mget_mask;
983 pstring buf;
984 char *p=buf;
986 *mget_mask = 0;
988 if (recurse)
989 attribute |= aDIR;
991 abort_mget = False;
993 while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
994 pstrcpy(mget_mask,cur_dir);
995 if(mget_mask[strlen(mget_mask)-1]!='\\')
996 pstrcat(mget_mask,"\\");
998 if (*p == '\\')
999 pstrcpy(mget_mask,p);
1000 else
1001 pstrcat(mget_mask,p);
1002 do_list(mget_mask, attribute,do_mget,False,True);
1005 if (!*mget_mask) {
1006 pstrcpy(mget_mask,cur_dir);
1007 if(mget_mask[strlen(mget_mask)-1]!='\\')
1008 pstrcat(mget_mask,"\\");
1009 pstrcat(mget_mask,"*");
1010 do_list(mget_mask, attribute,do_mget,False,True);
1013 return 0;
1016 /****************************************************************************
1017 Make a directory of name "name".
1018 ****************************************************************************/
1020 static BOOL do_mkdir(char *name)
1022 struct cli_state *targetcli;
1023 pstring targetname;
1025 if ( !cli_resolve_path( "", cli, name, &targetcli, targetname ) ) {
1026 d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
1027 return False;
1030 if (!cli_mkdir(targetcli, targetname)) {
1031 d_printf("%s making remote directory %s\n",
1032 cli_errstr(targetcli),name);
1033 return(False);
1036 return(True);
1039 /****************************************************************************
1040 Show 8.3 name of a file.
1041 ****************************************************************************/
1043 static BOOL do_altname(char *name)
1045 pstring altname;
1046 if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1047 d_printf("%s getting alt name for %s\n",
1048 cli_errstr(cli),name);
1049 return(False);
1051 d_printf("%s\n", altname);
1053 return(True);
1056 /****************************************************************************
1057 Exit client.
1058 ****************************************************************************/
1060 static int cmd_quit(void)
1062 cli_cm_shutdown();
1063 exit(0);
1064 /* NOTREACHED */
1065 return 0;
1068 /****************************************************************************
1069 Make a directory.
1070 ****************************************************************************/
1072 static int cmd_mkdir(void)
1074 pstring mask;
1075 pstring buf;
1076 char *p=buf;
1078 pstrcpy(mask,cur_dir);
1080 if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1081 if (!recurse)
1082 d_printf("mkdir <dirname>\n");
1083 return 1;
1085 pstrcat(mask,p);
1087 if (recurse) {
1088 pstring ddir;
1089 pstring ddir2;
1090 *ddir2 = 0;
1092 pstrcpy(ddir,mask);
1093 trim_char(ddir,'.','\0');
1094 p = strtok(ddir,"/\\");
1095 while (p) {
1096 pstrcat(ddir2,p);
1097 if (!cli_chkpath(cli, ddir2)) {
1098 do_mkdir(ddir2);
1100 pstrcat(ddir2,"\\");
1101 p = strtok(NULL,"/\\");
1103 } else {
1104 do_mkdir(mask);
1107 return 0;
1110 /****************************************************************************
1111 Show alt name.
1112 ****************************************************************************/
1114 static int cmd_altname(void)
1116 pstring name;
1117 pstring buf;
1118 char *p=buf;
1120 pstrcpy(name,cur_dir);
1122 if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1123 d_printf("altname <file>\n");
1124 return 1;
1126 pstrcat(name,p);
1128 do_altname(name);
1130 return 0;
1133 /****************************************************************************
1134 Put a single file.
1135 ****************************************************************************/
1137 static int do_put(char *rname, char *lname, BOOL reput)
1139 int fnum;
1140 XFILE *f;
1141 SMB_OFF_T start = 0;
1142 off_t nread = 0;
1143 char *buf = NULL;
1144 int maxwrite = io_bufsize;
1145 int rc = 0;
1146 struct timeval tp_start;
1147 struct cli_state *targetcli;
1148 pstring targetname;
1150 if ( !cli_resolve_path( "", cli, rname, &targetcli, targetname ) ) {
1151 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1152 return 1;
1155 GetTimeOfDay(&tp_start);
1157 if (reput) {
1158 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
1159 if (fnum >= 0) {
1160 if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
1161 !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
1162 d_printf("getattrib: %s\n",cli_errstr(cli));
1163 return 1;
1166 } else {
1167 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
1170 if (fnum == -1) {
1171 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
1172 return 1;
1175 /* allow files to be piped into smbclient
1176 jdblair 24.jun.98
1178 Note that in this case this function will exit(0) rather
1179 than returning. */
1180 if (!strcmp(lname, "-")) {
1181 f = x_stdin;
1182 /* size of file is not known */
1183 } else {
1184 f = x_fopen(lname,O_RDONLY, 0);
1185 if (f && reput) {
1186 if (x_tseek(f, start, SEEK_SET) == -1) {
1187 d_printf("Error seeking local file\n");
1188 return 1;
1193 if (!f) {
1194 d_printf("Error opening local file %s\n",lname);
1195 return 1;
1198 DEBUG(1,("putting file %s as %s ",lname,
1199 rname));
1201 buf = (char *)SMB_MALLOC(maxwrite);
1202 if (!buf) {
1203 d_printf("ERROR: Not enough memory!\n");
1204 return 1;
1206 while (!x_feof(f)) {
1207 int n = maxwrite;
1208 int ret;
1210 if ((n = readfile(buf,n,f)) < 1) {
1211 if((n == 0) && x_feof(f))
1212 break; /* Empty local file. */
1214 d_printf("Error reading local file: %s\n", strerror(errno));
1215 rc = 1;
1216 break;
1219 ret = cli_write(targetcli, fnum, 0, buf, nread + start, n);
1221 if (n != ret) {
1222 d_printf("Error writing file: %s\n", cli_errstr(cli));
1223 rc = 1;
1224 break;
1227 nread += n;
1230 if (!cli_close(targetcli, fnum)) {
1231 d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
1232 x_fclose(f);
1233 SAFE_FREE(buf);
1234 return 1;
1238 if (f != x_stdin) {
1239 x_fclose(f);
1242 SAFE_FREE(buf);
1245 struct timeval tp_end;
1246 int this_time;
1248 GetTimeOfDay(&tp_end);
1249 this_time =
1250 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1251 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1252 put_total_time_ms += this_time;
1253 put_total_size += nread;
1255 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1256 nread / (1.024*this_time + 1.0e-4),
1257 put_total_size / (1.024*put_total_time_ms)));
1260 if (f == x_stdin) {
1261 cli_cm_shutdown();
1262 exit(0);
1265 return rc;
1268 /****************************************************************************
1269 Put a file.
1270 ****************************************************************************/
1272 static int cmd_put(void)
1274 pstring lname;
1275 pstring rname;
1276 pstring buf;
1277 char *p=buf;
1279 pstrcpy(rname,cur_dir);
1280 pstrcat(rname,"\\");
1282 if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1283 d_printf("put <filename>\n");
1284 return 1;
1286 pstrcpy(lname,p);
1288 if (next_token_nr(NULL,p,NULL,sizeof(buf)))
1289 pstrcat(rname,p);
1290 else
1291 pstrcat(rname,lname);
1293 dos_clean_name(rname);
1296 SMB_STRUCT_STAT st;
1297 /* allow '-' to represent stdin
1298 jdblair, 24.jun.98 */
1299 if (!file_exist(lname,&st) &&
1300 (strcmp(lname,"-"))) {
1301 d_printf("%s does not exist\n",lname);
1302 return 1;
1306 return do_put(rname, lname, False);
1309 /*************************************
1310 File list structure.
1311 *************************************/
1313 static struct file_list {
1314 struct file_list *prev, *next;
1315 char *file_path;
1316 BOOL isdir;
1317 } *file_list;
1319 /****************************************************************************
1320 Free a file_list structure.
1321 ****************************************************************************/
1323 static void free_file_list (struct file_list * list)
1325 struct file_list *tmp;
1327 while (list) {
1328 tmp = list;
1329 DLIST_REMOVE(list, list);
1330 SAFE_FREE(tmp->file_path);
1331 SAFE_FREE(tmp);
1335 /****************************************************************************
1336 Seek in a directory/file list until you get something that doesn't start with
1337 the specified name.
1338 ****************************************************************************/
1340 static BOOL seek_list(struct file_list *list, char *name)
1342 while (list) {
1343 trim_string(list->file_path,"./","\n");
1344 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1345 return(True);
1347 list = list->next;
1350 return(False);
1353 /****************************************************************************
1354 Set the file selection mask.
1355 ****************************************************************************/
1357 static int cmd_select(void)
1359 pstrcpy(fileselection,"");
1360 next_token_nr(NULL,fileselection,NULL,sizeof(fileselection));
1362 return 0;
1365 /****************************************************************************
1366 Recursive file matching function act as find
1367 match must be always set to True when calling this function
1368 ****************************************************************************/
1370 static int file_find(struct file_list **list, const char *directory,
1371 const char *expression, BOOL match)
1373 DIR *dir;
1374 struct file_list *entry;
1375 struct stat statbuf;
1376 int ret;
1377 char *path;
1378 BOOL isdir;
1379 const char *dname;
1381 dir = opendir(directory);
1382 if (!dir)
1383 return -1;
1385 while ((dname = readdirname(dir))) {
1386 if (!strcmp("..", dname))
1387 continue;
1388 if (!strcmp(".", dname))
1389 continue;
1391 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1392 continue;
1395 isdir = False;
1396 if (!match || !gen_fnmatch(expression, dname)) {
1397 if (recurse) {
1398 ret = stat(path, &statbuf);
1399 if (ret == 0) {
1400 if (S_ISDIR(statbuf.st_mode)) {
1401 isdir = True;
1402 ret = file_find(list, path, expression, False);
1404 } else {
1405 d_printf("file_find: cannot stat file %s\n", path);
1408 if (ret == -1) {
1409 SAFE_FREE(path);
1410 closedir(dir);
1411 return -1;
1414 entry = SMB_MALLOC_P(struct file_list);
1415 if (!entry) {
1416 d_printf("Out of memory in file_find\n");
1417 closedir(dir);
1418 return -1;
1420 entry->file_path = path;
1421 entry->isdir = isdir;
1422 DLIST_ADD(*list, entry);
1423 } else {
1424 SAFE_FREE(path);
1428 closedir(dir);
1429 return 0;
1432 /****************************************************************************
1433 mput some files.
1434 ****************************************************************************/
1436 static int cmd_mput(void)
1438 pstring buf;
1439 char *p=buf;
1441 while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1442 int ret;
1443 struct file_list *temp_list;
1444 char *quest, *lname, *rname;
1446 file_list = NULL;
1448 ret = file_find(&file_list, ".", p, True);
1449 if (ret) {
1450 free_file_list(file_list);
1451 continue;
1454 quest = NULL;
1455 lname = NULL;
1456 rname = NULL;
1458 for (temp_list = file_list; temp_list;
1459 temp_list = temp_list->next) {
1461 SAFE_FREE(lname);
1462 if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
1463 continue;
1464 trim_string(lname, "./", "/");
1466 /* check if it's a directory */
1467 if (temp_list->isdir) {
1468 /* if (!recurse) continue; */
1470 SAFE_FREE(quest);
1471 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
1472 if (prompt && !yesno(quest)) { /* No */
1473 /* Skip the directory */
1474 lname[strlen(lname)-1] = '/';
1475 if (!seek_list(temp_list, lname))
1476 break;
1477 } else { /* Yes */
1478 SAFE_FREE(rname);
1479 if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
1480 dos_format(rname);
1481 if (!cli_chkpath(cli, rname) &&
1482 !do_mkdir(rname)) {
1483 DEBUG (0, ("Unable to make dir, skipping..."));
1484 /* Skip the directory */
1485 lname[strlen(lname)-1] = '/';
1486 if (!seek_list(temp_list, lname))
1487 break;
1490 continue;
1491 } else {
1492 SAFE_FREE(quest);
1493 if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
1494 if (prompt && !yesno(quest)) /* No */
1495 continue;
1497 /* Yes */
1498 SAFE_FREE(rname);
1499 if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
1502 dos_format(rname);
1504 do_put(rname, lname, False);
1506 free_file_list(file_list);
1507 SAFE_FREE(quest);
1508 SAFE_FREE(lname);
1509 SAFE_FREE(rname);
1512 return 0;
1515 /****************************************************************************
1516 Cancel a print job.
1517 ****************************************************************************/
1519 static int do_cancel(int job)
1521 if (cli_printjob_del(cli, job)) {
1522 d_printf("Job %d cancelled\n",job);
1523 return 0;
1524 } else {
1525 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
1526 return 1;
1530 /****************************************************************************
1531 Cancel a print job.
1532 ****************************************************************************/
1534 static int cmd_cancel(void)
1536 pstring buf;
1537 int job;
1539 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1540 d_printf("cancel <jobid> ...\n");
1541 return 1;
1543 do {
1544 job = atoi(buf);
1545 do_cancel(job);
1546 } while (next_token_nr(NULL,buf,NULL,sizeof(buf)));
1548 return 0;
1551 /****************************************************************************
1552 Print a file.
1553 ****************************************************************************/
1555 static int cmd_print(void)
1557 pstring lname;
1558 pstring rname;
1559 char *p;
1561 if (!next_token_nr(NULL,lname,NULL, sizeof(lname))) {
1562 d_printf("print <filename>\n");
1563 return 1;
1566 pstrcpy(rname,lname);
1567 p = strrchr_m(rname,'/');
1568 if (p) {
1569 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)sys_getpid());
1572 if (strequal(lname,"-")) {
1573 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid());
1576 return do_put(rname, lname, False);
1579 /****************************************************************************
1580 Show a print queue entry.
1581 ****************************************************************************/
1583 static void queue_fn(struct print_job_info *p)
1585 d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
1588 /****************************************************************************
1589 Show a print queue.
1590 ****************************************************************************/
1592 static int cmd_queue(void)
1594 cli_print_queue(cli, queue_fn);
1596 return 0;
1599 /****************************************************************************
1600 Delete some files.
1601 ****************************************************************************/
1603 static void do_del(file_info *finfo)
1605 pstring mask;
1607 pstrcpy(mask,cur_dir);
1608 pstrcat(mask,finfo->name);
1610 if (finfo->mode & aDIR)
1611 return;
1613 if (!cli_unlink(cli, mask)) {
1614 d_printf("%s deleting remote file %s\n",cli_errstr(cli),mask);
1618 /****************************************************************************
1619 Delete some files.
1620 ****************************************************************************/
1622 static int cmd_del(void)
1624 pstring mask;
1625 pstring buf;
1626 uint16 attribute = aSYSTEM | aHIDDEN;
1628 if (recurse)
1629 attribute |= aDIR;
1631 pstrcpy(mask,cur_dir);
1633 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1634 d_printf("del <filename>\n");
1635 return 1;
1637 pstrcat(mask,buf);
1639 do_list(mask, attribute,do_del,False,False);
1641 return 0;
1644 /****************************************************************************
1645 ****************************************************************************/
1647 static int cmd_open(void)
1649 pstring mask;
1650 pstring buf;
1651 struct cli_state *targetcli;
1652 pstring targetname;
1654 pstrcpy(mask,cur_dir);
1656 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1657 d_printf("open <filename>\n");
1658 return 1;
1660 pstrcat(mask,buf);
1662 if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1663 d_printf("open %s: %s\n", mask, cli_errstr(cli));
1664 return 1;
1667 cli_nt_create(targetcli, targetname, FILE_READ_DATA);
1669 return 0;
1673 /****************************************************************************
1674 Remove a directory.
1675 ****************************************************************************/
1677 static int cmd_rmdir(void)
1679 pstring mask;
1680 pstring buf;
1681 struct cli_state *targetcli;
1682 pstring targetname;
1684 pstrcpy(mask,cur_dir);
1686 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1687 d_printf("rmdir <dirname>\n");
1688 return 1;
1690 pstrcat(mask,buf);
1692 if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1693 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
1694 return 1;
1697 if (!cli_rmdir(targetcli, targetname)) {
1698 d_printf("%s removing remote directory file %s\n",
1699 cli_errstr(targetcli),mask);
1702 return 0;
1705 /****************************************************************************
1706 UNIX hardlink.
1707 ****************************************************************************/
1709 static int cmd_link(void)
1711 pstring oldname,newname;
1712 pstring buf,buf2;
1713 struct cli_state *targetcli;
1714 pstring targetname;
1716 pstrcpy(oldname,cur_dir);
1717 pstrcpy(newname,cur_dir);
1719 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
1720 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1721 d_printf("link <oldname> <newname>\n");
1722 return 1;
1725 pstrcat(oldname,buf);
1726 pstrcat(newname,buf2);
1728 if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) {
1729 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
1730 return 1;
1733 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
1734 d_printf("Server doesn't support UNIX CIFS calls.\n");
1735 return 1;
1738 if (!cli_unix_hardlink(targetcli, targetname, newname)) {
1739 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
1740 return 1;
1743 return 0;
1746 /****************************************************************************
1747 UNIX symlink.
1748 ****************************************************************************/
1750 static int cmd_symlink(void)
1752 pstring oldname,newname;
1753 pstring buf,buf2;
1755 if (!SERVER_HAS_UNIX_CIFS(cli)) {
1756 d_printf("Server doesn't support UNIX CIFS calls.\n");
1757 return 1;
1760 pstrcpy(newname,cur_dir);
1762 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
1763 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1764 d_printf("symlink <oldname> <newname>\n");
1765 return 1;
1768 pstrcpy(oldname,buf);
1769 pstrcat(newname,buf2);
1771 if (!cli_unix_symlink(cli, oldname, newname)) {
1772 d_printf("%s symlinking files (%s -> %s)\n",
1773 cli_errstr(cli), newname, oldname);
1774 return 1;
1777 return 0;
1780 /****************************************************************************
1781 UNIX chmod.
1782 ****************************************************************************/
1784 static int cmd_chmod(void)
1786 pstring src;
1787 mode_t mode;
1788 pstring buf, buf2;
1789 struct cli_state *targetcli;
1790 pstring targetname;
1792 pstrcpy(src,cur_dir);
1794 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
1795 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1796 d_printf("chmod mode file\n");
1797 return 1;
1800 mode = (mode_t)strtol(buf, NULL, 8);
1801 pstrcat(src,buf2);
1803 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
1804 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
1805 return 1;
1808 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
1809 d_printf("Server doesn't support UNIX CIFS calls.\n");
1810 return 1;
1813 if (!cli_unix_chmod(targetcli, targetname, mode)) {
1814 d_printf("%s chmod file %s 0%o\n",
1815 cli_errstr(targetcli), src, (unsigned int)mode);
1816 return 1;
1819 return 0;
1822 static const char *filetype_to_str(mode_t mode)
1824 if (S_ISREG(mode)) {
1825 return "regular file";
1826 } else if (S_ISDIR(mode)) {
1827 return "directory";
1828 } else
1829 #ifdef S_ISCHR
1830 if (S_ISCHR(mode)) {
1831 return "character device";
1832 } else
1833 #endif
1834 #ifdef S_ISBLK
1835 if (S_ISBLK(mode)) {
1836 return "block device";
1837 } else
1838 #endif
1839 #ifdef S_ISFIFO
1840 if (S_ISFIFO(mode)) {
1841 return "fifo";
1842 } else
1843 #endif
1844 #ifdef S_ISLNK
1845 if (S_ISLNK(mode)) {
1846 return "symbolic link";
1847 } else
1848 #endif
1849 #ifdef S_ISSOCK
1850 if (S_ISSOCK(mode)) {
1851 return "socket";
1852 } else
1853 #endif
1854 return "";
1857 static char rwx_to_str(mode_t m, mode_t bt, char ret)
1859 if (m & bt) {
1860 return ret;
1861 } else {
1862 return '-';
1866 static char *unix_mode_to_str(char *s, mode_t m)
1868 char *p = s;
1869 const char *str = filetype_to_str(m);
1871 switch(str[0]) {
1872 case 'd':
1873 *p++ = 'd';
1874 break;
1875 case 'c':
1876 *p++ = 'c';
1877 break;
1878 case 'b':
1879 *p++ = 'b';
1880 break;
1881 case 'f':
1882 *p++ = 'p';
1883 break;
1884 case 's':
1885 *p++ = str[1] == 'y' ? 'l' : 's';
1886 break;
1887 case 'r':
1888 default:
1889 *p++ = '-';
1890 break;
1892 *p++ = rwx_to_str(m, S_IRUSR, 'r');
1893 *p++ = rwx_to_str(m, S_IWUSR, 'w');
1894 *p++ = rwx_to_str(m, S_IXUSR, 'x');
1895 *p++ = rwx_to_str(m, S_IRGRP, 'r');
1896 *p++ = rwx_to_str(m, S_IWGRP, 'w');
1897 *p++ = rwx_to_str(m, S_IXGRP, 'x');
1898 *p++ = rwx_to_str(m, S_IROTH, 'r');
1899 *p++ = rwx_to_str(m, S_IWOTH, 'w');
1900 *p++ = rwx_to_str(m, S_IXOTH, 'x');
1901 *p++ = '\0';
1902 return s;
1905 /****************************************************************************
1906 Utility function for UNIX getfacl.
1907 ****************************************************************************/
1909 static char *perms_to_string(fstring permstr, unsigned char perms)
1911 fstrcpy(permstr, "---");
1912 if (perms & SMB_POSIX_ACL_READ) {
1913 permstr[0] = 'r';
1915 if (perms & SMB_POSIX_ACL_WRITE) {
1916 permstr[1] = 'w';
1918 if (perms & SMB_POSIX_ACL_EXECUTE) {
1919 permstr[2] = 'x';
1921 return permstr;
1924 /****************************************************************************
1925 UNIX getfacl.
1926 ****************************************************************************/
1928 static int cmd_getfacl(void)
1930 pstring src, name;
1931 uint16 major, minor;
1932 uint32 caplow, caphigh;
1933 char *retbuf = NULL;
1934 size_t rb_size = 0;
1935 SMB_STRUCT_STAT sbuf;
1936 uint16 num_file_acls = 0;
1937 uint16 num_dir_acls = 0;
1938 uint16 i;
1939 struct cli_state *targetcli;
1940 pstring targetname;
1942 pstrcpy(src,cur_dir);
1944 if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
1945 d_printf("stat file\n");
1946 return 1;
1949 pstrcat(src,name);
1951 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
1952 d_printf("stat %s: %s\n", src, cli_errstr(cli));
1953 return 1;
1956 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
1957 d_printf("Server doesn't support UNIX CIFS calls.\n");
1958 return 1;
1961 if (!cli_unix_extensions_version(targetcli, &major, &minor, &caplow, &caphigh)) {
1962 d_printf("Can't get UNIX CIFS version from server.\n");
1963 return 1;
1966 if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
1967 d_printf("This server supports UNIX extensions but doesn't support POSIX ACLs.\n");
1968 return 1;
1972 if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
1973 d_printf("%s getfacl doing a stat on file %s\n",
1974 cli_errstr(targetcli), src);
1975 return 1;
1978 if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
1979 d_printf("%s getfacl file %s\n",
1980 cli_errstr(targetcli), src);
1981 return 1;
1984 /* ToDo : Print out the ACL values. */
1985 if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
1986 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
1987 src, (unsigned int)CVAL(retbuf,0) );
1988 SAFE_FREE(retbuf);
1989 return 1;
1992 num_file_acls = SVAL(retbuf,2);
1993 num_dir_acls = SVAL(retbuf,4);
1994 if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
1995 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
1996 src,
1997 (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
1998 (unsigned int)rb_size);
2000 SAFE_FREE(retbuf);
2001 return 1;
2004 d_printf("# file: %s\n", src);
2005 d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
2007 if (num_file_acls == 0 && num_dir_acls == 0) {
2008 d_printf("No acls found.\n");
2011 for (i = 0; i < num_file_acls; i++) {
2012 uint32 uorg;
2013 fstring permstring;
2014 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
2015 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2017 switch(tagtype) {
2018 case SMB_POSIX_ACL_USER_OBJ:
2019 d_printf("user::");
2020 break;
2021 case SMB_POSIX_ACL_USER:
2022 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2023 d_printf("user:%u:", uorg);
2024 break;
2025 case SMB_POSIX_ACL_GROUP_OBJ:
2026 d_printf("group::");
2027 break;
2028 case SMB_POSIX_ACL_GROUP:
2029 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2030 d_printf("group:%u", uorg);
2031 break;
2032 case SMB_POSIX_ACL_MASK:
2033 d_printf("mask::");
2034 break;
2035 case SMB_POSIX_ACL_OTHER:
2036 d_printf("other::");
2037 break;
2038 default:
2039 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2040 src, (unsigned int)tagtype );
2041 SAFE_FREE(retbuf);
2042 return 1;
2045 d_printf("%s\n", perms_to_string(permstring, perms));
2048 for (i = 0; i < num_dir_acls; i++) {
2049 uint32 uorg;
2050 fstring permstring;
2051 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
2052 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2054 switch(tagtype) {
2055 case SMB_POSIX_ACL_USER_OBJ:
2056 d_printf("default:user::");
2057 break;
2058 case SMB_POSIX_ACL_USER:
2059 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2060 d_printf("default:user:%u:", uorg);
2061 break;
2062 case SMB_POSIX_ACL_GROUP_OBJ:
2063 d_printf("default:group::");
2064 break;
2065 case SMB_POSIX_ACL_GROUP:
2066 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2067 d_printf("default:group:%u", uorg);
2068 break;
2069 case SMB_POSIX_ACL_MASK:
2070 d_printf("default:mask::");
2071 break;
2072 case SMB_POSIX_ACL_OTHER:
2073 d_printf("default:other::");
2074 break;
2075 default:
2076 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2077 src, (unsigned int)tagtype );
2078 SAFE_FREE(retbuf);
2079 return 1;
2082 d_printf("%s\n", perms_to_string(permstring, perms));
2085 SAFE_FREE(retbuf);
2086 return 0;
2089 /****************************************************************************
2090 UNIX stat.
2091 ****************************************************************************/
2093 static int cmd_stat(void)
2095 pstring src, name;
2096 fstring mode_str;
2097 SMB_STRUCT_STAT sbuf;
2098 struct cli_state *targetcli;
2099 pstring targetname;
2101 if (!SERVER_HAS_UNIX_CIFS(cli)) {
2102 d_printf("Server doesn't support UNIX CIFS calls.\n");
2103 return 1;
2106 pstrcpy(src,cur_dir);
2108 if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2109 d_printf("stat file\n");
2110 return 1;
2113 pstrcat(src,name);
2116 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2117 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2118 return 1;
2121 if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2122 d_printf("%s stat file %s\n",
2123 cli_errstr(targetcli), src);
2124 return 1;
2127 /* Print out the stat values. */
2128 d_printf("File: %s\n", src);
2129 d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
2130 (double)sbuf.st_size,
2131 (unsigned int)sbuf.st_blocks,
2132 filetype_to_str(sbuf.st_mode));
2134 #if defined(S_ISCHR) && defined(S_ISBLK)
2135 if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
2136 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
2137 (double)sbuf.st_ino,
2138 (unsigned int)sbuf.st_nlink,
2139 unix_dev_major(sbuf.st_rdev),
2140 unix_dev_minor(sbuf.st_rdev));
2141 } else
2142 #endif
2143 d_printf("Inode: %.0f\tLinks: %u\n",
2144 (double)sbuf.st_ino,
2145 (unsigned int)sbuf.st_nlink);
2147 d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
2148 ((int)sbuf.st_mode & 0777),
2149 unix_mode_to_str(mode_str, sbuf.st_mode),
2150 (unsigned int)sbuf.st_uid,
2151 (unsigned int)sbuf.st_gid);
2153 strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_atime));
2154 d_printf("Access: %s\n", mode_str);
2156 strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_mtime));
2157 d_printf("Modify: %s\n", mode_str);
2159 strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_ctime));
2160 d_printf("Change: %s\n", mode_str);
2162 return 0;
2166 /****************************************************************************
2167 UNIX chown.
2168 ****************************************************************************/
2170 static int cmd_chown(void)
2172 pstring src;
2173 uid_t uid;
2174 gid_t gid;
2175 pstring buf, buf2, buf3;
2176 struct cli_state *targetcli;
2177 pstring targetname;
2179 pstrcpy(src,cur_dir);
2181 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
2182 !next_token_nr(NULL,buf2,NULL, sizeof(buf2)) ||
2183 !next_token_nr(NULL,buf3,NULL, sizeof(buf3))) {
2184 d_printf("chown uid gid file\n");
2185 return 1;
2188 uid = (uid_t)atoi(buf);
2189 gid = (gid_t)atoi(buf2);
2190 pstrcat(src,buf3);
2192 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2193 d_printf("chown %s: %s\n", src, cli_errstr(cli));
2194 return 1;
2198 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2199 d_printf("Server doesn't support UNIX CIFS calls.\n");
2200 return 1;
2203 if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
2204 d_printf("%s chown file %s uid=%d, gid=%d\n",
2205 cli_errstr(targetcli), src, (int)uid, (int)gid);
2206 return 1;
2209 return 0;
2212 /****************************************************************************
2213 Rename some file.
2214 ****************************************************************************/
2216 static int cmd_rename(void)
2218 pstring src,dest;
2219 pstring buf,buf2;
2221 pstrcpy(src,cur_dir);
2222 pstrcpy(dest,cur_dir);
2224 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
2225 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2226 d_printf("rename <src> <dest>\n");
2227 return 1;
2230 pstrcat(src,buf);
2231 pstrcat(dest,buf2);
2233 if (!cli_rename(cli, src, dest)) {
2234 d_printf("%s renaming files\n",cli_errstr(cli));
2235 return 1;
2238 return 0;
2241 /****************************************************************************
2242 Print the volume name.
2243 ****************************************************************************/
2245 static int cmd_volume(void)
2247 fstring volname;
2248 uint32 serial_num;
2249 time_t create_date;
2251 if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
2252 d_printf("Errr %s getting volume info\n",cli_errstr(cli));
2253 return 1;
2256 d_printf("Volume: |%s| serial number 0x%x\n", volname, (unsigned int)serial_num);
2257 return 0;
2260 /****************************************************************************
2261 Hard link files using the NT call.
2262 ****************************************************************************/
2264 static int cmd_hardlink(void)
2266 pstring src,dest;
2267 pstring buf,buf2;
2268 struct cli_state *targetcli;
2269 pstring targetname;
2271 pstrcpy(src,cur_dir);
2272 pstrcpy(dest,cur_dir);
2274 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
2275 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2276 d_printf("hardlink <src> <dest>\n");
2277 return 1;
2280 pstrcat(src,buf);
2281 pstrcat(dest,buf2);
2283 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2284 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
2285 return 1;
2288 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2289 d_printf("Server doesn't support UNIX CIFS calls.\n");
2290 return 1;
2293 if (!cli_nt_hardlink(targetcli, targetname, dest)) {
2294 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
2295 return 1;
2298 return 0;
2301 /****************************************************************************
2302 Toggle the prompt flag.
2303 ****************************************************************************/
2305 static int cmd_prompt(void)
2307 prompt = !prompt;
2308 DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2310 return 1;
2313 /****************************************************************************
2314 Set the newer than time.
2315 ****************************************************************************/
2317 static int cmd_newer(void)
2319 pstring buf;
2320 BOOL ok;
2321 SMB_STRUCT_STAT sbuf;
2323 ok = next_token_nr(NULL,buf,NULL,sizeof(buf));
2324 if (ok && (sys_stat(buf,&sbuf) == 0)) {
2325 newer_than = sbuf.st_mtime;
2326 DEBUG(1,("Getting files newer than %s",
2327 asctime(LocalTime(&newer_than))));
2328 } else {
2329 newer_than = 0;
2332 if (ok && newer_than == 0) {
2333 d_printf("Error setting newer-than time\n");
2334 return 1;
2337 return 0;
2340 /****************************************************************************
2341 Set the archive level.
2342 ****************************************************************************/
2344 static int cmd_archive(void)
2346 pstring buf;
2348 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2349 archive_level = atoi(buf);
2350 } else
2351 d_printf("Archive level is %d\n",archive_level);
2353 return 0;
2356 /****************************************************************************
2357 Toggle the lowercaseflag.
2358 ****************************************************************************/
2360 static int cmd_lowercase(void)
2362 lowercase = !lowercase;
2363 DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2365 return 0;
2368 /****************************************************************************
2369 Toggle the case sensitive flag.
2370 ****************************************************************************/
2372 static int cmd_setcase(void)
2374 BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False);
2376 cli_set_case_sensitive(cli, !orig_case_sensitive);
2377 DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
2378 "on":"off"));
2380 return 0;
2383 /****************************************************************************
2384 Toggle the recurse flag.
2385 ****************************************************************************/
2387 static int cmd_recurse(void)
2389 recurse = !recurse;
2390 DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2392 return 0;
2395 /****************************************************************************
2396 Toggle the translate flag.
2397 ****************************************************************************/
2399 static int cmd_translate(void)
2401 translation = !translation;
2402 DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2403 translation?"on":"off"));
2405 return 0;
2408 /****************************************************************************
2409 Do a printmode command.
2410 ****************************************************************************/
2412 static int cmd_printmode(void)
2414 fstring buf;
2415 fstring mode;
2417 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2418 if (strequal(buf,"text")) {
2419 printmode = 0;
2420 } else {
2421 if (strequal(buf,"graphics"))
2422 printmode = 1;
2423 else
2424 printmode = atoi(buf);
2428 switch(printmode) {
2429 case 0:
2430 fstrcpy(mode,"text");
2431 break;
2432 case 1:
2433 fstrcpy(mode,"graphics");
2434 break;
2435 default:
2436 slprintf(mode,sizeof(mode)-1,"%d",printmode);
2437 break;
2440 DEBUG(2,("the printmode is now %s\n",mode));
2442 return 0;
2445 /****************************************************************************
2446 Do the lcd command.
2447 ****************************************************************************/
2449 static int cmd_lcd(void)
2451 pstring buf;
2452 pstring d;
2454 if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
2455 chdir(buf);
2456 DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2458 return 0;
2461 /****************************************************************************
2462 Get a file restarting at end of local file.
2463 ****************************************************************************/
2465 static int cmd_reget(void)
2467 pstring local_name;
2468 pstring remote_name;
2469 char *p;
2471 pstrcpy(remote_name, cur_dir);
2472 pstrcat(remote_name, "\\");
2474 p = remote_name + strlen(remote_name);
2476 if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2477 d_printf("reget <filename>\n");
2478 return 1;
2480 pstrcpy(local_name, p);
2481 dos_clean_name(remote_name);
2483 next_token_nr(NULL, local_name, NULL, sizeof(local_name));
2485 return do_get(remote_name, local_name, True);
2488 /****************************************************************************
2489 Put a file restarting at end of local file.
2490 ****************************************************************************/
2492 static int cmd_reput(void)
2494 pstring local_name;
2495 pstring remote_name;
2496 pstring buf;
2497 char *p = buf;
2498 SMB_STRUCT_STAT st;
2500 pstrcpy(remote_name, cur_dir);
2501 pstrcat(remote_name, "\\");
2503 if (!next_token_nr(NULL, p, NULL, sizeof(buf))) {
2504 d_printf("reput <filename>\n");
2505 return 1;
2507 pstrcpy(local_name, p);
2509 if (!file_exist(local_name, &st)) {
2510 d_printf("%s does not exist\n", local_name);
2511 return 1;
2514 if (next_token_nr(NULL, p, NULL, sizeof(buf)))
2515 pstrcat(remote_name, p);
2516 else
2517 pstrcat(remote_name, local_name);
2519 dos_clean_name(remote_name);
2521 return do_put(remote_name, local_name, True);
2524 /****************************************************************************
2525 List a share name.
2526 ****************************************************************************/
2528 static void browse_fn(const char *name, uint32 m,
2529 const char *comment, void *state)
2531 fstring typestr;
2533 *typestr=0;
2535 switch (m)
2537 case STYPE_DISKTREE:
2538 fstrcpy(typestr,"Disk"); break;
2539 case STYPE_PRINTQ:
2540 fstrcpy(typestr,"Printer"); break;
2541 case STYPE_DEVICE:
2542 fstrcpy(typestr,"Device"); break;
2543 case STYPE_IPC:
2544 fstrcpy(typestr,"IPC"); break;
2546 /* FIXME: If the remote machine returns non-ascii characters
2547 in any of these fields, they can corrupt the output. We
2548 should remove them. */
2549 if (!grepable) {
2550 d_printf("\t%-15s %-10.10s%s\n",
2551 name,typestr,comment);
2552 } else {
2553 d_printf ("%s|%s|%s\n",typestr,name,comment);
2557 /****************************************************************************
2558 Try and browse available connections on a host.
2559 ****************************************************************************/
2561 static BOOL browse_host(BOOL sort)
2563 int ret;
2564 if (!grepable) {
2565 d_printf("\n\tSharename Type Comment\n");
2566 d_printf("\t--------- ---- -------\n");
2569 if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
2570 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
2572 return (ret != -1);
2575 /****************************************************************************
2576 List a server name.
2577 ****************************************************************************/
2579 static void server_fn(const char *name, uint32 m,
2580 const char *comment, void *state)
2583 if (!grepable){
2584 d_printf("\t%-16s %s\n", name, comment);
2585 } else {
2586 d_printf("%s|%s|%s\n",(char *)state, name, comment);
2590 /****************************************************************************
2591 Try and browse available connections on a host.
2592 ****************************************************************************/
2594 static BOOL list_servers(const char *wk_grp)
2596 fstring state;
2598 if (!cli->server_domain)
2599 return False;
2601 if (!grepable) {
2602 d_printf("\n\tServer Comment\n");
2603 d_printf("\t--------- -------\n");
2605 fstrcpy( state, "Server" );
2606 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
2607 state);
2609 if (!grepable) {
2610 d_printf("\n\tWorkgroup Master\n");
2611 d_printf("\t--------- -------\n");
2614 fstrcpy( state, "Workgroup" );
2615 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
2616 server_fn, state);
2617 return True;
2620 /****************************************************************************
2621 Print or set current VUID
2622 ****************************************************************************/
2624 static int cmd_vuid(void)
2626 fstring buf;
2628 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2629 d_printf("Current VUID is %d\n", cli->vuid);
2630 return 0;
2633 cli->vuid = atoi(buf);
2634 return 0;
2637 /****************************************************************************
2638 Setup a new VUID, by issuing a session setup
2639 ****************************************************************************/
2641 static int cmd_logon(void)
2643 pstring l_username, l_password;
2644 pstring buf,buf2;
2646 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2647 d_printf("logon <username> [<password>]\n");
2648 return 0;
2651 pstrcpy(l_username, buf);
2653 if (!next_token_nr(NULL,buf2,NULL,sizeof(buf)))
2655 char *pass = getpass("Password: ");
2656 if (pass)
2657 pstrcpy(l_password, pass);
2659 else
2660 pstrcpy(l_password, buf2);
2662 if (!cli_session_setup(cli, l_username,
2663 l_password, strlen(l_password),
2664 l_password, strlen(l_password),
2665 lp_workgroup())) {
2666 d_printf("session setup failed: %s\n", cli_errstr(cli));
2667 return -1;
2670 d_printf("Current VUID is %d\n", cli->vuid);
2671 return 0;
2675 /****************************************************************************
2676 list active connections
2677 ****************************************************************************/
2679 static int cmd_list_connect(void)
2681 cli_cm_display();
2683 return 0;
2686 /****************************************************************************
2687 display the current active client connection
2688 ****************************************************************************/
2690 static int cmd_show_connect( void )
2692 struct cli_state *targetcli;
2693 pstring targetpath;
2695 if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
2696 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
2697 return 1;
2700 d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
2701 return 0;
2704 /* Some constants for completing filename arguments */
2706 #define COMPL_NONE 0 /* No completions */
2707 #define COMPL_REMOTE 1 /* Complete remote filename */
2708 #define COMPL_LOCAL 2 /* Complete local filename */
2710 /* This defines the commands supported by this client.
2711 * NOTE: The "!" must be the last one in the list because it's fn pointer
2712 * field is NULL, and NULL in that field is used in process_tok()
2713 * (below) to indicate the end of the list. crh
2715 static struct
2717 const char *name;
2718 int (*fn)(void);
2719 const char *description;
2720 char compl_args[2]; /* Completion argument info */
2721 } commands[] = {
2722 {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2723 {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
2724 {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
2725 {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
2726 {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
2727 {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
2728 {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2729 {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
2730 {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
2731 {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2732 {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2733 {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2734 {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2735 {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2736 {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
2737 {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2738 {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2739 {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2740 {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2741 {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2742 {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
2743 {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2744 {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
2745 {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2746 {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2747 {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2748 {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
2749 {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2750 {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2751 {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
2752 {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
2753 {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
2754 {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
2755 {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2756 {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2757 {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2758 {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
2759 {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2760 {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2761 {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
2762 {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
2763 {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2764 {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
2765 {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2766 {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2767 {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
2768 {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
2769 {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
2770 {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
2771 {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
2772 {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2773 {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
2774 {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
2775 {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
2776 {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
2777 {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
2779 /* Yes, this must be here, see crh's comment above. */
2780 {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2781 {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2784 /*******************************************************************
2785 Lookup a command string in the list of commands, including
2786 abbreviations.
2787 ******************************************************************/
2789 static int process_tok(pstring tok)
2791 int i = 0, matches = 0;
2792 int cmd=0;
2793 int tok_len = strlen(tok);
2795 while (commands[i].fn != NULL) {
2796 if (strequal(commands[i].name,tok)) {
2797 matches = 1;
2798 cmd = i;
2799 break;
2800 } else if (strnequal(commands[i].name, tok, tok_len)) {
2801 matches++;
2802 cmd = i;
2804 i++;
2807 if (matches == 0)
2808 return(-1);
2809 else if (matches == 1)
2810 return(cmd);
2811 else
2812 return(-2);
2815 /****************************************************************************
2816 Help.
2817 ****************************************************************************/
2819 static int cmd_help(void)
2821 int i=0,j;
2822 pstring buf;
2824 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2825 if ((i = process_tok(buf)) >= 0)
2826 d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
2827 } else {
2828 while (commands[i].description) {
2829 for (j=0; commands[i].description && (j<5); j++) {
2830 d_printf("%-15s",commands[i].name);
2831 i++;
2833 d_printf("\n");
2836 return 0;
2839 /****************************************************************************
2840 Process a -c command string.
2841 ****************************************************************************/
2843 static int process_command_string(char *cmd)
2845 pstring line;
2846 const char *ptr;
2847 int rc = 0;
2849 /* establish the connection if not already */
2851 if (!cli) {
2852 cli = cli_cm_open(desthost, service, True);
2853 if (!cli)
2854 return 0;
2857 while (cmd[0] != '\0') {
2858 char *p;
2859 pstring tok;
2860 int i;
2862 if ((p = strchr_m(cmd, ';')) == 0) {
2863 strncpy(line, cmd, 999);
2864 line[1000] = '\0';
2865 cmd += strlen(cmd);
2866 } else {
2867 if (p - cmd > 999)
2868 p = cmd + 999;
2869 strncpy(line, cmd, p - cmd);
2870 line[p - cmd] = '\0';
2871 cmd = p + 1;
2874 /* and get the first part of the command */
2875 ptr = line;
2876 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
2878 if ((i = process_tok(tok)) >= 0) {
2879 rc = commands[i].fn();
2880 } else if (i == -2) {
2881 d_printf("%s: command abbreviation ambiguous\n",tok);
2882 } else {
2883 d_printf("%s: command not found\n",tok);
2887 return rc;
2890 #define MAX_COMPLETIONS 100
2892 typedef struct {
2893 pstring dirmask;
2894 char **matches;
2895 int count, samelen;
2896 const char *text;
2897 int len;
2898 } completion_remote_t;
2900 static void completion_remote_filter(const char *mnt, file_info *f, const char *mask, void *state)
2902 completion_remote_t *info = (completion_remote_t *)state;
2904 if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
2905 if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
2906 info->matches[info->count] = SMB_STRDUP(f->name);
2907 else {
2908 pstring tmp;
2910 if (info->dirmask[0] != 0)
2911 pstrcpy(tmp, info->dirmask);
2912 else
2913 tmp[0] = 0;
2914 pstrcat(tmp, f->name);
2915 if (f->mode & aDIR)
2916 pstrcat(tmp, "/");
2917 info->matches[info->count] = SMB_STRDUP(tmp);
2919 if (info->matches[info->count] == NULL)
2920 return;
2921 if (f->mode & aDIR)
2922 smb_readline_ca_char(0);
2924 if (info->count == 1)
2925 info->samelen = strlen(info->matches[info->count]);
2926 else
2927 while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
2928 info->samelen--;
2929 info->count++;
2933 static char **remote_completion(const char *text, int len)
2935 pstring dirmask;
2936 int i;
2937 completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
2939 /* can't have non-static intialisation on Sun CC, so do it
2940 at run time here */
2941 info.samelen = len;
2942 info.text = text;
2943 info.len = len;
2945 if (len >= PATH_MAX)
2946 return(NULL);
2948 info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
2949 if (!info.matches) return NULL;
2950 info.matches[0] = NULL;
2952 for (i = len-1; i >= 0; i--)
2953 if ((text[i] == '/') || (text[i] == '\\'))
2954 break;
2955 info.text = text+i+1;
2956 info.samelen = info.len = len-i-1;
2958 if (i > 0) {
2959 strncpy(info.dirmask, text, i+1);
2960 info.dirmask[i+1] = 0;
2961 pstr_sprintf(dirmask, "%s%*s*", cur_dir, i-1, text);
2962 } else
2963 pstr_sprintf(dirmask, "%s*", cur_dir);
2965 if (cli_list(cli, dirmask, aDIR | aSYSTEM | aHIDDEN, completion_remote_filter, &info) < 0)
2966 goto cleanup;
2968 if (info.count == 2)
2969 info.matches[0] = SMB_STRDUP(info.matches[1]);
2970 else {
2971 info.matches[0] = SMB_MALLOC(info.samelen+1);
2972 if (!info.matches[0])
2973 goto cleanup;
2974 strncpy(info.matches[0], info.matches[1], info.samelen);
2975 info.matches[0][info.samelen] = 0;
2977 info.matches[info.count] = NULL;
2978 return info.matches;
2980 cleanup:
2981 for (i = 0; i < info.count; i++)
2982 free(info.matches[i]);
2983 free(info.matches);
2984 return NULL;
2987 static char **completion_fn(const char *text, int start, int end)
2989 smb_readline_ca_char(' ');
2991 if (start) {
2992 const char *buf, *sp;
2993 int i;
2994 char compl_type;
2996 buf = smb_readline_get_line_buffer();
2997 if (buf == NULL)
2998 return NULL;
3000 sp = strchr(buf, ' ');
3001 if (sp == NULL)
3002 return NULL;
3004 for (i = 0; commands[i].name; i++)
3005 if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
3006 break;
3007 if (commands[i].name == NULL)
3008 return NULL;
3010 while (*sp == ' ')
3011 sp++;
3013 if (sp == (buf + start))
3014 compl_type = commands[i].compl_args[0];
3015 else
3016 compl_type = commands[i].compl_args[1];
3018 if (compl_type == COMPL_REMOTE)
3019 return remote_completion(text, end - start);
3020 else /* fall back to local filename completion */
3021 return NULL;
3022 } else {
3023 char **matches;
3024 int i, len, samelen = 0, count=1;
3026 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
3027 if (!matches) {
3028 return NULL;
3030 matches[0] = NULL;
3032 len = strlen(text);
3033 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
3034 if (strncmp(text, commands[i].name, len) == 0) {
3035 matches[count] = SMB_STRDUP(commands[i].name);
3036 if (!matches[count])
3037 goto cleanup;
3038 if (count == 1)
3039 samelen = strlen(matches[count]);
3040 else
3041 while (strncmp(matches[count], matches[count-1], samelen) != 0)
3042 samelen--;
3043 count++;
3047 switch (count) {
3048 case 0: /* should never happen */
3049 case 1:
3050 goto cleanup;
3051 case 2:
3052 matches[0] = SMB_STRDUP(matches[1]);
3053 break;
3054 default:
3055 matches[0] = SMB_MALLOC(samelen+1);
3056 if (!matches[0])
3057 goto cleanup;
3058 strncpy(matches[0], matches[1], samelen);
3059 matches[0][samelen] = 0;
3061 matches[count] = NULL;
3062 return matches;
3064 cleanup:
3065 for (i = 0; i < count; i++)
3066 free(matches[i]);
3068 free(matches);
3069 return NULL;
3073 /****************************************************************************
3074 Make sure we swallow keepalives during idle time.
3075 ****************************************************************************/
3077 static void readline_callback(void)
3079 fd_set fds;
3080 struct timeval timeout;
3081 static time_t last_t;
3082 time_t t;
3084 t = time(NULL);
3086 if (t - last_t < 5)
3087 return;
3089 last_t = t;
3091 again:
3093 if (cli->fd == -1)
3094 return;
3096 FD_ZERO(&fds);
3097 FD_SET(cli->fd,&fds);
3099 timeout.tv_sec = 0;
3100 timeout.tv_usec = 0;
3101 sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
3103 /* We deliberately use receive_smb instead of
3104 client_receive_smb as we want to receive
3105 session keepalives and then drop them here.
3107 if (FD_ISSET(cli->fd,&fds)) {
3108 receive_smb(cli->fd,cli->inbuf,0);
3109 goto again;
3112 cli_chkpath(cli, "\\");
3115 /****************************************************************************
3116 Process commands on stdin.
3117 ****************************************************************************/
3119 static int process_stdin(void)
3121 const char *ptr;
3122 int rc = 0;
3124 while (1) {
3125 pstring tok;
3126 pstring the_prompt;
3127 char *cline;
3128 pstring line;
3129 int i;
3131 /* display a prompt */
3132 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
3133 cline = smb_readline(the_prompt, readline_callback, completion_fn);
3135 if (!cline) break;
3137 pstrcpy(line, cline);
3139 /* special case - first char is ! */
3140 if (*line == '!') {
3141 system(line + 1);
3142 continue;
3145 /* and get the first part of the command */
3146 ptr = line;
3147 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3149 if ((i = process_tok(tok)) >= 0) {
3150 rc = commands[i].fn();
3151 } else if (i == -2) {
3152 d_printf("%s: command abbreviation ambiguous\n",tok);
3153 } else {
3154 d_printf("%s: command not found\n",tok);
3157 return rc;
3160 /****************************************************************************
3161 Process commands from the client.
3162 ****************************************************************************/
3164 static int process(char *base_directory)
3166 int rc = 0;
3168 cli = cli_cm_open(desthost, service, True);
3169 if (!cli) {
3170 return 1;
3173 if (*base_directory) do_cd(base_directory);
3175 if (cmdstr) {
3176 rc = process_command_string(cmdstr);
3177 } else {
3178 process_stdin();
3181 cli_cm_shutdown();
3182 return rc;
3185 /****************************************************************************
3186 Handle a -L query.
3187 ****************************************************************************/
3189 static int do_host_query(char *query_host)
3191 cli = cli_cm_open(query_host, "IPC$", True);
3192 if (!cli)
3193 return 1;
3195 browse_host(True);
3197 if (port != 139) {
3199 /* Workgroups simply don't make sense over anything
3200 else but port 139... */
3202 cli_cm_shutdown();
3203 cli_cm_set_port( 139 );
3204 cli = cli_cm_open(query_host, "IPC$", True);
3207 if (cli == NULL) {
3208 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
3209 return 1;
3212 list_servers(lp_workgroup());
3214 cli_cm_shutdown();
3216 return(0);
3219 /****************************************************************************
3220 Handle a tar operation.
3221 ****************************************************************************/
3223 static int do_tar_op(char *base_directory)
3225 int ret;
3227 /* do we already have a connection? */
3228 if (!cli) {
3229 cli = cli_cm_open(desthost, service, True);
3230 if (!cli)
3231 return 1;
3234 recurse=True;
3236 if (*base_directory) do_cd(base_directory);
3238 ret=process_tar();
3240 cli_cm_shutdown();
3242 return(ret);
3245 /****************************************************************************
3246 Handle a message operation.
3247 ****************************************************************************/
3249 static int do_message_op(void)
3251 struct in_addr ip;
3252 struct nmb_name called, calling;
3253 fstring server_name;
3254 char name_type_hex[10];
3255 int msg_port;
3257 make_nmb_name(&calling, calling_name, 0x0);
3258 make_nmb_name(&called , desthost, name_type);
3260 fstrcpy(server_name, desthost);
3261 snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
3262 fstrcat(server_name, name_type_hex);
3264 zero_ip(&ip);
3265 if (have_ip)
3266 ip = dest_ip;
3268 /* we can only do messages over port 139 (to windows clients at least) */
3270 msg_port = port ? port : 139;
3272 if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, msg_port) != msg_port) ||
3273 !cli_connect(cli, server_name, &ip)) {
3274 d_printf("Connection to %s failed\n", desthost);
3275 return 1;
3278 if (!cli_session_request(cli, &calling, &called)) {
3279 d_printf("session request failed\n");
3280 cli_cm_shutdown();
3281 return 1;
3284 send_message();
3285 cli_cm_shutdown();
3287 return 0;
3291 /****************************************************************************
3292 main program
3293 ****************************************************************************/
3295 int main(int argc,char *argv[])
3297 pstring base_directory;
3298 int opt;
3299 pstring query_host;
3300 BOOL message = False;
3301 pstring term_code;
3302 static const char *new_name_resolve_order = NULL;
3303 poptContext pc;
3304 char *p;
3305 int rc = 0;
3306 fstring new_workgroup;
3307 struct poptOption long_options[] = {
3308 POPT_AUTOHELP
3310 { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
3311 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
3312 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
3313 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
3314 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
3315 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
3316 { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
3317 { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
3318 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
3319 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" },
3320 { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
3321 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
3322 { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
3323 POPT_COMMON_SAMBA
3324 POPT_COMMON_CONNECTION
3325 POPT_COMMON_CREDENTIALS
3326 POPT_TABLEEND
3330 #ifdef KANJI
3331 pstrcpy(term_code, KANJI);
3332 #else /* KANJI */
3333 *term_code = 0;
3334 #endif /* KANJI */
3336 *query_host = 0;
3337 *base_directory = 0;
3339 /* initialize the workgroup name so we can determine whether or
3340 not it was set by a command line option */
3342 set_global_myworkgroup( "" );
3343 set_global_myname( "" );
3345 /* set default debug level to 0 regardless of what smb.conf sets */
3346 setup_logging( "smbclient", True );
3347 DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
3348 dbf = x_stderr;
3349 x_setbuf( x_stderr, NULL );
3351 pc = poptGetContext("smbclient", argc, (const char **) argv, long_options,
3352 POPT_CONTEXT_KEEP_FIRST);
3353 poptSetOtherOptionHelp(pc, "service <password>");
3355 in_client = True; /* Make sure that we tell lp_load we are */
3357 while ((opt = poptGetNextOpt(pc)) != -1) {
3358 switch (opt) {
3359 case 'M':
3360 /* Messages are sent to NetBIOS name type 0x3
3361 * (Messenger Service). Make sure we default
3362 * to port 139 instead of port 445. srl,crh
3364 name_type = 0x03;
3365 cli_cm_set_dest_name_type( name_type );
3366 pstrcpy(desthost,poptGetOptArg(pc));
3367 if( !port )
3368 cli_cm_set_port( 139 );
3369 message = True;
3370 break;
3371 case 'I':
3373 dest_ip = *interpret_addr2(poptGetOptArg(pc));
3374 if (is_zero_ip(dest_ip))
3375 exit(1);
3376 have_ip = True;
3378 cli_cm_set_dest_ip( dest_ip );
3380 break;
3381 case 'E':
3382 dbf = x_stderr;
3383 display_set_stderr();
3384 break;
3386 case 'L':
3387 pstrcpy(query_host, poptGetOptArg(pc));
3388 break;
3389 case 't':
3390 pstrcpy(term_code, poptGetOptArg(pc));
3391 break;
3392 case 'm':
3393 max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol);
3394 break;
3395 case 'T':
3396 /* We must use old option processing for this. Find the
3397 * position of the -T option in the raw argv[]. */
3399 int i, optnum;
3400 for (i = 1; i < argc; i++) {
3401 if (strncmp("-T", argv[i],2)==0)
3402 break;
3404 i++;
3405 if (!(optnum = tar_parseargs(argc, argv, poptGetOptArg(pc), i))) {
3406 poptPrintUsage(pc, stderr, 0);
3407 exit(1);
3409 /* Now we must eat (optnum - i) options - they have
3410 * been processed by tar_parseargs().
3412 optnum -= i;
3413 for (i = 0; i < optnum; i++)
3414 poptGetOptArg(pc);
3416 break;
3417 case 'D':
3418 pstrcpy(base_directory,poptGetOptArg(pc));
3419 break;
3420 case 'g':
3421 grepable=True;
3422 break;
3426 poptGetArg(pc);
3428 if ( have_ip )
3431 * Don't load debug level from smb.conf. It should be
3432 * set by cmdline arg or remain default (0)
3434 AllowDebugChange = False;
3436 /* save the workgroup...
3438 FIXME!! do we need to do this for other options as well
3439 (or maybe a generic way to keep lp_load() from overwriting
3440 everything)? */
3442 fstrcpy( new_workgroup, lp_workgroup() );
3443 pstrcpy( calling_name, global_myname() );
3445 if ( override_logfile )
3446 setup_logging( lp_logfile(), False );
3448 if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
3449 fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
3450 argv[0], dyn_CONFIGFILE);
3453 load_interfaces();
3455 if ( strlen(new_workgroup) != 0 )
3456 set_global_myworkgroup( new_workgroup );
3458 if ( strlen(calling_name) != 0 )
3459 set_global_myname( calling_name );
3461 if(poptPeekArg(pc)) {
3462 pstrcpy(service,poptGetArg(pc));
3463 /* Convert any '/' characters in the service name to '\' characters */
3464 string_replace(service, '/','\\');
3466 if (count_chars(service,'\\') < 3) {
3467 d_printf("\n%s: Not enough '\\' characters in service\n",service);
3468 poptPrintUsage(pc, stderr, 0);
3469 exit(1);
3473 if (poptPeekArg(pc) && !cmdline_auth_info.got_pass) {
3474 cmdline_auth_info.got_pass = True;
3475 pstrcpy(cmdline_auth_info.password,poptGetArg(pc));
3478 init_names();
3480 if(new_name_resolve_order)
3481 lp_set_name_resolve_order(new_name_resolve_order);
3483 if (!tar_type && !*query_host && !*service && !message) {
3484 poptPrintUsage(pc, stderr, 0);
3485 exit(1);
3488 poptFreeContext(pc);
3490 /* store the username an password for dfs support */
3492 cli_cm_set_credentials( &cmdline_auth_info );
3493 pstrcpy(username, cmdline_auth_info.username);
3495 DEBUG(3,("Client started (version %s).\n", SAMBA_VERSION_STRING));
3497 if (tar_type) {
3498 if (cmdstr)
3499 process_command_string(cmdstr);
3500 return do_tar_op(base_directory);
3503 if (*query_host) {
3504 char *qhost = query_host;
3505 char *slash;
3507 while (*qhost == '\\' || *qhost == '/')
3508 qhost++;
3510 if ((slash = strchr_m(qhost, '/'))
3511 || (slash = strchr_m(qhost, '\\'))) {
3512 *slash = 0;
3515 if ((p=strchr_m(qhost, '#'))) {
3516 *p = 0;
3517 p++;
3518 sscanf(p, "%x", &name_type);
3519 cli_cm_set_dest_name_type( name_type );
3522 return do_host_query(qhost);
3525 if (message) {
3526 return do_message_op();
3529 if (process(base_directory)) {
3530 return 1;
3533 return rc;