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