~vadim-tk/percona-server/percona-galera-5.1.57-0.8.1

« back to all changes in this revision

Viewing changes to netware/mysqld_safe.c

  • Committer: root
  • Date: 2011-07-28 00:14:23 UTC
  • Revision ID: root@r815.office.percona.com-20110728001423-6pw0v4b7r0dkbsr4
Ported to Galera 0.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2003 Novell, Inc. All Rights Reserved.
 
3
 
 
4
  This program is free software; you can redistribute it and/or modify
 
5
  it under the terms of the GNU General Public License as published by
 
6
  the Free Software Foundation; either version 2 of the License, or
 
7
  (at your option) any later version.
 
8
 
 
9
  This program is distributed in the hope that it will be useful,
 
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
  GNU General Public License for more details.
 
13
 
 
14
  You should have received a copy of the GNU General Public License
 
15
  along with this program; if not, write to the Free Software
 
16
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
17
*/
 
18
 
 
19
#include <stdlib.h>
 
20
#include <stdio.h>
 
21
#include <netdb.h>
 
22
#include <sys/stat.h>
 
23
#include <monitor.h>
 
24
#include <strings.h>
 
25
#include <getopt.h>
 
26
#include <screen.h>
 
27
#include <dirent.h>
 
28
 
 
29
#include "my_config.h"
 
30
#include "my_manage.h"
 
31
#include "mysql_version.h"
 
32
 
 
33
/******************************************************************************
 
34
 
 
35
        global variables
 
36
 
 
37
******************************************************************************/
 
38
char autoclose;
 
39
char basedir[PATH_MAX];
 
40
char checktables;
 
41
char datadir[PATH_MAX];
 
42
char pid_file[PATH_MAX];
 
43
char address[PATH_MAX];
 
44
char port[PATH_MAX];
 
45
char err_log[PATH_MAX];
 
46
char safe_log[PATH_MAX];
 
47
char mysqld[PATH_MAX];
 
48
char hostname[PATH_MAX];
 
49
char default_option[PATH_MAX];
 
50
 
 
51
FILE *log_fd= NULL;
 
52
 
 
53
/******************************************************************************
 
54
 
 
55
        prototypes
 
56
 
 
57
******************************************************************************/
 
58
 
 
59
void usage(void);
 
60
void vlog(char *, va_list);
 
61
void log(char *, ...);
 
62
void start_defaults(int, char *[]);
 
63
void finish_defaults();
 
64
void read_defaults(arg_list_t *);
 
65
void parse_args(int, char *[]);
 
66
void get_options(int, char *[]);
 
67
void check_data_vol();
 
68
void check_setup();
 
69
void check_tables();
 
70
void mysql_start(int, char *[]);
 
71
void parse_setvar(char *arg);
 
72
 
 
73
/******************************************************************************
 
74
 
 
75
        functions
 
76
 
 
77
******************************************************************************/
 
78
 
 
79
/******************************************************************************
 
80
 
 
81
  usage()
 
82
 
 
83
  Show usage.
 
84
 
 
85
******************************************************************************/
 
86
void usage(void)
 
87
{
 
88
  // keep the screen up
 
89
  setscreenmode(SCR_NO_MODE);
 
90
 
 
91
  puts("\
 
92
\n\
 
93
usage: mysqld_safe [options]\n\
 
94
\n\
 
95
Program to start the MySQL daemon and restart it if it dies unexpectedly.\n\
 
96
All options, besides those listed below, are passed on to the MySQL daemon.\n\
 
97
\n\
 
98
options:\n\
 
99
\n\
 
100
--autoclose                 Automatically close the mysqld_safe screen.\n\
 
101
\n\
 
102
--check-tables              Check the tables before starting the MySQL daemon.\n\
 
103
\n\
 
104
--err-log=<file>            Send the MySQL daemon error output to <file>.\n\
 
105
\n\
 
106
--help                      Show this help information.\n\
 
107
\n\
 
108
--mysqld=<file>             Use the <file> MySQL daemon.\n\
 
109
\n\
 
110
  ");
 
111
 
 
112
  exit(-1);
 
113
}
 
114
 
 
115
/******************************************************************************
 
116
 
 
117
  vlog()
 
118
 
 
119
  Log the message.
 
120
 
 
121
******************************************************************************/
 
122
void vlog(char *format, va_list ap)
 
123
{
 
124
  vfprintf(stdout, format, ap);
 
125
  fflush(stdout);
 
126
 
 
127
  if (log_fd)
 
128
  {
 
129
    vfprintf(log_fd, format, ap);
 
130
    fflush(log_fd);
 
131
  }
 
132
}
 
133
 
 
134
/******************************************************************************
 
135
 
 
136
  log()
 
137
 
 
138
  Log the message.
 
139
 
 
140
******************************************************************************/
 
141
void log(char *format, ...)
 
142
{
 
143
  va_list ap;
 
144
 
 
145
  va_start(ap, format);
 
146
 
 
147
  vlog(format, ap);
 
148
 
 
149
  va_end(ap);
 
150
}
 
151
 
 
152
/******************************************************************************
 
153
 
 
154
        start_defaults()
 
155
 
 
156
        Start setting the defaults.
 
157
 
 
158
******************************************************************************/
 
159
void start_defaults(int argc, char *argv[])
 
160
{
 
161
  struct stat buf;
 
162
  int i;
 
163
 
 
164
  // default options
 
165
  static char *default_options[]=
 
166
  {
 
167
    "--no-defaults",
 
168
    "--defaults-file=",
 
169
    "--defaults-extra-file=",
 
170
    NULL
 
171
  };
 
172
 
 
173
  // autoclose
 
174
  autoclose= FALSE;
 
175
 
 
176
  // basedir
 
177
  get_basedir(argv[0], basedir);
 
178
 
 
179
  // check-tables
 
180
  checktables= FALSE;
 
181
 
 
182
  // hostname
 
183
  if (gethostname(hostname, PATH_MAX) < 0)
 
184
  {
 
185
    // default
 
186
    strcpy(hostname, "mysql");
 
187
  }
 
188
 
 
189
  // address
 
190
  snprintf(address, PATH_MAX, "0.0.0.0");
 
191
 
 
192
  // port
 
193
  snprintf(port, PATH_MAX, "%d", MYSQL_PORT);
 
194
 
 
195
  // default option
 
196
  default_option[0]= NULL;
 
197
  for (i= 0; (argc > 1) && default_options[i]; i++)
 
198
  {
 
199
    if (!strnicmp(argv[1], default_options[i], strlen(default_options[i])))
 
200
    {
 
201
      strncpy(default_option, argv[1], PATH_MAX);
 
202
      break;
 
203
    }
 
204
  }
 
205
 
 
206
  // set after basedir is established
 
207
  datadir[0]= NULL;
 
208
  pid_file[0]= NULL;
 
209
  err_log[0]= NULL;
 
210
  safe_log[0]= NULL;
 
211
  mysqld[0]= NULL;
 
212
}
 
213
 
 
214
/******************************************************************************
 
215
 
 
216
        finish_defaults()
 
217
 
 
218
        Finish settig the defaults.
 
219
 
 
220
******************************************************************************/
 
221
void finish_defaults()
 
222
{
 
223
  struct stat buf;
 
224
  int i;
 
225
 
 
226
  // datadir
 
227
  if (!datadir[0])
 
228
    snprintf(datadir, PATH_MAX, "%s/data", basedir);
 
229
 
 
230
  // pid-file
 
231
  if (!pid_file[0])
 
232
    snprintf(pid_file, PATH_MAX, "%s/%s.pid", datadir, hostname);
 
233
 
 
234
  // err-log
 
235
  if (!err_log[0])
 
236
    snprintf(err_log, PATH_MAX, "%s/%s.err", datadir, hostname);
 
237
 
 
238
  // safe-log
 
239
  if (!safe_log[0])
 
240
    snprintf(safe_log, PATH_MAX, "%s/%s.safe", datadir, hostname);
 
241
 
 
242
  // mysqld
 
243
  if (!mysqld[0])
 
244
    snprintf(mysqld, PATH_MAX, "%s/bin/mysqld-max", basedir);
 
245
 
 
246
  if (stat(mysqld, &buf))
 
247
  {
 
248
    snprintf(mysqld, PATH_MAX, "%s/bin/mysqld", basedir);
 
249
  }
 
250
}
 
251
 
 
252
/******************************************************************************
 
253
 
 
254
        read_defaults()
 
255
 
 
256
        Read the defaults.
 
257
 
 
258
******************************************************************************/
 
259
void read_defaults(arg_list_t *pal)
 
260
{
 
261
  arg_list_t al;
 
262
  char defaults_file[PATH_MAX];
 
263
  char mydefaults[PATH_MAX];
 
264
  char line[PATH_MAX];
 
265
  FILE *fp;
 
266
 
 
267
  // defaults output file
 
268
  snprintf(defaults_file, PATH_MAX, "%s/bin/defaults.out", basedir);
 
269
  remove(defaults_file);
 
270
 
 
271
  // mysqladmin file
 
272
  snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir);
 
273
 
 
274
  // args
 
275
  init_args(&al);
 
276
  add_arg(&al, mydefaults);
 
277
  if (default_option[0])
 
278
    add_arg(&al, default_option);
 
279
  add_arg(&al, "mysqld");
 
280
  add_arg(&al, "server");
 
281
  add_arg(&al, "mysqld_safe");
 
282
  add_arg(&al, "safe_mysqld");
 
283
 
 
284
  spawn(mydefaults, &al, TRUE, NULL, defaults_file, NULL);
 
285
 
 
286
  free_args(&al);
 
287
 
 
288
  // gather defaults
 
289
  if ((fp= fopen(defaults_file, "r")) != NULL)
 
290
  {
 
291
    while (fgets(line, PATH_MAX, fp))
 
292
    {
 
293
      char *p;
 
294
 
 
295
      // remove end-of-line character
 
296
      if ((p= strrchr(line, '\n')) != NULL)
 
297
        *p= '\0';
 
298
 
 
299
      // add the option as an argument
 
300
      add_arg(pal, line);
 
301
    }
 
302
 
 
303
    fclose(fp);
 
304
  }
 
305
 
 
306
  // remove file
 
307
  remove(defaults_file);
 
308
}
 
309
 
 
310
/******************************************************************************
 
311
 
 
312
        parse_args()
 
313
 
 
314
        Get the options.
 
315
 
 
316
******************************************************************************/
 
317
void parse_args(int argc, char *argv[])
 
318
{
 
319
  int index= 0;
 
320
  int c;
 
321
 
 
322
  // parse options
 
323
  enum opts
 
324
  {
 
325
    OPT_BASEDIR= 0xFF,
 
326
    OPT_DATADIR,
 
327
    OPT_PID_FILE,
 
328
    OPT_BIND_ADDRESS,
 
329
    OPT_PORT,
 
330
    OPT_ERR_LOG,
 
331
    OPT_SAFE_LOG,
 
332
    OPT_MYSQLD,
 
333
    OPT_HELP,
 
334
    OPT_SETVAR
 
335
  };
 
336
 
 
337
  static struct option options[]=
 
338
  {
 
339
    {"autoclose", no_argument, &autoclose, TRUE},
 
340
    {"basedir", required_argument, 0, OPT_BASEDIR},
 
341
    {"check-tables", no_argument, &checktables, TRUE},
 
342
    {"datadir", required_argument, 0, OPT_DATADIR},
 
343
    {"pid-file", required_argument, 0, OPT_PID_FILE},
 
344
    {"bind-address", required_argument, 0, OPT_BIND_ADDRESS},
 
345
    {"port", required_argument, 0, OPT_PORT},
 
346
    {"err-log", required_argument, 0, OPT_ERR_LOG},
 
347
    {"safe-log", required_argument, 0, OPT_SAFE_LOG},
 
348
    {"mysqld", required_argument, 0, OPT_MYSQLD},
 
349
    {"help", no_argument, 0, OPT_HELP},
 
350
    {"set-variable", required_argument, 0, OPT_SETVAR},
 
351
    {0, 0, 0, 0}
 
352
  };
 
353
 
 
354
  // we have to reset getopt_long because we use it multiple times
 
355
  optind= 1;
 
356
 
 
357
  // turn off error reporting
 
358
  opterr= 0;
 
359
 
 
360
  while ((c= getopt_long(argc, argv, "b:h:P:", options, &index)) >= 0)
 
361
  {
 
362
    switch (c) {
 
363
    case OPT_BASEDIR:
 
364
    case 'b':
 
365
      strcpy(basedir, optarg);
 
366
      break;
 
367
 
 
368
    case OPT_DATADIR:
 
369
    case 'h':
 
370
      strcpy(datadir, optarg);
 
371
      break;
 
372
 
 
373
    case OPT_PID_FILE:
 
374
      strcpy(pid_file, optarg);
 
375
      break;
 
376
 
 
377
    case OPT_BIND_ADDRESS:
 
378
      strcpy(address, optarg);
 
379
      break;
 
380
 
 
381
    case OPT_PORT:
 
382
    case 'P':
 
383
      strcpy(port, optarg);
 
384
      break;
 
385
 
 
386
    case OPT_ERR_LOG:
 
387
      strcpy(err_log, optarg);
 
388
      break;
 
389
 
 
390
    case OPT_SAFE_LOG:
 
391
      strcpy(safe_log, optarg);
 
392
      break;
 
393
 
 
394
    case OPT_MYSQLD:
 
395
      strcpy(mysqld, optarg);
 
396
      break;
 
397
 
 
398
    case OPT_SETVAR:
 
399
      parse_setvar(optarg);
 
400
      break;
 
401
 
 
402
    case OPT_HELP:
 
403
      usage();
 
404
      break;
 
405
 
 
406
    default:
 
407
      // ignore
 
408
      break;
 
409
    }
 
410
  }
 
411
}
 
412
 
 
413
/*
 
414
  parse_setvar(char *arg)
 
415
  Pasrsing for port just to display the port num on the mysqld_safe screen
 
416
*/
 
417
void parse_setvar(char *arg)
 
418
{
 
419
  char *pos;
 
420
 
 
421
  if ((pos= strindex(arg, "port")))
 
422
  {
 
423
    for (; *pos && *pos != '='; pos++);
 
424
    if (*pos)
 
425
      strcpy(port, pos + 1);
 
426
  }
 
427
}
 
428
 
 
429
/******************************************************************************
 
430
 
 
431
 
 
432
 
 
433
/******************************************************************************
 
434
 
 
435
        get_options()
 
436
 
 
437
        Get the options.
 
438
 
 
439
******************************************************************************/
 
440
void get_options(int argc, char *argv[])
 
441
{
 
442
  arg_list_t al;
 
443
 
 
444
  // start defaults
 
445
  start_defaults(argc, argv);
 
446
 
 
447
  // default file arguments
 
448
  init_args(&al);
 
449
  add_arg(&al, "ignore");
 
450
  read_defaults(&al);
 
451
  parse_args(al.argc, al.argv);
 
452
  free_args(&al);
 
453
 
 
454
  // command-line arguments
 
455
  parse_args(argc, argv);
 
456
 
 
457
  // finish defaults
 
458
  finish_defaults();
 
459
}
 
460
 
 
461
/******************************************************************************
 
462
 
 
463
        check_data_vol()
 
464
 
 
465
        Check the database volume.
 
466
 
 
467
******************************************************************************/
 
468
void check_data_vol()
 
469
{
 
470
  // warn if the data is on a Traditional volume
 
471
  struct volume_info vol;
 
472
  char buff[PATH_MAX];
 
473
  char *p;
 
474
 
 
475
  // clear struct
 
476
  memset(&vol, 0, sizeof(vol));
 
477
 
 
478
  // find volume name
 
479
  strcpy(buff, datadir);
 
480
  if (p= strchr(buff, ':'))
 
481
  {
 
482
    // terminate after volume name
 
483
    *p= 0;
 
484
  }
 
485
  else
 
486
  {
 
487
    // assume SYS volume
 
488
    strcpy(buff, "SYS");
 
489
  }
 
490
 
 
491
  // retrieve information
 
492
  netware_vol_info_from_name(&vol, buff);
 
493
 
 
494
  if ((vol.flags & VOL_NSS_PRESENT) == 0)
 
495
  {
 
496
    log("Error: Either the data directory does not exist or is not on an NSS volume!\n\n");
 
497
    exit(-1);
 
498
  }
 
499
}
 
500
 
 
501
/******************************************************************************
 
502
 
 
503
        check_setup()
 
504
 
 
505
        Check the current setup.
 
506
 
 
507
******************************************************************************/
 
508
void check_setup()
 
509
{
 
510
  struct stat info;
 
511
  char temp[PATH_MAX];
 
512
 
 
513
  // remove any current pid_file
 
514
  if (!stat(pid_file, &info) && (remove(pid_file) < 0))
 
515
  {
 
516
    log("ERROR: Unable to remove current pid file!\n\n");
 
517
    exit(-1);
 
518
  }
 
519
 
 
520
  // check the data volume
 
521
  check_data_vol();
 
522
 
 
523
  // check for a database
 
524
  snprintf(temp, PATH_MAX, "%s/mysql/host.frm", datadir);
 
525
  if (stat(temp, &info))
 
526
  {
 
527
    log("ERROR: No database found in the data directory!\n\n");
 
528
    exit(-1);
 
529
  }
 
530
}
 
531
 
 
532
/******************************************************************************
 
533
 
 
534
        check_tables()
 
535
 
 
536
        Check the database tables.
 
537
 
 
538
******************************************************************************/
 
539
void check_tables()
 
540
{
 
541
  arg_list_t al;
 
542
  char mycheck[PATH_MAX];
 
543
  char table[PATH_MAX];
 
544
  char db[PATH_MAX];
 
545
  DIR *datadir_entry, *db_entry, *table_entry;
 
546
 
 
547
  // status
 
548
  log("checking tables...\n");
 
549
 
 
550
  // list databases
 
551
  if ((datadir_entry= opendir(datadir)) == NULL)
 
552
  {
 
553
    return;
 
554
  }
 
555
 
 
556
  while ((db_entry= readdir(datadir_entry)) != NULL)
 
557
  {
 
558
    if (db_entry->d_name[0] == '.')
 
559
    {
 
560
      // Skip
 
561
    }
 
562
    else if (S_ISDIR(db_entry->d_type))
 
563
    {
 
564
      // create long db name
 
565
      snprintf(db, PATH_MAX, "%s/%s", datadir, db_entry->d_name);
 
566
 
 
567
      // list tables
 
568
      if ((db_entry= opendir(db)) == NULL)
 
569
      {
 
570
        continue;
 
571
      }
 
572
 
 
573
      while ((table_entry= readdir(db_entry)) != NULL)
 
574
      {
 
575
        // create long table name
 
576
        snprintf(table, PATH_MAX, "%s/%s", db, strlwr(table_entry->d_name));
 
577
 
 
578
        if (strindex(table, ".myi"))
 
579
        {
 
580
          // ** myisamchk
 
581
 
 
582
          // mysqladmin file
 
583
          snprintf(mycheck, PATH_MAX, "%s/bin/myisamchk", basedir);
 
584
 
 
585
          // args
 
586
          init_args(&al);
 
587
          add_arg(&al, mycheck);
 
588
          add_arg(&al, "--silent");
 
589
          add_arg(&al, "--force");
 
590
          add_arg(&al, "--fast");
 
591
          add_arg(&al, "--medium-check");
 
592
          add_arg(&al, "-O");
 
593
          add_arg(&al, "key_buffer=64M");
 
594
          add_arg(&al, "-O");
 
595
          add_arg(&al, "sort_buffer=64M");
 
596
          add_arg(&al, table);
 
597
 
 
598
          spawn(mycheck, &al, TRUE, NULL, NULL, NULL);
 
599
 
 
600
          free_args(&al);
 
601
        }
 
602
        else if (strindex(table, ".ism"))
 
603
        {
 
604
          // ** isamchk
 
605
 
 
606
          // mysqladmin file
 
607
          snprintf(mycheck, PATH_MAX, "%s/bin/isamchk", basedir);
 
608
 
 
609
          // args
 
610
          init_args(&al);
 
611
          add_arg(&al, mycheck);
 
612
          add_arg(&al, "--silent");
 
613
          add_arg(&al, "--force");
 
614
          add_arg(&al, "-O");
 
615
          add_arg(&al, "sort_buffer=64M");
 
616
          add_arg(&al, table);
 
617
 
 
618
          spawn(mycheck, &al, TRUE, NULL, NULL, NULL);
 
619
 
 
620
          free_args(&al);
 
621
        }
 
622
      }
 
623
    }
 
624
  }
 
625
}
 
626
 
 
627
/******************************************************************************
 
628
 
 
629
        mysql_start()
 
630
 
 
631
        Start the mysql server.
 
632
 
 
633
******************************************************************************/
 
634
void mysql_start(int argc, char *argv[])
 
635
{
 
636
  arg_list_t al;
 
637
  int i, j, err;
 
638
  struct stat info;
 
639
  time_t cal;
 
640
  struct tm lt;
 
641
  char stamp[PATH_MAX];
 
642
  char skip;
 
643
 
 
644
  // private options
 
645
  static char *private_options[]=
 
646
  {
 
647
    "--autoclose",
 
648
    "--check-tables",
 
649
    "--help",
 
650
    "--err-log=",
 
651
    "--mysqld=",
 
652
    NULL
 
653
  };
 
654
 
 
655
  // args
 
656
  init_args(&al);
 
657
  add_arg(&al, "%s", mysqld);
 
658
 
 
659
  // parent args
 
660
  for (i= 1; i < argc; i++)
 
661
  {
 
662
    skip= FALSE;
 
663
 
 
664
    // skip private arguments
 
665
    for (j= 0; private_options[j]; j++)
 
666
    {
 
667
      if (!strnicmp(argv[i], private_options[j], strlen(private_options[j])))
 
668
      {
 
669
        skip= TRUE;
 
670
        break;
 
671
      }
 
672
    }
 
673
 
 
674
    if (!skip)
 
675
    {
 
676
      add_arg(&al, "%s", argv[i]);
 
677
    }
 
678
  }
 
679
  // spawn
 
680
  do
 
681
  {
 
682
    // check the database tables
 
683
    if (checktables)
 
684
      check_tables();
 
685
 
 
686
    // status
 
687
    time(&cal);
 
688
    localtime_r(&cal, &lt);
 
689
    strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", &lt);
 
690
    log("mysql started    : %s\n", stamp);
 
691
 
 
692
    // spawn mysqld
 
693
    spawn(mysqld, &al, TRUE, NULL, NULL, err_log);
 
694
  }
 
695
  while (!stat(pid_file, &info));
 
696
 
 
697
  // status
 
698
  time(&cal);
 
699
  localtime_r(&cal, &lt);
 
700
  strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", &lt);
 
701
  log("mysql stopped    : %s\n\n", stamp);
 
702
 
 
703
  // free args
 
704
  free_args(&al);
 
705
}
 
706
 
 
707
/******************************************************************************
 
708
 
 
709
        main()
 
710
 
 
711
******************************************************************************/
 
712
int main(int argc, char **argv)
 
713
{
 
714
  char temp[PATH_MAX];
 
715
 
 
716
  // get the options
 
717
  get_options(argc, argv);
 
718
 
 
719
  // keep the screen up
 
720
  if (!autoclose)
 
721
    setscreenmode(SCR_NO_MODE);
 
722
 
 
723
  // create log file
 
724
  log_fd= fopen(safe_log, "w+");
 
725
 
 
726
  // header
 
727
  log("MySQL Server %s, for %s (%s)\n\n", VERSION, SYSTEM_TYPE, MACHINE_TYPE);
 
728
 
 
729
  // status
 
730
  log("address          : %s\n", address);
 
731
  log("port             : %s\n", port);
 
732
  log("daemon           : %s\n", mysqld);
 
733
  log("base directory   : %s\n", basedir);
 
734
  log("data directory   : %s\n", datadir);
 
735
  log("pid file         : %s\n", pid_file);
 
736
  log("error file       : %s\n", err_log);
 
737
  log("log file         : %s\n", safe_log);
 
738
  log("\n");
 
739
 
 
740
  // check setup
 
741
  check_setup();
 
742
 
 
743
  // start the MySQL server
 
744
  mysql_start(argc, argv);
 
745
 
 
746
  // close log file
 
747
  if (log_fd)
 
748
    fclose(log_fd);
 
749
 
 
750
  return 0;
 
751
}