sys_select added one more argument (read, write selectors).
[tprouty/samba.git] / source / client / smbmount.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define NO_SYSLOG
23
24 #include <linux/version.h>
25 #define LVERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
26 #if LINUX_VERSION_CODE < LVERSION(2,1,70)
27 #error this code will only compile on versions of linux after 2.1.70
28 #endif
29
30 #include "includes.h"
31
32 #include <mntent.h>
33
34 #include <asm/types.h>
35 #include <linux/smb_fs.h>
36 static struct smb_conn_opt conn_options;
37
38 #ifndef REGISTER
39 #define REGISTER 0
40 #endif
41
42 /* Uncomment this to allow debug the smbmount daemon */
43 /* WARNING!  This option is incompatible with autofs/automount because
44         it does not close the stdout pipe back to the automount
45         process, which automount depends on.  This will cause automount
46         to hang!  Use with caution! */
47 /* #define SMBFS_DEBUG 1        */
48
49 pstring cur_dir = "\\";
50 pstring cd_path = "";
51 extern pstring service;
52 extern pstring desthost;
53 extern pstring global_myname;
54 extern pstring myhostname;
55 extern pstring password;
56 extern pstring smb_login_passwd;
57 extern pstring username;
58 extern pstring workgroup;
59 char *cmdstr="";
60 extern BOOL got_pass;
61 extern BOOL connect_as_printer;
62 extern BOOL connect_as_ipc;
63 extern struct in_addr ipzero;
64
65 extern BOOL doencrypt;
66
67 extern pstring user_socket_options;
68
69 /* 30 second timeout on most commands */
70 #define CLIENT_TIMEOUT (30*1000)
71 #define SHORT_TIMEOUT (5*1000)
72
73 /* value for unused fid field in trans2 secondary request */
74 #define FID_UNUSED (0xFFFF)
75
76 extern int name_type;
77
78 extern int max_protocol;
79 int port = SMB_PORT;
80
81 time_t newer_than = 0;
82 int archive_level = 0;
83
84 extern pstring debugf;
85 extern int DEBUGLEVEL;
86
87 BOOL translation = False;
88
89 extern uint16 cnum;
90 extern uint16 mid;
91 extern uint16 pid;
92 extern uint16 vuid;
93
94 extern BOOL have_ip;
95 extern int max_xmit;
96
97 /* clitar bits insert */
98 extern int blocksize;
99 extern BOOL tar_inc;
100 extern BOOL tar_reset;
101 /* clitar bits end */
102  
103
104 mode_t myumask = 0755;
105
106 extern pstring scope;
107
108 BOOL prompt = True;
109
110 int printmode = 1;
111
112 BOOL recurse = False;
113 BOOL lowercase = False;
114
115 struct in_addr dest_ip;
116
117 #define SEPARATORS " \t\n\r"
118
119 BOOL abort_mget = True;
120
121 extern int Protocol;
122
123 extern BOOL readbraw_supported ;
124 extern BOOL writebraw_supported;
125
126 pstring fileselection = "";
127
128 extern file_info def_finfo;
129
130 /* timing globals */
131 int get_total_size = 0;
132 int get_total_time_ms = 0;
133 int put_total_size = 0;
134 int put_total_time_ms = 0;
135
136 /* totals globals */
137 int dir_total = 0;
138
139 extern int Client;
140
141 #define USENMB
142
143 #define CNV_LANG(s) dos_to_unix(s,False)
144 #define CNV_INPUT(s) unix_to_dos(s,True)
145
146 /****************************************************************************
147 check for existance of a dir
148 ****************************************************************************/
149 static BOOL chkpath(char *path,BOOL report)
150 {
151   fstring path2;
152   pstring inbuf,outbuf;
153   char *p;
154
155   fstrcpy(path2,path);
156   trim_string(path2,NULL,"\\");
157   if (!*path2) *path2 = '\\';
158
159   memset(outbuf,'\0',smb_size);
160   set_message(outbuf,0,4 + strlen(path2),True);
161   SCVAL(outbuf,smb_com,SMBchkpth);
162   SSVAL(outbuf,smb_tid,cnum);
163   cli_setup_pkt(outbuf);
164
165   p = smb_buf(outbuf);
166   *p++ = 4;
167   fstrcpy(p,path2);
168
169 #if 0
170   {
171           /* this little bit of code can be used to extract NT error codes.
172              Just feed a bunch of "cd foo" commands to smbclient then watch
173              in netmon (tridge) */
174           static int code=0;
175           SIVAL(outbuf, smb_rcls, code | 0xC0000000);
176           SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
177           code++;
178   }
179 #endif
180
181   send_smb(Client,outbuf);
182   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
183
184   if (report && CVAL(inbuf,smb_rcls) != 0)
185     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
186
187   return(CVAL(inbuf,smb_rcls) == 0);
188 }
189
190 static void
191 exit_parent( int sig )
192 {
193         /* parent simply exits when child says go... */
194         exit(0);
195 }
196
197 static void
198 daemonize(void)
199 {
200         int j, status;
201         pid_t child_pid;
202
203         signal( SIGTERM, exit_parent );
204
205         if ((child_pid = fork()) < 0)
206         {
207                 DEBUG(0, ("could not fork\n"));
208         }
209         if (child_pid > 0)
210         {
211                 while( 1 ) {
212                         j = waitpid( child_pid, &status, 0 );
213                         if( j < 0 ) {
214                                 if( EINTR == errno ) {
215                                         continue;
216                                 }
217                                 status = errno;
218                         }
219                         break;
220                 }
221                 /* If we get here - the child exited with some error status */
222                 exit(status);
223         }
224         /* Programmers Note:
225                 Danger Will Robinson!  Danger!
226
227                 There use to be a call to setsid() here.  This does no
228                 harm to normal mount operations, but it broke automounting.
229                 The setsid call has been moved to just before the child
230                 sends the SIGTERM to the parent.  All of our deadly embrace
231                 conditions with autofs will have been cleared by then...
232                 -mhw-
233         */
234         signal( SIGTERM, SIG_DFL );
235         chdir("/");
236 }
237
238 static void
239 close_our_files(void)
240 {
241         int i;
242         for (i = 0; i < NR_OPEN; i++) {
243                 if (i == Client) {
244                         continue;
245                 }
246                 close(i);
247         }
248 }
249
250 static void
251 usr1_handler(int x)
252 {
253         return;
254 }
255
256 /*
257  * Send a login and store the connection options. This is a separate
258  * function to keep clientutil.c independent of linux kernel changes.
259  */
260 static BOOL mount_send_login(char *inbuf, char *outbuf)
261 {
262   struct connection_options opt;
263   int res = cli_send_login(inbuf, outbuf, True, True, &opt);
264
265   if (!res)
266     return res;
267
268   if( !got_pass ) {
269         /* Ok...  If we got this thing connected and got_pass is false,
270            that means that the client util prompted for a password and
271            got a good one...  We need to cache this in password and set
272            got_pass for future retries.  We don't want to prompt for the
273            $#@$#$ password everytime the network blinks!
274         */
275
276       pstrcpy(password,smb_login_passwd);
277       got_pass = True;
278   }
279   conn_options.protocol = opt.protocol;
280   conn_options.case_handling = CASE_LOWER;
281   conn_options.max_xmit = opt.max_xmit;
282   conn_options.server_uid = opt.server_vuid;
283   conn_options.tid = opt.tid;
284   conn_options.secmode = opt.sec_mode;
285   conn_options.maxmux = opt.max_mux;
286   conn_options.maxvcs = opt.max_vcs;
287   conn_options.rawmode = opt.rawmode;
288   conn_options.sesskey = opt.sesskey;
289   conn_options.maxraw = opt.maxraw;
290   conn_options.capabilities = opt.capabilities;
291   conn_options.serverzone = opt.serverzone;
292
293   return True;
294 }
295
296 /****************************************************************************
297 unmount smbfs  (this is a bailout routine to clean up if a reconnect fails)
298         Code blatently stolen from smbumount.c
299                 -mhw-
300 ****************************************************************************/
301 static void smb_umount( char *mount_point )
302 {
303         int fd;
304         struct mntent *mnt;
305         FILE* mtab;
306         FILE* new_mtab;
307
308         /* Programmers Note:
309                 This routine only gets called to the scene of a disaster
310                 to shoot the survivors...  A connection that was working
311                 has now apparently failed.  We have an active mount point
312                 (presumably) that we need to dump.  If we get errors along
313                 the way - make some noise, but we are already turning out
314                 the lights to exit anyways...
315         */
316         if (umount(mount_point) != 0) {
317                 DEBUG(0, ("Could not umount %s: %s\n",
318                         mount_point, strerror(errno)));
319                 return;
320         }
321
322         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
323         {
324                 DEBUG(0, ("Can't get "MOUNTED"~ lock file"));
325                 return;
326         }
327         close(fd);
328         
329         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
330                 DEBUG(0, ("Can't open " MOUNTED ": %s\n",
331                         strerror(errno)));
332                 return;
333         }
334
335 #define MOUNTED_TMP MOUNTED".tmp"
336
337         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
338                 DEBUG(0, ("Can't open " MOUNTED_TMP ": %s\n",
339                         strerror(errno)));
340                 endmntent(mtab);
341                 return;
342         }
343
344         while ((mnt = getmntent(mtab)) != NULL) {
345                 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
346                         addmntent(new_mtab, mnt);
347                 }
348         }
349
350         endmntent(mtab);
351
352         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
353                 DEBUG(0, ("Error changing mode of %s: %s\n",
354                         MOUNTED_TMP, strerror(errno)));
355                 return;
356         }
357
358         endmntent(new_mtab);
359
360         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
361                 DEBUG(0, ("Cannot rename %s to %s: %s\n",
362                         MOUNTED, MOUNTED_TMP, strerror(errno)));
363                 return;
364         }
365
366         if (unlink(MOUNTED"~") == -1)
367         {
368                 DEBUG(0, ("Can't remove "MOUNTED"~"));
369                 return;
370         }
371
372         return;
373 }
374
375
376 /*
377  * Call the smbfs ioctl to install a connection socket,
378  * then wait for a signal to reconnect. Note that we do
379  * not exit after open_sockets() or send_login() errors,
380  * as the smbfs mount would then have no way to recover.
381  */
382 static void
383 send_fs_socket(char *mount_point, char *inbuf, char *outbuf)
384 {
385         int fd, closed = 0, res = 1;
386
387         pid_t parentpid = getppid();
388
389         while (1)
390         {
391                 if ((fd = open(mount_point, O_RDONLY)) < 0)
392                 {
393                         DEBUG(0, ("smbmount: can't open %s\n", mount_point));
394                         break;
395                 }               
396
397                 /*
398                  * Call the ioctl even if we couldn't get a socket ...
399                  * there's no point in making smbfs wait for a timeout.
400                  */
401                 conn_options.fd = -1;
402                 if (res)
403                         conn_options.fd = Client;
404                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
405                 if (res != 0)
406                 {
407                         DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
408                 }
409
410                 if( parentpid ) {
411                         /* Ok...  We are going to kill the parent.  Now
412                                 is the time to break the process group... */
413                         setsid();
414                         /* Send a signal to the parent to terminate */
415                         kill( parentpid, SIGTERM );
416                         parentpid = 0;
417                 }
418
419                 close_sockets();
420                 close(fd);
421                 /*
422                  * Close all open files if we haven't done so yet.
423                  */
424 #ifndef SMBFS_DEBUG
425                 if (!closed)
426                 {
427                         closed = 1;
428                         close_our_files();
429                 }
430 #endif
431
432                 /*
433                  * Wait for a signal from smbfs ...
434                  */
435                 CatchSignal(SIGUSR1, &usr1_handler);
436                 pause();
437                 DEBUG(0, ("smbmount: got signal, getting new socket\n"));
438
439                 res = cli_open_sockets(port);
440                 if (!res)
441                 {
442                         DEBUG(0, ("smbmount: can't open sockets\n"));
443                         continue;
444                 }
445
446                 res = mount_send_login(inbuf, outbuf);
447                 if (!res)
448                 {
449                         DEBUG(0, ("smbmount: login failed\n"));
450                         break;
451                 }
452         }
453         smb_umount( mount_point );
454         DEBUG(0, ("smbmount: exit\n"));
455         exit(1);
456 }
457
458 /****************************************************************************
459 mount smbfs
460 ****************************************************************************/
461 static void cmd_mount(char *inbuf,char *outbuf)
462 {
463         pstring mpoint;
464         pstring share_name;
465         pstring mount_command;
466         fstring buf;
467         int retval;
468         char mount_point[MAXPATHLEN+1];
469
470         if (!next_token(NULL, mpoint, NULL, sizeof(mpoint)))
471         {
472                 DEBUG(0,("You must supply a mount point\n"));
473                 return;
474         }
475
476         memset(mount_point, 0, sizeof(mount_point));
477
478         if (realpath(mpoint, mount_point) == NULL)
479         {
480                 DEBUG(0, ("Could not resolve mount point\n"));
481                 return;
482         }
483
484         /*
485          * Build the service name to report on the Unix side,
486          * converting '\' to '/' and ' ' to '_'.
487          */
488         pstrcpy(share_name, service);  
489         string_replace(share_name, '\\', '/');
490         string_replace(share_name, ' ', '_');
491
492         slprintf(mount_command, sizeof(mount_command)-1,"smbmnt %s -s %s", mount_point, share_name);
493
494         while(next_token(NULL, buf, NULL, sizeof(buf)))
495         {
496                 pstrcat(mount_command, " ");
497                 pstrcat(mount_command, buf);
498         }
499
500         DEBUG(3, ("mount command: %s\n", mount_command));
501
502         /*
503                 Set up to return as a daemon child and wait in the parent
504                 until the child say it's ready...
505         */
506         daemonize();
507
508         if ((retval = system(mount_command)) != 0)
509         {
510                 DEBUG(0,("mount failed\n"));
511                 exit(1);
512         }
513
514         /* Ok...  This is the rubicon for that mount point...  At any point
515            after this, if the connections fail and can not be reconstructed
516            for any reason, we will have to unmount the mount point.  There
517            is no exit from the next call...
518         */
519         send_fs_socket(mount_point, inbuf, outbuf);
520 }
521
522
523 /* This defines the commands supported by this client */
524 struct
525 {
526   char *name;
527   void (*fn)();
528   char *description;
529 } commands[] = 
530 {
531   {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
532   {"",NULL,NULL}
533 };
534
535
536 /*******************************************************************
537   lookup a command string in the list of commands, including 
538   abbreviations
539   ******************************************************************/
540 static int process_tok(fstring tok)
541 {
542   int i = 0, matches = 0;
543   int cmd=0;
544   int tok_len = strlen(tok);
545   
546   while (commands[i].fn != NULL)
547     {
548       if (strequal(commands[i].name,tok))
549         {
550           matches = 1;
551           cmd = i;
552           break;
553         }
554       else if (strnequal(commands[i].name, tok, tok_len))
555         {
556           matches++;
557           cmd = i;
558         }
559       i++;
560     }
561   
562   if (matches == 0)
563     return(-1);
564   else if (matches == 1)
565     return(cmd);
566   else
567     return(-2);
568 }
569
570 /****************************************************************************
571 help
572 ****************************************************************************/
573 void cmd_help(char *dum_in, char *dum_out)
574 {
575   int i=0,j;
576   fstring buf;
577
578   if (next_token(NULL,buf,NULL,sizeof(buf)))
579     {
580       if ((i = process_tok(buf)) >= 0)
581         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
582     }
583   else
584     while (commands[i].description)
585       {
586         for (j=0; commands[i].description && (j<5); j++) {
587           DEBUG(0,("%-15s",commands[i].name));
588           i++;
589         }
590         DEBUG(0,("\n"));
591       }
592 }
593
594 /****************************************************************************
595 wait for keyboard activity, swallowing network packets
596 ****************************************************************************/
597 static void wait_keyboard(char *buffer)
598 {
599   fd_set fds;
600   int selrtn;
601   struct timeval timeout;
602   
603   while (1) 
604     {
605       extern int Client;
606       FD_ZERO(&fds);
607       FD_SET(Client,&fds);
608       FD_SET(fileno(stdin),&fds);
609
610       timeout.tv_sec = 20;
611       timeout.tv_usec = 0;
612       selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,NULL, &timeout);
613       
614       if (FD_ISSET(fileno(stdin),&fds))
615         return;
616
617       /* We deliberately use receive_smb instead of
618          client_receive_smb as we want to receive
619          session keepalives and then drop them here.
620        */
621       if (FD_ISSET(Client,&fds))
622         receive_smb(Client,buffer,0);
623       
624       chkpath("\\",False);
625     }  
626 }
627
628
629 /****************************************************************************
630   process commands from the client
631 ****************************************************************************/
632 static BOOL process(char *base_directory)
633 {
634   extern FILE *dbf;
635   pstring line;
636   char *cmd;
637
638   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
639   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
640
641   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
642     return(False);
643   
644   memset(OutBuffer,'\0',smb_size);
645
646   if (!mount_send_login(InBuffer,OutBuffer))
647     return(False);
648
649   cmd = cmdstr;
650   if (cmd[0] != '\0') while (cmd[0] != '\0')
651     {
652       char *p;
653       fstring tok;
654       int i;
655
656       if ((p = strchr(cmd, ';')) == 0)
657         {
658           strncpy(line, cmd, 999);
659           line[1000] = '\0';
660           cmd += strlen(cmd);
661         }
662       else
663         {
664           if (p - cmd > 999) p = cmd + 999;
665           strncpy(line, cmd, p - cmd);
666           line[p - cmd] = '\0';
667           cmd = p + 1;
668         }
669
670       /* input language code to internal one */
671       CNV_INPUT (line);
672       
673       /* and get the first part of the command */
674       {
675         char *ptr = line;
676         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
677       }
678
679       if ((i = process_tok(tok)) >= 0)
680         commands[i].fn(InBuffer,OutBuffer);
681       else if (i == -2)
682         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
683       else
684         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
685     }
686   else while (!feof(stdin))
687     {
688       fstring tok;
689       int i;
690
691       memset(OutBuffer,'\0',smb_size);
692
693       /* display a prompt */
694       DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
695       dbgflush();
696
697       wait_keyboard(InBuffer);
698   
699       /* and get a response */
700       if (!fgets(line,1000,stdin))
701         break;
702
703       /* input language code to internal one */
704       CNV_INPUT (line);
705
706       /* special case - first char is ! */
707       if (*line == '!')
708         {
709           system(line + 1);
710           continue;
711         }
712       
713       /* and get the first part of the command */
714       {
715         char *ptr = line;
716         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
717       }
718
719       if ((i = process_tok(tok)) >= 0)
720         commands[i].fn(InBuffer,OutBuffer);
721       else if (i == -2)
722         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
723       else
724         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
725     }
726   
727   cli_send_logout(InBuffer,OutBuffer);
728   return(True);
729 }
730
731 /****************************************************************************
732 usage on the program
733 ****************************************************************************/
734 static void usage(char *pname)
735 {
736   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
737            pname));
738
739   DEBUG(0,("\nVersion %s\n",VERSION));
740   DEBUG(0,("\t-p port               connect to the specified port\n"));
741   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
742   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
743   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
744   DEBUG(0,("\t-N                    don't ask for a password\n"));
745   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
746   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
747   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
748   DEBUG(0,("\t-U username           set the network username\n"));
749   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
750   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
751   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
752   DEBUG(0,("\t-D directory          start from directory\n"));
753   DEBUG(0,("\n"));
754 }
755
756 /****************************************************************************
757   main program
758 ****************************************************************************/
759  int main(int argc,char *argv[])
760 {
761   fstring base_directory;
762   char *pname = argv[0];
763   int opt;
764   extern FILE *dbf;
765   extern char *optarg;
766   extern int optind;
767   pstring query_host;
768   BOOL nt_domain_logon = False;
769   static pstring servicesf = CONFIGFILE;
770   pstring term_code;
771   char *p;
772
773 #ifdef KANJI
774   pstrcpy(term_code, KANJI);
775 #else /* KANJI */
776   *term_code = 0;
777 #endif /* KANJI */
778
779   *query_host = 0;
780   *base_directory = 0;
781
782   DEBUGLEVEL = 2;
783
784   setup_logging(pname,True);
785
786   TimeInit();
787   charset_initialise();
788
789   pid = (uint16)getpid();
790   vuid = (uint16)getuid();
791   mid = pid + 100;
792   myumask = umask(0);
793   umask(myumask);
794
795   if (getenv("USER"))
796   {
797     pstrcpy(username,getenv("USER"));
798
799     /* modification to support userid%passwd syntax in the USER var
800        25.Aug.97, jdblair@uab.edu */
801
802     if ((p=strchr(username,'%')))
803     {
804       *p = 0;
805       pstrcpy(password,p+1);
806       got_pass = True;
807       memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
808     }
809     strupper(username);
810   }
811
812  /* modification to support PASSWD environmental var
813   25.Aug.97, jdblair@uab.edu */
814
815   if (getenv("PASSWD"))
816     pstrcpy(password,getenv("PASSWD"));
817
818   if (*username == 0 && getenv("LOGNAME"))
819     {
820       pstrcpy(username,getenv("LOGNAME"));
821       strupper(username);
822     }
823
824   if (argc < 2)
825     {
826       usage(pname);
827       exit(1);
828     }
829   
830   if (*argv[1] != '-')
831     {
832
833       pstrcpy(service, argv[1]);  
834       /* Convert any '/' characters in the service name to '\' characters */
835       string_replace( service, '/','\\');
836       argc--;
837       argv++;
838
839       if (count_chars(service,'\\') < 3)
840         {
841           usage(pname);
842           printf("\n%s: Not enough '\\' characters in service\n",service);
843           exit(1);
844         }
845
846       if (argc > 1 && (*argv[1] != '-'))
847         {
848           got_pass = True;
849           pstrcpy(password,argv[1]);  
850           memset(argv[1],'X',strlen(argv[1]));
851           argc--;
852           argv++;
853         }
854     }
855
856   while ((opt = 
857           getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
858     switch (opt)
859       {
860       case 'm':
861         max_protocol = interpret_protocol(optarg,max_protocol);
862         break;
863       case 'O':
864         pstrcpy(user_socket_options,optarg);
865         break;  
866       case 'S':
867         pstrcpy(desthost,optarg);
868         strupper(desthost);
869         nt_domain_logon = True;
870         break;
871       case 'B':
872         iface_set_default(NULL,optarg,NULL);
873         break;
874       case 'D':
875         pstrcpy(base_directory,optarg);
876         break;
877       case 'i':
878         pstrcpy(scope,optarg);
879         break;
880       case 'U':
881         {
882           char *lp;
883         pstrcpy(username,optarg);
884         if ((lp=strchr(username,'%')))
885           {
886             *lp = 0;
887             pstrcpy(password,lp+1);
888             got_pass = True;
889             memset(strchr(optarg,'%')+1,'X',strlen(password));
890           }
891         }
892             
893         break;
894       case 'W':
895         pstrcpy(workgroup,optarg);
896         break;
897       case 'E':
898         dbf = stderr;
899         break;
900       case 'I':
901         {
902           dest_ip = *interpret_addr2(optarg);
903           if (zero_ip(dest_ip)) exit(1);
904           have_ip = True;
905         }
906         break;
907       case 'n':
908         pstrcpy(global_myname,optarg);
909         break;
910       case 'N':
911         got_pass = True;
912         break;
913       case 'd':
914         if (*optarg == 'A')
915           DEBUGLEVEL = 10000;
916         else
917           DEBUGLEVEL = atoi(optarg);
918         break;
919       case 'l':
920         slprintf(debugf,sizeof(debugf)-1,"%s.client",optarg);
921         break;
922       case 'p':
923         port = atoi(optarg);
924         break;
925       case 'c':
926         cmdstr = optarg;
927         got_pass = True;
928         break;
929       case 'h':
930         usage(pname);
931         exit(0);
932         break;
933       case 's':
934         pstrcpy(servicesf, optarg);
935         break;
936       case 't':
937         pstrcpy(term_code, optarg);
938         break;
939       default:
940         usage(pname);
941         exit(1);
942       }
943
944   if (!*query_host && !*service)
945     {
946       usage(pname);
947       exit(1);
948     }
949
950
951   DEBUG( 3, ( "Client started (version %s)\n", VERSION ) );
952
953   if(!get_myname(myhostname,NULL))
954   {
955     DEBUG(0,("Failed to get my hostname.\n"));
956   }
957
958   if (!lp_load(servicesf,True,False,False)) {
959     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
960   }
961
962   codepage_initialise(lp_client_code_page());
963
964   interpret_coding_system(term_code);
965
966   if (*workgroup == 0)
967     pstrcpy(workgroup,lp_workgroup());
968
969   load_interfaces();
970   get_myname((*global_myname)?NULL:global_myname,NULL);  
971   strupper(global_myname);
972
973   if (cli_open_sockets(port))
974     {
975       if (!process(base_directory))
976         {
977           close_sockets();
978           return(1);
979         }
980       close_sockets();
981     }
982   else
983     return(1);
984
985   return(0);
986 }