Merge branch 'vendor/TCPDUMP'
[dragonfly.git] / sbin / hammer / hammer.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sbin/hammer/hammer.c,v 1.44 2008/11/13 02:04:27 dillon Exp $
35  */
36
37 #include "hammer.h"
38 #include <signal.h>
39 #include <math.h>
40 #include <fstab.h>
41
42 static void hammer_parsedevs(const char *blkdevs);
43 static void sigalrm(int signo);
44 static void sigintr(int signo);
45 static void usage(int exit_code);
46
47 int RecurseOpt;
48 int VerboseOpt;
49 int QuietOpt;
50 int NoSyncOpt;
51 int TwoWayPipeOpt;
52 int TimeoutOpt;
53 int DelayOpt = 5;
54 char *SshPort;
55 int ForceYesOpt = 0;
56 int CompressOpt;
57 int ForceOpt;
58 int RunningIoctl;
59 int DidInterrupt;
60 int BulkOpt;
61 u_int64_t BandwidthOpt;
62 u_int64_t SplitupOpt = 4ULL * 1024ULL * 1024ULL * 1024ULL;
63 u_int64_t MemoryLimit = 1024LLU * 1024 * 1024;
64 const char *SplitupOptStr;
65 const char *CyclePath;
66 const char *LinkPath;
67
68 int
69 main(int ac, char **av)
70 {
71         char *blkdevs = NULL;
72         char *ptr;
73         u_int32_t status;
74         int ch;
75         int cacheSize = 0;
76
77         while ((ch = getopt(ac, av, "b:c:dhf:i:m:p:qrs:t:v2yBC:FS:X")) != -1) {
78                 switch(ch) {
79                 case '2':
80                         TwoWayPipeOpt = 1;
81                         break;
82                 case 'y':
83                         ForceYesOpt = 1;
84                         break;
85                 case 'b':
86                         BandwidthOpt = strtoull(optarg, &ptr, 0);
87                         switch(*ptr) {
88                         case 'g':
89                         case 'G':
90                                 BandwidthOpt *= 1024;
91                                 /* fall through */
92                         case 'm':
93                         case 'M':
94                                 BandwidthOpt *= 1024;
95                                 /* fall through */
96                         case 'k':
97                         case 'K':
98                                 BandwidthOpt *= 1024;
99                                 break;
100                         case '\0':
101                                 /* bytes per second if no suffix */
102                                 break;
103                         default:
104                                 usage(1);
105                         }
106                         break;
107                 case 'S':
108                         SplitupOptStr = strdup(optarg);
109                         SplitupOpt = strtoull(optarg, &ptr, 0);
110                         switch(*ptr) {
111                         case 'g':
112                         case 'G':
113                                 SplitupOpt *= 1024;
114                                 /* fall through */
115                         case 'm':
116                         case 'M':
117                                 SplitupOpt *= 1024;
118                                 /* fall through */
119                         case 'k':
120                         case 'K':
121                                 SplitupOpt *= 1024;
122                                 break;
123                         case '\0':
124                                 /* bytes per second if no suffix */
125                                 break;
126                         default:
127                                 usage(1);
128                         }
129                         break;
130                 case 'c':
131                         CyclePath = optarg;
132                         break;
133                 case 'd':
134                         ++DebugOpt;
135                         break;
136                 case 'h':
137                         usage(0);
138                         /* not reached */
139                 case 'i':
140                         DelayOpt = strtol(optarg, NULL, 0);
141                         break;
142                 case 'm':
143                         MemoryLimit = strtouq(optarg, &ptr, 0);
144                         switch(*ptr) {
145                         case 't':
146                         case 'T':
147                                 MemoryLimit *= 1024;
148                                 /* fall through */
149                         case 'g':
150                         case 'G':
151                                 MemoryLimit *= 1024;
152                                 /* fall through */
153                         case 'm':
154                         case 'M':
155                                 MemoryLimit *= 1024;
156                                 /* fall through */
157                         case 'k':
158                         case 'K':
159                                 MemoryLimit *= 1024;
160                                 /* fall through */
161                         default:
162                                 break;
163                         }
164
165                         /* minimum limit */
166                         if (MemoryLimit < 1024 * 1024)
167                                 MemoryLimit = 1024 * 1024;
168                         break;
169                 case 'p':
170                         SshPort = optarg;
171                         break;
172                 case 'r':
173                         RecurseOpt = 1;
174                         break;
175                 case 'f':
176                         blkdevs = optarg;
177                         break;
178                 case 's':
179                         LinkPath = optarg;
180                         break;
181                 case 't':
182                         TimeoutOpt = strtol(optarg, NULL, 0);
183                         break;
184                 case 'v':
185                         if (QuietOpt > 0)
186                                 --QuietOpt;
187                         else
188                                 ++VerboseOpt;
189                         break;
190                 case 'q':
191                         if (VerboseOpt > 0)
192                                 --VerboseOpt;
193                         else
194                                 ++QuietOpt;
195                         break;
196                 case 'B':
197                         BulkOpt = 1;
198                         break;
199                 case 'C':
200                         cacheSize = strtol(optarg, &ptr, 0);
201                         switch(*ptr) {
202                         case 'm':
203                         case 'M':
204                                 cacheSize *= 1024;
205                                 /* fall through */
206                         case 'k':
207                         case 'K':
208                                 cacheSize *= 1024;
209                                 ++ptr;
210                                 break;
211                         case '\0':
212                         case ':':
213                                 /* bytes if no suffix */
214                                 break;
215                         default:
216                                 usage(1);
217                         }
218                         if (*ptr == ':') {
219                                 UseReadAhead = strtol(ptr + 1, NULL, 0);
220                                 UseReadBehind = -UseReadAhead;
221                         }
222                         if (cacheSize < 1024 * 1024)
223                                 cacheSize = 1024 * 1024;
224                         if (UseReadAhead < 0)
225                                 usage(1);
226                         if (UseReadAhead * HAMMER_BUFSIZE / cacheSize / 16) {
227                                 UseReadAhead = cacheSize / 16 / HAMMER_BUFSIZE;
228                                 UseReadBehind = -UseReadAhead;
229                         }
230                         hammer_cache_set(cacheSize);
231                         break;
232                 case 'F':
233                         ForceOpt = 1;
234                         break;
235                 case 'X':
236                         CompressOpt = 1;
237                         break;
238                 default:
239                         usage(1);
240                         /* not reached */
241                 }
242         }
243         ac -= optind;
244         av += optind;
245         if (ac < 1) {
246                 usage(1);
247                 /* not reached */
248         }
249
250         signal(SIGALRM, sigalrm);
251         signal(SIGINT, sigintr);
252
253         if (strcmp(av[0], "synctid") == 0) {
254                 hammer_cmd_synctid(av + 1, ac - 1);
255                 exit(0);
256         }
257         if (strcmp(av[0], "namekey2") == 0) {
258                 int64_t key;
259                 int32_t crcx;
260                 int len;
261                 const char *aname = av[1];
262
263                 if (aname == NULL)
264                         usage(1);
265                 len = strlen(aname);
266                 key = (u_int32_t)crc32(aname, len) & 0xFFFFFFFEU;
267
268                 switch(len) {
269                 default:
270                         crcx = crc32(aname + 3, len - 5);
271                         crcx = crcx ^ (crcx >> 6) ^ (crcx >> 12);
272                         key |= (int64_t)(crcx & 0x3F) << 42;
273                         /* fall through */
274                 case 5:
275                 case 4:
276                         /* fall through */
277                 case 3:
278                         key |= ((int64_t)(aname[2] & 0x1F) << 48);
279                         /* fall through */
280                 case 2:
281                         key |= ((int64_t)(aname[1] & 0x1F) << 53) |
282                                ((int64_t)(aname[len-2] & 0x1F) << 37);
283                         /* fall through */
284                 case 1:
285                         key |= ((int64_t)(aname[0] & 0x1F) << 58) |
286                                ((int64_t)(aname[len-1] & 0x1F) << 32);
287                         /* fall through */
288                 case 0:
289                         break;
290                 }
291                 if (key == 0)
292                         key |= 0x100000000LL;
293                 printf("0x%016jx\n", (uintmax_t)key);
294                 exit(0);
295         }
296         if (strcmp(av[0], "namekey1") == 0) {
297                 int64_t key;
298
299                 if (av[1] == NULL)
300                         usage(1);
301                 key = (int64_t)(crc32(av[1], strlen(av[1])) & 0x7FFFFFFF) << 32;
302                 if (key == 0)
303                         key |= 0x100000000LL;
304                 printf("0x%016jx\n", (uintmax_t)key);
305                 exit(0);
306         }
307         if (strcmp(av[0], "namekey32") == 0) {
308                 int32_t key;
309
310                 if (av[1] == NULL)
311                         usage(1);
312                 key = crc32(av[1], strlen(av[1])) & 0x7FFFFFFF;
313                 if (key == 0)
314                         ++key;
315                 printf("0x%08x\n", key);
316                 exit(0);
317         }
318         if (strcmp(av[0], "pfs-status") == 0) {
319                 hammer_cmd_pseudofs_status(av + 1, ac - 1);
320                 exit(0);
321         }
322         if (strcmp(av[0], "pfs-master") == 0) {
323                 hammer_cmd_pseudofs_create(av + 1, ac - 1, 0);
324                 exit(0);
325         }
326         if (strcmp(av[0], "pfs-slave") == 0) {
327                 hammer_cmd_pseudofs_create(av + 1, ac - 1, 1);
328                 exit(0);
329         }
330         if (strcmp(av[0], "pfs-update") == 0) {
331                 hammer_cmd_pseudofs_update(av + 1, ac - 1);
332                 exit(0);
333         }
334         if (strcmp(av[0], "pfs-upgrade") == 0) {
335                 hammer_cmd_pseudofs_upgrade(av + 1, ac - 1);
336                 exit(0);
337         }
338         if (strcmp(av[0], "pfs-downgrade") == 0) {
339                 hammer_cmd_pseudofs_downgrade(av + 1, ac - 1);
340                 exit(0);
341         }
342         if (strcmp(av[0], "pfs-destroy") == 0) {
343                 hammer_cmd_pseudofs_destroy(av + 1, ac - 1);
344                 exit(0);
345         }
346         if (strcmp(av[0], "status") == 0) {
347                 hammer_cmd_status(av + 1, ac - 1);
348                 exit(0);
349         }
350         if (strcmp(av[0], "prune") == 0) {
351                 hammer_cmd_softprune(av + 1, ac - 1, 0);
352                 exit(0);
353         }
354         if (strcmp(av[0], "config") == 0) {
355                 hammer_cmd_config(av + 1, ac - 1);
356                 exit(0);
357         }
358         if (strcmp(av[0], "viconfig") == 0) {
359                 hammer_cmd_viconfig(av + 1, ac - 1);
360                 exit(0);
361         }
362         if (strcmp(av[0], "cleanup") == 0) {
363                 hammer_cmd_cleanup(av + 1, ac - 1);
364                 exit(0);
365         }
366         if (strcmp(av[0], "info") == 0) {
367                 hammer_cmd_info();
368                 exit(0);
369         }
370         if (strcmp(av[0], "prune-everything") == 0) {
371                 hammer_cmd_softprune(av + 1, ac - 1, 1);
372                 exit(0);
373         }
374         if (strcmp(av[0], "snap") == 0) {
375                 hammer_cmd_snap(av + 1, ac - 1, 0, 1);
376                 exit(0);
377         }
378         if (strcmp(av[0], "snaplo") == 0) {
379                 hammer_cmd_snap(av + 1, ac - 1, 0, 0);
380                 exit(0);
381         }
382         if (strcmp(av[0], "snapq") == 0) {
383                 hammer_cmd_snap(av + 1, ac - 1, 1, 0);
384                 exit(0);
385         }
386         if (strcmp(av[0], "snapls") == 0) {
387                 hammer_cmd_snapls(av + 1, ac - 1);
388                 exit(0);
389         }
390         if (strcmp(av[0], "snaprm") == 0) {
391                 hammer_cmd_snaprm(av + 1, ac - 1);
392                 exit(0);
393         }
394         if (strcmp(av[0], "snapshot") == 0) {
395                 hammer_cmd_snapshot(av + 1, ac - 1);
396                 exit(0);
397         }
398         if (strcmp(av[0], "bstats") == 0) {
399                 hammer_cmd_bstats(av + 1, ac - 1);
400                 exit(0);
401         }
402         if (strcmp(av[0], "iostats") == 0) {
403                 hammer_cmd_iostats(av + 1, ac - 1);
404                 exit(0);
405         }
406
407         if (strncmp(av[0], "history", 7) == 0) {
408                 hammer_cmd_history(av[0] + 7, av + 1, ac - 1);
409                 exit(0);
410         }
411         if (strcmp(av[0], "rebalance") == 0) {
412                 signal(SIGINT, sigalrm);
413                 hammer_cmd_rebalance(av + 1, ac - 1);
414                 exit(0);
415         }
416         if (strncmp(av[0], "reblock", 7) == 0) {
417                 signal(SIGINT, sigalrm);
418                 if (strcmp(av[0], "reblock") == 0)
419                         hammer_cmd_reblock(av + 1, ac - 1, -1);
420                 else if (strcmp(av[0], "reblock-btree") == 0)
421                         hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_BTREE);
422                 else if (strcmp(av[0], "reblock-inodes") == 0)
423                         hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_INODES);
424                 else if (strcmp(av[0], "reblock-dirs") == 0)
425                         hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DIRS);
426                 else if (strcmp(av[0], "reblock-data") == 0)
427                         hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DATA);
428                 else
429                         usage(1);
430                 exit(0);
431         }
432         if (strncmp(av[0], "mirror", 6) == 0) {
433                 if (strcmp(av[0], "mirror-read") == 0)
434                         hammer_cmd_mirror_read(av + 1, ac - 1, 0);
435                 else if (strcmp(av[0], "mirror-read-stream") == 0)
436                         hammer_cmd_mirror_read(av + 1, ac - 1, 1);
437                 else if (strcmp(av[0], "mirror-write") == 0)
438                         hammer_cmd_mirror_write(av + 1, ac - 1);
439                 else if (strcmp(av[0], "mirror-copy") == 0)
440                         hammer_cmd_mirror_copy(av + 1, ac - 1, 0);
441                 else if (strcmp(av[0], "mirror-stream") == 0)
442                         hammer_cmd_mirror_copy(av + 1, ac - 1, 1);
443                 else if (strcmp(av[0], "mirror-dump") == 0)
444                         hammer_cmd_mirror_dump();
445                 else
446                         usage(1);
447                 exit(0);
448         }
449         if (strcmp(av[0], "dedup-simulate") == 0) {
450                 hammer_cmd_dedup_simulate(av + 1, ac - 1);
451                 exit(0);
452         }
453         if (strcmp(av[0], "dedup") == 0) {
454                 hammer_cmd_dedup(av + 1, ac - 1);
455                 exit(0);
456         }
457         if (strcmp(av[0], "version") == 0) {
458                 hammer_cmd_get_version(av + 1, ac - 1);
459                 exit(0);
460         }
461         if (strcmp(av[0], "version-upgrade") == 0) {
462                 hammer_cmd_set_version(av + 1, ac - 1);
463                 exit(0);
464         }
465         if (strcmp(av[0], "volume-add") == 0) {
466                 hammer_cmd_volume_add(av + 1, ac - 1);
467                 exit(0);
468         }
469         if (strcmp(av[0], "volume-del") == 0) {
470                 hammer_cmd_volume_del(av + 1, ac - 1);
471                 exit(0);
472         }
473         if (strcmp(av[0], "volume-list") == 0) {
474                 hammer_cmd_volume_list(av + 1, ac - 1);
475                 exit(0);
476         }
477
478         uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status);
479         if (status != uuid_s_ok) {
480                 errx(1, "uuids file does not have the DragonFly "
481                         "HAMMER filesystem type");
482         }
483
484         if (strcmp(av[0], "show") == 0) {
485                 u_int32_t lo = 0;
486                 intmax_t obj_id = (int64_t)HAMMER_MIN_OBJID;
487
488                 hammer_parsedevs(blkdevs);
489                 if (ac > 1)
490                         sscanf(av[1], "%08x:%jx", &lo, &obj_id);
491                 hammer_cmd_show(-1, lo, (int64_t)obj_id, 0, NULL, NULL);
492                 exit(0);
493         }
494         if (strcmp(av[0], "show-undo") == 0) {
495                 hammer_parsedevs(blkdevs);
496                 hammer_cmd_show_undo();
497                 exit(0);
498         }
499         if (strcmp(av[0], "recover") == 0) {
500                 hammer_parsedevs(blkdevs);
501                 if (ac <= 1)
502                         errx(1, "hammer recover required target directory");
503                 hammer_cmd_recover(av[1]);
504                 exit(0);
505         }
506         if (strcmp(av[0], "blockmap") == 0) {
507                 hammer_parsedevs(blkdevs);
508                 hammer_cmd_blockmap();
509                 exit(0);
510         }
511         if (strcmp(av[0], "checkmap") == 0) {
512                 hammer_parsedevs(blkdevs);
513                 hammer_cmd_checkmap();
514                 exit(0);
515         }
516         usage(1);
517         /* not reached */
518         return(0);
519 }
520
521 /*
522  * Parse the device specification.
523  *
524  * Multi-volume hammer devices are colon-separated.  Each element
525  * may be further expanded via /etc/devtab.  One may also specify
526  * a single element which is expanded into multiple elements via
527  * /etc/devtab.
528  */
529 static
530 void
531 hammer_parsedevs(const char *blkdevs)
532 {
533         char *copy;
534         char *volname;
535
536         if (blkdevs == NULL) {
537                 errx(1, "A -f blkdevs specification is required "
538                         "for this command");
539         }
540
541         copy = strdup(blkdevs);
542         while ((volname = copy) != NULL) {
543                 if ((copy = strchr(copy, ':')) != NULL)
544                         *copy++ = 0;
545                 volname = getdevpath(volname, 0);
546                 if (strchr(volname, ':'))
547                         hammer_parsedevs(volname);
548                 else
549                         setup_volume(-1, volname, 0, O_RDONLY);
550         }
551 }
552
553 static
554 void
555 sigalrm(int signo __unused)
556 {
557         /* do nothing (interrupts HAMMER ioctl) */
558 }
559
560 static
561 void
562 sigintr(int signo __unused)
563 {
564         if (RunningIoctl == 0)
565                 _exit(1);
566         DidInterrupt = 1;
567         /* do nothing (interrupts HAMMER ioctl) */
568 }
569
570 static
571 void
572 usage(int exit_code)
573 {
574         fprintf(stderr,
575                 "hammer -h\n"
576                 "hammer [-2BqrvXy] [-b bandwidth] [-C cachesize[:readahead]] [-c cyclefile]\n"
577                 "       [-f blkdevs] [-i delay] [-t seconds] [-S splitup]\n"
578                 "       command [argument ...]\n"
579                 "hammer synctid <filesystem> [quick]\n"
580                 "hammer bstats [interval]\n"
581                 "hammer iostats [interval]\n"
582                 "hammer history[@offset[,len]] <file> ...\n"
583                 "hammer namekey1 <path>\n"
584                 "hammer namekey2 <path>\n"
585                 "hammer namekey32 <path>\n"
586                 "hammer cleanup [<filesystem> ...]\n"
587                 "hammer info\n"
588                 "hammer snapshot [<filesystem>] <snapshot-dir>\n"
589                 "hammer snapshot <filesystem> <snapshot-dir> [<note>]\n"
590                 "hammer prune <softlink-dir>\n"
591                 "hammer prune-everything <filesystem>\n"
592                 "hammer rebalance <filesystem> [saturation_percentage]\n"
593                 "hammer reblock[-btree|-inodes|-dirs|-data] "
594                         "<filesystem> [fill_percentage]\n"
595                 "hammer pfs-status <dirpath> ...\n"
596                 "hammer pfs-master <dirpath> [options]\n"
597                 "hammer pfs-slave <dirpath> [options]\n"
598                 "hammer pfs-update <dirpath> [options]\n"
599                 "hammer pfs-upgrade <dirpath>\n"
600                 "hammer pfs-downgrade <dirpath>\n"
601                 "hammer pfs-destroy <dirpath>\n"
602                 "hammer mirror-read <filesystem> [begin-tid]\n"
603                 "hammer mirror-read-stream <filesystem> [begin-tid]\n"
604                 "hammer mirror-write <filesystem>\n"
605                 "hammer mirror-dump\n"
606                 "hammer mirror-copy [[user@]host:]<filesystem>"
607                                   " [[user@]host:]<filesystem>\n"
608                 "hammer mirror-stream [[user@]host:]<filesystem>"
609                                     " [[user@]host:]<filesystem>\n"
610                 "hammer version <filesystem>\n"
611                 "hammer version-upgrade <filesystem> <version> [force]\n"
612                 "hammer volume-add <device> <filesystem>\n"
613                 "hammer volume-del <device> <filesystem>\n"
614                 "hammer volume-list <filesystem>\n"
615         );
616
617         fprintf(stderr, "\nHAMMER utility version 3+ commands:\n");
618
619         fprintf(stderr,
620                 "hammer config [<filesystem> [<configfile>]]\n"
621                 "hammer viconfig [<filesystem>]\n"
622                 "hammer snap <path> [<note>]\n"
623                 "hammer snaplo <path> [<note>]\n"
624                 "hammer snapq <dir> [<note>]\n"
625                 "hammer snaprm <path> ...\n"
626                 "hammer snaprm <transid> ...\n"
627                 "hammer snaprm <filesystem> <transid> ...\n"
628                 "hammer snapls [<path> ...]\n"
629         );
630
631         fprintf(stderr, "\nHAMMER utility version 4+ commands:\n");
632
633         fprintf(stderr,
634                 "hammer -f blkdevs blockmap\n"
635                 "hammer -f blkdevs checkmap\n"
636                 "hammer -f blkdevs [-qqq] show [lo:objid]\n"
637                 "hammer -f blkdevs show-undo\n"
638                 "hammer -f blkdevs recover <target_dir>\n"
639         );
640
641         fprintf(stderr, "\nHAMMER utility version 5+ commands:\n");
642
643         fprintf(stderr,
644                 "hammer dedup-simulate <filesystem>\n"
645                 "hammer dedup <filesystem>\n"
646         );
647
648         exit(exit_code);
649 }
650