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 8 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. 13 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. 18 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. 22*/ 23 24#define NO_SYSLOG 25 26#include "includes.h" 27#include "client/client_proto.h" 28#ifndef REGISTER 29#define REGISTER 0 30#endif 31 32extern BOOL in_client; 33static int port = 0; 34pstring cur_dir = "\\"; 35static pstring cd_path = ""; 36static pstring service; 37static pstring desthost; 38static pstring username; 39static pstring calling_name; 40static BOOL grepable=False; 41static char *cmdstr = NULL; 42 43static int io_bufsize = 64512; 44 45static int name_type = 0x20; 46extern int max_protocol; 47 48static int process_tok(pstring tok); 49static int cmd_help(void); 50 51/* 30 second timeout on most commands */ 52#define CLIENT_TIMEOUT (30*1000) 53#define SHORT_TIMEOUT (5*1000) 54 55/* value for unused fid field in trans2 secondary request */ 56#define FID_UNUSED (0xFFFF) 57 58time_t newer_than = 0; 59static int archive_level = 0; 60 61static BOOL translation = False; 62static BOOL have_ip; 63 64/* clitar bits insert */ 65extern int blocksize; 66extern BOOL tar_inc; 67extern BOOL tar_reset; 68/* clitar bits end */ 69 70 71static BOOL prompt = True; 72 73static int printmode = 1; 74 75static BOOL recurse = False; 76BOOL lowercase = False; 77 78static struct in_addr dest_ip; 79 80#define SEPARATORS " \t\n\r" 81 82static BOOL abort_mget = True; 83 84static pstring fileselection = ""; 85 86extern file_info def_finfo; 87 88/* timing globals */ 89SMB_BIG_UINT get_total_size = 0; 90unsigned int get_total_time_ms = 0; 91static SMB_BIG_UINT put_total_size = 0; 92static unsigned int put_total_time_ms = 0; 93 94/* totals globals */ 95static double dir_total; 96 97/* root cli_state connection */ 98 99struct cli_state *cli; 100 101 102 103/**************************************************************************** 104 Write to a local file with CR/LF->LF translation if appropriate. Return the 105 number taken from the buffer. This may not equal the number written. 106****************************************************************************/ 107 108static int writefile(int f, char *b, int n) 109{ 110 int i; 111 112 if (!translation) { 113 return write(f,b,n); 114 } 115 116 i = 0; 117 while (i < n) { 118 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') { 119 b++;i++; 120 } 121 if (write(f, b, 1) != 1) { 122 break; 123 } 124 b++; 125 i++; 126 } 127 128 return(i); 129} 130 131/**************************************************************************** 132 Read from a file with LF->CR/LF translation if appropriate. Return the 133 number read. read approx n bytes. 134****************************************************************************/ 135 136static int readfile(char *b, int n, XFILE *f) 137{ 138 int i; 139 int c; 140 141 if (!translation) 142 return x_fread(b,1,n,f); 143 144 i = 0; 145 while (i < (n - 1) && (i < BUFFER_SIZE)) { 146 if ((c = x_getc(f)) == EOF) { 147 break; 148 } 149 150 if (c == '\n') { /* change all LFs to CR/LF */ 151 b[i++] = '\r'; 152 } 153 154 b[i++] = c; 155 } 156 157 return(i); 158} 159 160/**************************************************************************** 161 Send a message. 162****************************************************************************/ 163 164static void send_message(void) 165{ 166 int total_len = 0; 167 int grp_id; 168 169 if (!cli_message_start(cli, desthost, username, &grp_id)) { 170 d_printf("message start: %s\n", cli_errstr(cli)); 171 return; 172 } 173 174 175 d_printf("Connected. Type your message, ending it with a Control-D\n"); 176 177 while (!feof(stdin) && total_len < 1600) { 178 int maxlen = MIN(1600 - total_len,127); 179 pstring msg; 180 int l=0; 181 int c; 182 183 ZERO_ARRAY(msg); 184 185 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) { 186 if (c == '\n') 187 msg[l++] = '\r'; 188 msg[l] = c; 189 } 190 191 if (!cli_message_text(cli, msg, l, grp_id)) { 192 d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli)); 193 return; 194 } 195 196 total_len += l; 197 } 198 199 if (total_len >= 1600) 200 d_printf("the message was truncated to 1600 bytes\n"); 201 else 202 d_printf("sent %d bytes\n",total_len); 203 204 if (!cli_message_end(cli, grp_id)) { 205 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli)); 206 return; 207 } 208} 209 210/**************************************************************************** 211 Check the space on a device. 212****************************************************************************/ 213 214static int do_dskattr(void) 215{ 216 int total, bsize, avail; 217 struct cli_state *targetcli; 218 pstring targetpath; 219 220 if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) { 221 d_printf("Error in dskattr: %s\n", cli_errstr(cli)); 222 return 1; 223 } 224 225 if (!cli_dskattr(targetcli, &bsize, &total, &avail)) { 226 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli)); 227 return 1; 228 } 229 230 d_printf("\n\t\t%d blocks of size %d. %d blocks available\n", 231 total, bsize, avail); 232 233 return 0; 234} 235 236/**************************************************************************** 237 Show cd/pwd. 238****************************************************************************/ 239 240static int cmd_pwd(void) 241{ 242 d_printf("Current directory is %s",service); 243 d_printf("%s\n",cur_dir); 244 return 0; 245} 246 247/**************************************************************************** 248 Change directory - inner section. 249****************************************************************************/ 250 251static int do_cd(char *newdir) 252{ 253 char *p = newdir; 254 pstring saved_dir; 255 pstring dname; 256 pstring targetpath; 257 struct cli_state *targetcli; 258 SMB_STRUCT_STAT sbuf; 259 uint32 attributes; 260 261 dos_format(newdir); 262 263 /* Save the current directory in case the new directory is invalid */ 264 265 pstrcpy(saved_dir, cur_dir); 266 267 if (*p == '\\') 268 pstrcpy(cur_dir,p); 269 else 270 pstrcat(cur_dir,p); 271 272 if (*(cur_dir+strlen(cur_dir)-1) != '\\') { 273 pstrcat(cur_dir, "\\"); 274 } 275 276 dos_clean_name(cur_dir); 277 pstrcpy( dname, cur_dir ); 278 pstrcat(cur_dir,"\\"); 279 dos_clean_name(cur_dir); 280 281 if ( !cli_resolve_path( "", cli, dname, &targetcli, targetpath ) ) { 282 d_printf("cd %s: %s\n", dname, cli_errstr(cli)); 283 pstrcpy(cur_dir,saved_dir); 284 goto out; 285 } 286 287 288 if ( strequal(targetpath,"\\" ) ) 289 return 0; 290 291 /* use a trans2_qpathinfo to test directories for modern servers */ 292 293 if ( targetcli->protocol >= PROTOCOL_LANMAN2 ) { 294 if ( !cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) { 295 d_printf("cd %s: %s\n", dname, cli_errstr(targetcli)); 296 pstrcpy(cur_dir,saved_dir); 297 goto out; 298 } 299 300 if ( !(attributes&FILE_ATTRIBUTE_DIRECTORY) ) { 301 d_printf("cd %s: not a directory\n", dname); 302 pstrcpy(cur_dir,saved_dir); 303 goto out; 304 } 305 } 306 else { 307 pstrcat( targetpath, "\\" ); 308 dos_clean_name( targetpath ); 309 310 if ( !cli_chkpath(targetcli, targetpath) ) { 311 d_printf("cd %s: %s\n", dname, cli_errstr(targetcli)); 312 pstrcpy(cur_dir,saved_dir); 313 } 314 } 315 316out: 317 pstrcpy(cd_path,cur_dir); 318 319 return 0; 320} 321 322/**************************************************************************** 323 Change directory. 324****************************************************************************/ 325 326static int cmd_cd(void) 327{ 328 pstring buf; 329 int rc = 0; 330 331 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) 332 rc = do_cd(buf); 333 else 334 d_printf("Current directory is %s\n",cur_dir); 335 336 return rc; 337} 338 339/******************************************************************* 340 Decide if a file should be operated on. 341********************************************************************/ 342 343static BOOL do_this_one(file_info *finfo) 344{ 345 if (finfo->mode & aDIR) 346 return(True); 347 348 if (*fileselection && 349 !mask_match(finfo->name,fileselection,False)) { 350 DEBUG(3,("mask_match %s failed\n", finfo->name)); 351 return False; 352 } 353 354 if (newer_than && finfo->mtime < newer_than) { 355 DEBUG(3,("newer_than %s failed\n", finfo->name)); 356 return(False); 357 } 358 359 if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) { 360 DEBUG(3,("archive %s failed\n", finfo->name)); 361 return(False); 362 } 363 364 return(True); 365} 366 367/**************************************************************************** 368 Display info about a file. 369****************************************************************************/ 370 371static void display_finfo(file_info *finfo) 372{ 373 if (do_this_one(finfo)) { 374 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */ 375 d_printf(" %-30s%7.7s %8.0f %s", 376 finfo->name, 377 attrib_string(finfo->mode), 378 (double)finfo->size, 379 asctime(LocalTime(&t))); 380 dir_total += finfo->size; 381 } 382} 383 384/**************************************************************************** 385 Accumulate size of a file. 386****************************************************************************/ 387 388static void do_du(file_info *finfo) 389{ 390 if (do_this_one(finfo)) { 391 dir_total += finfo->size; 392 } 393} 394 395static BOOL do_list_recurse; 396static BOOL do_list_dirs; 397static char *do_list_queue = 0; 398static long do_list_queue_size = 0; 399static long do_list_queue_start = 0; 400static long do_list_queue_end = 0; 401static void (*do_list_fn)(file_info *); 402 403/**************************************************************************** 404 Functions for do_list_queue. 405****************************************************************************/ 406 407/* 408 * The do_list_queue is a NUL-separated list of strings stored in a 409 * char*. Since this is a FIFO, we keep track of the beginning and 410 * ending locations of the data in the queue. When we overflow, we 411 * double the size of the char*. When the start of the data passes 412 * the midpoint, we move everything back. This is logically more 413 * complex than a linked list, but easier from a memory management 414 * angle. In any memory error condition, do_list_queue is reset. 415 * Functions check to ensure that do_list_queue is non-NULL before 416 * accessing it. 417 */ 418 419static void reset_do_list_queue(void) 420{ 421 SAFE_FREE(do_list_queue); 422 do_list_queue_size = 0; 423 do_list_queue_start = 0; 424 do_list_queue_end = 0; 425} 426 427static void init_do_list_queue(void) 428{ 429 reset_do_list_queue(); 430 do_list_queue_size = 1024; 431 do_list_queue = SMB_MALLOC(do_list_queue_size); 432 if (do_list_queue == 0) { 433 d_printf("malloc fail for size %d\n", 434 (int)do_list_queue_size); 435 reset_do_list_queue(); 436 } else { 437 memset(do_list_queue, 0, do_list_queue_size); 438 } 439} 440 441static void adjust_do_list_queue(void) 442{ 443 /* 444 * If the starting point of the queue is more than half way through, 445 * move everything toward the beginning. 446 */ 447 if (do_list_queue && (do_list_queue_start == do_list_queue_end)) { 448 DEBUG(4,("do_list_queue is empty\n")); 449 do_list_queue_start = do_list_queue_end = 0; 450 *do_list_queue = '\0'; 451 } else if (do_list_queue_start > (do_list_queue_size / 2)) { 452 DEBUG(4,("sliding do_list_queue backward\n")); 453 memmove(do_list_queue, 454 do_list_queue + do_list_queue_start, 455 do_list_queue_end - do_list_queue_start); 456 do_list_queue_end -= do_list_queue_start; 457 do_list_queue_start = 0; 458 } 459} 460 461static void add_to_do_list_queue(const char* entry) 462{ 463 char *dlq; 464 long new_end = do_list_queue_end + ((long)strlen(entry)) + 1; 465 while (new_end > do_list_queue_size) { 466 do_list_queue_size *= 2; 467 DEBUG(4,("enlarging do_list_queue to %d\n", 468 (int)do_list_queue_size)); 469 dlq = SMB_REALLOC(do_list_queue, do_list_queue_size); 470 if (! dlq) { 471 d_printf("failure enlarging do_list_queue to %d bytes\n", 472 (int)do_list_queue_size); 473 reset_do_list_queue(); 474 } else { 475 do_list_queue = dlq; 476 memset(do_list_queue + do_list_queue_size / 2, 477 0, do_list_queue_size / 2); 478 } 479 } 480 if (do_list_queue) { 481 safe_strcpy_base(do_list_queue + do_list_queue_end, 482 entry, do_list_queue, do_list_queue_size); 483 do_list_queue_end = new_end; 484 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n", 485 entry, (int)do_list_queue_start, (int)do_list_queue_end)); 486 } 487} 488 489static char *do_list_queue_head(void) 490{ 491 return do_list_queue + do_list_queue_start; 492} 493 494static void remove_do_list_queue_head(void) 495{ 496 if (do_list_queue_end > do_list_queue_start) { 497 do_list_queue_start += strlen(do_list_queue_head()) + 1; 498 adjust_do_list_queue(); 499 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n", 500 (int)do_list_queue_start, (int)do_list_queue_end)); 501 } 502} 503 504static int do_list_queue_empty(void) 505{ 506 return (! (do_list_queue && *do_list_queue)); 507} 508 509/**************************************************************************** 510 A helper for do_list. 511****************************************************************************/ 512 513static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state) 514{ 515 if (f->mode & aDIR) { 516 if (do_list_dirs && do_this_one(f)) { 517 do_list_fn(f); 518 } 519 if (do_list_recurse && 520 !strequal(f->name,".") && 521 !strequal(f->name,"..")) { 522 pstring mask2; 523 char *p; 524 525 if (!f->name[0]) { 526 d_printf("Empty dir name returned. Possible server misconfiguration.\n"); 527 return; 528 } 529 530 pstrcpy(mask2, mntpoint); 531 pstrcat(mask2, mask); 532 p = strrchr_m(mask2,'\\'); 533 if (!p) 534 return; 535 p[1] = 0; 536 pstrcat(mask2, f->name); 537 pstrcat(mask2,"\\*"); 538 add_to_do_list_queue(mask2); 539 } 540 return; 541 } 542 543 if (do_this_one(f)) { 544 do_list_fn(f); 545 } 546} 547 548/**************************************************************************** 549 A wrapper around cli_list that adds recursion. 550****************************************************************************/ 551 552void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs) 553{ 554 static int in_do_list = 0; 555 struct cli_state *targetcli; 556 pstring targetpath; 557 558 if (in_do_list && rec) { 559 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n"); 560 exit(1); 561 } 562 563 in_do_list = 1; 564 565 do_list_recurse = rec; 566 do_list_dirs = dirs; 567 do_list_fn = fn; 568 569 if (rec) { 570 init_do_list_queue(); 571 add_to_do_list_queue(mask); 572 573 while (! do_list_queue_empty()) { 574 /* 575 * Need to copy head so that it doesn't become 576 * invalid inside the call to cli_list. This 577 * would happen if the list were expanded 578 * during the call. 579 * Fix from E. Jay Berkenbilt (ejb@ql.org) 580 */ 581 pstring head; 582 pstrcpy(head, do_list_queue_head()); 583 584 /* check for dfs */ 585 586 if ( !cli_resolve_path( "", cli, head, &targetcli, targetpath ) ) { 587 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli)); 588 remove_do_list_queue_head(); 589 continue; 590 } 591 592 cli_list(targetcli, targetpath, attribute, do_list_helper, NULL); 593 remove_do_list_queue_head(); 594 if ((! do_list_queue_empty()) && (fn == display_finfo)) { 595 char* next_file = do_list_queue_head(); 596 char* save_ch = 0; 597 if ((strlen(next_file) >= 2) && 598 (next_file[strlen(next_file) - 1] == '*') && 599 (next_file[strlen(next_file) - 2] == '\\')) { 600 save_ch = next_file + 601 strlen(next_file) - 2; 602 *save_ch = '\0'; 603 } 604 d_printf("\n%s\n",next_file); 605 if (save_ch) { 606 *save_ch = '\\'; 607 } 608 } 609 } 610 } else { 611 /* check for dfs */ 612 613 if ( cli_resolve_path( "", cli, mask, &targetcli, targetpath ) ) { 614 if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) 615 d_printf("%s listing %s\n", cli_errstr(targetcli), targetpath); 616 } 617 else 618 d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli)); 619 620 } 621 622 in_do_list = 0; 623 reset_do_list_queue(); 624} 625 626/**************************************************************************** 627 Get a directory listing. 628****************************************************************************/ 629 630static int cmd_dir(void) 631{ 632 uint16 attribute = aDIR | aSYSTEM | aHIDDEN; 633 pstring mask; 634 pstring buf; 635 char *p=buf; 636 int rc; 637 638 dir_total = 0; 639 if (strcmp(cur_dir, "\\") != 0) { 640 pstrcpy(mask,cur_dir); 641 if(mask[strlen(mask)-1]!='\\') 642 pstrcat(mask,"\\"); 643 } else { 644 pstrcpy(mask, "\\"); 645 } 646 647 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) { 648 dos_format(p); 649 if (*p == '\\') 650 pstrcpy(mask,p + 1); 651 else 652 pstrcat(mask,p); 653 } else { 654 pstrcat(mask,"*"); 655 } 656 657 do_list(mask, attribute, display_finfo, recurse, True); 658 659 rc = do_dskattr(); 660 661 DEBUG(3, ("Total bytes listed: %.0f\n", dir_total)); 662 663 return rc; 664} 665 666/**************************************************************************** 667 Get a directory listing. 668****************************************************************************/ 669 670static int cmd_du(void) 671{ 672 uint16 attribute = aDIR | aSYSTEM | aHIDDEN; 673 pstring mask; 674 pstring buf; 675 char *p=buf; 676 int rc; 677 678 dir_total = 0; 679 pstrcpy(mask,cur_dir); 680 if(mask[strlen(mask)-1]!='\\') 681 pstrcat(mask,"\\"); 682 683 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) { 684 dos_format(p); 685 if (*p == '\\') 686 pstrcpy(mask,p); 687 else 688 pstrcat(mask,p); 689 } else { 690 pstrcat(mask,"*"); 691 } 692 693 do_list(mask, attribute, do_du, recurse, True); 694 695 rc = do_dskattr(); 696 697 d_printf("Total number of bytes: %.0f\n", dir_total); 698 699 return rc; 700} 701 702/**************************************************************************** 703 Get a file from rname to lname 704****************************************************************************/ 705 706static int do_get(char *rname, char *lname, BOOL reget) 707{ 708 int handle = 0, fnum; 709 BOOL newhandle = False; 710 char *data; 711 struct timeval tp_start; 712 int read_size = io_bufsize; 713 uint16 attr; 714 size_t size; 715 off_t start = 0; 716 off_t nread = 0; 717 int rc = 0; 718 struct cli_state *targetcli; 719 pstring targetname; 720 721 722 if (lowercase) { 723 strlower_m(lname); 724 } 725 726 if ( !cli_resolve_path( "", cli, rname, &targetcli, targetname ) ) { 727 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli)); 728 return 1; 729 } 730 731 732 GetTimeOfDay(&tp_start); 733 734 fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE); 735 736 if (fnum == -1) { 737 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname); 738 return 1; 739 } 740 741 if(!strcmp(lname,"-")) { 742 handle = fileno(stdout); 743 } else { 744 if (reget) { 745 handle = sys_open(lname, O_WRONLY|O_CREAT, 0644); 746 if (handle >= 0) { 747 start = sys_lseek(handle, 0, SEEK_END); 748 if (start == -1) { 749 d_printf("Error seeking local file\n"); 750 return 1; 751 } 752 } 753 } else { 754 handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644); 755 } 756 newhandle = True; 757 } 758 if (handle < 0) { 759 d_printf("Error opening local file %s\n",lname); 760 return 1; 761 } 762 763 764 if (!cli_qfileinfo(targetcli, fnum, 765 &attr, &size, NULL, NULL, NULL, NULL, NULL) && 766 !cli_getattrE(targetcli, fnum, 767 &attr, &size, NULL, NULL, NULL)) { 768 d_printf("getattrib: %s\n",cli_errstr(targetcli)); 769 return 1; 770 } 771 772 DEBUG(1,("getting file %s of size %.0f as %s ", 773 rname, (double)size, lname)); 774 775 if(!(data = (char *)SMB_MALLOC(read_size))) { 776 d_printf("malloc fail for size %d\n", read_size); 777 cli_close(targetcli, fnum); 778 return 1; 779 } 780 781 while (1) { 782 int n = cli_read(targetcli, fnum, data, nread + start, read_size); 783 784 if (n <= 0) 785 break; 786 787 if (writefile(handle,data, n) != n) { 788 d_printf("Error writing local file\n"); 789 rc = 1; 790 break; 791 } 792 793 nread += n; 794 } 795 796 if (nread + start < size) { 797 DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n", 798 rname, (long)nread)); 799 800 rc = 1; 801 } 802 803 SAFE_FREE(data); 804 805 if (!cli_close(targetcli, fnum)) { 806 d_printf("Error %s closing remote file\n",cli_errstr(cli)); 807 rc = 1; 808 } 809 810 if (newhandle) { 811 close(handle); 812 } 813 814 if (archive_level >= 2 && (attr & aARCH)) { 815 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0); 816 } 817 818 { 819 struct timeval tp_end; 820 int this_time; 821 822 GetTimeOfDay(&tp_end); 823 this_time = 824 (tp_end.tv_sec - tp_start.tv_sec)*1000 + 825 (tp_end.tv_usec - tp_start.tv_usec)/1000; 826 get_total_time_ms += this_time; 827 get_total_size += nread; 828 829 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n", 830 nread / (1.024*this_time + 1.0e-4), 831 get_total_size / (1.024*get_total_time_ms))); 832 } 833 834 return rc; 835} 836 837/**************************************************************************** 838 Get a file. 839****************************************************************************/ 840 841static int cmd_get(void) 842{ 843 pstring lname; 844 pstring rname; 845 char *p; 846 847 pstrcpy(rname,cur_dir); 848 pstrcat(rname,"\\"); 849 850 p = rname + strlen(rname); 851 852 if (!next_token_nr(NULL,p,NULL,sizeof(rname)-strlen(rname))) { 853 d_printf("get <filename>\n"); 854 return 1; 855 } 856 pstrcpy(lname,p); 857 dos_clean_name(rname); 858 859 next_token_nr(NULL,lname,NULL,sizeof(lname)); 860 861 return do_get(rname, lname, False); 862} 863 864/**************************************************************************** 865 Do an mget operation on one file. 866****************************************************************************/ 867 868static void do_mget(file_info *finfo) 869{ 870 pstring rname; 871 pstring quest; 872 pstring saved_curdir; 873 pstring mget_mask; 874 875 if (strequal(finfo->name,".") || strequal(finfo->name,"..")) 876 return; 877 878 if (abort_mget) { 879 d_printf("mget aborted\n"); 880 return; 881 } 882 883 if (finfo->mode & aDIR) 884 slprintf(quest,sizeof(pstring)-1, 885 "Get directory %s? ",finfo->name); 886 else 887 slprintf(quest,sizeof(pstring)-1, 888 "Get file %s? ",finfo->name); 889 890 if (prompt && !yesno(quest)) 891 return; 892 893 if (!(finfo->mode & aDIR)) { 894 pstrcpy(rname,cur_dir); 895 pstrcat(rname,finfo->name); 896 do_get(rname, finfo->name, False); 897 return; 898 } 899 900 /* handle directories */ 901 pstrcpy(saved_curdir,cur_dir); 902 903 pstrcat(cur_dir,finfo->name); 904 pstrcat(cur_dir,"\\"); 905 906 unix_format(finfo->name); 907 if (lowercase) 908 strlower_m(finfo->name); 909 910 if (!directory_exist(finfo->name,NULL) && 911 mkdir(finfo->name,0777) != 0) { 912 d_printf("failed to create directory %s\n",finfo->name); 913 pstrcpy(cur_dir,saved_curdir); 914 return; 915 } 916 917 if (chdir(finfo->name) != 0) { 918 d_printf("failed to chdir to directory %s\n",finfo->name); 919 pstrcpy(cur_dir,saved_curdir); 920 return; 921 } 922 923 pstrcpy(mget_mask,cur_dir); 924 pstrcat(mget_mask,"*"); 925 926 do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,False, True); 927 chdir(".."); 928 pstrcpy(cur_dir,saved_curdir); 929} 930 931/**************************************************************************** 932 View the file using the pager. 933****************************************************************************/ 934 935static int cmd_more(void) 936{ 937 pstring rname,lname,pager_cmd; 938 char *pager; 939 int fd; 940 int rc = 0; 941 942 pstrcpy(rname,cur_dir); 943 pstrcat(rname,"\\"); 944 945 slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir()); 946 fd = smb_mkstemp(lname); 947 if (fd == -1) { 948 d_printf("failed to create temporary file for more\n"); 949 return 1; 950 } 951 close(fd); 952 953 if (!next_token_nr(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) { 954 d_printf("more <filename>\n"); 955 unlink(lname); 956 return 1; 957 } 958 dos_clean_name(rname); 959 960 rc = do_get(rname, lname, False); 961 962 pager=getenv("PAGER"); 963 964 slprintf(pager_cmd,sizeof(pager_cmd)-1, 965 "%s %s",(pager? pager:PAGER), lname); 966 system(pager_cmd); 967 unlink(lname); 968 969 return rc; 970} 971 972/**************************************************************************** 973 Do a mget command. 974****************************************************************************/ 975 976static int cmd_mget(void) 977{ 978 uint16 attribute = aSYSTEM | aHIDDEN; 979 pstring mget_mask; 980 pstring buf; 981 char *p=buf; 982 983 *mget_mask = 0; 984 985 if (recurse) 986 attribute |= aDIR; 987 988 abort_mget = False; 989 990 while (next_token_nr(NULL,p,NULL,sizeof(buf))) { 991 pstrcpy(mget_mask,cur_dir); 992 if(mget_mask[strlen(mget_mask)-1]!='\\') 993 pstrcat(mget_mask,"\\"); 994 995 if (*p == '\\') 996 pstrcpy(mget_mask,p); 997 else 998 pstrcat(mget_mask,p); 999 do_list(mget_mask, attribute,do_mget,False,True); 1000 } 1001 1002 if (!*mget_mask) { 1003 pstrcpy(mget_mask,cur_dir); 1004 if(mget_mask[strlen(mget_mask)-1]!='\\') 1005 pstrcat(mget_mask,"\\"); 1006 pstrcat(mget_mask,"*"); 1007 do_list(mget_mask, attribute,do_mget,False,True); 1008 } 1009 1010 return 0; 1011} 1012 1013/**************************************************************************** 1014 Make a directory of name "name". 1015****************************************************************************/ 1016 1017static BOOL do_mkdir(char *name) 1018{ 1019 struct cli_state *targetcli; 1020 pstring targetname; 1021 1022 if ( !cli_resolve_path( "", cli, name, &targetcli, targetname ) ) { 1023 d_printf("mkdir %s: %s\n", name, cli_errstr(cli)); 1024 return False; 1025 } 1026 1027 if (!cli_mkdir(targetcli, targetname)) { 1028 d_printf("%s making remote directory %s\n", 1029 cli_errstr(targetcli),name); 1030 return(False); 1031 } 1032 1033 return(True); 1034} 1035 1036/**************************************************************************** 1037 Show 8.3 name of a file. 1038****************************************************************************/ 1039 1040static BOOL do_altname(char *name) 1041{ 1042 pstring altname; 1043 if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) { 1044 d_printf("%s getting alt name for %s\n", 1045 cli_errstr(cli),name); 1046 return(False); 1047 } 1048 d_printf("%s\n", altname); 1049 1050 return(True); 1051} 1052 1053/**************************************************************************** 1054 Exit client. 1055****************************************************************************/ 1056 1057static int cmd_quit(void) 1058{ 1059 cli_cm_shutdown(); 1060 exit(0); 1061 /* NOTREACHED */ 1062 return 0; 1063} 1064 1065/**************************************************************************** 1066 Make a directory. 1067****************************************************************************/ 1068 1069static int cmd_mkdir(void) 1070{ 1071 pstring mask; 1072 pstring buf; 1073 char *p=buf; 1074 1075 pstrcpy(mask,cur_dir); 1076 1077 if (!next_token_nr(NULL,p,NULL,sizeof(buf))) { 1078 if (!recurse) 1079 d_printf("mkdir <dirname>\n"); 1080 return 1; 1081 } 1082 pstrcat(mask,p); 1083 1084 if (recurse) { 1085 pstring ddir; 1086 pstring ddir2; 1087 *ddir2 = 0; 1088 1089 pstrcpy(ddir,mask); 1090 trim_char(ddir,'.','\0'); 1091 p = strtok(ddir,"/\\"); 1092 while (p) { 1093 pstrcat(ddir2,p); 1094 if (!cli_chkpath(cli, ddir2)) { 1095 do_mkdir(ddir2); 1096 } 1097 pstrcat(ddir2,"\\"); 1098 p = strtok(NULL,"/\\"); 1099 } 1100 } else { 1101 do_mkdir(mask); 1102 } 1103 1104 return 0; 1105} 1106 1107/**************************************************************************** 1108 Show alt name. 1109****************************************************************************/ 1110 1111static int cmd_altname(void) 1112{ 1113 pstring name; 1114 pstring buf; 1115 char *p=buf; 1116 1117 pstrcpy(name,cur_dir); 1118 1119 if (!next_token_nr(NULL,p,NULL,sizeof(buf))) { 1120 d_printf("altname <file>\n"); 1121 return 1; 1122 } 1123 pstrcat(name,p); 1124 1125 do_altname(name); 1126 1127 return 0; 1128} 1129 1130/**************************************************************************** 1131 Put a single file. 1132****************************************************************************/ 1133 1134static int do_put(char *rname, char *lname, BOOL reput) 1135{ 1136 int fnum; 1137 XFILE *f; 1138 size_t start = 0; 1139 off_t nread = 0; 1140 char *buf = NULL; 1141 int maxwrite = io_bufsize; 1142 int rc = 0; 1143 struct timeval tp_start; 1144 struct cli_state *targetcli; 1145 pstring targetname; 1146 1147 if ( !cli_resolve_path( "", cli, rname, &targetcli, targetname ) ) { 1148 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli)); 1149 return 1; 1150 } 1151 1152 GetTimeOfDay(&tp_start); 1153 1154 if (reput) { 1155 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE); 1156 if (fnum >= 0) { 1157 if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) && 1158 !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) { 1159 d_printf("getattrib: %s\n",cli_errstr(cli)); 1160 return 1; 1161 } 1162 } 1163 } else { 1164 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE); 1165 } 1166 1167 if (fnum == -1) { 1168 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname); 1169 return 1; 1170 } 1171 1172 /* allow files to be piped into smbclient 1173 jdblair 24.jun.98 1174 1175 Note that in this case this function will exit(0) rather 1176 than returning. */ 1177 if (!strcmp(lname, "-")) { 1178 f = x_stdin; 1179 /* size of file is not known */ 1180 } else { 1181 f = x_fopen(lname,O_RDONLY, 0); 1182 if (f && reput) { 1183 if (x_tseek(f, start, SEEK_SET) == -1) { 1184 d_printf("Error seeking local file\n"); 1185 return 1; 1186 } 1187 } 1188 } 1189 1190 if (!f) { 1191 d_printf("Error opening local file %s\n",lname); 1192 return 1; 1193 } 1194 1195 DEBUG(1,("putting file %s as %s ",lname, 1196 rname)); 1197 1198 buf = (char *)SMB_MALLOC(maxwrite); 1199 if (!buf) { 1200 d_printf("ERROR: Not enough memory!\n"); 1201 return 1; 1202 } 1203 while (!x_feof(f)) { 1204 int n = maxwrite; 1205 int ret; 1206 1207 if ((n = readfile(buf,n,f)) < 1) { 1208 if((n == 0) && x_feof(f)) 1209 break; /* Empty local file. */ 1210 1211 d_printf("Error reading local file: %s\n", strerror(errno)); 1212 rc = 1; 1213 break; 1214 } 1215 1216 ret = cli_write(targetcli, fnum, 0, buf, nread + start, n); 1217 1218 if (n != ret) { 1219 d_printf("Error writing file: %s\n", cli_errstr(cli)); 1220 rc = 1; 1221 break; 1222 } 1223 1224 nread += n; 1225 } 1226 1227 if (!cli_close(targetcli, fnum)) { 1228 d_printf("%s closing remote file %s\n",cli_errstr(cli),rname); 1229 x_fclose(f); 1230 SAFE_FREE(buf); 1231 return 1; 1232 } 1233 1234 1235 if (f != x_stdin) { 1236 x_fclose(f); 1237 } 1238 1239 SAFE_FREE(buf); 1240 1241 { 1242 struct timeval tp_end; 1243 int this_time; 1244 1245 GetTimeOfDay(&tp_end); 1246 this_time = 1247 (tp_end.tv_sec - tp_start.tv_sec)*1000 + 1248 (tp_end.tv_usec - tp_start.tv_usec)/1000; 1249 put_total_time_ms += this_time; 1250 put_total_size += nread; 1251 1252 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n", 1253 nread / (1.024*this_time + 1.0e-4), 1254 put_total_size / (1.024*put_total_time_ms))); 1255 } 1256 1257 if (f == x_stdin) { 1258 cli_cm_shutdown(); 1259 exit(0); 1260 } 1261 1262 return rc; 1263} 1264 1265/**************************************************************************** 1266 Put a file. 1267****************************************************************************/ 1268 1269static int cmd_put(void) 1270{ 1271 pstring lname; 1272 pstring rname; 1273 pstring buf; 1274 char *p=buf; 1275 1276 pstrcpy(rname,cur_dir); 1277 pstrcat(rname,"\\"); 1278 1279 if (!next_token_nr(NULL,p,NULL,sizeof(buf))) { 1280 d_printf("put <filename>\n"); 1281 return 1; 1282 } 1283 pstrcpy(lname,p); 1284 1285 if (next_token_nr(NULL,p,NULL,sizeof(buf))) 1286 pstrcat(rname,p); 1287 else 1288 pstrcat(rname,lname); 1289 1290 dos_clean_name(rname); 1291 1292 { 1293 SMB_STRUCT_STAT st; 1294 /* allow '-' to represent stdin 1295 jdblair, 24.jun.98 */ 1296 if (!file_exist(lname,&st) && 1297 (strcmp(lname,"-"))) { 1298 d_printf("%s does not exist\n",lname); 1299 return 1; 1300 } 1301 } 1302 1303 return do_put(rname, lname, False); 1304} 1305 1306/************************************* 1307 File list structure. 1308*************************************/ 1309 1310static struct file_list { 1311 struct file_list *prev, *next; 1312 char *file_path; 1313 BOOL isdir; 1314} *file_list; 1315 1316/**************************************************************************** 1317 Free a file_list structure. 1318****************************************************************************/ 1319 1320static void free_file_list (struct file_list * list) 1321{ 1322 struct file_list *tmp; 1323 1324 while (list) { 1325 tmp = list; 1326 DLIST_REMOVE(list, list); 1327 SAFE_FREE(tmp->file_path); 1328 SAFE_FREE(tmp); 1329 } 1330} 1331 1332/**************************************************************************** 1333 Seek in a directory/file list until you get something that doesn't start with 1334 the specified name. 1335****************************************************************************/ 1336 1337static BOOL seek_list(struct file_list *list, char *name) 1338{ 1339 while (list) { 1340 trim_string(list->file_path,"./","\n"); 1341 if (strncmp(list->file_path, name, strlen(name)) != 0) { 1342 return(True); 1343 } 1344 list = list->next; 1345 } 1346 1347 return(False); 1348} 1349 1350/**************************************************************************** 1351 Set the file selection mask. 1352****************************************************************************/ 1353 1354static int cmd_select(void) 1355{ 1356 pstrcpy(fileselection,""); 1357 next_token_nr(NULL,fileselection,NULL,sizeof(fileselection)); 1358 1359 return 0; 1360} 1361 1362/**************************************************************************** 1363 Recursive file matching function act as find 1364 match must be always set to True when calling this function 1365****************************************************************************/ 1366 1367static int file_find(struct file_list **list, const char *directory, 1368 const char *expression, BOOL match) 1369{ 1370 DIR *dir; 1371 struct file_list *entry; 1372 struct stat statbuf; 1373 int ret; 1374 char *path; 1375 BOOL isdir; 1376 const char *dname; 1377 1378 dir = opendir(directory); 1379 if (!dir) 1380 return -1; 1381 1382 while ((dname = readdirname(dir))) { 1383 if (!strcmp("..", dname)) 1384 continue; 1385 if (!strcmp(".", dname)) 1386 continue; 1387 1388 if (asprintf(&path, "%s/%s", directory, dname) <= 0) { 1389 continue; 1390 } 1391 1392 isdir = False; 1393 if (!match || !gen_fnmatch(expression, dname)) { 1394 if (recurse) { 1395 ret = stat(path, &statbuf); 1396 if (ret == 0) { 1397 if (S_ISDIR(statbuf.st_mode)) { 1398 isdir = True; 1399 ret = file_find(list, path, expression, False); 1400 } 1401 } else { 1402 d_printf("file_find: cannot stat file %s\n", path); 1403 } 1404 1405 if (ret == -1) { 1406 SAFE_FREE(path); 1407 closedir(dir); 1408 return -1; 1409 } 1410 } 1411 entry = SMB_MALLOC_P(struct file_list); 1412 if (!entry) { 1413 d_printf("Out of memory in file_find\n"); 1414 closedir(dir); 1415 return -1; 1416 } 1417 entry->file_path = path; 1418 entry->isdir = isdir; 1419 DLIST_ADD(*list, entry); 1420 } else { 1421 SAFE_FREE(path); 1422 } 1423 } 1424 1425 closedir(dir); 1426 return 0; 1427} 1428 1429/**************************************************************************** 1430 mput some files. 1431****************************************************************************/ 1432 1433static int cmd_mput(void) 1434{ 1435 pstring buf; 1436 char *p=buf; 1437 1438 while (next_token_nr(NULL,p,NULL,sizeof(buf))) { 1439 int ret; 1440 struct file_list *temp_list; 1441 char *quest, *lname, *rname; 1442 1443 file_list = NULL; 1444 1445 ret = file_find(&file_list, ".", p, True); 1446 if (ret) { 1447 free_file_list(file_list); 1448 continue; 1449 } 1450 1451 quest = NULL; 1452 lname = NULL; 1453 rname = NULL; 1454 1455 for (temp_list = file_list; temp_list; 1456 temp_list = temp_list->next) { 1457 1458 SAFE_FREE(lname); 1459 if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) 1460 continue; 1461 trim_string(lname, "./", "/"); 1462 1463 /* check if it's a directory */ 1464 if (temp_list->isdir) { 1465 /* if (!recurse) continue; */ 1466 1467 SAFE_FREE(quest); 1468 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break; 1469 if (prompt && !yesno(quest)) { /* No */ 1470 /* Skip the directory */ 1471 lname[strlen(lname)-1] = '/'; 1472 if (!seek_list(temp_list, lname)) 1473 break; 1474 } else { /* Yes */ 1475 SAFE_FREE(rname); 1476 if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) break; 1477 dos_format(rname); 1478 if (!cli_chkpath(cli, rname) && 1479 !do_mkdir(rname)) { 1480 DEBUG (0, ("Unable to make dir, skipping...")); 1481 /* Skip the directory */ 1482 lname[strlen(lname)-1] = '/'; 1483 if (!seek_list(temp_list, lname)) 1484 break; 1485 } 1486 } 1487 continue; 1488 } else { 1489 SAFE_FREE(quest); 1490 if (asprintf(&quest,"Put file %s? ", lname) < 0) break; 1491 if (prompt && !yesno(quest)) /* No */ 1492 continue; 1493 1494 /* Yes */ 1495 SAFE_FREE(rname); 1496 if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) break; 1497 } 1498 1499 dos_format(rname); 1500 1501 do_put(rname, lname, False); 1502 } 1503 free_file_list(file_list); 1504 SAFE_FREE(quest); 1505 SAFE_FREE(lname); 1506 SAFE_FREE(rname); 1507 } 1508 1509 return 0; 1510} 1511 1512/**************************************************************************** 1513 Cancel a print job. 1514****************************************************************************/ 1515 1516static int do_cancel(int job) 1517{ 1518 if (cli_printjob_del(cli, job)) { 1519 d_printf("Job %d cancelled\n",job); 1520 return 0; 1521 } else { 1522 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli)); 1523 return 1; 1524 } 1525} 1526 1527/**************************************************************************** 1528 Cancel a print job. 1529****************************************************************************/ 1530 1531static int cmd_cancel(void) 1532{ 1533 pstring buf; 1534 int job; 1535 1536 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { 1537 d_printf("cancel <jobid> ...\n"); 1538 return 1; 1539 } 1540 do { 1541 job = atoi(buf); 1542 do_cancel(job); 1543 } while (next_token_nr(NULL,buf,NULL,sizeof(buf))); 1544 1545 return 0; 1546} 1547 1548/**************************************************************************** 1549 Print a file. 1550****************************************************************************/ 1551 1552static int cmd_print(void) 1553{ 1554 pstring lname; 1555 pstring rname; 1556 char *p; 1557 1558 if (!next_token_nr(NULL,lname,NULL, sizeof(lname))) { 1559 d_printf("print <filename>\n"); 1560 return 1; 1561 } 1562 1563 pstrcpy(rname,lname); 1564 p = strrchr_m(rname,'/'); 1565 if (p) { 1566 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)sys_getpid()); 1567 } 1568 1569 if (strequal(lname,"-")) { 1570 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid()); 1571 } 1572 1573 return do_put(rname, lname, False); 1574} 1575 1576/**************************************************************************** 1577 Show a print queue entry. 1578****************************************************************************/ 1579 1580static void queue_fn(struct print_job_info *p) 1581{ 1582 d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name); 1583} 1584 1585/**************************************************************************** 1586 Show a print queue. 1587****************************************************************************/ 1588 1589static int cmd_queue(void) 1590{ 1591 cli_print_queue(cli, queue_fn); 1592 1593 return 0; 1594} 1595 1596/**************************************************************************** 1597 Delete some files. 1598****************************************************************************/ 1599 1600static void do_del(file_info *finfo) 1601{ 1602 pstring mask; 1603 1604 pstrcpy(mask,cur_dir); 1605 pstrcat(mask,finfo->name); 1606 1607 if (finfo->mode & aDIR) 1608 return; 1609 1610 if (!cli_unlink(cli, mask)) { 1611 d_printf("%s deleting remote file %s\n",cli_errstr(cli),mask); 1612 } 1613} 1614 1615/**************************************************************************** 1616 Delete some files. 1617****************************************************************************/ 1618 1619static int cmd_del(void) 1620{ 1621 pstring mask; 1622 pstring buf; 1623 uint16 attribute = aSYSTEM | aHIDDEN; 1624 1625 if (recurse) 1626 attribute |= aDIR; 1627 1628 pstrcpy(mask,cur_dir); 1629 1630 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { 1631 d_printf("del <filename>\n"); 1632 return 1; 1633 } 1634 pstrcat(mask,buf); 1635 1636 do_list(mask, attribute,do_del,False,False); 1637 1638 return 0; 1639} 1640 1641/**************************************************************************** 1642****************************************************************************/ 1643 1644static int cmd_open(void) 1645{ 1646 pstring mask; 1647 pstring buf; 1648 struct cli_state *targetcli; 1649 pstring targetname; 1650 1651 pstrcpy(mask,cur_dir); 1652 1653 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { 1654 d_printf("open <filename>\n"); 1655 return 1; 1656 } 1657 pstrcat(mask,buf); 1658 1659 if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) { 1660 d_printf("open %s: %s\n", mask, cli_errstr(cli)); 1661 return 1; 1662 } 1663 1664 cli_nt_create(targetcli, targetname, FILE_READ_DATA); 1665 1666 return 0; 1667} 1668 1669 1670/**************************************************************************** 1671 Remove a directory. 1672****************************************************************************/ 1673 1674static int cmd_rmdir(void) 1675{ 1676 pstring mask; 1677 pstring buf; 1678 struct cli_state *targetcli; 1679 pstring targetname; 1680 1681 pstrcpy(mask,cur_dir); 1682 1683 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { 1684 d_printf("rmdir <dirname>\n"); 1685 return 1; 1686 } 1687 pstrcat(mask,buf); 1688 1689 if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) { 1690 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli)); 1691 return 1; 1692 } 1693 1694 if (!cli_rmdir(targetcli, targetname)) { 1695 d_printf("%s removing remote directory file %s\n", 1696 cli_errstr(targetcli),mask); 1697 } 1698 1699 return 0; 1700} 1701 1702/**************************************************************************** 1703 UNIX hardlink. 1704****************************************************************************/ 1705 1706static int cmd_link(void) 1707{ 1708 pstring oldname,newname; 1709 pstring buf,buf2; 1710 struct cli_state *targetcli; 1711 pstring targetname; 1712 1713 pstrcpy(oldname,cur_dir); 1714 pstrcpy(newname,cur_dir); 1715 1716 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 1717 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) { 1718 d_printf("link <oldname> <newname>\n"); 1719 return 1; 1720 } 1721 1722 pstrcat(oldname,buf); 1723 pstrcat(newname,buf2); 1724 1725 if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) { 1726 d_printf("link %s: %s\n", oldname, cli_errstr(cli)); 1727 return 1; 1728 } 1729 1730 if (!SERVER_HAS_UNIX_CIFS(targetcli)) { 1731 d_printf("Server doesn't support UNIX CIFS calls.\n"); 1732 return 1; 1733 } 1734 1735 if (!cli_unix_hardlink(targetcli, targetname, newname)) { 1736 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname); 1737 return 1; 1738 } 1739 1740 return 0; 1741} 1742 1743/**************************************************************************** 1744 UNIX symlink. 1745****************************************************************************/ 1746 1747static int cmd_symlink(void) 1748{ 1749 pstring oldname,newname; 1750 pstring buf,buf2; 1751 1752 if (!SERVER_HAS_UNIX_CIFS(cli)) { 1753 d_printf("Server doesn't support UNIX CIFS calls.\n"); 1754 return 1; 1755 } 1756 1757 pstrcpy(newname,cur_dir); 1758 1759 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 1760 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) { 1761 d_printf("symlink <oldname> <newname>\n"); 1762 return 1; 1763 } 1764 1765 pstrcpy(oldname,buf); 1766 pstrcat(newname,buf2); 1767 1768 if (!cli_unix_symlink(cli, oldname, newname)) { 1769 d_printf("%s symlinking files (%s -> %s)\n", 1770 cli_errstr(cli), newname, oldname); 1771 return 1; 1772 } 1773 1774 return 0; 1775} 1776 1777/**************************************************************************** 1778 UNIX chmod. 1779****************************************************************************/ 1780 1781static int cmd_chmod(void) 1782{ 1783 pstring src; 1784 mode_t mode; 1785 pstring buf, buf2; 1786 struct cli_state *targetcli; 1787 pstring targetname; 1788 1789 pstrcpy(src,cur_dir); 1790 1791 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 1792 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) { 1793 d_printf("chmod mode file\n"); 1794 return 1; 1795 } 1796 1797 mode = (mode_t)strtol(buf, NULL, 8); 1798 pstrcat(src,buf2); 1799 1800 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { 1801 d_printf("chmod %s: %s\n", src, cli_errstr(cli)); 1802 return 1; 1803 } 1804 1805 if (!SERVER_HAS_UNIX_CIFS(targetcli)) { 1806 d_printf("Server doesn't support UNIX CIFS calls.\n"); 1807 return 1; 1808 } 1809 1810 if (!cli_unix_chmod(targetcli, targetname, mode)) { 1811 d_printf("%s chmod file %s 0%o\n", 1812 cli_errstr(targetcli), src, (unsigned int)mode); 1813 return 1; 1814 } 1815 1816 return 0; 1817} 1818 1819static const char *filetype_to_str(mode_t mode) 1820{ 1821 if (S_ISREG(mode)) { 1822 return "regular file"; 1823 } else if (S_ISDIR(mode)) { 1824 return "directory"; 1825 } else 1826#ifdef S_ISCHR 1827 if (S_ISCHR(mode)) { 1828 return "character device"; 1829 } else 1830#endif 1831#ifdef S_ISBLK 1832 if (S_ISBLK(mode)) { 1833 return "block device"; 1834 } else 1835#endif 1836#ifdef S_ISFIFO 1837 if (S_ISFIFO(mode)) { 1838 return "fifo"; 1839 } else 1840#endif 1841#ifdef S_ISLNK 1842 if (S_ISLNK(mode)) { 1843 return "symbolic link"; 1844 } else 1845#endif 1846#ifdef S_ISSOCK 1847 if (S_ISSOCK(mode)) { 1848 return "socket"; 1849 } else 1850#endif 1851 return ""; 1852} 1853 1854static char rwx_to_str(mode_t m, mode_t bt, char ret) 1855{ 1856 if (m & bt) { 1857 return ret; 1858 } else { 1859 return '-'; 1860 } 1861} 1862 1863static char *unix_mode_to_str(char *s, mode_t m) 1864{ 1865 char *p = s; 1866 const char *str = filetype_to_str(m); 1867 1868 switch(str[0]) { 1869 case 'd': 1870 *p++ = 'd'; 1871 break; 1872 case 'c': 1873 *p++ = 'c'; 1874 break; 1875 case 'b': 1876 *p++ = 'b'; 1877 break; 1878 case 'f': 1879 *p++ = 'p'; 1880 break; 1881 case 's': 1882 *p++ = str[1] == 'y' ? 'l' : 's'; 1883 break; 1884 case 'r': 1885 default: 1886 *p++ = '-'; 1887 break; 1888 } 1889 *p++ = rwx_to_str(m, S_IRUSR, 'r'); 1890 *p++ = rwx_to_str(m, S_IWUSR, 'w'); 1891 *p++ = rwx_to_str(m, S_IXUSR, 'x'); 1892 *p++ = rwx_to_str(m, S_IRGRP, 'r'); 1893 *p++ = rwx_to_str(m, S_IWGRP, 'w'); 1894 *p++ = rwx_to_str(m, S_IXGRP, 'x'); 1895 *p++ = rwx_to_str(m, S_IROTH, 'r'); 1896 *p++ = rwx_to_str(m, S_IWOTH, 'w'); 1897 *p++ = rwx_to_str(m, S_IXOTH, 'x'); 1898 *p++ = '\0'; 1899 return s; 1900} 1901 1902/**************************************************************************** 1903 Utility function for UNIX getfacl. 1904****************************************************************************/ 1905 1906static char *perms_to_string(fstring permstr, unsigned char perms) 1907{ 1908 fstrcpy(permstr, "---"); 1909 if (perms & SMB_POSIX_ACL_READ) { 1910 permstr[0] = 'r'; 1911 } 1912 if (perms & SMB_POSIX_ACL_WRITE) { 1913 permstr[1] = 'w'; 1914 } 1915 if (perms & SMB_POSIX_ACL_EXECUTE) { 1916 permstr[2] = 'x'; 1917 } 1918 return permstr; 1919} 1920 1921/**************************************************************************** 1922 UNIX getfacl. 1923****************************************************************************/ 1924 1925static int cmd_getfacl(void) 1926{ 1927 pstring src, name; 1928 uint16 major, minor; 1929 uint32 caplow, caphigh; 1930 char *retbuf = NULL; 1931 size_t rb_size = 0; 1932 SMB_STRUCT_STAT sbuf; 1933 uint16 num_file_acls = 0; 1934 uint16 num_dir_acls = 0; 1935 uint16 i; 1936 struct cli_state *targetcli; 1937 pstring targetname; 1938 1939 pstrcpy(src,cur_dir); 1940 1941 if (!next_token_nr(NULL,name,NULL,sizeof(name))) { 1942 d_printf("stat file\n"); 1943 return 1; 1944 } 1945 1946 pstrcat(src,name); 1947 1948 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { 1949 d_printf("stat %s: %s\n", src, cli_errstr(cli)); 1950 return 1; 1951 } 1952 1953 if (!SERVER_HAS_UNIX_CIFS(targetcli)) { 1954 d_printf("Server doesn't support UNIX CIFS calls.\n"); 1955 return 1; 1956 } 1957 1958 if (!cli_unix_extensions_version(targetcli, &major, &minor, &caplow, &caphigh)) { 1959 d_printf("Can't get UNIX CIFS version from server.\n"); 1960 return 1; 1961 } 1962 1963 if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) { 1964 d_printf("This server supports UNIX extensions but doesn't support POSIX ACLs.\n"); 1965 return 1; 1966 } 1967 1968 1969 if (!cli_unix_stat(targetcli, targetname, &sbuf)) { 1970 d_printf("%s getfacl doing a stat on file %s\n", 1971 cli_errstr(targetcli), src); 1972 return 1; 1973 } 1974 1975 if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) { 1976 d_printf("%s getfacl file %s\n", 1977 cli_errstr(targetcli), src); 1978 return 1; 1979 } 1980 1981 /* ToDo : Print out the ACL values. */ 1982 if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) { 1983 d_printf("getfacl file %s, unknown POSIX acl version %u.\n", 1984 src, (unsigned int)CVAL(retbuf,0) ); 1985 SAFE_FREE(retbuf); 1986 return 1; 1987 } 1988 1989 num_file_acls = SVAL(retbuf,2); 1990 num_dir_acls = SVAL(retbuf,4); 1991 if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) { 1992 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n", 1993 src, 1994 (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)), 1995 (unsigned int)rb_size); 1996 1997 SAFE_FREE(retbuf); 1998 return 1; 1999 } 2000 2001 d_printf("# file: %s\n", src); 2002 d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid); 2003 2004 if (num_file_acls == 0 && num_dir_acls == 0) { 2005 d_printf("No acls found.\n"); 2006 } 2007 2008 for (i = 0; i < num_file_acls; i++) { 2009 uint32 uorg; 2010 fstring permstring; 2011 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)); 2012 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1); 2013 2014 switch(tagtype) { 2015 case SMB_POSIX_ACL_USER_OBJ: 2016 d_printf("user::"); 2017 break; 2018 case SMB_POSIX_ACL_USER: 2019 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2); 2020 d_printf("user:%u:", uorg); 2021 break; 2022 case SMB_POSIX_ACL_GROUP_OBJ: 2023 d_printf("group::"); 2024 break; 2025 case SMB_POSIX_ACL_GROUP: 2026 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2); 2027 d_printf("group:%u", uorg); 2028 break; 2029 case SMB_POSIX_ACL_MASK: 2030 d_printf("mask::"); 2031 break; 2032 case SMB_POSIX_ACL_OTHER: 2033 d_printf("other::"); 2034 break; 2035 default: 2036 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n", 2037 src, (unsigned int)tagtype ); 2038 SAFE_FREE(retbuf); 2039 return 1; 2040 } 2041 2042 d_printf("%s\n", perms_to_string(permstring, perms)); 2043 } 2044 2045 for (i = 0; i < num_dir_acls; i++) { 2046 uint32 uorg; 2047 fstring permstring; 2048 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)); 2049 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1); 2050 2051 switch(tagtype) { 2052 case SMB_POSIX_ACL_USER_OBJ: 2053 d_printf("default:user::"); 2054 break; 2055 case SMB_POSIX_ACL_USER: 2056 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2); 2057 d_printf("default:user:%u:", uorg); 2058 break; 2059 case SMB_POSIX_ACL_GROUP_OBJ: 2060 d_printf("default:group::"); 2061 break; 2062 case SMB_POSIX_ACL_GROUP: 2063 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2); 2064 d_printf("default:group:%u", uorg); 2065 break; 2066 case SMB_POSIX_ACL_MASK: 2067 d_printf("default:mask::"); 2068 break; 2069 case SMB_POSIX_ACL_OTHER: 2070 d_printf("default:other::"); 2071 break; 2072 default: 2073 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n", 2074 src, (unsigned int)tagtype ); 2075 SAFE_FREE(retbuf); 2076 return 1; 2077 } 2078 2079 d_printf("%s\n", perms_to_string(permstring, perms)); 2080 } 2081 2082 SAFE_FREE(retbuf); 2083 return 0; 2084} 2085 2086/**************************************************************************** 2087 UNIX stat. 2088****************************************************************************/ 2089 2090static int cmd_stat(void) 2091{ 2092 pstring src, name; 2093 fstring mode_str; 2094 SMB_STRUCT_STAT sbuf; 2095 struct cli_state *targetcli; 2096 pstring targetname; 2097 2098 if (!SERVER_HAS_UNIX_CIFS(cli)) { 2099 d_printf("Server doesn't support UNIX CIFS calls.\n"); 2100 return 1; 2101 } 2102 2103 pstrcpy(src,cur_dir); 2104 2105 if (!next_token_nr(NULL,name,NULL,sizeof(name))) { 2106 d_printf("stat file\n"); 2107 return 1; 2108 } 2109 2110 pstrcat(src,name); 2111 2112 2113 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { 2114 d_printf("stat %s: %s\n", src, cli_errstr(cli)); 2115 return 1; 2116 } 2117 2118 if (!cli_unix_stat(targetcli, targetname, &sbuf)) { 2119 d_printf("%s stat file %s\n", 2120 cli_errstr(targetcli), src); 2121 return 1; 2122 } 2123 2124 /* Print out the stat values. */ 2125 d_printf("File: %s\n", src); 2126 d_printf("Size: %-12.0f\tBlocks: %u\t%s\n", 2127 (double)sbuf.st_size, 2128 (unsigned int)sbuf.st_blocks, 2129 filetype_to_str(sbuf.st_mode)); 2130 2131#if defined(S_ISCHR) && defined(S_ISBLK) 2132 if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) { 2133 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n", 2134 (double)sbuf.st_ino, 2135 (unsigned int)sbuf.st_nlink, 2136 unix_dev_major(sbuf.st_rdev), 2137 unix_dev_minor(sbuf.st_rdev)); 2138 } else 2139#endif 2140 d_printf("Inode: %.0f\tLinks: %u\n", 2141 (double)sbuf.st_ino, 2142 (unsigned int)sbuf.st_nlink); 2143 2144 d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n", 2145 ((int)sbuf.st_mode & 0777), 2146 unix_mode_to_str(mode_str, sbuf.st_mode), 2147 (unsigned int)sbuf.st_uid, 2148 (unsigned int)sbuf.st_gid); 2149 2150 strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_atime)); 2151 d_printf("Access: %s\n", mode_str); 2152 2153 strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_mtime)); 2154 d_printf("Modify: %s\n", mode_str); 2155 2156 strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_ctime)); 2157 d_printf("Change: %s\n", mode_str); 2158 2159 return 0; 2160} 2161 2162 2163/**************************************************************************** 2164 UNIX chown. 2165****************************************************************************/ 2166 2167static int cmd_chown(void) 2168{ 2169 pstring src; 2170 uid_t uid; 2171 gid_t gid; 2172 pstring buf, buf2, buf3; 2173 struct cli_state *targetcli; 2174 pstring targetname; 2175 2176 pstrcpy(src,cur_dir); 2177 2178 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 2179 !next_token_nr(NULL,buf2,NULL, sizeof(buf2)) || 2180 !next_token_nr(NULL,buf3,NULL, sizeof(buf3))) { 2181 d_printf("chown uid gid file\n"); 2182 return 1; 2183 } 2184 2185 uid = (uid_t)atoi(buf); 2186 gid = (gid_t)atoi(buf2); 2187 pstrcat(src,buf3); 2188 2189 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { 2190 d_printf("chown %s: %s\n", src, cli_errstr(cli)); 2191 return 1; 2192 } 2193 2194 2195 if (!SERVER_HAS_UNIX_CIFS(targetcli)) { 2196 d_printf("Server doesn't support UNIX CIFS calls.\n"); 2197 return 1; 2198 } 2199 2200 if (!cli_unix_chown(targetcli, targetname, uid, gid)) { 2201 d_printf("%s chown file %s uid=%d, gid=%d\n", 2202 cli_errstr(targetcli), src, (int)uid, (int)gid); 2203 return 1; 2204 } 2205 2206 return 0; 2207} 2208 2209/**************************************************************************** 2210 Rename some file. 2211****************************************************************************/ 2212 2213static int cmd_rename(void) 2214{ 2215 pstring src,dest; 2216 pstring buf,buf2; 2217 2218 pstrcpy(src,cur_dir); 2219 pstrcpy(dest,cur_dir); 2220 2221 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 2222 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) { 2223 d_printf("rename <src> <dest>\n"); 2224 return 1; 2225 } 2226 2227 pstrcat(src,buf); 2228 pstrcat(dest,buf2); 2229 2230 if (!cli_rename(cli, src, dest)) { 2231 d_printf("%s renaming files\n",cli_errstr(cli)); 2232 return 1; 2233 } 2234 2235 return 0; 2236} 2237 2238/**************************************************************************** 2239 Hard link files using the NT call. 2240****************************************************************************/ 2241 2242static int cmd_hardlink(void) 2243{ 2244 pstring src,dest; 2245 pstring buf,buf2; 2246 struct cli_state *targetcli; 2247 pstring targetname; 2248 2249 pstrcpy(src,cur_dir); 2250 pstrcpy(dest,cur_dir); 2251 2252 if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 2253 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) { 2254 d_printf("hardlink <src> <dest>\n"); 2255 return 1; 2256 } 2257 2258 pstrcat(src,buf); 2259 pstrcat(dest,buf2); 2260 2261 if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { 2262 d_printf("hardlink %s: %s\n", src, cli_errstr(cli)); 2263 return 1; 2264 } 2265 2266 if (!SERVER_HAS_UNIX_CIFS(targetcli)) { 2267 d_printf("Server doesn't support UNIX CIFS calls.\n"); 2268 return 1; 2269 } 2270 2271 if (!cli_nt_hardlink(targetcli, targetname, dest)) { 2272 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli)); 2273 return 1; 2274 } 2275 2276 return 0; 2277} 2278 2279/**************************************************************************** 2280 Toggle the prompt flag. 2281****************************************************************************/ 2282 2283static int cmd_prompt(void) 2284{ 2285 prompt = !prompt; 2286 DEBUG(2,("prompting is now %s\n",prompt?"on":"off")); 2287 2288 return 1; 2289} 2290 2291/**************************************************************************** 2292 Set the newer than time. 2293****************************************************************************/ 2294 2295static int cmd_newer(void) 2296{ 2297 pstring buf; 2298 BOOL ok; 2299 SMB_STRUCT_STAT sbuf; 2300 2301 ok = next_token_nr(NULL,buf,NULL,sizeof(buf)); 2302 if (ok && (sys_stat(buf,&sbuf) == 0)) { 2303 newer_than = sbuf.st_mtime; 2304 DEBUG(1,("Getting files newer than %s", 2305 asctime(LocalTime(&newer_than)))); 2306 } else { 2307 newer_than = 0; 2308 } 2309 2310 if (ok && newer_than == 0) { 2311 d_printf("Error setting newer-than time\n"); 2312 return 1; 2313 } 2314 2315 return 0; 2316} 2317 2318/**************************************************************************** 2319 Set the archive level. 2320****************************************************************************/ 2321 2322static int cmd_archive(void) 2323{ 2324 pstring buf; 2325 2326 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) { 2327 archive_level = atoi(buf); 2328 } else 2329 d_printf("Archive level is %d\n",archive_level); 2330 2331 return 0; 2332} 2333 2334/**************************************************************************** 2335 Toggle the lowercaseflag. 2336****************************************************************************/ 2337 2338static int cmd_lowercase(void) 2339{ 2340 lowercase = !lowercase; 2341 DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off")); 2342 2343 return 0; 2344} 2345 2346/**************************************************************************** 2347 Toggle the case sensitive flag. 2348****************************************************************************/ 2349 2350static int cmd_setcase(void) 2351{ 2352 BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False); 2353 2354 cli_set_case_sensitive(cli, !orig_case_sensitive); 2355 DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ? 2356 "on":"off")); 2357 2358 return 0; 2359} 2360 2361/**************************************************************************** 2362 Toggle the recurse flag. 2363****************************************************************************/ 2364 2365static int cmd_recurse(void) 2366{ 2367 recurse = !recurse; 2368 DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off")); 2369 2370 return 0; 2371} 2372 2373/**************************************************************************** 2374 Toggle the translate flag. 2375****************************************************************************/ 2376 2377static int cmd_translate(void) 2378{ 2379 translation = !translation; 2380 DEBUG(2,("CR/LF<->LF and print text translation now %s\n", 2381 translation?"on":"off")); 2382 2383 return 0; 2384} 2385 2386/**************************************************************************** 2387 Do a printmode command. 2388****************************************************************************/ 2389 2390static int cmd_printmode(void) 2391{ 2392 fstring buf; 2393 fstring mode; 2394 2395 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) { 2396 if (strequal(buf,"text")) { 2397 printmode = 0; 2398 } else { 2399 if (strequal(buf,"graphics")) 2400 printmode = 1; 2401 else 2402 printmode = atoi(buf); 2403 } 2404 } 2405 2406 switch(printmode) { 2407 case 0: 2408 fstrcpy(mode,"text"); 2409 break; 2410 case 1: 2411 fstrcpy(mode,"graphics"); 2412 break; 2413 default: 2414 slprintf(mode,sizeof(mode)-1,"%d",printmode); 2415 break; 2416 } 2417 2418 DEBUG(2,("the printmode is now %s\n",mode)); 2419 2420 return 0; 2421} 2422 2423/**************************************************************************** 2424 Do the lcd command. 2425 ****************************************************************************/ 2426 2427static int cmd_lcd(void) 2428{ 2429 pstring buf; 2430 pstring d; 2431 2432 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) 2433 chdir(buf); 2434 DEBUG(2,("the local directory is now %s\n",sys_getwd(d))); 2435 2436 return 0; 2437} 2438 2439/**************************************************************************** 2440 Get a file restarting at end of local file. 2441 ****************************************************************************/ 2442 2443static int cmd_reget(void) 2444{ 2445 pstring local_name; 2446 pstring remote_name; 2447 char *p; 2448 2449 pstrcpy(remote_name, cur_dir); 2450 pstrcat(remote_name, "\\"); 2451 2452 p = remote_name + strlen(remote_name); 2453 2454 if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) { 2455 d_printf("reget <filename>\n"); 2456 return 1; 2457 } 2458 pstrcpy(local_name, p); 2459 dos_clean_name(remote_name); 2460 2461 next_token_nr(NULL, local_name, NULL, sizeof(local_name)); 2462 2463 return do_get(remote_name, local_name, True); 2464} 2465 2466/**************************************************************************** 2467 Put a file restarting at end of local file. 2468 ****************************************************************************/ 2469 2470static int cmd_reput(void) 2471{ 2472 pstring local_name; 2473 pstring remote_name; 2474 pstring buf; 2475 char *p = buf; 2476 SMB_STRUCT_STAT st; 2477 2478 pstrcpy(remote_name, cur_dir); 2479 pstrcat(remote_name, "\\"); 2480 2481 if (!next_token_nr(NULL, p, NULL, sizeof(buf))) { 2482 d_printf("reput <filename>\n"); 2483 return 1; 2484 } 2485 pstrcpy(local_name, p); 2486 2487 if (!file_exist(local_name, &st)) { 2488 d_printf("%s does not exist\n", local_name); 2489 return 1; 2490 } 2491 2492 if (next_token_nr(NULL, p, NULL, sizeof(buf))) 2493 pstrcat(remote_name, p); 2494 else 2495 pstrcat(remote_name, local_name); 2496 2497 dos_clean_name(remote_name); 2498 2499 return do_put(remote_name, local_name, True); 2500} 2501 2502/**************************************************************************** 2503 List a share name. 2504 ****************************************************************************/ 2505 2506static void browse_fn(const char *name, uint32 m, 2507 const char *comment, void *state) 2508{ 2509 fstring typestr; 2510 2511 *typestr=0; 2512 2513 switch (m) 2514 { 2515 case STYPE_DISKTREE: 2516 fstrcpy(typestr,"Disk"); break; 2517 case STYPE_PRINTQ: 2518 fstrcpy(typestr,"Printer"); break; 2519 case STYPE_DEVICE: 2520 fstrcpy(typestr,"Device"); break; 2521 case STYPE_IPC: 2522 fstrcpy(typestr,"IPC"); break; 2523 } 2524 /* FIXME: If the remote machine returns non-ascii characters 2525 in any of these fields, they can corrupt the output. We 2526 should remove them. */ 2527 if (!grepable) { 2528 d_printf("\t%-15s %-10.10s%s\n", 2529 name,typestr,comment); 2530 } else { 2531 d_printf ("%s|%s|%s\n",typestr,name,comment); 2532 } 2533} 2534 2535/**************************************************************************** 2536 Try and browse available connections on a host. 2537****************************************************************************/ 2538 2539static BOOL browse_host(BOOL sort) 2540{ 2541 int ret; 2542 if (!grepable) { 2543 d_printf("\n\tSharename Type Comment\n"); 2544 d_printf("\t--------- ---- -------\n"); 2545 } 2546 2547 if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1) 2548 d_printf("Error returning browse list: %s\n", cli_errstr(cli)); 2549 2550 return (ret != -1); 2551} 2552 2553/**************************************************************************** 2554 List a server name. 2555****************************************************************************/ 2556 2557static void server_fn(const char *name, uint32 m, 2558 const char *comment, void *state) 2559{ 2560 2561 if (!grepable){ 2562 d_printf("\t%-16s %s\n", name, comment); 2563 } else { 2564 d_printf("%s|%s|%s\n",(char *)state, name, comment); 2565 } 2566} 2567 2568/**************************************************************************** 2569 Try and browse available connections on a host. 2570****************************************************************************/ 2571 2572static BOOL list_servers(const char *wk_grp) 2573{ 2574 fstring state; 2575 2576 if (!cli->server_domain) 2577 return False; 2578 2579 if (!grepable) { 2580 d_printf("\n\tServer Comment\n"); 2581 d_printf("\t--------- -------\n"); 2582 }; 2583 fstrcpy( state, "Server" ); 2584 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn, 2585 state); 2586 2587 if (!grepable) { 2588 d_printf("\n\tWorkgroup Master\n"); 2589 d_printf("\t--------- -------\n"); 2590 }; 2591 2592 fstrcpy( state, "Workgroup" ); 2593 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM, 2594 server_fn, state); 2595 return True; 2596} 2597 2598/**************************************************************************** 2599 Print or set current VUID 2600****************************************************************************/ 2601 2602static int cmd_vuid(void) 2603{ 2604 fstring buf; 2605 2606 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { 2607 d_printf("Current VUID is %d\n", cli->vuid); 2608 return 0; 2609 } 2610 2611 cli->vuid = atoi(buf); 2612 return 0; 2613} 2614 2615/**************************************************************************** 2616 Setup a new VUID, by issuing a session setup 2617****************************************************************************/ 2618 2619static int cmd_logon(void) 2620{ 2621 pstring l_username, l_password; 2622 pstring buf,buf2; 2623 2624 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { 2625 d_printf("logon <username> [<password>]\n"); 2626 return 0; 2627 } 2628 2629 pstrcpy(l_username, buf); 2630 2631 if (!next_token_nr(NULL,buf2,NULL,sizeof(buf))) 2632 { 2633 char *pass = getpass("Password: "); 2634 if (pass) 2635 pstrcpy(l_password, pass); 2636 } 2637 else 2638 pstrcpy(l_password, buf2); 2639 2640 if (!cli_session_setup(cli, l_username, 2641 l_password, strlen(l_password), 2642 l_password, strlen(l_password), 2643 lp_workgroup())) { 2644 d_printf("session setup failed: %s\n", cli_errstr(cli)); 2645 return -1; 2646 } 2647 2648 d_printf("Current VUID is %d\n", cli->vuid); 2649 return 0; 2650} 2651 2652 2653/**************************************************************************** 2654 list active connections 2655****************************************************************************/ 2656 2657static int cmd_list_connect(void) 2658{ 2659 cli_cm_display(); 2660 2661 return 0; 2662} 2663 2664/**************************************************************************** 2665 display the current active client connection 2666****************************************************************************/ 2667 2668static int cmd_show_connect( void ) 2669{ 2670 struct cli_state *targetcli; 2671 pstring targetpath; 2672 2673 if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) { 2674 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli)); 2675 return 1; 2676 } 2677 2678 d_printf("//%s/%s\n", targetcli->desthost, targetcli->share); 2679 return 0; 2680} 2681 2682/* Some constants for completing filename arguments */ 2683 2684#define COMPL_NONE 0 /* No completions */ 2685#define COMPL_REMOTE 1 /* Complete remote filename */ 2686#define COMPL_LOCAL 2 /* Complete local filename */ 2687 2688/* This defines the commands supported by this client. 2689 * NOTE: The "!" must be the last one in the list because it's fn pointer 2690 * field is NULL, and NULL in that field is used in process_tok() 2691 * (below) to indicate the end of the list. crh 2692 */ 2693static struct 2694{ 2695 const char *name; 2696 int (*fn)(void); 2697 const char *description; 2698 char compl_args[2]; /* Completion argument info */ 2699} commands[] = { 2700 {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}}, 2701 {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}}, 2702 {"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}}, 2703 {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}}, 2704 {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}}, 2705 {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}}, 2706 {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}}, 2707 {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}}, 2708 {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}}, 2709 {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, 2710 {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, 2711 {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}}, 2712 {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}}, 2713 {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}}, 2714 {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}}, 2715 {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}}, 2716 {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}}, 2717 {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}}, 2718 {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}}, 2719 {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}}, 2720 {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}}, 2721 {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, 2722 {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}}, 2723 {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}}, 2724 {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}}, 2725 {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}}, 2726 {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}}, 2727 {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}}, 2728 {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}}, 2729 {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}}, 2730 {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}}, 2731 {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}}, 2732 {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}}, 2733 {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}}, 2734 {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}}, 2735 {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}}, 2736 {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}}, 2737 {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}}, 2738 {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}}, 2739 {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}}, 2740 {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}}, 2741 {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}}, 2742 {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}}, 2743 {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, 2744 {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}}, 2745 {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}}, 2746 {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}}, 2747 {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}}, 2748 {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}}, 2749 {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}}, 2750 {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}}, 2751 {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}}, 2752 {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}}, 2753 {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}}, 2754 {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}}, 2755 2756 /* Yes, this must be here, see crh's comment above. */ 2757 {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}}, 2758 {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}} 2759}; 2760 2761/******************************************************************* 2762 Lookup a command string in the list of commands, including 2763 abbreviations. 2764******************************************************************/ 2765 2766static int process_tok(pstring tok) 2767{ 2768 int i = 0, matches = 0; 2769 int cmd=0; 2770 int tok_len = strlen(tok); 2771 2772 while (commands[i].fn != NULL) { 2773 if (strequal(commands[i].name,tok)) { 2774 matches = 1; 2775 cmd = i; 2776 break; 2777 } else if (strnequal(commands[i].name, tok, tok_len)) { 2778 matches++; 2779 cmd = i; 2780 } 2781 i++; 2782 } 2783 2784 if (matches == 0) 2785 return(-1); 2786 else if (matches == 1) 2787 return(cmd); 2788 else 2789 return(-2); 2790} 2791 2792/**************************************************************************** 2793 Help. 2794****************************************************************************/ 2795 2796static int cmd_help(void) 2797{ 2798 int i=0,j; 2799 pstring buf; 2800 2801 if (next_token_nr(NULL,buf,NULL,sizeof(buf))) { 2802 if ((i = process_tok(buf)) >= 0) 2803 d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description); 2804 } else { 2805 while (commands[i].description) { 2806 for (j=0; commands[i].description && (j<5); j++) { 2807 d_printf("%-15s",commands[i].name); 2808 i++; 2809 } 2810 d_printf("\n"); 2811 } 2812 } 2813 return 0; 2814} 2815 2816/**************************************************************************** 2817 Process a -c command string. 2818****************************************************************************/ 2819 2820static int process_command_string(char *cmd) 2821{ 2822 pstring line; 2823 const char *ptr; 2824 int rc = 0; 2825 2826 /* establish the connection if not already */ 2827 2828 if (!cli) { 2829 cli = cli_cm_open(desthost, service, True); 2830 if (!cli) 2831 return 0; 2832 } 2833 2834 while (cmd[0] != '\0') { 2835 char *p; 2836 pstring tok; 2837 int i; 2838 2839 if ((p = strchr_m(cmd, ';')) == 0) { 2840 strncpy(line, cmd, 999); 2841 line[1000] = '\0'; 2842 cmd += strlen(cmd); 2843 } else { 2844 if (p - cmd > 999) 2845 p = cmd + 999; 2846 strncpy(line, cmd, p - cmd); 2847 line[p - cmd] = '\0'; 2848 cmd = p + 1; 2849 } 2850 2851 /* and get the first part of the command */ 2852 ptr = line; 2853 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue; 2854 2855 if ((i = process_tok(tok)) >= 0) { 2856 rc = commands[i].fn(); 2857 } else if (i == -2) { 2858 d_printf("%s: command abbreviation ambiguous\n",tok); 2859 } else { 2860 d_printf("%s: command not found\n",tok); 2861 } 2862 } 2863 2864 return rc; 2865} 2866 2867#define MAX_COMPLETIONS 100 2868 2869typedef struct { 2870 pstring dirmask; 2871 char **matches; 2872 int count, samelen; 2873 const char *text; 2874 int len; 2875} completion_remote_t; 2876 2877static void completion_remote_filter(const char *mnt, file_info *f, const char *mask, void *state) 2878{ 2879 completion_remote_t *info = (completion_remote_t *)state; 2880 2881 if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) { 2882 if ((info->dirmask[0] == 0) && !(f->mode & aDIR)) 2883 info->matches[info->count] = SMB_STRDUP(f->name); 2884 else { 2885 pstring tmp; 2886 2887 if (info->dirmask[0] != 0) 2888 pstrcpy(tmp, info->dirmask); 2889 else 2890 tmp[0] = 0; 2891 pstrcat(tmp, f->name); 2892 if (f->mode & aDIR) 2893 pstrcat(tmp, "/"); 2894 info->matches[info->count] = SMB_STRDUP(tmp); 2895 } 2896 if (info->matches[info->count] == NULL) 2897 return; 2898 if (f->mode & aDIR) 2899 smb_readline_ca_char(0); 2900 2901 if (info->count == 1) 2902 info->samelen = strlen(info->matches[info->count]); 2903 else 2904 while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0) 2905 info->samelen--; 2906 info->count++; 2907 } 2908} 2909 2910static char **remote_completion(const char *text, int len) 2911{ 2912 pstring dirmask; 2913 int i; 2914 completion_remote_t info = { "", NULL, 1, 0, NULL, 0 }; 2915 2916 /* can't have non-static intialisation on Sun CC, so do it 2917 at run time here */ 2918 info.samelen = len; 2919 info.text = text; 2920 info.len = len; 2921 2922 if (len >= PATH_MAX) 2923 return(NULL); 2924 2925 info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS); 2926 if (!info.matches) return NULL; 2927 info.matches[0] = NULL; 2928 2929 for (i = len-1; i >= 0; i--) 2930 if ((text[i] == '/') || (text[i] == '\\')) 2931 break; 2932 info.text = text+i+1; 2933 info.samelen = info.len = len-i-1; 2934 2935 if (i > 0) { 2936 strncpy(info.dirmask, text, i+1); 2937 info.dirmask[i+1] = 0; 2938 pstr_sprintf(dirmask, "%s%*s*", cur_dir, i-1, text); 2939 } else 2940 pstr_sprintf(dirmask, "%s*", cur_dir); 2941 2942 if (cli_list(cli, dirmask, aDIR | aSYSTEM | aHIDDEN, completion_remote_filter, &info) < 0) 2943 goto cleanup; 2944 2945 if (info.count == 2) 2946 info.matches[0] = SMB_STRDUP(info.matches[1]); 2947 else { 2948 info.matches[0] = SMB_MALLOC(info.samelen+1); 2949 if (!info.matches[0]) 2950 goto cleanup; 2951 strncpy(info.matches[0], info.matches[1], info.samelen); 2952 info.matches[0][info.samelen] = 0; 2953 } 2954 info.matches[info.count] = NULL; 2955 return info.matches; 2956 2957cleanup: 2958 for (i = 0; i < info.count; i++) 2959 free(info.matches[i]); 2960 free(info.matches); 2961 return NULL; 2962} 2963 2964static char **completion_fn(const char *text, int start, int end) 2965{ 2966 smb_readline_ca_char(' '); 2967 2968 if (start) { 2969 const char *buf, *sp; 2970 int i; 2971 char compl_type; 2972 2973 buf = smb_readline_get_line_buffer(); 2974 if (buf == NULL) 2975 return NULL; 2976 2977 sp = strchr(buf, ' '); 2978 if (sp == NULL) 2979 return NULL; 2980 2981 for (i = 0; commands[i].name; i++) 2982 if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0)) 2983 break; 2984 if (commands[i].name == NULL) 2985 return NULL; 2986 2987 while (*sp == ' ') 2988 sp++; 2989 2990 if (sp == (buf + start)) 2991 compl_type = commands[i].compl_args[0]; 2992 else 2993 compl_type = commands[i].compl_args[1]; 2994 2995 if (compl_type == COMPL_REMOTE) 2996 return remote_completion(text, end - start); 2997 else /* fall back to local filename completion */ 2998 return NULL; 2999 } else { 3000 char **matches; 3001 int i, len, samelen = 0, count=1; 3002 3003 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS); 3004 if (!matches) { 3005 return NULL; 3006 } 3007 matches[0] = NULL; 3008 3009 len = strlen(text); 3010 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) { 3011 if (strncmp(text, commands[i].name, len) == 0) { 3012 matches[count] = SMB_STRDUP(commands[i].name); 3013 if (!matches[count]) 3014 goto cleanup; 3015 if (count == 1) 3016 samelen = strlen(matches[count]); 3017 else 3018 while (strncmp(matches[count], matches[count-1], samelen) != 0) 3019 samelen--; 3020 count++; 3021 } 3022 } 3023 3024 switch (count) { 3025 case 0: /* should never happen */ 3026 case 1: 3027 goto cleanup; 3028 case 2: 3029 matches[0] = SMB_STRDUP(matches[1]); 3030 break; 3031 default: 3032 matches[0] = SMB_MALLOC(samelen+1); 3033 if (!matches[0]) 3034 goto cleanup; 3035 strncpy(matches[0], matches[1], samelen); 3036 matches[0][samelen] = 0; 3037 } 3038 matches[count] = NULL; 3039 return matches; 3040 3041cleanup: 3042 for (i = 0; i < count; i++) 3043 free(matches[i]); 3044 3045 free(matches); 3046 return NULL; 3047 } 3048} 3049 3050/**************************************************************************** 3051 Make sure we swallow keepalives during idle time. 3052****************************************************************************/ 3053 3054static void readline_callback(void) 3055{ 3056 fd_set fds; 3057 struct timeval timeout; 3058 static time_t last_t; 3059 time_t t; 3060 3061 t = time(NULL); 3062 3063 if (t - last_t < 5) 3064 return; 3065 3066 last_t = t; 3067 3068 again: 3069 3070 if (cli->fd == -1) 3071 return; 3072 3073 FD_ZERO(&fds); 3074 FD_SET(cli->fd,&fds); 3075 3076 timeout.tv_sec = 0; 3077 timeout.tv_usec = 0; 3078 sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout); 3079 3080 /* We deliberately use receive_smb instead of 3081 client_receive_smb as we want to receive 3082 session keepalives and then drop them here. 3083 */ 3084 if (FD_ISSET(cli->fd,&fds)) { 3085 receive_smb(cli->fd,cli->inbuf,0); 3086 goto again; 3087 } 3088 3089 cli_chkpath(cli, "\\"); 3090} 3091 3092/**************************************************************************** 3093 Process commands on stdin. 3094****************************************************************************/ 3095 3096static int process_stdin(void) 3097{ 3098 const char *ptr; 3099 int rc = 0; 3100 3101 while (1) { 3102 pstring tok; 3103 pstring the_prompt; 3104 char *cline; 3105 pstring line; 3106 int i; 3107 3108 /* display a prompt */ 3109 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir); 3110 cline = smb_readline(the_prompt, readline_callback, completion_fn); 3111 3112 if (!cline) break; 3113 3114 pstrcpy(line, cline); 3115 3116 /* special case - first char is ! */ 3117 if (*line == '!') { 3118 system(line + 1); 3119 continue; 3120 } 3121 3122 /* and get the first part of the command */ 3123 ptr = line; 3124 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue; 3125 3126 if ((i = process_tok(tok)) >= 0) { 3127 rc = commands[i].fn(); 3128 } else if (i == -2) { 3129 d_printf("%s: command abbreviation ambiguous\n",tok); 3130 } else { 3131 d_printf("%s: command not found\n",tok); 3132 } 3133 } 3134 return rc; 3135} 3136 3137/**************************************************************************** 3138 Process commands from the client. 3139****************************************************************************/ 3140 3141static int process(char *base_directory) 3142{ 3143 int rc = 0; 3144 3145 cli = cli_cm_open(desthost, service, True); 3146 if (!cli) { 3147 return 1; 3148 } 3149 3150 if (*base_directory) do_cd(base_directory); 3151 3152 if (cmdstr) { 3153 rc = process_command_string(cmdstr); 3154 } else { 3155 process_stdin(); 3156 } 3157 3158 cli_cm_shutdown(); 3159 return rc; 3160} 3161 3162/**************************************************************************** 3163 Handle a -L query. 3164****************************************************************************/ 3165 3166static int do_host_query(char *query_host) 3167{ 3168 cli = cli_cm_open(query_host, "IPC$", True); 3169 if (!cli) 3170 return 1; 3171 3172 browse_host(True); 3173 3174 if (port != 139) { 3175 3176 /* Workgroups simply don't make sense over anything 3177 else but port 139... */ 3178 3179 cli_cm_shutdown(); 3180 cli_cm_set_port( 139 ); 3181 cli = cli_cm_open(query_host, "IPC$", True); 3182 } 3183 3184 if (cli == NULL) { 3185 d_printf("NetBIOS over TCP disabled -- no workgroup available\n"); 3186 return 1; 3187 } 3188 3189 list_servers(lp_workgroup()); 3190 3191 cli_cm_shutdown(); 3192 3193 return(0); 3194} 3195 3196/**************************************************************************** 3197 Handle a tar operation. 3198****************************************************************************/ 3199 3200static int do_tar_op(char *base_directory) 3201{ 3202 int ret; 3203 3204 /* do we already have a connection? */ 3205 if (!cli) { 3206 cli = cli_cm_open(desthost, service, True); 3207 if (!cli) 3208 return 1; 3209 } 3210 3211 recurse=True; 3212 3213 if (*base_directory) do_cd(base_directory); 3214 3215 ret=process_tar(); 3216 3217 cli_cm_shutdown(); 3218 3219 return(ret); 3220} 3221 3222/**************************************************************************** 3223 Handle a message operation. 3224****************************************************************************/ 3225 3226static int do_message_op(void) 3227{ 3228 struct in_addr ip; 3229 struct nmb_name called, calling; 3230 fstring server_name; 3231 char name_type_hex[10]; 3232 3233 make_nmb_name(&calling, calling_name, 0x0); 3234 make_nmb_name(&called , desthost, name_type); 3235 3236 fstrcpy(server_name, desthost); 3237 snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type); 3238 fstrcat(server_name, name_type_hex); 3239 3240 zero_ip(&ip); 3241 if (have_ip) 3242 ip = dest_ip; 3243 3244 if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) || 3245 !cli_connect(cli, server_name, &ip)) { 3246 d_printf("Connection to %s failed\n", desthost); 3247 return 1; 3248 } 3249 3250 if (!cli_session_request(cli, &calling, &called)) { 3251 d_printf("session request failed\n"); 3252 cli_cm_shutdown(); 3253 return 1; 3254 } 3255 3256 send_message(); 3257 cli_cm_shutdown(); 3258 3259 return 0; 3260} 3261 3262 3263/**************************************************************************** 3264 main program 3265****************************************************************************/ 3266 3267 int main(int argc,char *argv[]) 3268{ 3269 extern BOOL AllowDebugChange; 3270 extern BOOL override_logfile; 3271 pstring base_directory; 3272 int opt; 3273 pstring query_host; 3274 BOOL message = False; 3275 extern char tar_type; 3276 pstring term_code; 3277 static const char *new_name_resolve_order = NULL; 3278 poptContext pc; 3279 char *p; 3280 int rc = 0; 3281 fstring new_workgroup; 3282 struct poptOption long_options[] = { 3283 POPT_AUTOHELP 3284 3285 { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" }, 3286 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" }, 3287 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" }, 3288 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" }, 3289 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" }, 3290 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" }, 3291 { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" }, 3292 { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" }, 3293 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" }, 3294 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 3295 { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" }, 3296 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" }, 3297 { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" }, 3298 POPT_COMMON_SAMBA 3299 POPT_COMMON_CONNECTION 3300 POPT_COMMON_CREDENTIALS 3301 POPT_TABLEEND 3302 }; 3303 3304 3305#ifdef KANJI 3306 pstrcpy(term_code, KANJI); 3307#else /* KANJI */ 3308 *term_code = 0; 3309#endif /* KANJI */ 3310 3311 *query_host = 0; 3312 *base_directory = 0; 3313 3314 /* initialize the workgroup name so we can determine whether or 3315 not it was set by a command line option */ 3316 3317 set_global_myworkgroup( "" ); 3318 set_global_myname( "" ); 3319 3320 /* set default debug level to 0 regardless of what smb.conf sets */ 3321 setup_logging( "smbclient", True ); 3322 DEBUGLEVEL_CLASS[DBGC_ALL] = 1; 3323 dbf = x_stderr; 3324 x_setbuf( x_stderr, NULL ); 3325 3326 pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 3327 POPT_CONTEXT_KEEP_FIRST); 3328 poptSetOtherOptionHelp(pc, "service <password>"); 3329 3330 in_client = True; /* Make sure that we tell lp_load we are */ 3331 3332 while ((opt = poptGetNextOpt(pc)) != -1) { 3333 switch (opt) { 3334 case 'M': 3335 /* Messages are sent to NetBIOS name type 0x3 3336 * (Messenger Service). Make sure we default 3337 * to port 139 instead of port 445. srl,crh 3338 */ 3339 name_type = 0x03; 3340 cli_cm_set_dest_name_type( name_type ); 3341 pstrcpy(desthost,poptGetOptArg(pc)); 3342 if( !port ) 3343 cli_cm_set_port( 139 ); 3344 message = True; 3345 break; 3346 case 'I': 3347 { 3348 dest_ip = *interpret_addr2(poptGetOptArg(pc)); 3349 if (is_zero_ip(dest_ip)) 3350 exit(1); 3351 have_ip = True; 3352 3353 cli_cm_set_dest_ip( dest_ip ); 3354 } 3355 break; 3356 case 'E': 3357 dbf = x_stderr; 3358 display_set_stderr(); 3359 break; 3360 3361 case 'L': 3362 pstrcpy(query_host, poptGetOptArg(pc)); 3363 break; 3364 case 't': 3365 pstrcpy(term_code, poptGetOptArg(pc)); 3366 break; 3367 case 'm': 3368 max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol); 3369 break; 3370 case 'T': 3371 /* We must use old option processing for this. Find the 3372 * position of the -T option in the raw argv[]. */ 3373 { 3374 int i, optnum; 3375 for (i = 1; i < argc; i++) { 3376 if (strncmp("-T", argv[i],2)==0) 3377 break; 3378 } 3379 i++; 3380 if (!(optnum = tar_parseargs(argc, argv, poptGetOptArg(pc), i))) { 3381 poptPrintUsage(pc, stderr, 0); 3382 exit(1); 3383 } 3384 /* Now we must eat (optnum - i) options - they have 3385 * been processed by tar_parseargs(). 3386 */ 3387 optnum -= i; 3388 for (i = 0; i < optnum; i++) 3389 poptGetOptArg(pc); 3390 } 3391 break; 3392 case 'D': 3393 pstrcpy(base_directory,poptGetOptArg(pc)); 3394 break; 3395 case 'g': 3396 grepable=True; 3397 break; 3398 } 3399 } 3400 3401 poptGetArg(pc); 3402 3403 if ( have_ip ) 3404 3405 /* 3406 * Don't load debug level from smb.conf. It should be 3407 * set by cmdline arg or remain default (0) 3408 */ 3409 AllowDebugChange = False; 3410 3411 /* save the workgroup... 3412 3413 FIXME!! do we need to do this for other options as well 3414 (or maybe a generic way to keep lp_load() from overwriting 3415 everything)? */ 3416 3417 fstrcpy( new_workgroup, lp_workgroup() ); 3418 pstrcpy( calling_name, global_myname() ); 3419 3420 if ( override_logfile ) 3421 setup_logging( lp_logfile(), False ); 3422 3423 if (!lp_load(dyn_CONFIGFILE,True,False,False)) { 3424 fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n", 3425 argv[0], dyn_CONFIGFILE); 3426 } 3427 3428 load_interfaces(); 3429 3430 if ( strlen(new_workgroup) != 0 ) 3431 set_global_myworkgroup( new_workgroup ); 3432 3433 if ( strlen(calling_name) != 0 ) 3434 set_global_myname( calling_name ); 3435 3436 if(poptPeekArg(pc)) { 3437 pstrcpy(service,poptGetArg(pc)); 3438 /* Convert any '/' characters in the service name to '\' characters */ 3439 string_replace(service, '/','\\'); 3440 3441 if (count_chars(service,'\\') < 3) { 3442 d_printf("\n%s: Not enough '\\' characters in service\n",service); 3443 poptPrintUsage(pc, stderr, 0); 3444 exit(1); 3445 } 3446 } 3447 3448 if (poptPeekArg(pc) && !cmdline_auth_info.got_pass) { 3449 cmdline_auth_info.got_pass = True; 3450 pstrcpy(cmdline_auth_info.password,poptGetArg(pc)); 3451 } 3452 3453 init_names(); 3454 3455 if(new_name_resolve_order) 3456 lp_set_name_resolve_order(new_name_resolve_order); 3457 3458 if (!tar_type && !*query_host && !*service && !message) { 3459 poptPrintUsage(pc, stderr, 0); 3460 exit(1); 3461 } 3462 3463 poptFreeContext(pc); 3464 3465 /* store the username an password for dfs support */ 3466 3467 cli_cm_set_credentials( &cmdline_auth_info ); 3468 pstrcpy(username, cmdline_auth_info.username); 3469 3470 DEBUG(3,("Client started (version %s).\n", SAMBA_VERSION_STRING)); 3471 3472 if (tar_type) { 3473 if (cmdstr) 3474 process_command_string(cmdstr); 3475 return do_tar_op(base_directory); 3476 } 3477 3478 if (*query_host) { 3479 char *qhost = query_host; 3480 char *slash; 3481 3482 while (*qhost == '\\' || *qhost == '/') 3483 qhost++; 3484 3485 if ((slash = strchr_m(qhost, '/')) 3486 || (slash = strchr_m(qhost, '\\'))) { 3487 *slash = 0; 3488 } 3489 3490 if ((p=strchr_m(qhost, '#'))) { 3491 *p = 0; 3492 p++; 3493 sscanf(p, "%x", &name_type); 3494 cli_cm_set_dest_name_type( name_type ); 3495 } 3496 3497 return do_host_query(qhost); 3498 } 3499 3500 if (message) { 3501 return do_message_op(); 3502 } 3503 3504 if (process(base_directory)) { 3505 return 1; 3506 } 3507 3508 return rc; 3509} 3510