]> git.sesse.net Git - bcachefs-tools-debian/blob - bcacheadm.c
67f26b17f774294742b2d629138173d467dcdc79
[bcachefs-tools-debian] / bcacheadm.c
1 /*
2  * Authors: Kent Overstreet <kmo@daterainc.com>
3  *          Gabriel de Perthuis <g2p.code@gmail.com>
4  *          Jacob Malevich <jam@datera.io>
5  *
6  * GPLv2
7  */
8
9 #include <nih/option.h>
10 #include <nih/command.h>
11 #include <nih/main.h>
12 #include <nih/logging.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <blkid.h>
24 #include <string.h>
25 #include <linux/fs.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <uuid/uuid.h>
30 #include <dirent.h>
31 #include <bcache.h> //libbcache
32
33 #define PACKAGE_NAME "bcacheadm"
34 #define PACKAGE_VERSION "1.0"
35 #define PACKAGE_BUGREPORT "bugreport"
36
37 #define MAX_DEVS MAX_CACHES_PER_SET
38
39
40 /* make-bcache globals */
41 int bdev = -1;
42 int devs = 0;
43 char *cache_devices[MAX_DEVS];
44 int tier_mapping[MAX_DEVS];
45 char *backing_devices[MAX_DEVS];
46 char *backing_dev_labels[MAX_DEVS];
47 size_t i, nr_backing_devices = 0, nr_cache_devices = 0;
48 unsigned block_size = 0;
49 unsigned bucket_sizes[MAX_DEVS];
50 int num_bucket_sizes = 0;
51 int writeback = 0, discard = 0, wipe_bcache = 0;
52 unsigned replication_set = 0, replacement_policy = 0;
53 uint64_t data_offset = BDEV_DATA_START_DEFAULT;
54 char *label = NULL;
55 struct cache_sb *cache_set_sb = NULL;
56 const char *cache_set_uuid = 0;
57 const char *csum_type = 0;
58 char *metadata_replicas = 0;
59 char *data_replicas = 0;
60 char *tier = 0;
61
62 /* add-dev globals */
63 char *add_dev_uuid = NULL;
64
65 /* rm-dev globals */
66 bool force_remove = false;
67
68 /* Modify globals */
69 bool modify_list_attrs = false;
70 static const char *modify_set_uuid = NULL;
71 static const char *modify_dev_uuid = NULL;
72
73 /* query-dev globals */
74 bool force_csum = false;
75 bool uuid_only = false;
76
77 /* probe globals */
78 bool udev = false;
79
80 /* list globals */
81 char *cset_dir = "/sys/fs/bcache";
82 bool list_devs = false;
83
84 /* status globals */
85 bool status_all = false;
86
87 /* stats globals */
88 bool stats_all = false;
89 bool stats_list = false;
90 static const char *stats_uuid = NULL;
91 static const char *stats_dev_uuid = NULL;
92 static const char *stats_cache_num = NULL;
93 bool stats_five_min = false;
94 bool stats_hour = false;
95 bool stats_day = false;
96 bool stats_total = false;
97
98 /* make-bcache option setters */
99 static int set_block_size(NihOption *option, const char *arg)
100 {
101         block_size = hatoi_validate(arg, "block size");
102         return 0;
103 }
104
105 static int set_cache(NihOption *option, const char *arg)
106 {
107         bdev = 0;
108         cache_devices[nr_cache_devices] = strdup(arg);
109         if(!tier)
110                 tier_mapping[nr_cache_devices] = 0;
111         else {
112                 int ntier = atoi(tier);
113                 if(ntier == 0 || ntier == 1)
114                         tier_mapping[nr_cache_devices] = ntier;
115                 else
116                         printf("Invalid tier\n");
117         }
118
119         devs++;
120         nr_cache_devices++;
121
122         return 0;
123 }
124
125 static int set_bdev(NihOption *option, const char *arg)
126 {
127         bdev = 1;
128
129         if(label)
130                 backing_dev_labels[nr_backing_devices] = strdup(label);
131
132         backing_devices[nr_backing_devices] = strdup(arg);
133
134         nr_backing_devices++;
135         devs++;
136
137         return 0;
138 }
139
140 static int set_bucket_sizes(NihOption *option, const char *arg)
141 {
142         bucket_sizes[num_bucket_sizes]=hatoi_validate(arg, "bucket size");
143         num_bucket_sizes++;
144         return 0;
145 }
146
147 /* probe setters */
148 static int set_udev(NihOption *option, const char *arg)
149 {
150         if (strcmp("udev", arg)) {
151                 printf("Invalid output format %s\n", arg);
152                 exit(EXIT_FAILURE);
153         }
154         udev = true;
155         return 0;
156 }
157
158
159 /* options */
160 static NihOption make_bcache_options[] = {
161 //      {int shortoption, char* longoption, char* help, NihOptionGroup, char* argname, void *value, NihOptionSetter}
162         {'C', "cache",  N_("Format a cache device"), NULL, "dev", NULL, set_cache},
163         {'B', "bdev",   N_("Format a backing device"), NULL, "dev", NULL, set_bdev},
164         {'l', "label",  N_("label"), NULL, "label", &label, NULL},
165         //Only one bucket_size supported until a list of bucket sizes is parsed correctly
166         {'b', "bucket", N_("bucket size"), NULL, "size", NULL, set_bucket_sizes},
167         //Does the default setter automatically convert strings to an int?
168         {'w', "block",  N_("block size (hard sector size of SSD, often 2k"), NULL,"size", NULL, set_block_size},
169         {'t', "tier",   N_("tier of subsequent devices"), NULL,"#", &tier, NULL},
170         {'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,"policy", &replacement_policy, NULL},
171         {'o', "data_offset", N_("data offset in sectors"), NULL,"offset", &data_offset, NULL},
172
173         {0, "cset-uuid",        N_("UUID for the cache set"),           NULL,   "uuid", &cache_set_uuid, NULL},
174         {0, "csum-type",        N_("One of (none|crc32c|crc64)"),               NULL,   "type", &csum_type, NULL },
175         {0, "replication-set",N_("replication set of subsequent devices"),      NULL,   NULL, &replication_set, NULL },
176         {0, "meta-replicas",N_("number of metadata replicas"),          NULL,   "#", &metadata_replicas, NULL},
177         {0, "data-replicas",N_("number of data replicas"),              NULL,   "#", &data_replicas, NULL },
178
179         {0, "wipe-bcache",      N_("destroy existing bcache data if present"),          NULL, NULL, &wipe_bcache, NULL},
180         {0, "discard",          N_("enable discards"),          NULL, NULL, &discard,           NULL},
181         {0, "writeback",        N_("enable writeback"),         NULL, NULL, &writeback,         NULL},
182
183         NIH_OPTION_LAST
184 };
185
186 static NihOption probe_bcache_options[] = {
187         {'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev},
188         NIH_OPTION_LAST
189 };
190
191 static NihOption bcache_register_options[] = {
192         NIH_OPTION_LAST
193 };
194
195 static NihOption bcache_unregister_options[] = {
196         NIH_OPTION_LAST
197 };
198
199 static NihOption bcache_add_device_options[] = {
200         {'u', "set", N_("cacheset uuid"), NULL, "UUID", &add_dev_uuid, NULL},
201         NIH_OPTION_LAST
202 };
203
204 static NihOption bcache_rm_device_options[] = {
205         {'f', "force", N_("force cache removal"), NULL, NULL, &force_remove, NULL},
206         NIH_OPTION_LAST
207 };
208
209 static NihOption bcache_modify_options[] = {
210         {'l', "list", N_("list attributes"), NULL, NULL, &modify_list_attrs, NULL},
211         {'u', "set", N_("cacheset uuid"), NULL, "UUID", &modify_set_uuid, NULL},
212         {'d', "dev", N_("device uuid"), NULL, "UUID", &modify_dev_uuid, NULL},
213         NIH_OPTION_LAST
214 };
215
216 static NihOption query_devs_options[] = {
217         {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
218         {'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL},
219         NIH_OPTION_LAST
220 };
221
222 static NihOption list_cachesets_options[] = {
223         {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
224         {0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
225         NIH_OPTION_LAST
226 };
227
228 static NihOption status_options[] = {
229         {'a', "all", N_("all"), NULL, NULL, &status_all, NULL},
230         NIH_OPTION_LAST
231 };
232
233 static NihOption stats_options[] = {
234         {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL},
235         {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL},
236         {'u', "set", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL},
237         {'d', "dev", N_("dev UUID"), NULL, "UUID", &stats_dev_uuid, NULL},
238         {'c', "cache", N_("cache number (starts from 0)"), NULL, "CACHE#", &stats_cache_num, NULL},
239         {0, "five-min-stats", N_("stats accumulated in last 5 minutes"), NULL, NULL, &stats_five_min, NULL},
240         {0, "hour-stats", N_("stats accumulated in last hour"), NULL, NULL, &stats_hour, NULL},
241         {0, "day-stats", N_("stats accumulated in last day"), NULL, NULL, &stats_day, NULL},
242         {0, "total-stats", N_("stats accumulated in total"), NULL, NULL, &stats_total, NULL},
243         NIH_OPTION_LAST
244 };
245
246 static NihOption options[] = {
247         NIH_OPTION_LAST
248 };
249
250
251 /* commands */
252 int make_bcache(NihCommand *command, char *const *args)
253 {
254         int cache_dev_fd[devs];
255
256         int backing_dev_fd[devs];
257
258         cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
259                                      sizeof(struct cache_member) * devs);
260
261         if (cache_set_uuid) {
262                 if(uuid_parse(cache_set_uuid, cache_set_sb->set_uuid.b)) {
263                         fprintf(stderr, "Bad uuid\n");
264                         return -1;
265                 }
266         } else {
267                 uuid_generate(cache_set_sb->set_uuid.b);
268         }
269
270         if (label) 
271                 memcpy(cache_set_sb->label, label, sizeof(cache_set_sb->label));
272
273         if (csum_type) {
274                 SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb,
275                                 read_string_list_or_die(csum_type, csum_types,
276                                         "csum type"));
277         } else {
278                 SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C);
279         }
280
281         if (metadata_replicas) {
282                 SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,
283                                 strtoul_or_die(metadata_replicas,
284                                         CACHE_SET_META_REPLICAS_WANT_MAX,
285                                         "meta replicas"));
286         } else {
287                 SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1);
288         }
289
290         if (data_replicas) {
291                 SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,
292                         strtoul_or_die(data_replicas,
293                                 CACHE_SET_DATA_REPLICAS_WANT_MAX,
294                                 "data replicas"));
295         } else {
296                 SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1);
297         }
298
299         if (bdev == -1) {
300                 fprintf(stderr, "Please specify -C or -B\n");
301                 exit(EXIT_FAILURE);
302         }
303
304         if(!bucket_sizes[0]) bucket_sizes[0] = 1024;
305
306         for(i = 0; i < nr_cache_devices; i++)
307                 next_cache_device(cache_set_sb,
308                                   replication_set,
309                                   tier_mapping[i],
310                                   replacement_policy,
311                                   discard);
312
313         if (!cache_set_sb->nr_in_set && !nr_backing_devices) {
314                 fprintf(stderr, "Please supply a device\n");
315                 exit(EXIT_FAILURE);
316         }
317
318         i = 0;
319         do {
320                 if (bucket_sizes[i] < block_size) {
321                         fprintf(stderr,
322                         "Bucket size cannot be smaller than block size\n");
323                         exit(EXIT_FAILURE);
324                 }
325                 i++;
326         } while (i < num_bucket_sizes);
327
328         if (!block_size) {
329                 for (i = 0; i < cache_set_sb->nr_in_set; i++)
330                         block_size = max(block_size,
331                                          get_blocksize(cache_devices[i]));
332
333                 for (i = 0; i < nr_backing_devices; i++)
334                         block_size = max(block_size,
335                                          get_blocksize(backing_devices[i]));
336         }
337
338         for (i = 0; i < cache_set_sb->nr_in_set; i++)
339                 cache_dev_fd[i] = dev_open(cache_devices[i], wipe_bcache);
340
341         for (i = 0; i < nr_backing_devices; i++)
342                 backing_dev_fd[i] = dev_open(backing_devices[i], wipe_bcache);
343
344         write_cache_sbs(cache_dev_fd, cache_set_sb, block_size,
345                                         bucket_sizes, num_bucket_sizes);
346
347         for (i = 0; i < nr_backing_devices; i++)
348                 write_backingdev_sb(backing_dev_fd[i],
349                                     block_size, bucket_sizes,
350                                     writeback, data_offset,
351                                     backing_dev_labels[i],
352                                     cache_set_sb->set_uuid);
353
354
355         return 0;
356 }
357
358 int probe_bcache(NihCommand *command, char *const *args)
359 {
360         int i;
361         char *err = NULL;
362
363         for (i = 0; args[i] != NULL; i++) {
364                 err = probe(args[i], udev);
365                 if(err) {
366                         printf("probe_bcache error: %s\n", err);
367                         return -1;
368                 }
369         }
370
371         return 0;
372 }
373
374 int bcache_register(NihCommand *command, char *const *args)
375 {
376         char *err = NULL;
377
378         err = register_bcache(args);
379         if (err) {
380                 printf("bcache_register error: %s\n", err);
381                 return -1;
382         }
383
384         return 0;
385 }
386
387 int bcache_unregister(NihCommand *command, char *const *args)
388 {
389         char *err = NULL;
390
391         err = unregister_bcache(args);
392         if (err) {
393                 printf("bcache_unregister error: %s\n", err);
394                 return -1;
395         }
396
397         return 0;
398 }
399
400 int bcache_add_devices(NihCommand *command, char *const *args)
401 {
402         char *err;
403
404         if (!add_dev_uuid) {
405                 printf("Must specify a cacheset uuid to add the disk to\n");
406                 return -1;
407         }
408
409         err = add_devices(args, add_dev_uuid);
410         if (err) {
411                 printf("bcache_add_devices error: %s\n", err);
412                 return -1;
413         }
414
415         return 0;
416 }
417
418 int bcache_rm_device(NihCommand *command, char *const *args)
419 {
420         char *err;
421
422         err = remove_device(args[0], force_remove);
423         if (err) {
424                 printf("bcache_rm_devices error: %s\n", err);
425                 return -1;
426         }
427
428         return 0;
429 }
430
431 int bcache_modify(NihCommand *command, char *const *args)
432 {
433         char *err;
434         char path[MAX_PATH];
435         DIR *path_dir;
436         struct stat cache_stat;
437         char *attr = args[0];
438         char *val = NULL;
439         int fd = -1;
440
441         if (modify_list_attrs) {
442                 sysfs_attr_list();
443                 return 0;
444         }
445
446         if (!modify_set_uuid) {
447                 printf("Must provide a cacheset uuid\n");
448                 return -1;
449         }
450
451         snprintf(path, MAX_PATH, "%s/%s", cset_dir, modify_set_uuid);
452
453         if(!attr) {
454                 printf("Must provide the name of an attribute to modify\n");
455                 goto err;
456         }
457
458         enum sysfs_attr type = sysfs_attr_type(attr);
459
460         if (type == -1)
461                 goto err;
462         else if(type == INTERNAL_ATTR)
463                 strcat(path, "/internal");
464         else if(type == CACHE_ATTR) {
465                 if(modify_dev_uuid) {
466                         /* searches all cache# for a matching uuid,
467                          * path gets modified to the correct cache path */
468                         char subdir[10] = "/cache";
469                         err = find_matching_uuid(path, subdir,
470                                         modify_dev_uuid);
471                         if (err) {
472                                 printf("Failed to find "
473                                         "matching dev %s\n", err);
474                                 goto err;
475                         } else {
476                                 strcat(path, subdir);
477                         }
478                 } else {
479                         printf("Must provide a device uuid\n");
480                 }
481         }
482         /* SET_ATTRs are just in the current dir */
483
484         strcat(path, "/");
485         strcat(path, attr);
486
487         val = args[1];
488         if (!val) {
489                 printf("Must provide a value to change the attribute to\n");
490                 goto err;
491         }
492
493         fd = open(path, O_WRONLY);
494         if (fd < 0) {
495                 printf("Unable to open modify attr with path %s\n", path);
496                 goto err;
497         }
498
499         write(fd, val, strlen(val));
500
501 err:
502         if(fd)
503                 close(fd);
504         return 0;
505 }
506
507 int bcache_list_cachesets(NihCommand *command, char *const *args)
508 {
509         char *err = NULL;
510         err = list_cachesets(cset_dir, list_devs);
511         if (err) {
512                 printf("bcache_list_cachesets error :%s\n", err);
513                 return -1;
514         }
515
516         return 0;
517 }
518
519 int bcache_query_devs(NihCommand *command, char *const *args)
520 {
521         int i;
522
523         for (i = 0; args[i] != NULL; i++) {
524                 char dev_uuid[40];
525                 query_dev(args[i], force_csum, true, uuid_only, dev_uuid);
526                 if(uuid_only)
527                         printf("%s\n", dev_uuid);
528         }
529
530         return 0;
531 }
532
533 int bcache_status(NihCommand *command, char *const *args)
534 {
535         int i, seq, nr_in_set = 0;
536         struct cache_sb *seq_sb = NULL;
537
538         for (i = 0; args[i] != NULL; i++) {
539                 struct cache_sb *sb = query_dev(args[i], false, false,
540                                 false, NULL);
541
542                 if(!sb) {
543                         printf("Unable to open superblock, bad path\n");
544                         return -1;
545                 }
546
547                 if(!seq_sb || sb->seq > seq) {
548                         seq = sb->seq;
549                         seq_sb = sb;
550                         nr_in_set = sb->nr_in_set;
551                 }
552         }
553
554         if(!seq_sb)
555                 printf("Unable to find a superblock\n");
556         else
557                 printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
558
559         for (i = 0; i < seq_sb->nr_in_set; i++) {
560                 char uuid_str[40];
561                 struct cache_member *m = ((struct cache_member *) seq_sb->d) + i;
562
563                 uuid_unparse(m->uuid.b, uuid_str);
564
565                 printf("%-50s%-15s%-4llu\n", uuid_str,
566                                 cache_state[CACHE_STATE(m)],
567                                 CACHE_TIER(m));
568         }
569
570         return 0;
571 }
572
573 static char *stats_subdir(char* stats_dir)
574 {
575         char tmp[50] = "/";
576         char *err = NULL;
577         if(stats_dev_uuid) {
578                 strcat(tmp, "cache");
579                 err = find_matching_uuid(stats_dir, tmp, stats_dev_uuid);
580                 if(err)
581                         goto err;
582         } else if(stats_cache_num) {
583                 strcat(tmp, "cache");
584                 strcat(tmp, stats_cache_num);
585         } else if (stats_five_min)
586                 strcat(tmp, "stats_five_minute");
587         else if (stats_hour)
588                 strcat(tmp, "stats_hour");
589         else if (stats_day)
590                 strcat(tmp, "stats_day");
591         else if (stats_total)
592                 strcat(tmp, "stats_total");
593         else
594                 return err;
595
596         strcat(stats_dir, tmp);
597
598 err:
599         return err;
600 }
601
602 int bcache_stats(NihCommand *command, char *const *args)
603 {
604         int i;
605         char stats_dir[MAX_PATH];
606         DIR *dir = NULL;
607         struct dirent *ent = NULL;
608         char *err = NULL;
609
610         if (stats_uuid) {
611                 snprintf(stats_dir, MAX_PATH, "%s/%s", cset_dir, stats_uuid);
612                 err = stats_subdir(stats_dir);
613                 if(err)
614                         goto err;
615
616                 dir = opendir(stats_dir);
617                 if (!dir) {
618                         err = "Failed to open dir";
619                         goto err;
620                 }
621         } else {
622                 err = "Must provide a cacheset uuid";
623                 goto err;
624         }
625
626         if(stats_list || stats_all) {
627                 while ((ent = readdir(dir)) != NULL) {
628                         err = read_stat_dir(dir, stats_dir, ent->d_name, stats_all);
629                         if (err)
630                                 goto err;
631                 }
632         }
633
634
635         for (i = 0; args[i] != NULL; i++) {
636                 err = read_stat_dir(dir, stats_dir, args[i], true);
637                 if (err)
638                         goto err;
639         }
640
641         closedir(dir);
642         return 0;
643
644 err:
645         closedir(dir);
646         printf("bcache_stats error: %s\n", err);
647         return -1;
648 }
649
650 static NihCommand commands[] = {
651         {"format", N_("format <list of drives>"),
652                   "Format one or a list of devices with bcache datastructures."
653                   " You need to do this before you create a volume",
654                   N_("format drive[s] with bcache"),
655                   NULL, make_bcache_options, make_bcache},
656         {"probe", N_("probe <list of devices>"),
657                   "Does a blkid_probe on a device",
658                   N_("Does a blkid_probe on a device"),
659                   NULL, probe_bcache_options, probe_bcache},
660         {"register", N_("register <list of devices>"),
661                      "Registers a list of devices",
662                      N_("Registers a list of devices"),
663                      NULL, bcache_register_options, bcache_register},
664         {"unregister", N_("unregister <list of devices>"),
665                      "Unregisters a list of devices",
666                      N_("Unregisters a list of devices"),
667                      NULL, bcache_unregister_options, bcache_unregister},
668         {"add-devs", N_("add-devs --set=UUID --tier=# <list of devices>"),
669                 "Adds a list of devices to a cacheset",
670                 N_("Adds a list of devices to a cacheset"),
671                 NULL, bcache_add_device_options, bcache_add_devices},
672         {"rm-dev", N_("rm-dev <dev>"),
673                 "Removes a device from its cacheset",
674                 N_("Removes a device from its cacheset"),
675                 NULL, bcache_rm_device_options, bcache_rm_device},
676         {"modify", N_("modify --set=UUID (dev=UUID) name value"),
677                 "Modifies attributes related to the cacheset",
678                 N_("Modifies attributes related to the cacheset"),
679                 NULL, bcache_modify_options, bcache_modify},
680         {"list-cachesets", N_("list-cachesets"),
681                            "Lists cachesets in /sys/fs/bcache",
682                            N_("Lists cachesets in /sys/fs/bcache"),
683                            NULL, list_cachesets_options, bcache_list_cachesets},
684         {"query-devs", N_("query <list of devices>"),
685                        "Gives info about the superblock of a list of devices",
686                        N_("show superblock on each of the listed drive"),
687                        NULL, query_devs_options, bcache_query_devs},
688         {"status", N_("status <list of devices>"),
689                    "Finds the status of the most up to date superblock",
690                    N_("Finds the status of the most up to date superblock"),
691                    NULL, status_options, bcache_status},
692         {"stats", N_("stats <list of devices>"),
693                   "List various bcache statistics",
694                   N_("List various bcache statistics"),
695                   NULL, stats_options, bcache_stats},
696         NIH_COMMAND_LAST
697 };
698
699
700 int main(int argc, char *argv[])
701 {
702         int ret = 0;
703         nih_main_init (argv[0]);
704
705         nih_option_set_synopsis (_("Manage bcache devices"));
706         nih_option_set_help (
707                         _("Helps you manage bcache devices"));
708
709         ret = nih_command_parser (NULL, argc, argv, options, commands);
710         if (ret < 0)
711                 exit (1);
712
713         nih_signal_reset();
714
715         return 0;
716 }