Tier/cli: removing warning message for tiering
[obnox/glusterfs.git] / cli / src / cli-cmd-volume.c
1 /*
2    Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
3    This file is part of GlusterFS.
4
5    This file is licensed to you under your choice of the GNU Lesser
6    General Public License, version 3 or any later version (LGPLv3 or
7    later), or the GNU General Public License, version 2 (GPLv2), in all
8    cases as published by the Free Software Foundation.
9 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <pthread.h>
15
16 #include <sys/socket.h>
17 #include <netdb.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <netinet/in.h>
21
22 #include "cli.h"
23 #include "cli-cmd.h"
24 #include "cli-mem-types.h"
25 #include "cli1-xdr.h"
26 #include "run.h"
27 #include "syscall.h"
28 #include "common-utils.h"
29
30 extern struct rpc_clnt *global_rpc;
31 extern struct rpc_clnt *global_quotad_rpc;
32
33 extern rpc_clnt_prog_t *cli_rpc_prog;
34 extern rpc_clnt_prog_t cli_quotad_clnt;
35
36 int
37 cli_cmd_volume_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
38                       const char **words, int wordcount);
39
40 int
41 cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word,
42                          const char **words, int wordcount)
43 {
44         int                             ret = -1;
45         rpc_clnt_procedure_t            *proc = NULL;
46         call_frame_t                    *frame = NULL;
47         cli_cmd_volume_get_ctx_t        ctx = {0,};
48         cli_local_t                     *local = NULL;
49         int                             sent = 0;
50         int                             parse_error = 0;
51
52         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOLUME];
53
54         frame = create_frame (THIS, THIS->ctx->pool);
55         if (!frame)
56                 goto out;
57
58         if ((wordcount == 2)  || (wordcount == 3 &&
59                                   !strcmp (words[2], "all"))) {
60                 ctx.flags = GF_CLI_GET_NEXT_VOLUME;
61                 proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_NEXT_VOLUME];
62         } else if (wordcount == 3) {
63                 ctx.flags = GF_CLI_GET_VOLUME;
64                 ctx.volname = (char *)words[2];
65                 if (strlen (ctx.volname) > GD_VOLUME_NAME_MAX) {
66                         cli_out ("Invalid volume name");
67                         goto out;
68                 }
69                 proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOLUME];
70         } else {
71                 cli_usage_out (word->pattern);
72                 parse_error = 1;
73                 return -1;
74         }
75
76         local = cli_local_get ();
77
78         if (!local)
79                 goto out;
80
81         local->get_vol.flags = ctx.flags;
82         if (ctx.volname)
83                 local->get_vol.volname = gf_strdup (ctx.volname);
84
85         frame->local = local;
86
87         if (proc->fn) {
88                 ret = proc->fn (frame, THIS, &ctx);
89         }
90
91 out:
92         if (ret) {
93                 cli_cmd_sent_status_get (&sent);
94                 if ((sent == 0) && (parse_error == 0))
95                         cli_out ("Getting Volume information failed!");
96         }
97
98         CLI_STACK_DESTROY (frame);
99
100         return ret;
101
102 }
103
104 int
105 cli_cmd_sync_volume_cbk (struct cli_state *state, struct cli_cmd_word *word,
106                          const char **words, int wordcount)
107 {
108         int                     ret = -1;
109         rpc_clnt_procedure_t    *proc = NULL;
110         call_frame_t            *frame = NULL;
111         int                     sent = 0;
112         int                     parse_error = 0;
113         dict_t                  *dict = NULL;
114         cli_local_t             *local = NULL;
115         gf_answer_t             answer = GF_ANSWER_NO;
116         const char              *question = "Sync volume may make data "
117                                             "inaccessible while the sync "
118                                             "is in progress. Do you want "
119                                             "to continue?";
120
121         if ((wordcount < 3) || (wordcount > 4)) {
122                 cli_usage_out (word->pattern);
123                 parse_error = 1;
124                 goto out;
125         }
126
127         dict = dict_new ();
128         if (!dict)
129                 goto out;
130
131         if ((wordcount == 3) || !strcmp(words[3], "all")) {
132                 ret = dict_set_int32 (dict, "flags", (int32_t)
133                                       GF_CLI_SYNC_ALL);
134                 if (ret) {
135                         gf_log (THIS->name, GF_LOG_ERROR, "failed to set"
136                                 "flag");
137                         goto out;
138                 }
139         } else {
140                 ret = dict_set_str (dict, "volname", (char *) words[3]);
141                 if (ret) {
142                         gf_log (THIS->name, GF_LOG_ERROR, "failed to set "
143                                 "volume");
144                         goto out;
145                 }
146         }
147
148         ret = dict_set_str (dict, "hostname", (char *) words[2]);
149         if (ret) {
150                 gf_log (THIS->name, GF_LOG_ERROR, "failed to set hostname");
151                 goto out;
152         }
153
154         if (!(state->mode & GLUSTER_MODE_SCRIPT)) {
155                 answer = cli_cmd_get_confirmation (state, question);
156                 if (GF_ANSWER_NO == answer) {
157                         ret = 0;
158                         goto out;
159                 }
160         }
161
162         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SYNC_VOLUME];
163
164         frame = create_frame (THIS, THIS->ctx->pool);
165         if (!frame)
166                 goto out;
167
168         CLI_LOCAL_INIT (local, words, frame, dict);
169
170         if (proc->fn) {
171                 ret = proc->fn (frame, THIS, dict);
172         }
173
174 out:
175         if (ret) {
176                 cli_cmd_sent_status_get (&sent);
177                 if ((sent == 0) && (parse_error == 0))
178                         cli_out ("Volume sync failed");
179         }
180
181         CLI_STACK_DESTROY (frame);
182
183         return ret;
184 }
185
186 int
187 cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word,
188                            const char **words, int wordcount)
189 {
190         int                     ret = -1;
191         rpc_clnt_procedure_t    *proc = NULL;
192         call_frame_t            *frame = NULL;
193         dict_t                  *options = NULL;
194         int                     sent = 0;
195         int                     parse_error = 0;
196         char                    *brick_list = NULL;
197         int32_t                 brick_count = 0;
198         int32_t                 sub_count = 0;
199         int32_t                 type = GF_CLUSTER_TYPE_NONE;
200         cli_local_t             *local = NULL;
201         char                    *trans_type = NULL;
202
203         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CREATE_VOLUME];
204
205         frame = create_frame (THIS, THIS->ctx->pool);
206         if (!frame)
207                 goto out;
208
209         ret = cli_cmd_volume_create_parse (state, words, wordcount, &options);
210
211         if (ret) {
212                 cli_usage_out (word->pattern);
213                 parse_error = 1;
214                 goto out;
215         }
216
217         ret = dict_get_str (options, "transport", &trans_type);
218         if (ret) {
219                 gf_log("cli", GF_LOG_ERROR, "Unable to get transport type");
220                 goto out;
221         }
222
223         if (state->mode & GLUSTER_MODE_WIGNORE) {
224                 ret = dict_set_int32 (options, "force", _gf_true);
225                 if (ret) {
226                         gf_log ("cli", GF_LOG_ERROR, "Failed to set force "
227                                 "option");
228                         goto out;
229                 }
230         }
231
232         CLI_LOCAL_INIT (local, words, frame, options);
233
234         if (proc->fn) {
235                 ret = proc->fn (frame, THIS, options);
236         }
237
238 out:
239         if (ret) {
240                 cli_cmd_sent_status_get (&sent);
241                 if ((sent == 0) && (parse_error == 0))
242                         cli_out ("Volume create failed");
243         }
244
245         CLI_STACK_DESTROY (frame);
246
247         return ret;
248 }
249
250
251 int
252 cli_cmd_volume_delete_cbk (struct cli_state *state, struct cli_cmd_word *word,
253                            const char **words, int wordcount)
254 {
255         int                     ret = -1;
256         rpc_clnt_procedure_t    *proc = NULL;
257         call_frame_t            *frame = NULL;
258         char                    *volname = NULL;
259         gf_answer_t             answer = GF_ANSWER_NO;
260         const char              *question = NULL;
261         int                     sent = 0;
262         int                     parse_error = 0;
263         cli_local_t             *local = NULL;
264         dict_t                  *dict = NULL;
265
266         question = "Deleting volume will erase all information about the volume. "
267                    "Do you want to continue?";
268         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_DELETE_VOLUME];
269
270         frame = create_frame (THIS, THIS->ctx->pool);
271         if (!frame)
272                 goto out;
273
274         dict = dict_new ();
275         if (!dict)
276                 goto out;
277
278         if (wordcount != 3) {
279                 cli_usage_out (word->pattern);
280                 parse_error = 1;
281                 goto out;
282         }
283
284         volname = (char *)words[2];
285
286         ret = dict_set_str (dict, "volname", volname);
287         if (ret) {
288                 gf_log (THIS->name, GF_LOG_WARNING, "dict set failed");
289                 goto out;
290         }
291
292         if (!strcmp (volname, GLUSTER_SHARED_STORAGE)) {
293                 question = "Deleting the shared storage volume"
294                            "(gluster_shared_storage), will affect features "
295                            "like snapshot scheduler, geo-replication "
296                            "and NFS-Ganesha. Do you still want to "
297                            "continue?";
298         }
299
300         answer = cli_cmd_get_confirmation (state, question);
301         if (GF_ANSWER_NO == answer) {
302                 ret = 0;
303                 goto out;
304         }
305
306         CLI_LOCAL_INIT (local, words, frame, dict);
307
308         if (proc->fn) {
309                 ret = proc->fn (frame, THIS, dict);
310         }
311
312 out:
313         if (ret) {
314                 cli_cmd_sent_status_get (&sent);
315                 if ((sent == 0) && (parse_error == 0))
316                         cli_out ("Volume delete failed");
317         }
318
319         CLI_STACK_DESTROY (frame);
320
321         return ret;
322 }
323
324 int
325 cli_cmd_volume_start_cbk (struct cli_state *state, struct cli_cmd_word *word,
326                           const char **words, int wordcount)
327 {
328         int                     ret = -1;
329         rpc_clnt_procedure_t    *proc = NULL;
330         call_frame_t            *frame = NULL;
331         int                     sent = 0;
332         int                     parse_error = 0;
333         dict_t                  *dict = NULL;
334         int                     flags = 0;
335         cli_local_t             *local = NULL;
336
337         frame = create_frame (THIS, THIS->ctx->pool);
338         if (!frame)
339                 goto out;
340
341         if (wordcount < 3 || wordcount > 4) {
342                cli_usage_out (word->pattern);
343                 parse_error = 1;
344                goto out;
345         }
346
347         dict = dict_new ();
348         if (!dict) {
349                 goto out;
350         }
351
352         if (!words[2])
353                 goto out;
354
355         ret = dict_set_str (dict, "volname", (char *)words[2]);
356         if (ret) {
357                 gf_log (THIS->name, GF_LOG_ERROR, "dict set failed");
358                 goto out;
359         }
360
361         if (wordcount == 4) {
362                 if (!strcmp("force", words[3])) {
363                         flags |= GF_CLI_FLAG_OP_FORCE;
364                 } else {
365                         ret = -1;
366                         cli_usage_out (word->pattern);
367                         parse_error = 1;
368                         goto out;
369                 }
370         }
371         ret = dict_set_int32 (dict, "flags", flags);
372         if (ret) {
373                  gf_log (THIS->name, GF_LOG_ERROR,
374                          "dict set failed");
375                  goto out;
376         }
377
378         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_START_VOLUME];
379
380         CLI_LOCAL_INIT (local, words, frame, dict);
381
382         if (proc->fn) {
383                 ret = proc->fn (frame, THIS, dict);
384         }
385
386 out:
387         if (ret) {
388                 cli_cmd_sent_status_get (&sent);
389                 if ((sent == 0) && (parse_error == 0))
390                         cli_out ("Volume start failed");
391         }
392
393         CLI_STACK_DESTROY (frame);
394
395         return ret;
396 }
397
398 gf_answer_t
399 cli_cmd_get_confirmation (struct cli_state *state, const char *question)
400 {
401         char                    answer[5] = {'\0', };
402         char                    flush = '\0';
403         size_t                  len;
404
405         if (state->mode & GLUSTER_MODE_SCRIPT)
406                 return GF_ANSWER_YES;
407
408         printf ("%s (y/n) ", question);
409
410         if (fgets (answer, 4, stdin) == NULL) {
411                 cli_out("gluster cli read error");
412                 goto out;
413         }
414
415         len = strlen (answer);
416
417         if (len && answer [len - 1] == '\n'){
418                 answer [--len] = '\0';
419         } else {
420                 do{
421                         flush = getchar ();
422                 }while (flush != '\n');
423         }
424
425         if (len > 3)
426                 goto out;
427
428         if (!strcasecmp (answer, "y") || !strcasecmp (answer, "yes"))
429                 return GF_ANSWER_YES;
430
431         else if (!strcasecmp (answer, "n") || !strcasecmp (answer, "no"))
432                 return GF_ANSWER_NO;
433
434 out:
435         cli_out ("Invalid input, please enter y/n");
436
437         return GF_ANSWER_NO;
438 }
439
440 int
441 cli_cmd_volume_stop_cbk (struct cli_state *state, struct cli_cmd_word *word,
442                            const char **words, int wordcount)
443 {
444         int                     ret = -1;
445         rpc_clnt_procedure_t    *proc = NULL;
446         call_frame_t            *frame = NULL;
447         int                     flags   = 0;
448         gf_answer_t             answer = GF_ANSWER_NO;
449         int                     sent = 0;
450         int                     parse_error = 0;
451         dict_t                  *dict = NULL;
452         char                    *volname = NULL;
453         cli_local_t             *local = NULL;
454
455         const char *question = "Stopping volume will make its data inaccessible. "
456                                "Do you want to continue?";
457
458         frame = create_frame (THIS, THIS->ctx->pool);
459         if (!frame)
460                 goto out;
461
462         if (wordcount < 3 || wordcount > 4) {
463                 cli_usage_out (word->pattern);
464                 parse_error = 1;
465                 goto out;
466         }
467
468         volname = (char*) words[2];
469
470         dict = dict_new ();
471         ret = dict_set_str (dict, "volname", volname);
472         if (ret) {
473                 gf_log (THIS->name, GF_LOG_ERROR, "dict set failed");
474                 goto out;
475         }
476
477         if (!strcmp (volname, GLUSTER_SHARED_STORAGE)) {
478                 question = "Stopping the shared storage volume"
479                            "(gluster_shared_storage), will affect features "
480                            "like snapshot scheduler, geo-replication "
481                            "and NFS-Ganesha. Do you still want to "
482                            "continue?";
483         }
484
485         if (wordcount == 4) {
486                 if (!strcmp("force", words[3])) {
487                         flags |= GF_CLI_FLAG_OP_FORCE;
488                 } else {
489                         ret = -1;
490                         cli_usage_out (word->pattern);
491                         parse_error = 1;
492                         goto out;
493                 }
494         }
495
496         ret = dict_set_int32 (dict, "flags", flags);
497         if (ret) {
498                 gf_log (THIS->name, GF_LOG_ERROR,
499                         "dict set failed");
500                 goto out;
501         }
502
503         answer = cli_cmd_get_confirmation (state, question);
504
505         if (GF_ANSWER_NO == answer) {
506                 ret = 0;
507                 goto out;
508         }
509
510         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STOP_VOLUME];
511
512         CLI_LOCAL_INIT (local, words, frame, dict);
513
514         if (proc->fn) {
515                 ret = proc->fn (frame, THIS, dict);
516         }
517
518 out:
519         if (ret) {
520                 cli_cmd_sent_status_get (&sent);
521                 if ((sent == 0) && (parse_error == 0))
522                         cli_out ("Volume stop on '%s' failed", volname);
523         }
524
525         CLI_STACK_DESTROY (frame);
526
527         return ret;
528 }
529
530
531 int
532 cli_cmd_volume_rename_cbk (struct cli_state *state, struct cli_cmd_word *word,
533                            const char **words, int wordcount)
534 {
535         int                     ret = -1;
536         rpc_clnt_procedure_t    *proc = NULL;
537         call_frame_t            *frame = NULL;
538         dict_t                  *dict = NULL;
539         int                     sent = 0;
540         int                     parse_error = 0;
541
542
543         frame = create_frame (THIS, THIS->ctx->pool);
544         if (!frame)
545                 goto out;
546
547         dict = dict_new ();
548         if (!dict)
549                 goto out;
550
551         if (wordcount != 4) {
552                 cli_usage_out (word->pattern);
553                 parse_error = 1;
554                 goto out;
555         }
556
557         ret = dict_set_str (dict, "old-volname", (char *)words[2]);
558
559         if (ret)
560                 goto out;
561
562         ret = dict_set_str (dict, "new-volname", (char *)words[3]);
563
564         if (ret)
565                 goto out;
566
567         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_RENAME_VOLUME];
568
569         if (proc->fn) {
570                 ret = proc->fn (frame, THIS, dict);
571         }
572
573 out:
574         if (dict)
575                 dict_destroy (dict);
576
577         if (ret) {
578                 cli_cmd_sent_status_get (&sent);
579                 if ((sent == 0) && (parse_error == 0))
580                         cli_out ("Volume rename on '%s' failed", (char *)words[2]);
581         }
582
583         CLI_STACK_DESTROY (frame);
584
585         return ret;
586 }
587
588 int
589 cli_cmd_volume_defrag_cbk (struct cli_state *state, struct cli_cmd_word *word,
590                            const char **words, int wordcount)
591 {
592         int                   ret     = -1;
593         rpc_clnt_procedure_t *proc    = NULL;
594         call_frame_t         *frame   = NULL;
595         dict_t               *dict = NULL;
596         int                     sent = 0;
597         int                     parse_error = 0;
598         cli_local_t          *local = NULL;
599 #ifdef GF_SOLARIS_HOST_OS
600         cli_out ("Command not supported on Solaris");
601         goto out;
602 #endif
603
604         frame = create_frame (THIS, THIS->ctx->pool);
605         if (!frame)
606                 goto out;
607
608         ret = cli_cmd_volume_defrag_parse (words, wordcount, &dict);
609
610         if (ret) {
611                 cli_usage_out (word->pattern);
612                 parse_error = 1;
613         }
614
615         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_DEFRAG_VOLUME];
616
617         CLI_LOCAL_INIT (local, words, frame, dict);
618
619         if (proc->fn) {
620                 ret = proc->fn (frame, THIS, dict);
621         }
622
623 out:
624         if (ret) {
625                 cli_cmd_sent_status_get (&sent);
626                 if ((sent == 0) && (parse_error == 0))
627                         cli_out ("Volume rebalance failed");
628         }
629
630         CLI_STACK_DESTROY (frame);
631
632         return ret;
633 }
634
635 int
636 cli_cmd_volume_reset_cbk (struct cli_state *state, struct cli_cmd_word *word,
637                           const char **words, int wordcount)
638 {
639         int                     sent = 0;
640         int                     parse_error = 0;
641         int                     ret = -1;
642         rpc_clnt_procedure_t    *proc = NULL;
643         call_frame_t            *frame = NULL;
644         dict_t                  *options = NULL;
645         cli_local_t             *local = NULL;
646
647         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_RESET_VOLUME];
648
649         frame = create_frame (THIS, THIS->ctx->pool);
650         if (!frame)
651                 goto out;
652
653         ret = cli_cmd_volume_reset_parse (words, wordcount, &options);
654         if (ret) {
655                 cli_usage_out (word->pattern);
656                 parse_error = 1;
657                 goto out;
658         }
659
660         CLI_LOCAL_INIT (local, words, frame, options);
661
662         if (proc->fn) {
663                 ret = proc->fn (frame, THIS, options);
664         }
665
666 out:
667         if (ret) {
668                 cli_cmd_sent_status_get (&sent);
669                 if ((sent == 0) && (parse_error == 0))
670                         cli_out ("Volume reset failed");
671         }
672
673         CLI_STACK_DESTROY (frame);
674
675         return ret;
676
677 }
678
679 int
680 cli_cmd_volume_profile_cbk (struct cli_state *state, struct cli_cmd_word *word,
681                           const char **words, int wordcount)
682 {
683         int                     sent = 0;
684         int                     parse_error = 0;
685
686         int                     ret      = -1;
687         rpc_clnt_procedure_t    *proc    = NULL;
688         call_frame_t            *frame   = NULL;
689         dict_t                  *options = NULL;
690         cli_local_t             *local = NULL;
691
692         ret = cli_cmd_volume_profile_parse (words, wordcount, &options);
693
694         if (ret) {
695                 cli_usage_out (word->pattern);
696                 parse_error = 1;
697                 goto out;
698         }
699
700         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_PROFILE_VOLUME];
701
702         frame = create_frame (THIS, THIS->ctx->pool);
703         if (!frame)
704                 goto out;
705
706         CLI_LOCAL_INIT (local, words, frame, options);
707
708         if (proc->fn) {
709                 ret = proc->fn (frame, THIS, options);
710         }
711
712 out:
713         if (ret) {
714                 cli_cmd_sent_status_get (&sent);
715                 if ((sent == 0) && (parse_error == 0))
716                         cli_out ("Volume profile failed");
717         }
718
719         CLI_STACK_DESTROY (frame);
720
721         return ret;
722
723 }
724
725 int
726 cli_cmd_volume_set_cbk (struct cli_state *state, struct cli_cmd_word *word,
727                         const char **words, int wordcount)
728 {
729         int                     sent = 0;
730         int                     parse_error = 0;
731
732         int                     ret = -1;
733         rpc_clnt_procedure_t    *proc = NULL;
734         call_frame_t            *frame = NULL;
735         dict_t                  *options = NULL;
736         cli_local_t             *local = NULL;
737         char                    *op_errstr = NULL;
738
739         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SET_VOLUME];
740
741         frame = create_frame (THIS, THIS->ctx->pool);
742         if (!frame)
743                 goto out;
744
745         ret = cli_cmd_volume_set_parse (state, words, wordcount,
746                                         &options, &op_errstr);
747         if (ret) {
748                 if (op_errstr) {
749                     cli_err ("%s", op_errstr);
750                     GF_FREE (op_errstr);
751                 } else
752                     cli_usage_out (word->pattern);
753
754                 parse_error = 1;
755                 goto out;
756         }
757
758         CLI_LOCAL_INIT (local, words, frame, options);
759
760         if (proc->fn) {
761                 ret = proc->fn (frame, THIS, options);
762         }
763
764 out:
765         if (ret) {
766                 cli_cmd_sent_status_get (&sent);
767                 if ((sent == 0) && (parse_error == 0))
768                         cli_out ("Volume set failed");
769         }
770
771         CLI_STACK_DESTROY (frame);
772
773         return ret;
774
775 }
776
777 int
778 cli_cmd_volume_add_brick_cbk (struct cli_state *state,
779                               struct cli_cmd_word *word, const char **words,
780                               int wordcount)
781 {
782         int                     ret = -1;
783         rpc_clnt_procedure_t    *proc = NULL;
784         call_frame_t            *frame = NULL;
785         dict_t                  *options = NULL;
786         int                     sent = 0;
787         int                     parse_error = 0;
788         gf_answer_t             answer = GF_ANSWER_NO;
789         cli_local_t             *local = NULL;
790
791         const char *question = "Changing the 'stripe count' of the volume is "
792                 "not a supported feature. In some cases it may result in data "
793                 "loss on the volume. Also there may be issues with regular "
794                 "filesystem operations on the volume after the change. Do you "
795                 "really want to continue with 'stripe' count option ? ";
796
797         frame = create_frame (THIS, THIS->ctx->pool);
798         if (!frame)
799                 goto out;
800
801         ret = cli_cmd_volume_add_brick_parse (words, wordcount, &options, 0);
802         if (ret) {
803                 cli_usage_out (word->pattern);
804                 parse_error = 1;
805                 goto out;
806         }
807
808         /* TODO: there are challenges in supporting changing of
809            stripe-count, until it is properly supported give warning to user */
810         if (dict_get (options, "stripe-count")) {
811                 answer = cli_cmd_get_confirmation (state, question);
812
813                 if (GF_ANSWER_NO == answer) {
814                         ret = 0;
815                         goto out;
816                 }
817         }
818
819         if (state->mode & GLUSTER_MODE_WIGNORE) {
820                 ret = dict_set_int32 (options, "force", _gf_true);
821                 if (ret) {
822                         gf_log ("cli", GF_LOG_ERROR, "Failed to set force "
823                                 "option");
824                         goto out;
825                 }
826         }
827
828         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_ADD_BRICK];
829
830         CLI_LOCAL_INIT (local, words, frame, options);
831
832         if (proc->fn) {
833                 ret = proc->fn (frame, THIS, options);
834         }
835
836 out:
837         if (ret) {
838                 cli_cmd_sent_status_get (&sent);
839                 if ((sent == 0) && (parse_error == 0))
840                         cli_out ("Volume add-brick failed");
841         }
842
843         CLI_STACK_DESTROY (frame);
844
845         return ret;
846 }
847
848 int
849 cli_tier_validate_replica_type (dict_t *dict, int type)
850 {
851
852         int             brick_count             = -1;
853         int             replica_count           = 1;
854         int             ret                     = -1;
855
856         ret = dict_get_int32 (dict, "count", &brick_count);
857         if (ret) {
858                 gf_log ("cli", GF_LOG_ERROR, "Failed to get brick count");
859                 goto out;
860         }
861
862         ret = dict_get_int32 (dict, "replica-count", &replica_count);
863         if (ret) {
864                 gf_log ("cli", GF_LOG_DEBUG, "Failed to get replica count. "
865                         "Defaulting to one");
866                 replica_count = 1;
867         }
868
869         /*
870          * Change the calculation of sub_count once attach-tier support
871          * disperse volume.
872          * sub_count = disperse_count for disperse volume
873          * */
874
875
876         if (brick_count % replica_count) {
877              if (type == GF_CLUSTER_TYPE_REPLICATE)
878                      cli_err ("number of bricks is not a multiple of "
879                               "replica count");
880              else if (type == GF_CLUSTER_TYPE_DISPERSE)
881                      cli_err ("number of bricks is not a multiple of "
882                               "disperse count");
883              else
884                      cli_err ("number of bricks given doesn't match "
885                               "required count");
886
887              ret = -1;
888              goto out;
889      }
890         ret = 0;
891 out:
892         return ret;
893 }
894
895 int
896 do_cli_cmd_volume_attach_tier (struct cli_state *state,
897                                 struct cli_cmd_word *word, const char **words,
898                                 int wordcount)
899 {
900         int                     ret = -1;
901         rpc_clnt_procedure_t    *proc = NULL;
902         call_frame_t            *frame = NULL;
903         dict_t                  *options = NULL;
904         int                     sent = 0;
905         int                     parse_error = 0;
906         cli_local_t             *local = NULL;
907         int                     type = 0;
908
909         frame = create_frame (THIS, THIS->ctx->pool);
910         if (!frame)
911                 goto out;
912
913         ret = cli_cmd_volume_add_brick_parse (words, wordcount, &options, &type);
914         if (ret) {
915                 cli_usage_out (word->pattern);
916                 parse_error = 1;
917                 goto out;
918         }
919
920         /*
921          * Merge this check when attach-tier has it's own cli parse function.
922          */
923         ret = cli_tier_validate_replica_type (options, type);
924         if (ret) {
925                 cli_usage_out (word->pattern);
926                 parse_error = 1;
927                 goto out;
928         }
929
930         if (state->mode & GLUSTER_MODE_WIGNORE) {
931                 ret = dict_set_int32 (options, "force", _gf_true);
932                 if (ret) {
933                         gf_log ("cli", GF_LOG_ERROR, "Failed to set force "
934                                 "option");
935                         goto out;
936                 }
937         }
938
939         ret = dict_set_int32 (options, "attach-tier", 1);
940         if (ret)
941                 goto out;
942
943         ret = dict_set_int32 (options, "hot-type", type);
944         if (ret)
945                 goto out;
946
947         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_ATTACH_TIER];
948
949         CLI_LOCAL_INIT (local, words, frame, options);
950
951         if (proc->fn) {
952                 ret = proc->fn (frame, THIS, options);
953         }
954
955 out:
956         if (ret) {
957                 cli_cmd_sent_status_get (&sent);
958                 if ((sent == 0) && (parse_error == 0))
959                         cli_out ("attach-tier failed");
960         }
961
962         CLI_STACK_DESTROY (frame);
963
964         return ret;
965 }
966
967 int
968 do_cli_cmd_volume_detach_tier (struct cli_state *state,
969                               struct cli_cmd_word *word, const char **words,
970                               int wordcount)
971 {
972         int                     ret = -1;
973         rpc_clnt_procedure_t    *proc = NULL;
974         call_frame_t            *frame = NULL;
975         dict_t                  *options = NULL;
976         int                     sent = 0;
977         int                     parse_error = 0;
978         gf_answer_t             answer = GF_ANSWER_NO;
979         cli_local_t             *local = NULL;
980         int                     need_question = 0;
981
982         const char *question = "Removing tier can result in data loss. "
983                                "Do you want to Continue?";
984
985         frame = create_frame (THIS, THIS->ctx->pool);
986         if (!frame)
987                 goto out;
988
989         ret = cli_cmd_volume_detach_tier_parse(words, wordcount, &options,
990                                                &need_question);
991         if (ret) {
992                 cli_usage_out (word->pattern);
993                 parse_error = 1;
994                 goto out;
995         }
996
997         ret = dict_set_int32 (options, "force", 1);
998         if (ret)
999                 goto out;
1000
1001         ret = dict_set_int32 (options, "count", 0);
1002         if (ret)
1003                 goto out;
1004
1005         if (!(state->mode & GLUSTER_MODE_SCRIPT) && need_question) {
1006                 /* we need to ask question only in case of 'commit or force' */
1007                 answer = cli_cmd_get_confirmation (state, question);
1008                 if (GF_ANSWER_NO == answer) {
1009                         ret = 0;
1010                         goto out;
1011                 }
1012         }
1013
1014         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_DETACH_TIER];
1015
1016         CLI_LOCAL_INIT (local, words, frame, options);
1017
1018         if (proc->fn) {
1019                 ret = proc->fn (frame, THIS, options);
1020         }
1021
1022 out:
1023         if (ret) {
1024                 cli_cmd_sent_status_get (&sent);
1025                 if ((sent == 0) && (parse_error == 0))
1026                         cli_out ("Volume detach-tier failed");
1027         }
1028
1029         CLI_STACK_DESTROY (frame);
1030
1031         return ret;
1032 }
1033
1034 int
1035 cli_cmd_volume_tier_cbk (struct cli_state *state,
1036                          struct cli_cmd_word *word, const char **words,
1037                          int wordcount)
1038 {
1039         int                      ret     = -1;
1040         call_frame_t            *frame   = NULL;
1041         dict_t                  *options = NULL;
1042         char                    *volname = NULL;
1043         rpc_clnt_procedure_t    *proc    = NULL;
1044         cli_local_t             *local   = NULL;
1045         int                      i       = 0;
1046
1047         if (wordcount < 4) {
1048                 cli_usage_out (word->pattern);
1049                 if (wordcount == 3 && !strcmp(words[2], "help"))
1050                         ret = 0;
1051                 goto out;
1052         }
1053
1054         if (!strcmp(words[1], "detach-tier")) {
1055                 ret = do_cli_cmd_volume_detach_tier (state, word,
1056                                                      words, wordcount);
1057                 goto out;
1058         } else if (!strcmp(words[3], "detach")) {
1059                 for (i = 3; i < wordcount; i++)
1060                         words[i] = words[i+1];
1061
1062                 ret = do_cli_cmd_volume_detach_tier (state, word,
1063                                                      words, wordcount-1);
1064                 goto out;
1065
1066         } else if (!strcmp(words[1], "attach-tier")) {
1067                 ret = do_cli_cmd_volume_attach_tier (state, word,
1068                                                      words, wordcount);
1069                 goto out;
1070         } else if (!strcmp(words[3], "attach")) {
1071                 for (i = 3; i < wordcount; i++)
1072                         words[i] = words[i+1];
1073
1074                 ret = do_cli_cmd_volume_attach_tier (state, word,
1075                                                      words, wordcount-1);
1076                 goto out;
1077         }
1078
1079         ret = cli_cmd_volume_tier_parse (words, wordcount, &options);
1080         if (ret) {
1081                 cli_usage_out (word->pattern);
1082                 goto out;
1083         }
1084
1085         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_TIER];
1086
1087         frame = create_frame (THIS, THIS->ctx->pool);
1088         if (!frame)
1089                 goto out;
1090
1091         CLI_LOCAL_INIT (local, words, frame, options);
1092
1093         if (proc->fn) {
1094                 ret = proc->fn (frame, THIS, options);
1095         }
1096
1097 out:
1098         if (ret) {
1099                 cli_out ("Tier command failed");
1100         }
1101         if (options)
1102                 dict_unref (options);
1103
1104         return ret;
1105 }
1106
1107 static int
1108 gf_cli_create_auxiliary_mount (char *volname)
1109 {
1110         int      ret                     = -1;
1111         char     mountdir[PATH_MAX]      = {0,};
1112         char     pidfile_path[PATH_MAX]  = {0,};
1113         char     logfile[PATH_MAX]       = {0,};
1114         char     qpid [16]               = {0,};
1115
1116         GLUSTERFS_GET_AUX_MOUNT_PIDFILE (pidfile_path, volname);
1117
1118         if (gf_is_service_running (pidfile_path, NULL)) {
1119                 gf_log ("cli", GF_LOG_DEBUG, "Aux mount of volume %s is running"
1120                         " already", volname);
1121                 ret = 0;
1122                 goto out;
1123         }
1124
1125         GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mountdir, volname, "/");
1126         ret = mkdir (mountdir, 0777);
1127         if (ret && errno != EEXIST) {
1128                 gf_log ("cli", GF_LOG_ERROR, "Failed to create auxiliary mount "
1129                         "directory %s. Reason : %s", mountdir,
1130                         strerror (errno));
1131                 goto out;
1132         }
1133
1134         snprintf (logfile, PATH_MAX-1, "%s/quota-mount-%s.log",
1135                   DEFAULT_LOG_FILE_DIRECTORY, volname);
1136         snprintf(qpid, 15, "%d", GF_CLIENT_PID_QUOTA_MOUNT);
1137
1138         ret = runcmd (SBIN_DIR"/glusterfs",
1139                       "-s", "localhost",
1140                       "--volfile-id", volname,
1141                       "-l", logfile,
1142                       "-p", pidfile_path,
1143                       "--client-pid", qpid,
1144                       mountdir,
1145                       NULL);
1146
1147         if (ret) {
1148                 gf_log ("cli", GF_LOG_WARNING, "failed to mount glusterfs "
1149                         "client. Please check the log file %s for more details",
1150                         logfile);
1151                 ret = -1;
1152                 goto out;
1153         }
1154
1155         ret = 0;
1156
1157 out:
1158         return ret;
1159 }
1160
1161 static int
1162 cli_stage_quota_op (char *volname, int op_code)
1163 {
1164         int ret = -1;
1165
1166         switch (op_code) {
1167         case GF_QUOTA_OPTION_TYPE_ENABLE:
1168         case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE:
1169         case GF_QUOTA_OPTION_TYPE_LIMIT_OBJECTS:
1170         case GF_QUOTA_OPTION_TYPE_REMOVE:
1171         case GF_QUOTA_OPTION_TYPE_REMOVE_OBJECTS:
1172         case GF_QUOTA_OPTION_TYPE_LIST:
1173                 ret = gf_cli_create_auxiliary_mount (volname);
1174                 if (ret) {
1175                         cli_err ("quota: Could not start quota "
1176                                  "auxiliary mount");
1177                         goto out;
1178                 }
1179                 ret = 0;
1180                 break;
1181
1182         default:
1183                 ret = 0;
1184                 break;
1185         }
1186
1187 out:
1188         return ret;
1189 }
1190
1191 int
1192 cli_get_soft_limit (dict_t *options, const char **words, dict_t *xdata)
1193 {
1194         call_frame_t            *frame          = NULL;
1195         cli_local_t             *local          = NULL;
1196         rpc_clnt_procedure_t    *proc           = NULL;
1197         char                    *default_sl     = NULL;
1198         char                    *default_sl_dup = NULL;
1199         int                      ret  = -1;
1200
1201         frame = create_frame (THIS, THIS->ctx->pool);
1202         if (!frame) {
1203                 ret = -1;
1204                 goto out;
1205         }
1206
1207         //We need a ref on @options to prevent CLI_STACK_DESTROY
1208         //from destroying it prematurely.
1209         dict_ref (options);
1210         CLI_LOCAL_INIT (local, words, frame, options);
1211         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA];
1212         ret = proc->fn (frame, THIS, options);
1213
1214         ret = dict_get_str (options, "default-soft-limit", &default_sl);
1215         if (ret) {
1216                 gf_log ("cli", GF_LOG_ERROR, "Failed to get default soft limit");
1217                 goto out;
1218         }
1219
1220         default_sl_dup = gf_strdup (default_sl);
1221         if (!default_sl_dup) {
1222                 ret = -1;
1223                 goto out;
1224         }
1225
1226         ret = dict_set_dynstr (xdata, "default-soft-limit", default_sl_dup);
1227         if (ret) {
1228                 gf_log ("cli", GF_LOG_ERROR, "Failed to set default soft limit");
1229                 GF_FREE (default_sl_dup);
1230                 goto out;
1231         }
1232
1233 out:
1234         CLI_STACK_DESTROY (frame);
1235         return ret;
1236 }
1237
1238 /* Checks if at least one limit has been set on the volume
1239  *
1240  * Returns true if at least one limit is set. Returns false otherwise.
1241  */
1242 gf_boolean_t
1243 _limits_set_on_volume (char *volname, int type) {
1244         gf_boolean_t    limits_set                = _gf_false;
1245         int             ret                       = -1;
1246         char            quota_conf_file[PATH_MAX] = {0,};
1247         int             fd                        = -1;
1248         char            buf[16]                   = {0,};
1249         float           version                   = 0.0f;
1250         char            gfid_type_stored          = 0;
1251         char            gfid_type                 = 0;
1252
1253         /* TODO: fix hardcoding; Need to perform an RPC call to glusterd
1254          * to fetch working directory
1255          */
1256         sprintf (quota_conf_file, "%s/vols/%s/quota.conf",
1257                  GLUSTERD_DEFAULT_WORKDIR,
1258                  volname);
1259         fd = open (quota_conf_file, O_RDONLY);
1260         if (fd == -1)
1261                 goto out;
1262
1263         ret = quota_conf_read_version (fd, &version);
1264         if (ret)
1265                 goto out;
1266
1267         if (type == GF_QUOTA_OPTION_TYPE_LIST)
1268                 gfid_type = GF_QUOTA_CONF_TYPE_USAGE;
1269         else
1270                 gfid_type = GF_QUOTA_CONF_TYPE_OBJECTS;
1271
1272         /* Try to read atleast one gfid  of type 'gfid_type' */
1273         while (1) {
1274                 ret = quota_conf_read_gfid (fd, buf, &gfid_type_stored,
1275                                             version);
1276                 if (ret <= 0)
1277                         break;
1278
1279                 if (gfid_type_stored == gfid_type) {
1280                         limits_set = _gf_true;
1281                         break;
1282                 }
1283         }
1284 out:
1285         if (fd != -1)
1286                 close (fd);
1287
1288         return limits_set;
1289 }
1290
1291 /* Checks if the mount is connected to the bricks
1292  *
1293  * Returns true if connected and false if not
1294  */
1295 gf_boolean_t
1296 _quota_aux_mount_online (char *volname)
1297 {
1298         int         ret = 0;
1299         char        mount_path[PATH_MAX + 1] = {0,};
1300         struct stat buf = {0,};
1301
1302         GF_ASSERT (volname);
1303
1304         /* Try to create the aux mount before checking if bricks are online */
1305         ret = gf_cli_create_auxiliary_mount (volname);
1306         if (ret) {
1307                 cli_err ("quota: Could not start quota auxiliary mount");
1308                 return _gf_false;
1309         }
1310
1311         GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mount_path, volname, "/");
1312
1313         ret = sys_stat (mount_path, &buf);
1314         if (ret) {
1315                 if (ENOTCONN == errno) {
1316                         cli_err ("quota: Cannot connect to bricks. Check if "
1317                                  "bricks are online.");
1318                 } else {
1319                         cli_err ("quota: Error on quota auxiliary mount (%s).",
1320                                  strerror (errno));
1321                 }
1322                 return _gf_false;
1323         }
1324         return _gf_true;
1325 }
1326
1327 int
1328 cli_cmd_quota_handle_list_all (const char **words, dict_t *options)
1329 {
1330         int                      all_failed = 1;
1331         int                      count      = 0;
1332         int                      ret        = -1;
1333         rpc_clnt_procedure_t    *proc       = NULL;
1334         cli_local_t             *local      = NULL;
1335         call_frame_t            *frame      = NULL;
1336         dict_t                  *xdata      = NULL;
1337         char                    *gfid_str   = NULL;
1338         char                    *volname    = NULL;
1339         char                    *volname_dup = NULL;
1340         unsigned char            buf[16]   = {0};
1341         int                      fd        = -1;
1342         char                     quota_conf_file[PATH_MAX] = {0};
1343         gf_boolean_t             xml_err_flag   = _gf_false;
1344         char                     err_str[NAME_MAX] = {0,};
1345         int32_t                  type       = 0;
1346         char                     gfid_type  = 0;
1347         float                    version    = 0.0f;
1348
1349         xdata = dict_new ();
1350         if (!xdata) {
1351                 ret = -1;
1352                 goto out;
1353         }
1354
1355         ret = dict_get_str (options, "volname", &volname);
1356         if (ret) {
1357                 gf_log ("cli", GF_LOG_ERROR, "Failed to get volume name");
1358                 goto out;
1359         }
1360
1361         ret = dict_get_int32 (options, "type", &type);
1362         if (ret) {
1363                 gf_log ("cli", GF_LOG_ERROR, "Failed to get quota option type");
1364                 goto out;
1365         }
1366
1367         ret = dict_set_int32 (xdata, "type", type);
1368         if (ret) {
1369                 gf_log ("cli", GF_LOG_ERROR, "Failed to set type in xdata");
1370                 goto out;
1371         }
1372
1373         ret = cli_get_soft_limit (options, words, xdata);
1374         if (ret) {
1375                 gf_log ("cli", GF_LOG_ERROR, "Failed to fetch default "
1376                         "soft-limit");
1377                 goto out;
1378         }
1379
1380         /* Check if at least one limit is set on volume. No need to check for
1381          * quota enabled as cli_get_soft_limit() handles that
1382          */
1383         if (!_limits_set_on_volume (volname, type)) {
1384                 snprintf (err_str, sizeof (err_str), "No%s quota configured on"
1385                           " volume %s",
1386                           (type == GF_QUOTA_OPTION_TYPE_LIST) ? "" : " inode",
1387                           volname);
1388                 if (global_state->mode & GLUSTER_MODE_XML) {
1389                         xml_err_flag = _gf_true;
1390                 } else {
1391                         cli_out ("quota: %s", err_str);
1392                 }
1393                 ret = 0;
1394                 goto out;
1395         }
1396
1397         /* Check if the mount is online before doing any listing */
1398         if (!_quota_aux_mount_online (volname)) {
1399                 ret = -1;
1400                 goto out;
1401         }
1402
1403         frame = create_frame (THIS, THIS->ctx->pool);
1404         if (!frame) {
1405                 ret = -1;
1406                 goto out;
1407         }
1408
1409         volname_dup = gf_strdup (volname);
1410         if (!volname_dup) {
1411                 ret = -1;
1412                 goto out;
1413         }
1414
1415         ret = dict_set_dynstr (xdata, "volume-uuid", volname_dup);
1416         if (ret) {
1417                 gf_log ("cli", GF_LOG_ERROR, "Failed to set volume-uuid");
1418                 GF_FREE (volname_dup);
1419                 goto out;
1420         }
1421
1422         //TODO: fix hardcoding; Need to perform an RPC call to glusterd
1423         //to fetch working directory
1424         sprintf (quota_conf_file, "%s/vols/%s/quota.conf",
1425                  GLUSTERD_DEFAULT_WORKDIR,
1426                  volname);
1427         fd = open (quota_conf_file, O_RDONLY);
1428         if (fd == -1) {
1429                 //This may because no limits were yet set on the volume
1430                 gf_log ("cli", GF_LOG_TRACE, "Unable to open "
1431                         "quota.conf");
1432                 ret = 0;
1433                 goto out;
1434          }
1435
1436         ret = quota_conf_read_version (fd, &version);
1437         if (ret)
1438                 goto out;
1439
1440         CLI_LOCAL_INIT (local, words, frame, xdata);
1441         proc = &cli_quotad_clnt.proctable[GF_AGGREGATOR_GETLIMIT];
1442
1443         gfid_str = GF_CALLOC (1, gf_common_mt_char, 64);
1444         if (!gfid_str) {
1445                 ret = -1;
1446                 goto out;
1447         }
1448         for (count = 0;; count++) {
1449                 ret = quota_conf_read_gfid (fd, buf, &gfid_type, version);
1450                 if (ret == 0) {
1451                         break;
1452                 } else if (ret < 0) {
1453                         gf_log (THIS->name, GF_LOG_CRITICAL, "Quota "
1454                                 "configuration store may be corrupt.");
1455                         goto out;
1456                 }
1457
1458                 if ((type == GF_QUOTA_OPTION_TYPE_LIST &&
1459                      gfid_type == GF_QUOTA_CONF_TYPE_OBJECTS) ||
1460                     (type == GF_QUOTA_OPTION_TYPE_LIST_OBJECTS &&
1461                      gfid_type == GF_QUOTA_CONF_TYPE_USAGE))
1462                         continue;
1463
1464                 uuid_utoa_r (buf, gfid_str);
1465                 ret = dict_set_str (xdata, "gfid", gfid_str);
1466                 if (ret) {
1467                         gf_log ("cli", GF_LOG_ERROR, "Failed to set gfid");
1468                         goto out;
1469                 }
1470
1471                 ret = proc->fn (frame, THIS, xdata);
1472                 if (ret) {
1473                         gf_log ("cli", GF_LOG_ERROR, "Failed to get quota "
1474                                 "limits for %s", uuid_utoa ((unsigned char*)buf));
1475                 }
1476
1477                 dict_del (xdata, "gfid");
1478                 all_failed = all_failed && ret;
1479         }
1480
1481         if (global_state->mode & GLUSTER_MODE_XML) {
1482                 ret = cli_xml_output_vol_quota_limit_list_end (local);
1483                 if (ret) {
1484                         gf_log ("cli", GF_LOG_ERROR, "Error in printing "
1485                                 "xml output");
1486                         goto out;
1487                 }
1488         }
1489
1490         if (count > 0) {
1491                 ret = all_failed? -1: 0;
1492         } else {
1493                 ret = 0;
1494         }
1495
1496
1497 out:
1498         if (xml_err_flag) {
1499                 ret = cli_xml_output_str ("volQuota", NULL, -1, 0, err_str);
1500                 if (ret) {
1501                         gf_log ("cli", GF_LOG_ERROR, "Error outputting in "
1502                                 "xml format");
1503                 }
1504         }
1505
1506         if (fd != -1) {
1507                 close (fd);
1508         }
1509
1510         GF_FREE (gfid_str);
1511         if (ret) {
1512                 gf_log ("cli", GF_LOG_ERROR, "Could not fetch and display quota"
1513                         " limits");
1514         }
1515         CLI_STACK_DESTROY (frame);
1516         return ret;
1517 }
1518
1519 int
1520 cli_cmd_bitrot_cbk (struct cli_state *state, struct cli_cmd_word *word,
1521                     const char **words, int wordcount)
1522 {
1523
1524         int                     ret        = -1;
1525         int                     parse_err  = 0;
1526         call_frame_t            *frame     = NULL;
1527         dict_t                  *options   = NULL;
1528         cli_local_t             *local     = NULL;
1529         rpc_clnt_procedure_t    *proc      = NULL;
1530         int                     sent       = 0;
1531
1532         ret = cli_cmd_bitrot_parse (words, wordcount, &options);
1533         if (ret < 0) {
1534                 cli_usage_out (word->pattern);
1535                 parse_err = 1;
1536                 goto out;
1537         }
1538
1539         frame = create_frame (THIS, THIS->ctx->pool);
1540         if (!frame) {
1541                 ret = -1;
1542                 goto out;
1543         }
1544
1545         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_BITROT];
1546         if (proc == NULL) {
1547                 ret = -1;
1548                 goto out;
1549         }
1550
1551         CLI_LOCAL_INIT (local, words, frame, options);
1552
1553         if (proc->fn) {
1554                 ret = proc->fn (frame, THIS, options);
1555         }
1556
1557 out:
1558         if (ret) {
1559                 cli_cmd_sent_status_get (&sent);
1560                 if ((sent == 0) && (parse_err == 0))
1561                     cli_err ("Bit rot command failed. Please check the cli "
1562                              "logs for more details");
1563
1564         }
1565
1566         CLI_STACK_DESTROY (frame);
1567
1568         return ret;
1569 }
1570
1571 int
1572 cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word,
1573                    const char **words, int wordcount)
1574 {
1575
1576         int                      ret       = 0;
1577         int                      parse_err = 0;
1578         int32_t                  type      = 0;
1579         rpc_clnt_procedure_t    *proc      = NULL;
1580         call_frame_t            *frame     = NULL;
1581         dict_t                  *options   = NULL;
1582         gf_answer_t              answer    = GF_ANSWER_NO;
1583         cli_local_t             *local     = NULL;
1584         int                      sent      = 0;
1585         char                    *volname   = NULL;
1586         const char *question = "Disabling quota will delete all the quota "
1587                                "configuration. Do you want to continue?";
1588
1589         //parse **words into options dictionary
1590         if (strcmp (words[1], "inode-quota") == 0) {
1591                 ret = cli_cmd_inode_quota_parse (words, wordcount, &options);
1592                 if (ret < 0) {
1593                         cli_usage_out (word->pattern);
1594                         parse_err = 1;
1595                         goto out;
1596                 }
1597         } else {
1598                 ret = cli_cmd_quota_parse (words, wordcount, &options);
1599                 if (ret < 0) {
1600                         cli_usage_out (word->pattern);
1601                         parse_err = 1;
1602                         goto out;
1603                 }
1604         }
1605
1606         ret = dict_get_int32 (options, "type", &type);
1607         if (ret) {
1608                 gf_log ("cli", GF_LOG_ERROR, "Failed to get opcode");
1609                 goto out;
1610         }
1611
1612         //handle quota-disable and quota-list-all different from others
1613         switch (type) {
1614         case GF_QUOTA_OPTION_TYPE_DISABLE:
1615                 answer = cli_cmd_get_confirmation (state, question);
1616                 if (answer == GF_ANSWER_NO)
1617                         goto out;
1618                 break;
1619         case GF_QUOTA_OPTION_TYPE_LIST:
1620         case GF_QUOTA_OPTION_TYPE_LIST_OBJECTS:
1621                 if (wordcount != 4)
1622                         break;
1623                 ret = cli_cmd_quota_handle_list_all (words, options);
1624                 goto out;
1625         default:
1626                 break;
1627         }
1628
1629         ret = dict_get_str (options, "volname", &volname);
1630         if (ret) {
1631                 gf_log ("cli", GF_LOG_ERROR, "Failed to get volume name");
1632                 goto out;
1633         }
1634
1635         //create auxiliary mount need for quota commands that operate on path
1636         ret = cli_stage_quota_op (volname, type);
1637         if (ret)
1638                 goto out;
1639
1640         frame = create_frame (THIS, THIS->ctx->pool);
1641         if (!frame) {
1642                 ret = -1;
1643                 goto out;
1644         }
1645
1646         CLI_LOCAL_INIT (local, words, frame, options);
1647         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA];
1648
1649         if (proc->fn)
1650                 ret = proc->fn (frame, THIS, options);
1651
1652 out:
1653         if (ret) {
1654                 cli_cmd_sent_status_get (&sent);
1655                 if (sent == 0 && parse_err == 0)
1656                         cli_out ("Quota command failed. Please check the cli "
1657                                  "logs for more details");
1658         }
1659
1660         CLI_STACK_DESTROY (frame);
1661         return ret;
1662 }
1663
1664 int
1665 cli_cmd_volume_remove_brick_cbk (struct cli_state *state,
1666                                  struct cli_cmd_word *word, const char **words,
1667                                  int wordcount)
1668 {
1669         int                     ret = -1;
1670         rpc_clnt_procedure_t    *proc = NULL;
1671         call_frame_t            *frame = NULL;
1672         dict_t                  *options = NULL;
1673         gf_answer_t             answer = GF_ANSWER_NO;
1674         int                     sent = 0;
1675         int                     parse_error = 0;
1676         int                     need_question = 0;
1677         cli_local_t             *local = NULL;
1678         char                    *volname = NULL;
1679
1680         const char *question = "Removing brick(s) can result in data loss. "
1681                                "Do you want to Continue?";
1682
1683         frame = create_frame (THIS, THIS->ctx->pool);
1684         if (!frame)
1685                 goto out;
1686
1687         ret = cli_cmd_volume_remove_brick_parse (words, wordcount, &options,
1688                                                  &need_question);
1689         if (ret) {
1690                 cli_usage_out (word->pattern);
1691                 parse_error = 1;
1692                 goto out;
1693         }
1694
1695         ret = dict_get_str (options, "volname", &volname);
1696         if (ret || !volname) {
1697                 gf_log ("cli", GF_LOG_ERROR, "Failed to fetch volname");
1698                 ret = -1;
1699                 goto out;
1700         }
1701
1702         if (!strcmp (volname, GLUSTER_SHARED_STORAGE)) {
1703                 question = "Removing brick from the shared storage volume"
1704                            "(gluster_shared_storage), will affect features "
1705                            "like snapshot scheduler, geo-replication "
1706                            "and NFS-Ganesha. Do you still want to "
1707                            "continue?";
1708                 need_question = _gf_true;
1709         }
1710
1711         if (!(state->mode & GLUSTER_MODE_SCRIPT) && need_question) {
1712                 /* we need to ask question only in case of 'commit or force' */
1713                 answer = cli_cmd_get_confirmation (state, question);
1714                 if (GF_ANSWER_NO == answer) {
1715                         ret = 0;
1716                         goto out;
1717                 }
1718         }
1719
1720         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_REMOVE_BRICK];
1721
1722         CLI_LOCAL_INIT (local, words, frame, options);
1723
1724         if (proc->fn) {
1725                 ret = proc->fn (frame, THIS, options);
1726         }
1727
1728 out:
1729         if (ret) {
1730                 cli_cmd_sent_status_get (&sent);
1731                 if ((sent == 0) && (parse_error == 0))
1732                         cli_out ("Volume remove-brick failed");
1733         }
1734
1735         CLI_STACK_DESTROY (frame);
1736
1737         return ret;
1738
1739 }
1740
1741 int
1742 cli_cmd_volume_replace_brick_cbk (struct cli_state *state,
1743                                   struct cli_cmd_word *word,
1744                                   const char **words,
1745                                   int wordcount)
1746 {
1747         int                      ret          = -1;
1748         rpc_clnt_procedure_t    *proc         = NULL;
1749         call_frame_t            *frame        = NULL;
1750         dict_t                  *options = NULL;
1751         int                      sent = 0;
1752         int                      parse_error = 0;
1753         cli_local_t             *local = NULL;
1754
1755 #ifdef GF_SOLARIS_HOST_OS
1756         cli_out ("Command not supported on Solaris");
1757         goto out;
1758 #endif
1759         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_REPLACE_BRICK];
1760
1761         frame = create_frame (THIS, THIS->ctx->pool);
1762         if (!frame)
1763                 goto out;
1764
1765         ret = cli_cmd_volume_replace_brick_parse (words, wordcount, &options);
1766
1767         if (ret) {
1768                 cli_usage_out (word->pattern);
1769                 parse_error = 1;
1770                 goto out;
1771         }
1772
1773         CLI_LOCAL_INIT (local, words, frame, options);
1774
1775         if (proc->fn) {
1776                 ret = proc->fn (frame, THIS, options);
1777         }
1778
1779 out:
1780         if (ret) {
1781                 cli_cmd_sent_status_get (&sent);
1782                 if ((sent == 0) && (parse_error == 0))
1783                         cli_out ("Volume replace-brick failed");
1784         }
1785
1786         CLI_STACK_DESTROY (frame);
1787
1788         return ret;
1789 }
1790
1791
1792 int
1793 cli_cmd_volume_set_transport_cbk (struct cli_state *state,
1794                                   struct cli_cmd_word *word,
1795                                   const char **words, int wordcount)
1796 {
1797         cli_cmd_broadcast_response (0);
1798         return 0;
1799 }
1800
1801 int
1802 cli_cmd_volume_top_cbk (struct cli_state *state, struct cli_cmd_word *word,
1803                           const char **words, int wordcount)
1804 {
1805
1806         int                     ret      = -1;
1807         rpc_clnt_procedure_t    *proc    = NULL;
1808         call_frame_t            *frame   = NULL;
1809         dict_t                  *options = NULL;
1810         int                     sent     = 0;
1811         int                     parse_error = 0;
1812         cli_local_t             *local = NULL;
1813
1814         ret = cli_cmd_volume_top_parse (words, wordcount, &options);
1815
1816         if (ret) {
1817                 parse_error = 1;
1818                 cli_usage_out (word->pattern);
1819                 goto out;
1820         }
1821
1822         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_TOP_VOLUME];
1823
1824         frame = create_frame (THIS, THIS->ctx->pool);
1825         if (!frame)
1826                 goto out;
1827
1828         CLI_LOCAL_INIT (local, words, frame, options);
1829
1830         if (proc->fn) {
1831                 ret = proc->fn (frame, THIS, options);
1832         }
1833
1834 out:
1835         if (ret) {
1836                 cli_cmd_sent_status_get (&sent);
1837                 if ((sent == 0) && (parse_error == 0))
1838                         cli_out ("Volume top failed");
1839         }
1840
1841         CLI_STACK_DESTROY (frame);
1842
1843         return ret;
1844
1845 }
1846
1847
1848 int
1849 cli_cmd_log_rotate_cbk (struct cli_state *state, struct cli_cmd_word *word,
1850                         const char **words, int wordcount)
1851 {
1852         int                     ret = -1;
1853         rpc_clnt_procedure_t    *proc = NULL;
1854         call_frame_t            *frame = NULL;
1855         dict_t                  *options = NULL;
1856         int                     sent = 0;
1857         int                     parse_error = 0;
1858         cli_local_t             *local = NULL;
1859
1860         if (!((wordcount == 4) || (wordcount == 5))) {
1861                 cli_usage_out (word->pattern);
1862                 parse_error = 1;
1863                 goto out;
1864         }
1865
1866         if (!((strcmp ("rotate", words[2]) == 0) ||
1867               (strcmp ("rotate", words[3]) == 0))) {
1868                 cli_usage_out (word->pattern);
1869                 parse_error = 1;
1870                 goto out;
1871         }
1872
1873         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LOG_ROTATE];
1874
1875         frame = create_frame (THIS, THIS->ctx->pool);
1876         if (!frame)
1877                 goto out;
1878
1879         ret = cli_cmd_log_rotate_parse (words, wordcount, &options);
1880         if (ret)
1881                 goto out;
1882
1883         CLI_LOCAL_INIT (local, words, frame, options);
1884
1885         if (proc->fn) {
1886                 ret = proc->fn (frame, THIS, options);
1887         }
1888
1889 out:
1890         if (ret) {
1891                 cli_cmd_sent_status_get (&sent);
1892                 if ((sent == 0) && (parse_error == 0))
1893                         cli_out ("Volume log rotate failed");
1894         }
1895         CLI_STACK_DESTROY (frame);
1896
1897         return ret;
1898 }
1899
1900 #if (SYNCDAEMON_COMPILE)
1901 static int
1902 cli_check_gsync_present ()
1903 {
1904         char                buff[PATH_MAX] = {0, };
1905         runner_t            runner = {0,};
1906         char                *ptr = NULL;
1907         int                 ret = 0;
1908
1909         ret = setenv ("_GLUSTERD_CALLED_", "1", 1);
1910         if (-1 == ret) {
1911                 gf_log ("", GF_LOG_WARNING, "setenv syscall failed, hence could"
1912                         "not assert if geo-replication is installed");
1913                 goto out;
1914         }
1915
1916         runinit (&runner);
1917         runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "--version", NULL);
1918         runner_redir (&runner, STDOUT_FILENO, RUN_PIPE);
1919         ret = runner_start (&runner);
1920         if (ret == -1) {
1921                 gf_log ("", GF_LOG_INFO, "geo-replication not installed");
1922                 goto out;
1923         }
1924
1925         ptr = fgets(buff, sizeof(buff), runner_chio (&runner, STDOUT_FILENO));
1926         if (ptr) {
1927                 if (!strstr (buff, "gsyncd")) {
1928                         ret  = -1;
1929                         goto out;
1930                 }
1931         } else {
1932                 ret = -1;
1933                 goto out;
1934         }
1935
1936         ret = runner_end (&runner);
1937
1938         if (ret)
1939                 gf_log ("", GF_LOG_ERROR, "geo-replication not installed");
1940
1941 out:
1942         gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
1943         return ret ? -1 : 0;
1944
1945 }
1946
1947 void
1948 cli_cmd_check_gsync_exists_cbk (struct cli_cmd *this)
1949 {
1950
1951         int             ret = 0;
1952
1953         ret = cli_check_gsync_present ();
1954         if (ret)
1955                 this->disable = _gf_true;
1956
1957 }
1958 #endif
1959
1960 int
1961 cli_cmd_volume_gsync_set_cbk (struct cli_state *state, struct cli_cmd_word *word,
1962                               const char **words, int wordcount)
1963 {
1964         int                      ret     = 0;
1965         int                      parse_err = 0;
1966         dict_t                  *options = NULL;
1967         rpc_clnt_procedure_t    *proc    = NULL;
1968         call_frame_t            *frame   = NULL;
1969         cli_local_t             *local   = NULL;
1970
1971         proc = &cli_rpc_prog->proctable [GLUSTER_CLI_GSYNC_SET];
1972
1973         frame = create_frame (THIS, THIS->ctx->pool);
1974         if (frame == NULL) {
1975                 ret = -1;
1976                 goto out;
1977         }
1978
1979         ret = cli_cmd_gsync_set_parse (words, wordcount, &options);
1980         if (ret) {
1981                 cli_usage_out (word->pattern);
1982                 parse_err = 1;
1983                 goto out;
1984         }
1985
1986         CLI_LOCAL_INIT (local, words, frame, options);
1987
1988         if (proc->fn)
1989                 ret = proc->fn (frame, THIS, options);
1990
1991 out:
1992         if (ret && parse_err == 0)
1993                 cli_out (GEOREP" command failed");
1994
1995         CLI_STACK_DESTROY (frame);
1996
1997         return ret;
1998 }
1999
2000 int
2001 cli_cmd_volume_status_cbk (struct cli_state *state,
2002                            struct cli_cmd_word *word,
2003                            const char **words, int wordcount)
2004 {
2005         int                   ret         = -1;
2006         rpc_clnt_procedure_t *proc        = NULL;
2007         call_frame_t         *frame       = NULL;
2008         dict_t               *dict        = NULL;
2009         uint32_t              cmd         = 0;
2010         cli_local_t          *local       = NULL;
2011
2012         ret = cli_cmd_volume_status_parse (words, wordcount, &dict);
2013
2014         if (ret) {
2015                 cli_usage_out (word->pattern);
2016                 goto out;
2017         }
2018
2019         ret = dict_get_uint32 (dict, "cmd", &cmd);
2020         if (ret)
2021                 goto out;
2022
2023         if (!(cmd & GF_CLI_STATUS_ALL)) {
2024                 /* for one volume or brick */
2025                 proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_VOLUME];
2026         } else {
2027                 /* volume status all or all detail */
2028                 proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_ALL];
2029         }
2030
2031         if (!proc->fn)
2032                 goto out;
2033
2034         frame = create_frame (THIS, THIS->ctx->pool);
2035         if (!frame)
2036                 goto out;
2037
2038         CLI_LOCAL_INIT (local, words, frame, dict);
2039
2040         ret = proc->fn (frame, THIS, dict);
2041
2042 out:
2043         CLI_STACK_DESTROY (frame);
2044
2045         return ret;
2046 }
2047
2048
2049 int
2050 cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status)
2051 {
2052         uint64_t                   free            = 0;
2053         uint64_t                   total           = 0;
2054         char                       key[1024]       = {0};
2055         int                        ret             = 0;
2056
2057         memset (key, 0, sizeof (key));
2058         snprintf (key, sizeof (key), "brick%d.free", i);
2059         ret = dict_get_uint64 (dict, key, &free);
2060
2061         status->free = gf_uint64_2human_readable (free);
2062         if (!status->free)
2063                 goto out;
2064
2065         memset (key, 0, sizeof (key));
2066         snprintf (key, sizeof (key), "brick%d.total", i);
2067         ret = dict_get_uint64 (dict, key, &total);
2068
2069         status->total = gf_uint64_2human_readable (total);
2070         if (!status->total)
2071                 goto out;
2072
2073 #ifdef GF_LINUX_HOST_OS
2074         memset (key, 0, sizeof (key));
2075         snprintf (key, sizeof (key), "brick%d.device", i);
2076         ret = dict_get_str (dict, key, &(status->device));
2077         if (ret)
2078                 status->device = NULL;
2079 #endif
2080
2081         memset (key, 0, sizeof (key));
2082         snprintf (key, sizeof (key), "brick%d.block_size", i);
2083         ret = dict_get_uint64 (dict, key, &(status->block_size));
2084         if (ret) {
2085                 ret = 0;
2086                 status->block_size = 0;
2087         }
2088
2089 #ifdef GF_LINUX_HOST_OS
2090         memset (key, 0, sizeof (key));
2091         snprintf (key, sizeof (key), "brick%d.mnt_options", i);
2092         ret = dict_get_str (dict, key, &(status->mount_options));
2093         if (ret)
2094                 status->mount_options = NULL;
2095
2096         memset (key, 0, sizeof (key));
2097         snprintf (key, sizeof (key), "brick%d.fs_name", i);
2098         ret = dict_get_str (dict, key, &(status->fs_name));
2099         if (ret) {
2100                 ret = 0;
2101                 status->fs_name = NULL;
2102         }
2103
2104         memset (key, 0, sizeof (key));
2105         snprintf (key, sizeof (key), "brick%d.inode_size", i);
2106         ret = dict_get_str (dict, key, &(status->inode_size));
2107         if (ret)
2108                 status->inode_size = NULL;
2109 #endif /* GF_LINUX_HOST_OS */
2110
2111         memset (key, 0, sizeof (key));
2112         snprintf (key, sizeof (key), "brick%d.total_inodes", i);
2113         ret = dict_get_uint64 (dict, key,
2114                         &(status->total_inodes));
2115         if (ret)
2116                 status->total_inodes = 0;
2117
2118         memset (key, 0, sizeof (key));
2119         snprintf (key, sizeof (key), "brick%d.free_inodes", i);
2120         ret = dict_get_uint64 (dict, key, &(status->free_inodes));
2121         if (ret) {
2122                 ret = 0;
2123                 status->free_inodes = 0;
2124         }
2125
2126
2127  out:
2128         return ret;
2129 }
2130
2131 void
2132 cli_print_detailed_status (cli_volume_status_t *status)
2133 {
2134         cli_out ("%-20s : %-20s", "Brick", status->brick);
2135
2136         if (status->online) {
2137                 cli_out ("%-20s : %-20d", "TCP Port", status->port);
2138                 cli_out ("%-20s : %-20d", "RDMA Port", status->rdma_port);
2139         } else {
2140                 cli_out ("%-20s : %-20s", "TCP Port", "N/A");
2141                 cli_out ("%-20s : %-20s", "RDMA Port", "N/A");
2142         }
2143
2144         cli_out ("%-20s : %-20c", "Online", (status->online) ? 'Y' : 'N');
2145         cli_out ("%-20s : %-20s", "Pid", status->pid_str);
2146
2147 #ifdef GF_LINUX_HOST_OS
2148         if (status->fs_name)
2149                 cli_out ("%-20s : %-20s", "File System", status->fs_name);
2150         else
2151                 cli_out ("%-20s : %-20s", "File System", "N/A");
2152
2153         if (status->device)
2154                 cli_out ("%-20s : %-20s", "Device", status->device);
2155         else
2156                 cli_out ("%-20s : %-20s", "Device", "N/A");
2157
2158         if (status->mount_options) {
2159                 cli_out ("%-20s : %-20s", "Mount Options",
2160                          status->mount_options);
2161         } else {
2162                 cli_out ("%-20s : %-20s", "Mount Options", "N/A");
2163         }
2164
2165         if (status->inode_size) {
2166                 cli_out ("%-20s : %-20s", "Inode Size",
2167                          status->inode_size);
2168         } else {
2169                 cli_out ("%-20s : %-20s", "Inode Size", "N/A");
2170         }
2171 #endif
2172         if (status->free)
2173                 cli_out ("%-20s : %-20s", "Disk Space Free", status->free);
2174         else
2175                 cli_out ("%-20s : %-20s", "Disk Space Free", "N/A");
2176
2177         if (status->total)
2178                 cli_out ("%-20s : %-20s", "Total Disk Space", status->total);
2179         else
2180                 cli_out ("%-20s : %-20s", "Total Disk Space", "N/A");
2181
2182
2183         if (status->total_inodes) {
2184                 cli_out ("%-20s : %-20"GF_PRI_INODE, "Inode Count",
2185                          status->total_inodes);
2186         } else {
2187                 cli_out ("%-20s : %-20s", "Inode Count", "N/A");
2188         }
2189
2190         if (status->free_inodes) {
2191                 cli_out ("%-20s : %-20"GF_PRI_INODE, "Free Inodes",
2192                          status->free_inodes);
2193         } else {
2194                 cli_out ("%-20s : %-20s", "Free Inodes", "N/A");
2195         }
2196 }
2197
2198 int
2199 cli_print_brick_status (cli_volume_status_t *status)
2200 {
2201         int  fieldlen = CLI_VOL_STATUS_BRICK_LEN;
2202         int  bricklen = 0;
2203         char *p = NULL;
2204         int  num_spaces = 0;
2205
2206         p = status->brick;
2207         bricklen = strlen (p);
2208         while (bricklen > 0) {
2209                 if (bricklen > fieldlen) {
2210                         cli_out ("%.*s", fieldlen, p);
2211                         p += fieldlen;
2212                         bricklen -= fieldlen;
2213                 } else {
2214                         num_spaces = (fieldlen - bricklen) + 1;
2215                         printf ("%s", p);
2216                         while (num_spaces-- != 0)
2217                                 printf (" ");
2218                         if (status->port || status->rdma_port) {
2219                                 if (status->online)
2220                                         cli_out ("%-10d%-11d%-8c%-5s",
2221                                                  status->port,
2222                                                  status->rdma_port,
2223                                                  status->online?'Y':'N',
2224                                                  status->pid_str);
2225                                 else
2226                                         cli_out ("%-10s%-11s%-8c%-5s",
2227                                                  "N/A",
2228                                                  "N/A",
2229                                                  status->online?'Y':'N',
2230                                                  status->pid_str);
2231                         }
2232                         else
2233                                 cli_out ("%-10s%-11s%-8c%-5s",
2234                                          "N/A", "N/A", status->online?'Y':'N',
2235                                          status->pid_str);
2236                         bricklen = 0;
2237                 }
2238         }
2239
2240         return 0;
2241 }
2242
2243 #define NEEDS_GLFS_HEAL(op) ((op == GF_SHD_OP_SBRAIN_HEAL_FROM_BIGGER_FILE) || \
2244                              (op == GF_SHD_OP_SBRAIN_HEAL_FROM_BRICK) ||      \
2245                              (op == GF_SHD_OP_INDEX_SUMMARY) ||               \
2246                              (op == GF_SHD_OP_SPLIT_BRAIN_FILES))
2247
2248 int
2249 cli_launch_glfs_heal (int heal_op, dict_t *options)
2250 {
2251         char      buff[PATH_MAX] = {0};
2252         runner_t  runner         = {0};
2253         char      *filename      = NULL;
2254         char      *hostname      = NULL;
2255         char      *path          = NULL;
2256         char      *volname       = NULL;
2257         char      *out           = NULL;
2258         int        ret           = 0;
2259
2260         runinit (&runner);
2261         ret = dict_get_str (options, "volname", &volname);
2262         runner_add_args (&runner, SBIN_DIR"/glfsheal", volname, NULL);
2263         runner_redir (&runner, STDOUT_FILENO, RUN_PIPE);
2264
2265         switch (heal_op) {
2266         case GF_SHD_OP_INDEX_SUMMARY:
2267                 break;
2268         case GF_SHD_OP_SBRAIN_HEAL_FROM_BIGGER_FILE:
2269                 ret = dict_get_str (options, "file", &filename);
2270                 runner_add_args (&runner, "bigger-file", filename, NULL);
2271                 break;
2272         case GF_SHD_OP_SBRAIN_HEAL_FROM_BRICK:
2273                 ret = dict_get_str (options, "heal-source-hostname",
2274                                     &hostname);
2275                 ret = dict_get_str (options, "heal-source-brickpath",
2276                                     &path);
2277                 runner_add_args (&runner, "source-brick", NULL);
2278                 runner_argprintf (&runner, "%s:%s", hostname, path);
2279                 if (dict_get_str (options, "file", &filename) == 0)
2280                         runner_argprintf (&runner, filename);
2281                 break;
2282         case GF_SHD_OP_SPLIT_BRAIN_FILES:
2283                 runner_add_args (&runner, "split-brain-info", NULL);
2284                 break;
2285         default:
2286                 ret = -1;
2287         }
2288         ret = runner_start (&runner);
2289         if (ret == -1)
2290                 goto out;
2291         while ((out = fgets (buff, sizeof(buff),
2292                              runner_chio (&runner, STDOUT_FILENO)))) {
2293                 printf ("%s", out);
2294         }
2295         ret = runner_end (&runner);
2296         ret = WEXITSTATUS (ret);
2297
2298 out:
2299         return ret;
2300 }
2301 int
2302 cli_cmd_volume_heal_cbk (struct cli_state *state, struct cli_cmd_word *word,
2303                           const char **words, int wordcount)
2304 {
2305         int                     ret = -1;
2306         rpc_clnt_procedure_t    *proc = NULL;
2307         call_frame_t            *frame = NULL;
2308         int                     sent = 0;
2309         int                     parse_error = 0;
2310         dict_t                  *options = NULL;
2311         xlator_t                *this = NULL;
2312         cli_local_t             *local = NULL;
2313         int                     heal_op = 0;
2314
2315         this = THIS;
2316         frame = create_frame (this, this->ctx->pool);
2317         if (!frame)
2318                 goto out;
2319
2320         if (wordcount < 3) {
2321                cli_usage_out (word->pattern);
2322                parse_error = 1;
2323                goto out;
2324         }
2325
2326         ret = cli_cmd_volume_heal_options_parse (words, wordcount, &options);
2327         if (ret) {
2328                 cli_usage_out (word->pattern);
2329                 parse_error = 1;
2330                 goto out;
2331         }
2332         ret = dict_get_int32 (options, "heal-op", &heal_op);
2333         if (ret < 0)
2334                 goto out;
2335         if (NEEDS_GLFS_HEAL (heal_op)) {
2336                 ret = cli_launch_glfs_heal (heal_op, options);
2337                 if (ret == -1)
2338                         goto out;
2339         }
2340         else {
2341                 proc = &cli_rpc_prog->proctable[GLUSTER_CLI_HEAL_VOLUME];
2342
2343                 CLI_LOCAL_INIT (local, words, frame, options);
2344
2345                 if (proc->fn) {
2346                         ret = proc->fn (frame, THIS, options);
2347                 }
2348         }
2349
2350 out:
2351         if (ret) {
2352                 cli_cmd_sent_status_get (&sent);
2353                 if ((sent == 0) && (parse_error == 0))
2354                         cli_out ("Volume heal failed.");
2355         }
2356
2357         CLI_STACK_DESTROY (frame);
2358
2359         return ret;
2360 }
2361
2362 int
2363 cli_cmd_volume_statedump_cbk (struct cli_state *state, struct cli_cmd_word *word,
2364                               const char **words, int wordcount)
2365 {
2366         int                             ret = -1;
2367         rpc_clnt_procedure_t            *proc = NULL;
2368         call_frame_t                    *frame = NULL;
2369         dict_t                          *options = NULL;
2370         int                             sent = 0;
2371         int                             parse_error = 0;
2372         cli_local_t                     *local = NULL;
2373
2374         frame = create_frame (THIS, THIS->ctx->pool);
2375         if (!frame)
2376                 goto out;
2377
2378         if (wordcount < 3) {
2379                 cli_usage_out (word->pattern);
2380                 parse_error = 1;
2381                 goto out;
2382         }
2383
2384         if (wordcount >= 3) {
2385                ret = cli_cmd_volume_statedump_options_parse (words, wordcount,
2386                                                               &options);
2387                if (ret) {
2388                        parse_error = 1;
2389                        gf_log ("cli", GF_LOG_ERROR, "Error parsing "
2390                                "statedump options");
2391                        cli_out ("Error parsing options");
2392                        cli_usage_out (word->pattern);
2393                }
2394         }
2395
2396         ret = dict_set_str (options, "volname", (char *)words[2]);
2397         if (ret)
2398                 goto out;
2399
2400         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATEDUMP_VOLUME];
2401
2402         CLI_LOCAL_INIT (local, words, frame, options);
2403
2404         if (proc->fn) {
2405                 ret = proc->fn (frame, THIS, options);
2406         }
2407
2408 out:
2409         if (ret) {
2410                 cli_cmd_sent_status_get (&sent);
2411                 if ((sent == 0) && (parse_error == 0))
2412                         cli_out ("Volume statedump failed");
2413         }
2414
2415         CLI_STACK_DESTROY (frame);
2416
2417         return ret;
2418 }
2419
2420 int
2421 cli_cmd_volume_list_cbk (struct cli_state *state, struct cli_cmd_word *word,
2422                          const char **words, int wordcount)
2423 {
2424         int                     ret = -1;
2425         call_frame_t            *frame = NULL;
2426         rpc_clnt_procedure_t    *proc = NULL;
2427         int                     sent = 0;
2428
2429         frame = create_frame (THIS, THIS->ctx->pool);
2430         if (!frame)
2431                 goto out;
2432
2433         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LIST_VOLUME];
2434         if (proc->fn) {
2435                 ret = proc->fn (frame, THIS, NULL);
2436         }
2437
2438 out:
2439         if (ret) {
2440                 cli_cmd_sent_status_get (&sent);
2441                 if (sent == 0)
2442                         cli_out ("Volume list failed");
2443         }
2444
2445         CLI_STACK_DESTROY (frame);
2446
2447         return ret;
2448 }
2449
2450 int
2451 cli_cmd_volume_clearlocks_cbk (struct cli_state *state,
2452                                struct cli_cmd_word *word,
2453                                const char **words, int wordcount)
2454 {
2455         int                             ret = -1;
2456         rpc_clnt_procedure_t            *proc = NULL;
2457         call_frame_t                    *frame = NULL;
2458         dict_t                          *options = NULL;
2459         int                             sent = 0;
2460         int                             parse_error = 0;
2461         cli_local_t                     *local = NULL;
2462
2463         frame = create_frame (THIS, THIS->ctx->pool);
2464         if (!frame)
2465                 goto out;
2466
2467         if (wordcount < 7 || wordcount > 8) {
2468                 cli_usage_out (word->pattern);
2469                 parse_error = 1;
2470                 goto out;
2471         }
2472
2473        ret = cli_cmd_volume_clrlks_opts_parse (words, wordcount, &options);
2474        if (ret) {
2475                parse_error = 1;
2476                gf_log ("cli", GF_LOG_ERROR, "Error parsing "
2477                        "clear-locks options");
2478                cli_out ("Error parsing options");
2479                cli_usage_out (word->pattern);
2480        }
2481
2482         ret = dict_set_str (options, "volname", (char *)words[2]);
2483         if (ret)
2484                 goto out;
2485
2486         ret = dict_set_str (options, "path", (char *)words[3]);
2487         if (ret)
2488                 goto out;
2489
2490         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CLRLOCKS_VOLUME];
2491
2492         CLI_LOCAL_INIT (local, words, frame, options);
2493
2494         if (proc->fn) {
2495                 ret = proc->fn (frame, THIS, options);
2496         }
2497
2498 out:
2499         if (ret) {
2500                 cli_cmd_sent_status_get (&sent);
2501                 if ((sent == 0) && (parse_error == 0))
2502                         cli_out ("Volume clear-locks failed");
2503         }
2504
2505         CLI_STACK_DESTROY (frame);
2506
2507         return ret;
2508 }
2509
2510 int
2511 cli_cmd_volume_barrier_cbk (struct cli_state *state, struct cli_cmd_word *word,
2512                             const char **words, int wordcount)
2513 {
2514         int ret = -1;
2515         rpc_clnt_procedure_t *proc = NULL;
2516         call_frame_t *frame = NULL;
2517         dict_t *options = NULL;
2518         int sent = 0;
2519         int parse_error = 0;
2520         cli_local_t *local = NULL;
2521
2522         frame = create_frame (THIS, THIS->ctx->pool);
2523         if (!frame)
2524                 goto out;
2525
2526         if (wordcount != 4) {
2527                 cli_usage_out (word->pattern);
2528                 parse_error = 1;
2529                 goto out;
2530         }
2531
2532         options = dict_new();
2533         if (!options) {
2534                 ret = -1;
2535                 goto out;
2536         }
2537         ret = dict_set_str(options, "volname", (char *)words[2]);
2538         if (ret)
2539                 goto out;
2540
2541         ret = dict_set_str (options, "barrier", (char *)words[3]);
2542         if (ret)
2543                 goto out;
2544
2545         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_BARRIER_VOLUME];
2546
2547         CLI_LOCAL_INIT (local, words, frame, options);
2548
2549         if (proc->fn)
2550                 ret = proc->fn (frame, THIS, options);
2551
2552 out:
2553         if (ret) {
2554                 cli_cmd_sent_status_get (&sent);
2555                 if ((sent == 0) && (parse_error == 0))
2556                         cli_err ("Volume barrier failed");
2557         }
2558         CLI_STACK_DESTROY (frame);
2559         if (options)
2560                 dict_unref (options);
2561
2562         return ret;
2563 }
2564
2565 int
2566 cli_cmd_volume_getopt_cbk (struct cli_state *state, struct cli_cmd_word *word,
2567                         const char **words, int wordcount)
2568 {
2569         int                   ret       = -1;
2570         rpc_clnt_procedure_t *proc      = NULL;
2571         call_frame_t         *frame     = NULL;
2572         dict_t               *options   = NULL;
2573         int                   sent      = 0;
2574         int                   parse_err = 0;
2575         cli_local_t          *local     = NULL;
2576
2577         if (wordcount != 4) {
2578                 cli_usage_out (word->pattern);
2579                 parse_err = 1;
2580                 goto out;
2581         }
2582
2583         frame = create_frame (THIS, THIS->ctx->pool);
2584         if (!frame)
2585                 goto out;
2586
2587         options = dict_new ();
2588         if (!options)
2589                 goto out;
2590
2591         ret = dict_set_str (options, "volname", (char *)words[2]);
2592         if (ret)
2593                 goto out;
2594
2595         ret = dict_set_str (options, "key", (char *)words[3]);
2596         if (ret)
2597                 goto out;
2598
2599         proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOL_OPT];
2600
2601         CLI_LOCAL_INIT (local, words, frame, options);
2602
2603         if (proc->fn)
2604                 ret = proc->fn (frame, THIS, options);
2605
2606 out:
2607         if (ret) {
2608                 cli_cmd_sent_status_get (&sent);
2609                 if ((sent == 0) && (parse_err == 0))
2610                         cli_err ("Volume get option failed");
2611         }
2612         CLI_STACK_DESTROY (frame);
2613         if (options)
2614                 dict_unref (options);
2615         return ret;
2616 }
2617
2618 struct cli_cmd volume_cmds[] = {
2619         { "volume info [all|<VOLNAME>]",
2620           cli_cmd_volume_info_cbk,
2621           "list information of all volumes"},
2622
2623         { "volume create <NEW-VOLNAME> [stripe <COUNT>] "
2624           "[replica <COUNT> [arbiter <COUNT>]] "
2625           "[disperse [<COUNT>]] [disperse-data <COUNT>] [redundancy <COUNT>] "
2626           "[transport <tcp|rdma|tcp,rdma>] <NEW-BRICK>"
2627 #ifdef HAVE_BD_XLATOR
2628           "?<vg_name>"
2629 #endif
2630           "... [force]",
2631
2632           cli_cmd_volume_create_cbk,
2633           "create a new volume of specified type with mentioned bricks"},
2634
2635         { "volume delete <VOLNAME>",
2636           cli_cmd_volume_delete_cbk,
2637           "delete volume specified by <VOLNAME>"},
2638
2639         { "volume start <VOLNAME> [force]",
2640           cli_cmd_volume_start_cbk,
2641           "start volume specified by <VOLNAME>"},
2642
2643         { "volume stop <VOLNAME> [force]",
2644           cli_cmd_volume_stop_cbk,
2645           "stop volume specified by <VOLNAME>"},
2646
2647         /*{ "volume rename <VOLNAME> <NEW-VOLNAME>",
2648           cli_cmd_volume_rename_cbk,
2649           "rename volume <VOLNAME> to <NEW-VOLNAME>"},*/
2650
2651         { "volume tier <VOLNAME> status\n"
2652         "volume tier <VOLNAME> attach [<replica COUNT>] <NEW-BRICK>...\n"
2653         "volume tier <VOLNAME> detach <start|stop|status|commit|[force]>\n",
2654         cli_cmd_volume_tier_cbk,
2655         "Tier translator specific operations."},
2656
2657         { "volume attach-tier <VOLNAME> [<replica COUNT>] <NEW-BRICK>...",
2658         cli_cmd_volume_tier_cbk,
2659           "NOTE: this is old syntax, will be depreciated in next release. "
2660           "Please use gluster volume tier <vol> attach "
2661           "[<replica COUNT>] <NEW-BRICK>..."},
2662
2663         { "volume detach-tier <VOLNAME> "
2664           " <start|stop|status|commit|force>",
2665         cli_cmd_volume_tier_cbk,
2666           "NOTE: this is old syntax, will be depreciated in next release. "
2667           "Please use gluster volume tier <vol> detach "
2668           "{start|stop|commit} [force]"},
2669
2670         { "volume add-brick <VOLNAME> [<stripe|replica> <COUNT>] <NEW-BRICK> ... [force]",
2671           cli_cmd_volume_add_brick_cbk,
2672           "add brick to volume <VOLNAME>"},
2673
2674         { "volume remove-brick <VOLNAME> [replica <COUNT>] <BRICK> ..."
2675           " <start|stop|status|commit|force>",
2676           cli_cmd_volume_remove_brick_cbk,
2677           "remove brick from volume <VOLNAME>"},
2678
2679         { "volume rebalance <VOLNAME> {{fix-layout start} | {start [force]|stop|status}}",
2680           cli_cmd_volume_defrag_cbk,
2681           "rebalance operations"},
2682
2683         { "volume replace-brick <VOLNAME> <SOURCE-BRICK> <NEW-BRICK> "
2684           "{commit force}",
2685           cli_cmd_volume_replace_brick_cbk,
2686           "replace-brick operations"},
2687
2688         /*{ "volume set-transport <VOLNAME> <TRANSPORT-TYPE> [<TRANSPORT-TYPE>] ...",
2689           cli_cmd_volume_set_transport_cbk,
2690           "set transport type for volume <VOLNAME>"},*/
2691
2692         { "volume set <VOLNAME> <KEY> <VALUE>",
2693           cli_cmd_volume_set_cbk,
2694          "set options for volume <VOLNAME>"},
2695
2696         { "volume help",
2697           cli_cmd_volume_help_cbk,
2698           "display help for the volume command"},
2699
2700         { "volume log <VOLNAME> rotate [BRICK]",
2701           cli_cmd_log_rotate_cbk,
2702          "rotate the log file for corresponding volume/brick"},
2703
2704         { "volume log rotate <VOLNAME> [BRICK]",
2705           cli_cmd_log_rotate_cbk,
2706          "rotate the log file for corresponding volume/brick"
2707          " NOTE: This is an old syntax, will be deprecated from next release."},
2708
2709         { "volume sync <HOSTNAME> [all|<VOLNAME>]",
2710           cli_cmd_sync_volume_cbk,
2711          "sync the volume information from a peer"},
2712
2713          { "volume reset <VOLNAME> [option] [force]",
2714          cli_cmd_volume_reset_cbk,
2715          "reset all the reconfigured options"},
2716
2717 #if (SYNCDAEMON_COMPILE)
2718         {"volume "GEOREP" [<VOLNAME>] [<SLAVE-URL>] {create [[no-verify]|[push-pem]] [force]"
2719          "|start [force]|stop [force]|pause [force]|resume [force]|config|status [detail]|delete} [options...]",
2720          cli_cmd_volume_gsync_set_cbk,
2721          "Geo-sync operations",
2722          cli_cmd_check_gsync_exists_cbk},
2723 #endif
2724
2725          { "volume profile <VOLNAME> {start|info [peek|incremental [peek]|cumulative|clear]|stop} [nfs]",
2726            cli_cmd_volume_profile_cbk,
2727            "volume profile operations"},
2728
2729         { "volume quota <VOLNAME> {enable|disable|list [<path> ...]| "
2730           "list-objects [<path> ...] | remove <path>| remove-objects <path> | "
2731           "default-soft-limit <percent>} |\n"
2732           "volume quota <VOLNAME> {limit-usage <path> <size> [<percent>]} |\n"
2733           "volume quota <VOLNAME> {limit-objects <path> <number> [<percent>]} |\n"
2734           "volume quota <VOLNAME> {alert-time|soft-timeout|hard-timeout} {<time>}",
2735           cli_cmd_quota_cbk,
2736           "quota translator specific operations"},
2737
2738         { "volume inode-quota <VOLNAME> enable",
2739           cli_cmd_quota_cbk,
2740           "quota translator specific operations"},
2741
2742          { "volume top <VOLNAME> {open|read|write|opendir|readdir|clear} [nfs|brick <brick>] [list-cnt <value>] |\n"
2743            "volume top <VOLNAME> {read-perf|write-perf} [bs <size> count <count>] [brick <brick>] [list-cnt <value>]",
2744            cli_cmd_volume_top_cbk,
2745            "volume top operations"},
2746
2747         { "volume status [all | <VOLNAME> [nfs|shd|<BRICK>|quotad]]"
2748           " [detail|clients|mem|inode|fd|callpool|tasks]",
2749           cli_cmd_volume_status_cbk,
2750           "display status of all or specified volume(s)/brick"},
2751
2752         { "volume heal <VOLNAME> [enable | disable | full |"
2753           "statistics [heal-count [replica <HOSTNAME:BRICKNAME>]] |"
2754           "info [healed | heal-failed | split-brain] |"
2755           "split-brain {bigger-file <FILE> |"
2756                        "source-brick <HOSTNAME:BRICKNAME> [<FILE>]}]",
2757           cli_cmd_volume_heal_cbk,
2758           "self-heal commands on volume specified by <VOLNAME>"},
2759
2760         {"volume statedump <VOLNAME> [nfs|quotad] [all|mem|iobuf|callpool|priv|fd|"
2761          "inode|history]...",
2762          cli_cmd_volume_statedump_cbk,
2763          "perform statedump on bricks"},
2764
2765         {"volume list",
2766          cli_cmd_volume_list_cbk,
2767          "list all volumes in cluster"},
2768
2769         {"volume clear-locks <VOLNAME> <path> kind {blocked|granted|all}"
2770           "{inode [range]|entry [basename]|posix [range]}",
2771           cli_cmd_volume_clearlocks_cbk,
2772           "Clear locks held on path"
2773         },
2774         {"volume barrier <VOLNAME> {enable|disable}",
2775          cli_cmd_volume_barrier_cbk,
2776          "Barrier/unbarrier file operations on a volume"
2777         },
2778         {"volume get <VOLNAME> <key|all>",
2779          cli_cmd_volume_getopt_cbk,
2780          "Get the value of the all options or given option for volume <VOLNAME>"
2781         },
2782         {"volume bitrot <VOLNAME> {enable|disable} |\n"
2783          "volume bitrot <volname> scrub-throttle {lazy|normal|aggressive} |\n"
2784          "volume bitrot <volname> scrub-frequency {hourly|daily|weekly|biweekly"
2785          "|monthly} |\n"
2786          "volume bitrot <volname> scrub {pause|resume}",
2787          cli_cmd_bitrot_cbk,
2788          "Bitrot translator specific operation. For more information about "
2789          "bitrot command type  'man gluster'"
2790         },
2791         { NULL, NULL, NULL }
2792 };
2793
2794 int
2795 cli_cmd_volume_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
2796                       const char **words, int wordcount)
2797 {
2798         struct cli_cmd        *cmd = NULL;
2799
2800         for (cmd = volume_cmds; cmd->pattern; cmd++)
2801                 if (_gf_false == cmd->disable)
2802                         cli_out ("%s - %s", cmd->pattern, cmd->desc);
2803
2804         return 0;
2805 }
2806
2807 int
2808 cli_cmd_volume_register (struct cli_state *state)
2809 {
2810         int  ret = 0;
2811         struct cli_cmd *cmd = NULL;
2812
2813         for (cmd = volume_cmds; cmd->pattern; cmd++) {
2814
2815                 ret = cli_cmd_register (&state->tree, cmd);
2816                 if (ret)
2817                         goto out;
2818         }
2819 out:
2820         return ret;
2821 }