Adding the same changes to HEAD as were added to BRANCH_1_9_18.
[kai/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 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
25
26 #include <linux/version.h>
27 #define LVERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
28 #if LINUX_VERSION_CODE < LVERSION(2,1,70)
29 #error this code will only compile on versions of linux after 2.1.70
30 #endif
31
32 #include "includes.h"
33 #include <linux/smb_fs.h>
34 static struct smb_conn_opt conn_options;
35
36 #ifndef REGISTER
37 #define REGISTER 0
38 #endif
39
40 /* Uncomment this to allow debug the smbmount daemon */
41 #define SMBFS_DEBUG 1
42
43 pstring cur_dir = "\\";
44 pstring cd_path = "";
45 extern pstring service;
46 extern pstring desthost;
47 extern pstring myname;
48 extern pstring myhostname;
49 extern pstring password;
50 extern pstring username;
51 extern pstring workgroup;
52 char *cmdstr="";
53 extern BOOL got_pass;
54 extern BOOL connect_as_printer;
55 extern BOOL connect_as_ipc;
56 extern struct in_addr ipzero;
57
58 extern BOOL doencrypt;
59
60 extern pstring user_socket_options;
61
62 /* 30 second timeout on most commands */
63 #define CLIENT_TIMEOUT (30*1000)
64 #define SHORT_TIMEOUT (5*1000)
65
66 /* value for unused fid field in trans2 secondary request */
67 #define FID_UNUSED (0xFFFF)
68
69 extern int name_type;
70
71 extern int max_protocol;
72 int port = SMB_PORT;
73
74
75 time_t newer_than = 0;
76 int archive_level = 0;
77
78 extern pstring debugf;
79 extern int DEBUGLEVEL;
80
81 BOOL translation = False;
82
83 extern int cnum;
84 extern int mid;
85 extern int pid;
86 extern int tid;
87 extern int gid;
88 extern int uid;
89
90 extern BOOL have_ip;
91 extern int max_xmit;
92
93 /* clitar bits insert */
94 extern int blocksize;
95 extern BOOL tar_inc;
96 extern BOOL tar_reset;
97 /* clitar bits end */
98  
99
100 int myumask = 0755;
101
102 extern pstring scope;
103
104 BOOL prompt = True;
105
106 int printmode = 1;
107
108 BOOL recurse = False;
109 BOOL lowercase = False;
110
111 struct in_addr dest_ip;
112
113 #define SEPARATORS " \t\n\r"
114
115 BOOL abort_mget = True;
116
117 extern int Protocol;
118
119 extern BOOL readbraw_supported ;
120 extern BOOL writebraw_supported;
121
122 pstring fileselection = "";
123
124 extern file_info def_finfo;
125
126 /* timing globals */
127 int get_total_size = 0;
128 int get_total_time_ms = 0;
129 int put_total_size = 0;
130 int put_total_time_ms = 0;
131
132 /* totals globals */
133 int dir_total = 0;
134
135 extern int Client;
136
137 #define USENMB
138
139 #define CNV_LANG(s) dos_to_unix(s,False)
140 #define CNV_INPUT(s) unix_to_dos(s,True)
141
142 /****************************************************************************
143 check for existance of a dir
144 ****************************************************************************/
145 static BOOL chkpath(char *path,BOOL report)
146 {
147   fstring path2;
148   pstring inbuf,outbuf;
149   char *p;
150
151   strcpy(path2,path);
152   trim_string(path2,NULL,"\\");
153   if (!*path2) *path2 = '\\';
154
155   bzero(outbuf,smb_size);
156   set_message(outbuf,0,4 + strlen(path2),True);
157   SCVAL(outbuf,smb_com,SMBchkpth);
158   SSVAL(outbuf,smb_tid,cnum);
159   cli_setup_pkt(outbuf);
160
161   p = smb_buf(outbuf);
162   *p++ = 4;
163   strcpy(p,path2);
164
165 #if 0
166   {
167           /* this little bit of code can be used to extract NT error codes.
168              Just feed a bunch of "cd foo" commands to smbclient then watch
169              in netmon (tridge) */
170           static int code=0;
171           SIVAL(outbuf, smb_rcls, code | 0xC0000000);
172           SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
173           code++;
174   }
175 #endif
176
177   send_smb(Client,outbuf);
178   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
179
180   if (report && CVAL(inbuf,smb_rcls) != 0)
181     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
182
183   return(CVAL(inbuf,smb_rcls) == 0);
184 }
185
186 static void
187 daemonize(void)
188 {
189         int i;
190         if ((i = fork()) < 0)
191         {
192                 DEBUG(0, ("could not fork\n"));
193         }
194         if (i > 0)
195         {
196                 /* parent simply exits */
197                 exit(0);
198         }
199         setsid();
200         chdir("/");
201 }
202
203 static void
204 close_our_files(void)
205 {
206         int i;
207         for (i = 0; i < NR_OPEN; i++) {
208                 if (i == Client) {
209                         continue;
210                 }
211                 close(i);
212         }
213 }
214
215 static void
216 usr1_handler(int x)
217 {
218         return;
219 }
220
221 /*
222  * Send a login and store the connection options. This is a separate
223  * function to keep clientutil.c independent of linux kernel changes.
224  */
225 static BOOL mount_send_login(char *inbuf, char *outbuf)
226 {
227   struct connection_options opt;
228   int res = cli_send_login(inbuf, outbuf, True, True, &opt);
229
230   if (!res)
231     return res;
232
233   conn_options.protocol = opt.protocol;
234   conn_options.case_handling = CASE_LOWER;
235   conn_options.max_xmit = opt.max_xmit;
236   conn_options.server_uid = opt.server_uid;
237   conn_options.tid = opt.tid;
238   conn_options.secmode = opt.sec_mode;
239   conn_options.maxmux = opt.max_mux;
240   conn_options.maxvcs = opt.max_vcs;
241   conn_options.rawmode = opt.rawmode;
242   conn_options.sesskey = opt.sesskey;
243   conn_options.maxraw = opt.maxraw;
244   conn_options.capabilities = opt.capabilities;
245   conn_options.serverzone = opt.serverzone;
246
247   return True;
248 }
249
250 /*
251  * Call the smbfs ioctl to install a connection socket,
252  * then wait for a signal to reconnect. Note that we do
253  * not exit after open_sockets() or send_login() errors,
254  * as the smbfs mount would then have no way to recover.
255  */
256 static void
257 send_fs_socket(char *mount_point, char *inbuf, char *outbuf)
258 {
259         int fd, closed = 0, res = 1;
260
261         while (1)
262         {
263                 if ((fd = open(mount_point, O_RDONLY)) < 0)
264                 {
265                         DEBUG(0, ("smbmount: can't open %s\n", mount_point));
266                         break;
267                 }               
268
269                 /*
270                  * Call the ioctl even if we couldn't get a socket ...
271                  * there's no point in making smbfs wait for a timeout.
272                  */
273                 conn_options.fd = -1;
274                 if (res)
275                         conn_options.fd = Client;
276                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
277                 if (res != 0)
278                 {
279                         DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
280                 }
281
282                 close_sockets();
283                 close(fd);
284                 /*
285                  * Close all open files if we haven't done so yet.
286                  */
287 #ifndef SMBFS_DEBUG
288                 if (!closed)
289                 {
290                         closed = 1;
291                         close_our_files();
292                 }
293 #endif
294
295                 /*
296                  * Wait for a signal from smbfs ...
297                  */
298                 signal(SIGUSR1, &usr1_handler);
299                 pause();
300                 DEBUG(0, ("smbmount: got signal, getting new socket\n"));
301
302                 res = cli_open_sockets(port);
303                 if (!res)
304                 {
305                         DEBUG(0, ("smbmount: can't open sockets\n"));
306                         continue;
307                 }
308
309                 res = mount_send_login(inbuf, outbuf);
310                 if (!res)
311                 {
312                         DEBUG(0, ("smbmount: login failed\n"));
313                 }
314         }
315         DEBUG(0, ("smbmount: exit\n"));
316         exit(1);
317 }
318
319 /****************************************************************************
320 mount smbfs
321 ****************************************************************************/
322 static void cmd_mount(char *inbuf,char *outbuf)
323 {
324         pstring mpoint;
325         pstring share_name;
326         pstring mount_command;
327         fstring buf;
328         int retval;
329         char mount_point[MAXPATHLEN+1];
330
331         if (!next_token(NULL, mpoint, NULL))
332         {
333                 DEBUG(0,("You must supply a mount point\n"));
334                 return;
335         }
336
337         memset(mount_point, 0, sizeof(mount_point));
338
339         if (realpath(mpoint, mount_point) == NULL)
340         {
341                 DEBUG(0, ("Could not resolve mount point\n"));
342                 return;
343         }
344
345         /*
346          * Build the service name to report on the Unix side,
347          * converting '\' to '/' and ' ' to '_'.
348          */
349         strcpy(share_name, service);  
350         string_replace(share_name, '\\', '/');
351         string_replace(share_name, ' ', '_');
352
353         sprintf(mount_command, "smbmnt %s -s %s", mount_point, share_name);
354
355         while(next_token(NULL, buf, NULL))
356         {
357                 strcat(mount_command, " ");
358                 strcat(mount_command, buf);
359         }
360
361         DEBUG(3, ("mount command: %s\n", mount_command));
362
363         /*
364          * Create the background process before trying the mount.
365          * (We delay closing files to allow diagnostic messages.)
366          */
367         daemonize();
368
369         /* The parent has exited here, the child handles the connection: */
370         if ((retval = system(mount_command)) != 0)
371         {
372                 DEBUG(0,("mount failed\n"));
373                 exit(1);
374         }
375         send_fs_socket(mount_point, inbuf, outbuf);
376 }       
377
378
379 /* This defines the commands supported by this client */
380 struct
381 {
382   char *name;
383   void (*fn)();
384   char *description;
385 } commands[] = 
386 {
387   {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
388   {"",NULL,NULL}
389 };
390
391
392 /*******************************************************************
393   lookup a command string in the list of commands, including 
394   abbreviations
395   ******************************************************************/
396 static int process_tok(fstring tok)
397 {
398   int i = 0, matches = 0;
399   int cmd=0;
400   int tok_len = strlen(tok);
401   
402   while (commands[i].fn != NULL)
403     {
404       if (strequal(commands[i].name,tok))
405         {
406           matches = 1;
407           cmd = i;
408           break;
409         }
410       else if (strnequal(commands[i].name, tok, tok_len))
411         {
412           matches++;
413           cmd = i;
414         }
415       i++;
416     }
417   
418   if (matches == 0)
419     return(-1);
420   else if (matches == 1)
421     return(cmd);
422   else
423     return(-2);
424 }
425
426 /****************************************************************************
427 help
428 ****************************************************************************/
429 void cmd_help(void)
430 {
431   int i=0,j;
432   fstring buf;
433
434   if (next_token(NULL,buf,NULL))
435     {
436       if ((i = process_tok(buf)) >= 0)
437         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
438     }
439   else
440     while (commands[i].description)
441       {
442         for (j=0; commands[i].description && (j<5); j++) {
443           DEBUG(0,("%-15s",commands[i].name));
444           i++;
445         }
446         DEBUG(0,("\n"));
447       }
448 }
449
450 /****************************************************************************
451 wait for keyboard activity, swallowing network packets
452 ****************************************************************************/
453 #ifdef CLIX
454 static char wait_keyboard(char *buffer)
455 #else
456 static void wait_keyboard(char *buffer)
457 #endif
458 {
459   fd_set fds;
460   int selrtn;
461   struct timeval timeout;
462   
463 #ifdef CLIX
464   int delay = 0;
465 #endif
466   
467   while (1) 
468     {
469       extern int Client;
470       FD_ZERO(&fds);
471       FD_SET(Client,&fds);
472 #ifndef CLIX
473       FD_SET(fileno(stdin),&fds);
474 #endif
475
476       timeout.tv_sec = 20;
477       timeout.tv_usec = 0;
478 #ifdef CLIX
479       timeout.tv_sec = 0;
480 #endif
481       selrtn = sys_select(&fds,&timeout);
482       
483 #ifndef CLIX
484       if (FD_ISSET(fileno(stdin),&fds))
485         return;
486 #else
487       {
488         char ch;
489         int readret;
490
491     set_blocking(fileno(stdin), False); 
492         readret = read_data( fileno(stdin), &ch, 1);
493         set_blocking(fileno(stdin), True);
494         if (readret == -1)
495           {
496             if (errno != EAGAIN)
497               {
498                 /* should crash here */
499                 DEBUG(1,("readchar stdin failed\n"));
500               }
501           }
502         else if (readret != 0)
503           {
504             return ch;
505           }
506       }
507 #endif
508
509       /* We deliberately use receive_smb instead of
510          client_receive_smb as we want to receive
511          session keepalives and then drop them here.
512        */
513       if (FD_ISSET(Client,&fds))
514         receive_smb(Client,buffer,0);
515       
516 #ifdef CLIX
517       delay++;
518       if (delay > 100000)
519         {
520           delay = 0;
521           chkpath("\\",False);
522         }
523 #else
524       chkpath("\\",False);
525 #endif
526     }  
527 }
528
529
530 /****************************************************************************
531   process commands from the client
532 ****************************************************************************/
533 static BOOL process(char *base_directory)
534 {
535   extern FILE *dbf;
536   pstring line;
537   char *cmd;
538
539   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
540   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
541
542   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
543     return(False);
544   
545   bzero(OutBuffer,smb_size);
546
547   if (!mount_send_login(InBuffer,OutBuffer))
548     return(False);
549
550   cmd = cmdstr;
551   if (cmd[0] != '\0') while (cmd[0] != '\0')
552     {
553       char *p;
554       fstring tok;
555       int i;
556
557       if ((p = strchr(cmd, ';')) == 0)
558         {
559           strncpy(line, cmd, 999);
560           line[1000] = '\0';
561           cmd += strlen(cmd);
562         }
563       else
564         {
565           if (p - cmd > 999) p = cmd + 999;
566           strncpy(line, cmd, p - cmd);
567           line[p - cmd] = '\0';
568           cmd = p + 1;
569         }
570
571       /* input language code to internal one */
572       CNV_INPUT (line);
573       
574       /* and get the first part of the command */
575       {
576         char *ptr = line;
577         if (!next_token(&ptr,tok,NULL)) continue;
578       }
579
580       if ((i = process_tok(tok)) >= 0)
581         commands[i].fn(InBuffer,OutBuffer);
582       else if (i == -2)
583         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
584       else
585         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
586     }
587   else while (!feof(stdin))
588     {
589       fstring tok;
590       int i;
591
592       bzero(OutBuffer,smb_size);
593
594       /* display a prompt */
595       DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
596       fflush(dbf);
597
598 #ifdef CLIX
599       line[0] = wait_keyboard(InBuffer);
600       /* this might not be such a good idea... */
601       if ( line[0] == EOF)
602         break;
603 #else
604       wait_keyboard(InBuffer);
605 #endif
606   
607       /* and get a response */
608 #ifdef CLIX
609       fgets( &line[1],999, stdin);
610 #else
611       if (!fgets(line,1000,stdin))
612         break;
613 #endif
614
615       /* input language code to internal one */
616       CNV_INPUT (line);
617
618       /* special case - first char is ! */
619       if (*line == '!')
620         {
621           system(line + 1);
622           continue;
623         }
624       
625       /* and get the first part of the command */
626       {
627         char *ptr = line;
628         if (!next_token(&ptr,tok,NULL)) continue;
629       }
630
631       if ((i = process_tok(tok)) >= 0)
632         commands[i].fn(InBuffer,OutBuffer);
633       else if (i == -2)
634         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
635       else
636         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
637     }
638   
639   cli_send_logout();
640   return(True);
641 }
642
643 /****************************************************************************
644 usage on the program
645 ****************************************************************************/
646 static void usage(char *pname)
647 {
648   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
649            pname));
650
651   DEBUG(0,("\nVersion %s\n",VERSION));
652   DEBUG(0,("\t-p port               connect to the specified port\n"));
653   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
654   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
655   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
656   DEBUG(0,("\t-N                    don't ask for a password\n"));
657   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
658   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
659   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
660   DEBUG(0,("\t-U username           set the network username\n"));
661   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
662   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
663   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
664   DEBUG(0,("\t-D directory          start from directory\n"));
665   DEBUG(0,("\n"));
666 }
667
668 /****************************************************************************
669   main program
670 ****************************************************************************/
671  int main(int argc,char *argv[])
672 {
673   fstring base_directory;
674   char *pname = argv[0];
675   int opt;
676   extern FILE *dbf;
677   extern char *optarg;
678   extern int optind;
679   pstring query_host;
680   BOOL nt_domain_logon = False;
681   static pstring servicesf = CONFIGFILE;
682   pstring term_code;
683   char *p;
684
685 #ifdef KANJI
686   strcpy(term_code, KANJI);
687 #else /* KANJI */
688   *term_code = 0;
689 #endif /* KANJI */
690
691   *query_host = 0;
692   *base_directory = 0;
693
694   DEBUGLEVEL = 2;
695
696   setup_logging(pname,True);
697
698   TimeInit();
699   charset_initialise();
700
701   pid = getpid();
702   uid = getuid();
703   gid = getgid();
704   mid = pid + 100;
705   myumask = umask(0);
706   umask(myumask);
707
708   if (getenv("USER"))
709   {
710     strcpy(username,getenv("USER"));
711
712     /* modification to support userid%passwd syntax in the USER var
713        25.Aug.97, jdblair@uab.edu */
714
715     if ((p=strchr(username,'%')))
716     {
717       *p = 0;
718       strcpy(password,p+1);
719       got_pass = True;
720       memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
721     }
722     strupper(username);
723   }
724
725  /* modification to support PASSWD environmental var
726   25.Aug.97, jdblair@uab.edu */
727
728   if (getenv("PASSWD"))
729     strcpy(password,getenv("PASSWD"));
730
731   if (*username == 0 && getenv("LOGNAME"))
732     {
733       strcpy(username,getenv("LOGNAME"));
734       strupper(username);
735     }
736
737   if (argc < 2)
738     {
739       usage(pname);
740       exit(1);
741     }
742   
743   if (*argv[1] != '-')
744     {
745
746       strcpy(service, argv[1]);  
747       /* Convert any '/' characters in the service name to '\' characters */
748       string_replace( service, '/','\\');
749       argc--;
750       argv++;
751
752       if (count_chars(service,'\\') < 3)
753         {
754           usage(pname);
755           printf("\n%s: Not enough '\\' characters in service\n",service);
756           exit(1);
757         }
758
759       if (argc > 1 && (*argv[1] != '-'))
760         {
761           got_pass = True;
762           strcpy(password,argv[1]);  
763           memset(argv[1],'X',strlen(argv[1]));
764           argc--;
765           argv++;
766         }
767     }
768
769   while ((opt = 
770           getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
771     switch (opt)
772       {
773       case 'm':
774         max_protocol = interpret_protocol(optarg,max_protocol);
775         break;
776       case 'O':
777         strcpy(user_socket_options,optarg);
778         break;  
779       case 'S':
780         strcpy(desthost,optarg);
781         strupper(desthost);
782         nt_domain_logon = True;
783         break;
784       case 'B':
785         iface_set_default(NULL,optarg,NULL);
786         break;
787       case 'D':
788         strcpy(base_directory,optarg);
789         break;
790       case 'i':
791         strcpy(scope,optarg);
792         break;
793       case 'U':
794         {
795           char *lp;
796         strcpy(username,optarg);
797         if ((lp=strchr(username,'%')))
798           {
799             *lp = 0;
800             strcpy(password,lp+1);
801             got_pass = True;
802             memset(strchr(optarg,'%')+1,'X',strlen(password));
803           }
804         }
805             
806         break;
807       case 'W':
808         strcpy(workgroup,optarg);
809         break;
810       case 'E':
811         dbf = stderr;
812         break;
813       case 'I':
814         {
815           dest_ip = *interpret_addr2(optarg);
816           if (zero_ip(dest_ip)) exit(1);
817           have_ip = True;
818         }
819         break;
820       case 'n':
821         strcpy(myname,optarg);
822         break;
823       case 'N':
824         got_pass = True;
825         break;
826       case 'd':
827         if (*optarg == 'A')
828           DEBUGLEVEL = 10000;
829         else
830           DEBUGLEVEL = atoi(optarg);
831         break;
832       case 'l':
833         sprintf(debugf,"%s.client",optarg);
834         break;
835       case 'p':
836         port = atoi(optarg);
837         break;
838       case 'c':
839         cmdstr = optarg;
840         got_pass = True;
841         break;
842       case 'h':
843         usage(pname);
844         exit(0);
845         break;
846       case 's':
847         strcpy(servicesf, optarg);
848         break;
849       case 't':
850         strcpy(term_code, optarg);
851         break;
852       default:
853         usage(pname);
854         exit(1);
855       }
856
857   if (!*query_host && !*service)
858     {
859       usage(pname);
860       exit(1);
861     }
862
863
864   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
865
866   if(!get_myname(myhostname,NULL))
867   {
868     DEBUG(0,("Failed to get my hostname.\n"));
869   }
870
871   if (!lp_load(servicesf,True,False,False)) {
872     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
873   }
874
875   codepage_initialise(lp_client_code_page());
876
877   interpret_coding_system(term_code);
878
879   if (*workgroup == 0)
880     strcpy(workgroup,lp_workgroup());
881
882   load_interfaces();
883   get_myname((*myname)?NULL:myname,NULL);  
884   strupper(myname);
885
886   if (cli_open_sockets(port))
887     {
888       if (!process(base_directory))
889         {
890           close_sockets();
891           return(1);
892         }
893       close_sockets();
894     }
895   else
896     return(1);
897
898   return(0);
899 }