glusterfs

Форк
0
/
glusterd-geo-rep.c 
6643 строки · 205.4 Кб
1
/*
2
   Copyright (c) 2011-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 "glusterd-op-sm.h"
11
#include "glusterd-geo-rep.h"
12
#include "glusterd-store.h"
13
#include "glusterd-utils.h"
14
#include "glusterd-volgen.h"
15
#include "glusterd-svc-helper.h"
16
#include <glusterfs/run.h>
17
#include <glusterfs/syscall.h>
18
#include "glusterd-messages.h"
19

20
#include <signal.h>
21

22
static int
23
dict_get_param(dict_t *dict, char *key, char **param);
24

25
struct gsync_config_opt_vals_ gsync_confopt_vals[] = {
26
    {
27
        .op_name = "change_detector",
28
        .no_of_pos_vals = 2,
29
        .case_sensitive = _gf_true,
30
        .values = {"xsync", "changelog"},
31
    },
32
    {.op_name = "special_sync_mode",
33
     .no_of_pos_vals = 2,
34
     .case_sensitive = _gf_true,
35
     .values = {"partial", "recover"}},
36
    {.op_name = "log-level",
37
     .no_of_pos_vals = 5,
38
     .case_sensitive = _gf_false,
39
     .values = {"critical", "error", "warning", "info", "debug"}},
40
    {.op_name = "use-tarssh",
41
     .no_of_pos_vals = 6,
42
     .case_sensitive = _gf_false,
43
     .values = {"true", "false", "0", "1", "yes", "no"}},
44
    {.op_name = "ignore_deletes",
45
     .no_of_pos_vals = 6,
46
     .case_sensitive = _gf_false,
47
     .values = {"true", "false", "0", "1", "yes", "no"}},
48
    {.op_name = "use_meta_volume",
49
     .no_of_pos_vals = 6,
50
     .case_sensitive = _gf_false,
51
     .values = {"true", "false", "0", "1", "yes", "no"}},
52
    {.op_name = "use-meta-volume",
53
     .no_of_pos_vals = 6,
54
     .case_sensitive = _gf_false,
55
     .values = {"true", "false", "0", "1", "yes", "no"}},
56
    {
57
        .op_name = NULL,
58
    },
59
};
60

61
static char *gsync_reserved_opts[] = {
62
    "gluster-command",        "pid-file",  "state-file", "session-owner",
63
    "state-socket-unencoded", "socketdir", "local-id",   "local-path",
64
    "secondary-id",           NULL};
65

66
static char *gsync_no_restart_opts[] = {"checkpoint", "log_rsync_performance",
67
                                        "log-rsync-performance", NULL};
68

69
void
70
set_gsyncd_inet6_arg(runner_t *runner)
71
{
72
    char *af;
73
    int ret;
74

75
    ret = dict_get_str(THIS->options, "transport.address-family", &af);
76
    if (ret == 0)
77
        runner_argprintf(runner, "--%s", af);
78
}
79

80
int
81
__glusterd_handle_sys_exec(rpcsvc_request_t *req)
82
{
83
    int32_t ret = 0;
84
    dict_t *dict = NULL;
85
    gf_cli_req cli_req = {
86
        {0},
87
    };
88
    glusterd_op_t cli_op = GD_OP_SYS_EXEC;
89
    glusterd_conf_t *priv = NULL;
90
    char *host_uuid = NULL;
91
    char err_str[64] = {
92
        0,
93
    };
94
    xlator_t *this = THIS;
95

96
    GF_ASSERT(req);
97

98
    priv = this->private;
99
    GF_ASSERT(priv);
100

101
    ret = xdr_to_generic(req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);
102
    if (ret < 0) {
103
        req->rpc_err = GARBAGE_ARGS;
104
        snprintf(err_str, sizeof(err_str), "Garbage args received");
105
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_GARBAGE_ARGS, NULL);
106
        goto out;
107
    }
108

109
    if (cli_req.dict.dict_len) {
110
        dict = dict_new();
111
        if (!dict) {
112
            gf_smsg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL,
113
                    NULL);
114
            goto out;
115
        }
116

117
        ret = dict_unserialize(cli_req.dict.dict_val, cli_req.dict.dict_len,
118
                               &dict);
119
        if (ret < 0) {
120
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_UNSERIALIZE_FAIL,
121
                   "failed to "
122
                   "unserialize req-buffer to dictionary");
123
            snprintf(err_str, sizeof(err_str),
124
                     "Unable to decode "
125
                     "the command");
126
            goto out;
127
        } else {
128
            dict->extra_stdfree = cli_req.dict.dict_val;
129
        }
130

131
        host_uuid = gf_strdup(uuid_utoa(MY_UUID));
132
        if (host_uuid == NULL) {
133
            snprintf(err_str, sizeof(err_str),
134
                     "Failed to get "
135
                     "the uuid of local glusterd");
136
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_UUID_GET_FAIL,
137
                    NULL);
138
            ret = -1;
139
            goto out;
140
        }
141

142
        ret = dict_set_dynstr(dict, "host-uuid", host_uuid);
143
        if (ret) {
144
            gf_smsg(this->name, GF_LOG_ERROR, -ret, GD_MSG_DICT_SET_FAILED,
145
                    "Key=host-uuid", NULL);
146
            goto out;
147
        }
148
    }
149

150
    ret = glusterd_op_begin_synctask(req, cli_op, dict);
151

152
out:
153
    if (ret) {
154
        if (err_str[0] == '\0')
155
            snprintf(err_str, sizeof(err_str), "Operation failed");
156
        ret = glusterd_op_send_cli_response(cli_op, ret, 0, req, dict, err_str);
157
    }
158
    return ret;
159
}
160

161
int
162
__glusterd_handle_copy_file(rpcsvc_request_t *req)
163
{
164
    int32_t ret = 0;
165
    dict_t *dict = NULL;
166
    gf_cli_req cli_req = {
167
        {0},
168
    };
169
    glusterd_op_t cli_op = GD_OP_COPY_FILE;
170
    glusterd_conf_t *priv = NULL;
171
    char *host_uuid = NULL;
172
    char err_str[64] = {
173
        0,
174
    };
175
    xlator_t *this = THIS;
176

177
    GF_ASSERT(req);
178

179
    priv = this->private;
180
    GF_ASSERT(priv);
181

182
    ret = xdr_to_generic(req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);
183
    if (ret < 0) {
184
        req->rpc_err = GARBAGE_ARGS;
185
        snprintf(err_str, sizeof(err_str), "Garbage args received");
186
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_GARBAGE_ARGS, NULL);
187
        goto out;
188
    }
189

190
    if (cli_req.dict.dict_len) {
191
        dict = dict_new();
192
        if (!dict) {
193
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL,
194
                    NULL);
195
            goto out;
196
        }
197

198
        ret = dict_unserialize(cli_req.dict.dict_val, cli_req.dict.dict_len,
199
                               &dict);
200
        if (ret < 0) {
201
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_UNSERIALIZE_FAIL,
202
                   "failed to"
203
                   "unserialize req-buffer to dictionary");
204
            snprintf(err_str, sizeof(err_str),
205
                     "Unable to decode "
206
                     "the command");
207
            goto out;
208
        } else {
209
            dict->extra_stdfree = cli_req.dict.dict_val;
210
        }
211

212
        host_uuid = gf_strdup(uuid_utoa(MY_UUID));
213
        if (host_uuid == NULL) {
214
            snprintf(err_str, sizeof(err_str),
215
                     "Failed to get "
216
                     "the uuid of local glusterd");
217
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_UUID_GET_FAIL,
218
                    NULL);
219
            ret = -1;
220
            goto out;
221
        }
222

223
        ret = dict_set_dynstr(dict, "host-uuid", host_uuid);
224
        if (ret)
225
            goto out;
226
    }
227

228
    ret = glusterd_op_begin_synctask(req, cli_op, dict);
229

230
out:
231
    if (ret) {
232
        if (err_str[0] == '\0')
233
            snprintf(err_str, sizeof(err_str), "Operation failed");
234
        ret = glusterd_op_send_cli_response(cli_op, ret, 0, req, dict, err_str);
235
    }
236
    return ret;
237
}
238

239
int
240
__glusterd_handle_gsync_set(rpcsvc_request_t *req)
241
{
242
    int32_t ret = 0;
243
    dict_t *dict = NULL;
244
    gf_cli_req cli_req = {
245
        {0},
246
    };
247
    glusterd_op_t cli_op = GD_OP_GSYNC_SET;
248
    char *primary = NULL;
249
    char *secondary = NULL;
250
    char operation[64] = {
251
        0,
252
    };
253
    int type = 0;
254
    glusterd_conf_t *priv = NULL;
255
    char *host_uuid = NULL;
256
    char err_str[64] = {
257
        0,
258
    };
259
    xlator_t *this = THIS;
260

261
    GF_ASSERT(req);
262

263
    priv = this->private;
264
    GF_ASSERT(priv);
265

266
    ret = xdr_to_generic(req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);
267
    if (ret < 0) {
268
        req->rpc_err = GARBAGE_ARGS;
269
        snprintf(err_str, sizeof(err_str), "Garbage args received");
270
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_GARBAGE_ARGS, NULL);
271
        goto out;
272
    }
273

274
    if (cli_req.dict.dict_len) {
275
        dict = dict_new();
276
        if (!dict) {
277
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_CREATE_FAIL,
278
                    NULL);
279
            goto out;
280
        }
281

282
        ret = dict_unserialize(cli_req.dict.dict_val, cli_req.dict.dict_len,
283
                               &dict);
284
        if (ret < 0) {
285
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_UNSERIALIZE_FAIL,
286
                   "failed to "
287
                   "unserialize req-buffer to dictionary");
288
            snprintf(err_str, sizeof(err_str),
289
                     "Unable to decode "
290
                     "the command");
291
            goto out;
292
        } else {
293
            dict->extra_stdfree = cli_req.dict.dict_val;
294
        }
295

296
        host_uuid = gf_strdup(uuid_utoa(MY_UUID));
297
        if (host_uuid == NULL) {
298
            snprintf(err_str, sizeof(err_str),
299
                     "Failed to get "
300
                     "the uuid of local glusterd");
301
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_UUID_GET_FAIL,
302
                    NULL);
303
            ret = -1;
304
            goto out;
305
        }
306
        ret = dict_set_dynstr(dict, "host-uuid", host_uuid);
307
        if (ret)
308
            goto out;
309
    }
310

311
    ret = dict_get_str(dict, "primary", &primary);
312
    if (ret < 0) {
313
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DICT_GET_FAILED,
314
               "primary not found, while handling " GEOREP " options");
315
        primary = "(No Primary)";
316
    }
317

318
    ret = dict_get_str(dict, "secondary", &secondary);
319
    if (ret < 0) {
320
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DICT_GET_FAILED,
321
               "secondary not found, while handling " GEOREP " options");
322
        secondary = "(No Secondary)";
323
    }
324

325
    ret = dict_get_int32(dict, "type", &type);
326
    if (ret < 0) {
327
        snprintf(err_str, sizeof(err_str),
328
                 "Command type not found "
329
                 "while handling " GEOREP " options");
330
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
331
               err_str);
332
        goto out;
333
    }
334

335
    switch (type) {
336
        case GF_GSYNC_OPTION_TYPE_CREATE:
337
            snprintf(operation, sizeof(operation), "create");
338
            cli_op = GD_OP_GSYNC_CREATE;
339
            break;
340

341
        case GF_GSYNC_OPTION_TYPE_START:
342
            snprintf(operation, sizeof(operation), "start");
343
            break;
344

345
        case GF_GSYNC_OPTION_TYPE_STOP:
346
            snprintf(operation, sizeof(operation), "stop");
347
            break;
348

349
        case GF_GSYNC_OPTION_TYPE_PAUSE:
350
            snprintf(operation, sizeof(operation), "pause");
351
            break;
352

353
        case GF_GSYNC_OPTION_TYPE_RESUME:
354
            snprintf(operation, sizeof(operation), "resume");
355
            break;
356

357
        case GF_GSYNC_OPTION_TYPE_CONFIG:
358
            snprintf(operation, sizeof(operation), "config");
359
            break;
360

361
        case GF_GSYNC_OPTION_TYPE_STATUS:
362
            snprintf(operation, sizeof(operation), "status");
363
            break;
364
    }
365

366
    ret = glusterd_op_begin_synctask(req, cli_op, dict);
367

368
out:
369
    if (ret) {
370
        if (err_str[0] == '\0')
371
            snprintf(err_str, sizeof(err_str), "Operation failed");
372
        ret = glusterd_op_send_cli_response(cli_op, ret, 0, req, dict, err_str);
373
    }
374
    return ret;
375
}
376

377
int
378
glusterd_handle_sys_exec(rpcsvc_request_t *req)
379
{
380
    return glusterd_big_locked_handler(req, __glusterd_handle_sys_exec);
381
}
382

383
int
384
glusterd_handle_copy_file(rpcsvc_request_t *req)
385
{
386
    return glusterd_big_locked_handler(req, __glusterd_handle_copy_file);
387
}
388

389
int
390
glusterd_handle_gsync_set(rpcsvc_request_t *req)
391
{
392
    return glusterd_big_locked_handler(req, __glusterd_handle_gsync_set);
393
}
394

395
/*****
396
 *
397
 * glusterd_urltransform* internal API
398
 *
399
 *****/
400

401
static void
402
glusterd_urltransform_init(runner_t *runner, const char *transname)
403
{
404
    runinit(runner);
405
    runner_add_arg(runner, GSYNCD_PREFIX "/gsyncd");
406
    set_gsyncd_inet6_arg(runner);
407
    runner_argprintf(runner, "--%s-url", transname);
408
}
409

410
static void
411
glusterd_urltransform_add(runner_t *runner, const char *url)
412
{
413
    runner_add_arg(runner, url);
414
}
415

416
/* Helper routine to terminate just before secondary_voluuid */
417
static int32_t
418
parse_secondary_url(char *sec_url, char **secondary)
419
{
420
    char *tmp = NULL;
421
    xlator_t *this = THIS;
422
    int32_t ret = -1;
423

424
    this = THIS;
425

426
    /* secondary format:
427
     * primary_node_uuid:ssh://secondary_host::secondary_vol:secondary_voluuid
428
     */
429
    *secondary = strchr(sec_url, ':');
430
    if (!(*secondary)) {
431
        goto out;
432
    }
433
    (*secondary)++;
434

435
    /* To terminate at : before secondary volume uuid */
436
    tmp = strstr(*secondary, "::");
437
    if (!tmp) {
438
        goto out;
439
    }
440
    tmp += 2;
441
    tmp = strchr(tmp, ':');
442
    if (!tmp)
443
        gf_msg_debug(this->name, 0, "old secondary: %s!", *secondary);
444
    else
445
        *tmp = '\0';
446

447
    ret = 0;
448
    gf_msg_debug(this->name, 0, "parsed secondary: %s!", *secondary);
449
out:
450
    return ret;
451
}
452

453
static int
454
_glusterd_urltransform_add_iter(dict_t *dict, char *key, data_t *value,
455
                                void *data)
456
{
457
    runner_t *runner = (runner_t *)data;
458
    char sec_url[VOLINFO_SECONDARY_URL_MAX] = {0};
459
    char *secondary = NULL;
460
    xlator_t *this = THIS;
461
    int32_t ret = -1;
462

463
    gf_msg_debug(this->name, 0, "value->data %s", value->data);
464

465
    if (snprintf(sec_url, sizeof(sec_url), "%s", value->data) >=
466
        sizeof(sec_url)) {
467
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
468
               "Error in copying secondary: %s!", value->data);
469
        goto out;
470
    }
471

472
    ret = parse_secondary_url(sec_url, &secondary);
473
    if (ret == -1) {
474
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
475
               "Error in parsing secondary: %s!", value->data);
476
        goto out;
477
    }
478

479
    runner_add_arg(runner, secondary);
480
    ret = 0;
481
out:
482
    return ret;
483
}
484

485
static void
486
glusterd_urltransform_free(char **linearr, unsigned n)
487
{
488
    int i = 0;
489

490
    for (; i < n; i++)
491
        GF_FREE(linearr[i]);
492

493
    GF_FREE(linearr);
494
}
495

496
static int
497
glusterd_urltransform(runner_t *runner, char ***linearrp)
498
{
499
    char **linearr = NULL;
500
    char *line = NULL;
501
    unsigned arr_len = 32;
502
    unsigned arr_idx = 0;
503
    gf_boolean_t error = _gf_false;
504
    xlator_t *this = THIS;
505

506
    linearr = GF_CALLOC(arr_len, sizeof(char *), gf_gld_mt_linearr);
507
    if (!linearr) {
508
        error = _gf_true;
509
        goto out;
510
    }
511

512
    runner_redir(runner, STDOUT_FILENO, RUN_PIPE);
513
    if (runner_start(runner) != 0) {
514
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SPAWNING_CHILD_FAILED,
515
               "spawning child failed");
516

517
        error = _gf_true;
518
        goto out;
519
    }
520

521
    arr_idx = 0;
522
    for (;;) {
523
        size_t len;
524
        line = GF_MALLOC(1024, gf_gld_mt_linebuf);
525
        if (!line) {
526
            error = _gf_true;
527
            goto out;
528
        }
529

530
        if (fgets(line, 1024, runner_chio(runner, STDOUT_FILENO)) == NULL) {
531
            GF_FREE(line);
532
            break;
533
        }
534

535
        len = strlen(line);
536
        if (len == 0 || line[len - 1] != '\n') {
537
            GF_FREE(line);
538
            error = _gf_true;
539
            goto out;
540
        }
541
        line[len - 1] = '\0';
542

543
        if (arr_idx == arr_len) {
544
            void *p = linearr;
545
            arr_len <<= 1;
546
            p = GF_REALLOC(linearr, arr_len);
547
            if (!p) {
548
                GF_FREE(line);
549
                error = _gf_true;
550
                goto out;
551
            }
552
            linearr = p;
553
        }
554
        linearr[arr_idx] = line;
555

556
        arr_idx++;
557
    }
558

559
out:
560

561
    /* XXX chpid field is not exported by run API
562
     * but runner_end() does not abort the invoked
563
     * process (ie. it might block in waitpid(2))
564
     * so we resort to a manual kill a the private field
565
     */
566
    if (error && runner->chpid > 0)
567
        kill(runner->chpid, SIGKILL);
568

569
    if (runner_end(runner) != 0)
570
        error = _gf_true;
571

572
    if (error) {
573
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_READ_CHILD_DATA_FAILED,
574
               "reading data from child failed");
575
        glusterd_urltransform_free(linearr, arr_idx);
576
        return -1;
577
    }
578

579
    *linearrp = linearr;
580
    return arr_idx;
581
}
582

583
static int
584
glusterd_urltransform_single(const char *url, const char *transname,
585
                             char ***linearrp)
586
{
587
    runner_t runner = {
588
        0,
589
    };
590

591
    glusterd_urltransform_init(&runner, transname);
592
    glusterd_urltransform_add(&runner, url);
593
    return glusterd_urltransform(&runner, linearrp);
594
}
595

596
struct dictidxmark {
597
    unsigned isrch;
598
    unsigned ithis;
599
    char *ikey;
600
};
601

602
struct secondary_vol_config {
603
    char old_sechost[_POSIX_HOST_NAME_MAX + 1];
604
    char old_secuser[LOGIN_NAME_MAX];
605
    unsigned old_slvidx;
606
    char secondary_voluuid[UUID_CANONICAL_FORM_LEN + 1];
607
};
608

609
static int
610
_dict_mark_atindex(dict_t *dict, char *key, data_t *value, void *data)
611
{
612
    struct dictidxmark *dim = data;
613

614
    if (dim->isrch == dim->ithis)
615
        dim->ikey = key;
616

617
    dim->ithis++;
618
    return 0;
619
}
620

621
static char *
622
dict_get_by_index(dict_t *dict, unsigned i)
623
{
624
    struct dictidxmark dim = {
625
        0,
626
    };
627

628
    dim.isrch = i;
629
    dict_foreach(dict, _dict_mark_atindex, &dim);
630

631
    return dim.ikey;
632
}
633

634
static int
635
glusterd_get_secondary(glusterd_volinfo_t *vol, const char *secondaryurl,
636
                       char **secondarykey)
637
{
638
    runner_t runner = {
639
        0,
640
    };
641
    int n = 0;
642
    int i = 0;
643
    char **linearr = NULL;
644
    int32_t ret = 0;
645

646
    glusterd_urltransform_init(&runner, "canonicalize");
647
    ret = dict_foreach(vol->gsync_secondaries, _glusterd_urltransform_add_iter,
648
                       &runner);
649
    if (ret < 0)
650
        return -2;
651

652
    glusterd_urltransform_add(&runner, secondaryurl);
653

654
    n = glusterd_urltransform(&runner, &linearr);
655
    if (n == -1)
656
        return -2;
657

658
    for (i = 0; i < n - 1; i++) {
659
        if (strcmp(linearr[i], linearr[n - 1]) == 0)
660
            break;
661
    }
662
    glusterd_urltransform_free(linearr, n);
663

664
    if (i < n - 1)
665
        *secondarykey = dict_get_by_index(vol->gsync_secondaries, i);
666
    else
667
        i = -1;
668

669
    return i;
670
}
671

672
static int
673
glusterd_query_extutil_generic(char *resbuf, size_t blen, runner_t *runner,
674
                               void *data,
675
                               int (*fcbk)(char *resbuf, size_t blen, FILE *fp,
676
                                           void *data))
677
{
678
    int ret = 0;
679
    xlator_t *this = THIS;
680

681
    runner_redir(runner, STDOUT_FILENO, RUN_PIPE);
682
    if (runner_start(runner) != 0) {
683
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SPAWNING_CHILD_FAILED,
684
               "spawning child failed");
685

686
        return -1;
687
    }
688

689
    ret = fcbk(resbuf, blen, runner_chio(runner, STDOUT_FILENO), data);
690

691
    ret |= runner_end(runner);
692
    if (ret)
693
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_READ_CHILD_DATA_FAILED,
694
               "reading data from child failed");
695

696
    return ret ? -1 : 0;
697
}
698

699
static int
700
_fcbk_singleline(char *resbuf, size_t blen, FILE *fp, void *data)
701
{
702
    char *ptr = NULL;
703

704
    errno = 0;
705
    ptr = fgets(resbuf, blen, fp);
706
    if (ptr) {
707
        size_t len = strlen(resbuf);
708
        if (len && resbuf[len - 1] == '\n')
709
            resbuf[len - 1] = '\0';  // strip off \n
710
    }
711

712
    return errno ? -1 : 0;
713
}
714

715
static int
716
glusterd_query_extutil(char *resbuf, runner_t *runner)
717
{
718
    return glusterd_query_extutil_generic(resbuf, PATH_MAX, runner, NULL,
719
                                          _fcbk_singleline);
720
}
721

722
static int
723
glusterd_get_secondary_voluuid(char *secondary_host, char *secondary_vol,
724
                               char *vol_uuid)
725
{
726
    runner_t runner = {
727
        0,
728
    };
729
    glusterd_conf_t *priv = NULL;
730
    xlator_t *this = THIS;
731
    int ret = -1;
732

733
    priv = this->private;
734
    GF_VALIDATE_OR_GOTO(this->name, priv, out);
735

736
    runinit(&runner);
737
    runner_add_arg(&runner, GSYNCD_PREFIX "/gsyncd");
738
    set_gsyncd_inet6_arg(&runner);
739
    runner_add_arg(&runner, "--secondaryvoluuid-get");
740
    runner_argprintf(&runner, "%s::%s", secondary_host, secondary_vol);
741

742
    synclock_unlock(&priv->big_lock);
743
    ret = glusterd_query_extutil(vol_uuid, &runner);
744
    synclock_lock(&priv->big_lock);
745

746
out:
747
    return ret;
748
}
749

750
static int
751
_fcbk_conftodict(char *resbuf, size_t blen, FILE *fp, void *data)
752
{
753
    char *ptr = NULL;
754
    dict_t *dict = data;
755
    char *v = NULL;
756

757
    for (;;) {
758
        errno = 0;
759
        ptr = fgets(resbuf, blen - 2, fp);
760
        if (!ptr)
761
            break;
762
        v = resbuf + strlen(resbuf) - 1;
763
        while (isspace(*v))
764
            /* strip trailing space */
765
            *v-- = '\0';
766
        if (v == resbuf)
767
            /* skip empty line */
768
            continue;
769
        v = strchr(resbuf, ':');
770
        if (!v)
771
            return -1;
772
        *v++ = '\0';
773
        while (isspace(*v))
774
            v++;
775
        v = gf_strdup(v);
776
        if (!v)
777
            return -1;
778
        if (dict_set_dynstr(dict, resbuf, v) != 0) {
779
            GF_FREE(v);
780
            return -1;
781
        }
782
    }
783

784
    return errno ? -1 : 0;
785
}
786

787
static int
788
glusterd_gsync_get_config(char *primary, char *secondary, char *conf_path,
789
                          dict_t *dict)
790
{
791
    /* key + value, where value must be able to accommodate a path */
792
    char resbuf[256 + PATH_MAX] = {
793
        0,
794
    };
795
    runner_t runner = {
796
        0,
797
    };
798

799
    runinit(&runner);
800
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
801
    runner_argprintf(&runner, "%s", conf_path);
802
    set_gsyncd_inet6_arg(&runner);
803
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);
804
    runner_argprintf(&runner, ":%s", primary);
805
    runner_add_args(&runner, secondary, "--config-get-all", NULL);
806

807
    return glusterd_query_extutil_generic(resbuf, sizeof(resbuf), &runner, dict,
808
                                          _fcbk_conftodict);
809
}
810

811
static int
812
_fcbk_statustostruct(char *resbuf, size_t blen, FILE *fp, void *data)
813
{
814
    char *ptr = NULL;
815
    char *v = NULL;
816
    char *k = NULL;
817
    gf_gsync_status_t *sts_val = NULL;
818
    size_t len = 0;
819

820
    sts_val = (gf_gsync_status_t *)data;
821

822
    for (;;) {
823
        errno = 0;
824
        ptr = fgets(resbuf, blen - 2, fp);
825
        if (!ptr)
826
            break;
827

828
        v = resbuf + strlen(resbuf) - 1;
829
        while (isspace(*v))
830
            /* strip trailing space */
831
            *v-- = '\0';
832
        if (v == resbuf)
833
            /* skip empty line */
834
            continue;
835
        v = strchr(resbuf, ':');
836
        if (!v)
837
            return -1;
838
        *v++ = '\0';
839
        while (isspace(*v))
840
            v++;
841
        v = gf_strdup(v);
842
        if (!v)
843
            return -1;
844

845
        k = gf_strdup(resbuf);
846
        if (!k) {
847
            GF_FREE(v);
848
            return -1;
849
        }
850

851
        if (strcmp(k, "worker_status") == 0) {
852
            len = min(strlen(v), (sizeof(sts_val->worker_status) - 1));
853
            memcpy(sts_val->worker_status, v, len);
854
            sts_val->worker_status[len] = '\0';
855
        } else if (strcmp(k, "secondary_node") == 0) {
856
            len = min(strlen(v), (sizeof(sts_val->secondary_node) - 1));
857
            memcpy(sts_val->secondary_node, v, len);
858
            sts_val->secondary_node[len] = '\0';
859
        } else if (strcmp(k, "crawl_status") == 0) {
860
            len = min(strlen(v), (sizeof(sts_val->crawl_status) - 1));
861
            memcpy(sts_val->crawl_status, v, len);
862
            sts_val->crawl_status[len] = '\0';
863
        } else if (strcmp(k, "last_synced") == 0) {
864
            len = min(strlen(v), (sizeof(sts_val->last_synced) - 1));
865
            memcpy(sts_val->last_synced, v, len);
866
            sts_val->last_synced[len] = '\0';
867
        } else if (strcmp(k, "last_synced_utc") == 0) {
868
            len = min(strlen(v), (sizeof(sts_val->last_synced_utc) - 1));
869
            memcpy(sts_val->last_synced_utc, v, len);
870
            sts_val->last_synced_utc[len] = '\0';
871
        } else if (strcmp(k, "entry") == 0) {
872
            len = min(strlen(v), (sizeof(sts_val->entry) - 1));
873
            memcpy(sts_val->entry, v, len);
874
            sts_val->entry[len] = '\0';
875
        } else if (strcmp(k, "data") == 0) {
876
            len = min(strlen(v), (sizeof(sts_val->data) - 1));
877
            memcpy(sts_val->data, v, len);
878
            sts_val->data[len] = '\0';
879
        } else if (strcmp(k, "meta") == 0) {
880
            len = min(strlen(v), (sizeof(sts_val->meta) - 1));
881
            memcpy(sts_val->meta, v, len);
882
            sts_val->meta[len] = '\0';
883
        } else if (strcmp(k, "failures") == 0) {
884
            len = min(strlen(v), (sizeof(sts_val->failures) - 1));
885
            memcpy(sts_val->failures, v, len);
886
            sts_val->failures[len] = '\0';
887
        } else if (strcmp(k, "checkpoint_time") == 0) {
888
            len = min(strlen(v), (sizeof(sts_val->checkpoint_time) - 1));
889
            memcpy(sts_val->checkpoint_time, v, len);
890
            sts_val->checkpoint_time[len] = '\0';
891
        } else if (strcmp(k, "checkpoint_time_utc") == 0) {
892
            len = min(strlen(v), (sizeof(sts_val->checkpoint_time_utc) - 1));
893
            memcpy(sts_val->checkpoint_time_utc, v, len);
894
            sts_val->checkpoint_time_utc[len] = '\0';
895
        } else if (strcmp(k, "checkpoint_completed") == 0) {
896
            len = min(strlen(v), (sizeof(sts_val->checkpoint_completed) - 1));
897
            memcpy(sts_val->checkpoint_completed, v, len);
898
            sts_val->checkpoint_completed[len] = '\0';
899
        } else if (strcmp(k, "checkpoint_completion_time") == 0) {
900
            len = min(strlen(v),
901
                      (sizeof(sts_val->checkpoint_completion_time) - 1));
902
            memcpy(sts_val->checkpoint_completion_time, v, len);
903
            sts_val->checkpoint_completion_time[len] = '\0';
904
        } else if (strcmp(k, "checkpoint_completion_time_utc") == 0) {
905
            len = min(strlen(v),
906
                      (sizeof(sts_val->checkpoint_completion_time_utc) - 1));
907
            memcpy(sts_val->checkpoint_completion_time_utc, v, len);
908
            sts_val->checkpoint_completion_time_utc[len] = '\0';
909
        }
910
        GF_FREE(v);
911
        GF_FREE(k);
912
    }
913

914
    return errno ? -1 : 0;
915
}
916

917
static int
918
glusterd_gsync_get_status(char *primary, char *secondary, char *conf_path,
919
                          char *brick_path, gf_gsync_status_t *sts_val)
920
{
921
    /* key + value, where value must be able to accommodate a path */
922
    char resbuf[256 + PATH_MAX] = {
923
        0,
924
    };
925
    runner_t runner = {
926
        0,
927
    };
928

929
    runinit(&runner);
930
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
931
    runner_argprintf(&runner, "%s", conf_path);
932
    set_gsyncd_inet6_arg(&runner);
933
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);
934
    runner_argprintf(&runner, ":%s", primary);
935
    runner_add_args(&runner, secondary, "--status-get", NULL);
936
    runner_add_args(&runner, "--path", brick_path, NULL);
937

938
    return glusterd_query_extutil_generic(resbuf, sizeof(resbuf), &runner,
939
                                          sts_val, _fcbk_statustostruct);
940
}
941

942
static int
943
glusterd_gsync_get_param_file(char *prmfile, const char *param, char *primary,
944
                              char *secondary, char *conf_path)
945
{
946
    runner_t runner = {
947
        0,
948
    };
949

950
    runinit(&runner);
951
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
952
    runner_argprintf(&runner, "%s", conf_path);
953
    set_gsyncd_inet6_arg(&runner);
954
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);
955
    runner_argprintf(&runner, ":%s", primary);
956
    runner_add_args(&runner, secondary, "--config-get", NULL);
957
    runner_argprintf(&runner, "%s-file", param);
958

959
    return glusterd_query_extutil(prmfile, &runner);
960
}
961

962
static int
963
gsyncd_getpidfile(char *primary, char *secondary, char *pidfile,
964
                  char *conf_path, gf_boolean_t *is_template_in_use)
965
{
966
    char temp_conf_path[PATH_MAX] = "";
967
    char *working_conf_path = NULL;
968
    glusterd_conf_t *priv = NULL;
969
    int ret = -1;
970
    struct stat stbuf = {
971
        0,
972
    };
973
    xlator_t *this = THIS;
974
    int32_t len = 0;
975

976
    GF_ASSERT(this->private);
977
    GF_ASSERT(conf_path);
978

979
    priv = this->private;
980

981
    GF_VALIDATE_OR_GOTO("gsync", primary, out);
982
    GF_VALIDATE_OR_GOTO("gsync", secondary, out);
983

984
    len = snprintf(temp_conf_path, sizeof(temp_conf_path),
985
                   "%s/" GSYNC_CONF_TEMPLATE, priv->workdir);
986
    if ((len < 0) || (len >= sizeof(temp_conf_path))) {
987
        goto out;
988
    }
989

990
    ret = sys_lstat(conf_path, &stbuf);
991
    if (!ret) {
992
        gf_msg_debug(this->name, 0, "Using passed config template(%s).",
993
                     conf_path);
994
        working_conf_path = conf_path;
995
    } else {
996
        gf_msg(this->name, GF_LOG_WARNING, ENOENT, GD_MSG_FILE_OP_FAILED,
997
               "Config file (%s) missing. Looking for template "
998
               "config file (%s)",
999
               conf_path, temp_conf_path);
1000
        ret = sys_lstat(temp_conf_path, &stbuf);
1001
        if (ret) {
1002
            gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
1003
                   "Template config file (%s) missing.", temp_conf_path);
1004
            goto out;
1005
        }
1006
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DEFAULT_TEMP_CONFIG,
1007
               "Using default config template(%s).", temp_conf_path);
1008
        working_conf_path = temp_conf_path;
1009
        *is_template_in_use = _gf_true;
1010
    }
1011

1012
fetch_data:
1013

1014
    ret = glusterd_gsync_get_param_file(pidfile, "pid", primary, secondary,
1015
                                        working_conf_path);
1016
    if ((ret == -1) || strlen(pidfile) == 0) {
1017
        if (*is_template_in_use == _gf_false) {
1018
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_PIDFILE_CREATE_FAILED,
1019
                   "failed to create the pidfile string. "
1020
                   "Trying default config template");
1021
            working_conf_path = temp_conf_path;
1022
            *is_template_in_use = _gf_true;
1023
            goto fetch_data;
1024
        } else {
1025
            ret = -2;
1026
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_PIDFILE_CREATE_FAILED,
1027
                   "failed to "
1028
                   "create the pidfile string from template "
1029
                   "config");
1030
            goto out;
1031
        }
1032
    }
1033

1034
    gf_msg_debug(this->name, 0, "pidfile = %s", pidfile);
1035

1036
    ret = open(pidfile, O_RDWR);
1037
out:
1038
    return ret;
1039
}
1040

1041
static int
1042
gsync_status_byfd(int fd)
1043
{
1044
    GF_ASSERT(fd >= -1);
1045

1046
    if (lockf(fd, F_TEST, 0) == -1 && (errno == EAGAIN || errno == EACCES))
1047
        /* gsyncd keeps the pidfile locked */
1048
        return 0;
1049

1050
    return -1;
1051
}
1052

1053
/* status: return 0 when gsync is running
1054
 * return -1 when not running
1055
 */
1056
int
1057
gsync_status(char *primary, char *secondary, char *conf_path, int *status,
1058
             gf_boolean_t *is_template_in_use)
1059
{
1060
    char pidfile[PATH_MAX] = {
1061
        0,
1062
    };
1063
    int fd = -1;
1064

1065
    fd = gsyncd_getpidfile(primary, secondary, pidfile, conf_path,
1066
                           is_template_in_use);
1067
    if (fd == -2)
1068
        return -1;
1069

1070
    *status = gsync_status_byfd(fd);
1071

1072
    sys_close(fd);
1073

1074
    return 0;
1075
}
1076

1077
static int32_t
1078
glusterd_gsync_volinfo_dict_set(glusterd_volinfo_t *volinfo, char *key,
1079
                                char *value)
1080
{
1081
    int32_t ret = -1;
1082
    char *gsync_status = NULL;
1083
    xlator_t *this = THIS;
1084

1085
    gsync_status = gf_strdup(value);
1086
    if (!gsync_status) {
1087
        gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
1088
               "Unable to allocate memory");
1089
        goto out;
1090
    }
1091

1092
    ret = dict_set_dynstr(volinfo->dict, key, gsync_status);
1093
    if (ret) {
1094
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
1095
               "Unable to set dict");
1096
        goto out;
1097
    }
1098

1099
    ret = 0;
1100
out:
1101
    return ret;
1102
}
1103

1104
static int
1105
glusterd_verify_gsyncd_spawn(char *primary, char *secondary)
1106
{
1107
    int ret = 0;
1108
    runner_t runner = {
1109
        0,
1110
    };
1111
    xlator_t *this = THIS;
1112

1113
    runinit(&runner);
1114
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "--verify", "spawning",
1115
                    NULL);
1116
    runner_argprintf(&runner, ":%s", primary);
1117
    runner_add_args(&runner, secondary, NULL);
1118
    runner_redir(&runner, STDOUT_FILENO, RUN_PIPE);
1119
    ret = runner_start(&runner);
1120
    if (ret) {
1121
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SPAWNING_CHILD_FAILED,
1122
               "spawning child failed");
1123
        ret = -1;
1124
        goto out;
1125
    }
1126

1127
    if (runner_end(&runner) != 0)
1128
        ret = -1;
1129

1130
out:
1131
    gf_msg_debug(this->name, 0, "returning %d", ret);
1132
    return ret;
1133
}
1134

1135
static int
1136
gsync_verify_config_options(dict_t *dict, char **op_errstr, char *volname)
1137
{
1138
    char **resopt = NULL;
1139
    int i = 0;
1140
    int ret = -1;
1141
    char *subop = NULL;
1142
    char *secondary = NULL;
1143
    char *op_name = NULL;
1144
    char *op_value = NULL;
1145
    char *t = NULL;
1146
    char errmsg[PATH_MAX] = "";
1147
    gf_boolean_t banned = _gf_true;
1148
    gf_boolean_t op_match = _gf_true;
1149
    gf_boolean_t val_match = _gf_true;
1150
    struct gsync_config_opt_vals_ *conf_vals = NULL;
1151
    xlator_t *this = THIS;
1152

1153
    if (dict_get_str(dict, "subop", &subop) != 0) {
1154
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1155
               "missing subop");
1156
        *op_errstr = gf_strdup("Invalid config request");
1157
        return -1;
1158
    }
1159

1160
    if (dict_get_str(dict, "secondary", &secondary) != 0) {
1161
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1162
               GEOREP " CONFIG: no secondary given");
1163
        *op_errstr = gf_strdup("Secondary required");
1164
        return -1;
1165
    }
1166

1167
    if (strcmp(subop, "get-all") == 0)
1168
        return 0;
1169

1170
    if (dict_get_str(dict, "op_name", &op_name) != 0) {
1171
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1172
               "option name missing");
1173
        *op_errstr = gf_strdup("Option name missing");
1174
        return -1;
1175
    }
1176

1177
    if (runcmd(GSYNCD_PREFIX "/gsyncd", "--config-check", op_name, NULL)) {
1178
        ret = glusterd_verify_gsyncd_spawn(volname, secondary);
1179
        if (ret) {
1180
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_SPAWN_FAILED,
1181
                   "Unable to spawn "
1182
                   "gsyncd");
1183
            return 0;
1184
        }
1185

1186
        gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_INVALID_ENTRY,
1187
               "Invalid option %s", op_name);
1188
        *op_errstr = gf_strdup("Invalid option");
1189

1190
        return -1;
1191
    }
1192

1193
    if (strcmp(subop, "get") == 0)
1194
        return 0;
1195

1196
    t = strtail(subop, "set");
1197
    if (!t)
1198
        t = strtail(subop, "del");
1199
    if (!t || (t[0] && strcmp(t, "-glob") != 0)) {
1200
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_SUBOP_NOT_FOUND,
1201
               "unknown subop %s", subop);
1202
        *op_errstr = gf_strdup("Invalid config request");
1203
        return -1;
1204
    }
1205

1206
    if (strtail(subop, "set") &&
1207
        dict_get_str(dict, "op_value", &op_value) != 0) {
1208
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
1209
               "missing value for set");
1210
        *op_errstr = gf_strdup("missing value");
1211
    }
1212

1213
    /* match option name against reserved options, modulo -/_
1214
     * difference
1215
     */
1216
    for (resopt = gsync_reserved_opts; *resopt; resopt++) {
1217
        banned = _gf_true;
1218
        for (i = 0; (*resopt)[i] && op_name[i]; i++) {
1219
            if ((*resopt)[i] == op_name[i] ||
1220
                ((*resopt)[i] == '-' && op_name[i] == '_'))
1221
                continue;
1222
            banned = _gf_false;
1223
        }
1224

1225
        if (op_name[i] != '\0')
1226
            banned = _gf_false;
1227

1228
        if (banned) {
1229
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_RESERVED_OPTION,
1230
                   "Reserved option %s", op_name);
1231
            *op_errstr = gf_strdup("Reserved option");
1232

1233
            return -1;
1234
            break;
1235
        }
1236
    }
1237

1238
    /* Check options in gsync_confopt_vals for invalid values */
1239
    for (conf_vals = gsync_confopt_vals; conf_vals->op_name; conf_vals++) {
1240
        op_match = _gf_true;
1241
        for (i = 0; conf_vals->op_name[i] && op_name[i]; i++) {
1242
            if (conf_vals->op_name[i] == op_name[i] ||
1243
                (conf_vals->op_name[i] == '_' && op_name[i] == '-'))
1244
                continue;
1245
            op_match = _gf_false;
1246
        }
1247

1248
        if (op_match) {
1249
            if (!op_value)
1250
                goto out;
1251
            val_match = _gf_false;
1252
            for (i = 0; i < conf_vals->no_of_pos_vals; i++) {
1253
                if (conf_vals->case_sensitive) {
1254
                    if (!strcmp(conf_vals->values[i], op_value))
1255
                        val_match = _gf_true;
1256
                } else {
1257
                    if (!strcasecmp(conf_vals->values[i], op_value))
1258
                        val_match = _gf_true;
1259
                }
1260
            }
1261

1262
            if (!val_match) {
1263
                ret = snprintf(errmsg, sizeof(errmsg) - 1,
1264
                               "Invalid value(%s) for"
1265
                               " option %s",
1266
                               op_value, op_name);
1267
                errmsg[ret] = '\0';
1268

1269
                gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
1270
                       "%s", errmsg);
1271
                *op_errstr = gf_strdup(errmsg);
1272
                return -1;
1273
            }
1274
        }
1275
    }
1276
out:
1277
    return 0;
1278
}
1279

1280
static int
1281
glusterd_get_gsync_status_mst_slv(glusterd_volinfo_t *volinfo, char *secondary,
1282
                                  char *conf_path, dict_t *rsp_dict,
1283
                                  char *node);
1284

1285
static int
1286
_get_status_mst_slv(dict_t *dict, char *key, data_t *value, void *data)
1287
{
1288
    glusterd_gsync_status_temp_t *param = NULL;
1289
    char *secondary = NULL;
1290
    char *secondary_buf = NULL;
1291
    char *secondary_url = NULL;
1292
    char *secondary_vol = NULL;
1293
    char *secondary_host = NULL;
1294
    char *errmsg = NULL;
1295
    char conf_path[PATH_MAX] = "";
1296
    int ret = -1;
1297
    glusterd_conf_t *priv = NULL;
1298
    xlator_t *this = THIS;
1299
    char sec_url[VOLINFO_SECONDARY_URL_MAX] = {0};
1300

1301
    param = (glusterd_gsync_status_temp_t *)data;
1302

1303
    GF_VALIDATE_OR_GOTO(this->name, param, out);
1304
    GF_VALIDATE_OR_GOTO(this->name, param->volinfo, out);
1305

1306
    priv = this->private;
1307
    GF_VALIDATE_OR_GOTO(this->name, priv, out);
1308

1309
    if (snprintf(sec_url, sizeof(sec_url), "%s", value->data) >=
1310
        sizeof(sec_url)) {
1311
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
1312
               "Error in copying secondary: %s!", value->data);
1313
        goto out;
1314
    }
1315

1316
    ret = parse_secondary_url(sec_url, &secondary);
1317
    if (ret == -1) {
1318
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
1319
               "Error in parsing secondary: %s!", value->data);
1320
        goto out;
1321
    }
1322

1323
    ret = glusterd_get_secondary_info(secondary, &secondary_url,
1324
                                      &secondary_host, &secondary_vol, &errmsg);
1325
    if (ret) {
1326
        if (errmsg)
1327
            gf_msg(this->name, GF_LOG_ERROR, 0,
1328
                   GD_MSG_SECONDARYINFO_FETCH_ERROR,
1329
                   "Unable to fetch secondary details. Error: %s", errmsg);
1330
        else
1331
            gf_msg(this->name, GF_LOG_ERROR, 0,
1332
                   GD_MSG_SECONDARYINFO_FETCH_ERROR,
1333
                   "Unable to fetch secondary details.");
1334
        ret = -1;
1335
        goto out;
1336
    }
1337

1338
    ret = snprintf(conf_path, sizeof(conf_path) - 1,
1339
                   "%s/" GEOREP "/%s_%s_%s/gsyncd.conf", priv->workdir,
1340
                   param->volinfo->volname, secondary_host, secondary_vol);
1341
    conf_path[ret] = '\0';
1342

1343
    ret = glusterd_get_gsync_status_mst_slv(
1344
        param->volinfo, secondary, conf_path, param->rsp_dict, param->node);
1345
out:
1346

1347
    if (errmsg)
1348
        GF_FREE(errmsg);
1349

1350
    if (secondary_buf)
1351
        GF_FREE(secondary_buf);
1352

1353
    if (secondary_vol)
1354
        GF_FREE(secondary_vol);
1355

1356
    if (secondary_url)
1357
        GF_FREE(secondary_url);
1358

1359
    if (secondary_host)
1360
        GF_FREE(secondary_host);
1361

1362
    gf_msg_debug(this->name, 0, "Returning %d.", ret);
1363
    return ret;
1364
}
1365

1366
static int
1367
_get_max_gsync_secondary_num(dict_t *dict, char *key, data_t *value, void *data)
1368
{
1369
    int tmp_secnum = 0;
1370
    int *secnum = (int *)data;
1371

1372
    sscanf(key, "secondary%d", &tmp_secnum);
1373
    if (tmp_secnum > *secnum)
1374
        *secnum = tmp_secnum;
1375

1376
    return 0;
1377
}
1378

1379
static int
1380
_get_secondary_idx_secondary_voluuid(dict_t *dict, char *key, data_t *value,
1381
                                     void *data)
1382
{
1383
    char *secondary_info = NULL;
1384
    xlator_t *this = THIS;
1385
    struct secondary_vol_config *sec_cfg = NULL;
1386

1387
    int i = 0;
1388
    int ret = -1;
1389
    unsigned tmp_secnum = 0;
1390

1391
    sec_cfg = data;
1392

1393
    if (value)
1394
        secondary_info = value->data;
1395

1396
    if (!(secondary_info) || strlen(secondary_info) == 0) {
1397
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_SECONDARY,
1398
               "Invalid secondary in dict");
1399
        ret = -2;
1400
        goto out;
1401
    }
1402

1403
    /* secondary format:
1404
     * primary_node_uuid:ssh://secondary_host::secondary_vol:secondary_voluuid
1405
     */
1406
    while (i++ < 5) {
1407
        secondary_info = strchr(secondary_info, ':');
1408
        if (secondary_info)
1409
            secondary_info++;
1410
        else {
1411
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
1412
                   "secondary_info becomes NULL!");
1413
            ret = -2;
1414
            goto out;
1415
        }
1416
    }
1417
    if (strcmp(secondary_info, sec_cfg->secondary_voluuid) == 0) {
1418
        gf_msg_debug(this->name, 0,
1419
                     "Same secondary volume "
1420
                     "already present %s",
1421
                     sec_cfg->secondary_voluuid);
1422
        ret = -1;
1423

1424
        sscanf(key, "secondary%d", &tmp_secnum);
1425
        sec_cfg->old_slvidx = tmp_secnum;
1426

1427
        gf_msg_debug(this->name, 0,
1428
                     "and "
1429
                     "its index is: %d",
1430
                     tmp_secnum);
1431
        goto out;
1432
    }
1433

1434
    ret = 0;
1435
out:
1436
    return ret;
1437
}
1438

1439
static int
1440
glusterd_remove_secondary_in_info(glusterd_volinfo_t *volinfo, char *secondary,
1441
                                  char **op_errstr)
1442
{
1443
    int zero_secondary_entries = _gf_true;
1444
    int ret = 0;
1445
    char *secondarykey = NULL;
1446

1447
    GF_ASSERT(volinfo);
1448
    GF_ASSERT(secondary);
1449

1450
    do {
1451
        ret = glusterd_get_secondary(volinfo, secondary, &secondarykey);
1452
        if (ret < 0 && zero_secondary_entries) {
1453
            ret++;
1454
            goto out;
1455
        }
1456
        zero_secondary_entries = _gf_false;
1457
        dict_del(volinfo->gsync_secondaries, secondarykey);
1458
    } while (ret >= 0);
1459

1460
    ret = glusterd_store_volinfo(volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
1461
    if (ret) {
1462
        *op_errstr = gf_strdup(
1463
            "Failed to store the Volume"
1464
            "information");
1465
        goto out;
1466
    }
1467
out:
1468
    gf_msg_debug(THIS->name, 0, "returning %d", ret);
1469
    return ret;
1470
}
1471

1472
static int
1473
glusterd_gsync_get_uuid(char *secondary, glusterd_volinfo_t *vol, uuid_t uuid)
1474
{
1475
    int ret = 0;
1476
    char *secondarykey = NULL;
1477
    char *secondaryentry = NULL;
1478
    char *t = NULL;
1479

1480
    GF_ASSERT(vol);
1481
    GF_ASSERT(secondary);
1482

1483
    ret = glusterd_get_secondary(vol, secondary, &secondarykey);
1484
    if (ret < 0) {
1485
        /* XXX colliding cases of failure and non-extant
1486
         * secondary... now just doing this as callers of this
1487
         * function can make sense only of -1 and 0 as retvals;
1488
         * getting at the proper semanticals will involve
1489
         * fixing callers as well.
1490
         */
1491
        ret = -1;
1492
        goto out;
1493
    }
1494

1495
    ret = dict_get_str(vol->gsync_secondaries, secondarykey, &secondaryentry);
1496
    GF_ASSERT(ret == 0);
1497

1498
    t = strchr(secondaryentry, ':');
1499
    GF_ASSERT(t);
1500
    *t = '\0';
1501
    ret = gf_uuid_parse(secondaryentry, uuid);
1502
    *t = ':';
1503

1504
out:
1505
    gf_msg_debug(THIS->name, 0, "Returning %d", ret);
1506
    return ret;
1507
}
1508

1509
static int
1510
update_secondary_voluuid(dict_t *dict, char *key, data_t *value, void *data)
1511
{
1512
    char *secondary = NULL;
1513
    char *secondary_url = NULL;
1514
    char *secondary_vol = NULL;
1515
    char *secondary_host = NULL;
1516
    char *errmsg = NULL;
1517
    xlator_t *this = THIS;
1518
    int ret = -1;
1519
    char sec_url[VOLINFO_SECONDARY_URL_MAX] = {0};
1520
    char secondary_voluuid[GF_UUID_BUF_SIZE] = {0};
1521
    char *secondary_info = NULL;
1522
    char *new_value = NULL;
1523
    char *same_key = NULL;
1524
    int cnt = 0;
1525
    gf_boolean_t *voluuid_updated = NULL;
1526

1527
    voluuid_updated = data;
1528
    secondary_info = value->data;
1529
    gf_msg_debug(this->name, 0, "secondary_info: %s!", secondary_info);
1530

1531
    /* old secondary format:
1532
     * primary_node_uuid:ssh://secondary_host::secondary_vol
1533
     * New secondary format:
1534
     * primary_node_uuid:ssh://secondary_host::secondary_vol:secondary_voluuid
1535
     */
1536
    while (secondary_info) {
1537
        secondary_info = strchr(secondary_info, ':');
1538
        if (secondary_info)
1539
            cnt++;
1540
        else
1541
            break;
1542

1543
        secondary_info++;
1544
    }
1545

1546
    gf_msg_debug(this->name, 0, "cnt: %d", cnt);
1547
    /* check whether old secondary format and update vol uuid if old format.
1548
     * With volume uuid, number of ':' is 5 and is 4 without.
1549
     */
1550
    if (cnt == 4) {
1551
        if (snprintf(sec_url, sizeof(sec_url), "%s", value->data) >=
1552
            sizeof(sec_url)) {
1553
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
1554
                   "Error in copying secondary: %s!", value->data);
1555
            goto out;
1556
        }
1557

1558
        ret = parse_secondary_url(sec_url, &secondary);
1559
        if (ret == -1) {
1560
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
1561
                   "Error in parsing secondary: %s!", value->data);
1562
            goto out;
1563
        }
1564

1565
        ret = glusterd_get_secondary_info(secondary, &secondary_url,
1566
                                          &secondary_host, &secondary_vol,
1567
                                          &errmsg);
1568
        if (ret) {
1569
            if (errmsg)
1570
                gf_msg(this->name, GF_LOG_ERROR, 0,
1571
                       GD_MSG_SECONDARYINFO_FETCH_ERROR,
1572
                       "Unable to fetch secondary details. Error: %s", errmsg);
1573
            else
1574
                gf_msg(this->name, GF_LOG_ERROR, 0,
1575
                       GD_MSG_SECONDARYINFO_FETCH_ERROR,
1576
                       "Unable to fetch secondary details.");
1577
            ret = -1;
1578
            goto out;
1579
        }
1580

1581
        ret = glusterd_get_secondary_voluuid(secondary_host, secondary_vol,
1582
                                             secondary_voluuid);
1583
        if ((ret) || (strlen(secondary_voluuid) == 0)) {
1584
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REMOTE_VOL_UUID_FAIL,
1585
                   "Unable to get remote volume uuid"
1586
                   "secondaryhost:%s secondaryvol:%s",
1587
                   secondary_host, secondary_vol);
1588
            /* Avoiding failure due to remote vol uuid fetch */
1589
            ret = 0;
1590
            goto out;
1591
        }
1592
        ret = gf_asprintf(&new_value, "%s:%s", value->data, secondary_voluuid);
1593
        ret = gf_asprintf(&same_key, "%s", key);
1594

1595
        /* delete old key and add new value */
1596
        dict_del(dict, key);
1597

1598
        /* set new value for the same key*/
1599
        ret = dict_set_dynstr(dict, same_key, new_value);
1600
        if (ret) {
1601
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REMOTE_VOL_UUID_FAIL,
1602
                   "Error in setting dict value"
1603
                   "new_value :%s",
1604
                   new_value);
1605
            goto out;
1606
        }
1607
        *voluuid_updated = _gf_true;
1608
    }
1609

1610
    ret = 0;
1611
out:
1612
    if (errmsg)
1613
        GF_FREE(errmsg);
1614

1615
    if (secondary_url)
1616
        GF_FREE(secondary_url);
1617

1618
    if (secondary_vol)
1619
        GF_FREE(secondary_vol);
1620

1621
    if (secondary_host)
1622
        GF_FREE(secondary_host);
1623

1624
    if (same_key)
1625
        GF_FREE(same_key);
1626
    gf_msg_debug(this->name, 0, "Returning %d.", ret);
1627
    return ret;
1628
}
1629

1630
static int
1631
glusterd_update_secondary_voluuid_secondaryinfo(glusterd_volinfo_t *volinfo)
1632
{
1633
    int ret = -1;
1634
    xlator_t *this = THIS;
1635
    gf_boolean_t voluuid_updated = _gf_false;
1636

1637
    GF_VALIDATE_OR_GOTO(this->name, volinfo, out);
1638

1639
    ret = dict_foreach(volinfo->gsync_secondaries, update_secondary_voluuid,
1640
                       &voluuid_updated);
1641
    if (ret) {
1642
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REMOTE_VOL_UUID_FAIL,
1643
               "Error in updating"
1644
               "volinfo");
1645
        goto out;
1646
    }
1647

1648
    if (_gf_true == voluuid_updated) {
1649
        ret = glusterd_store_volinfo(volinfo,
1650
                                     GLUSTERD_VOLINFO_VER_AC_INCREMENT);
1651
        if (ret) {
1652
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_STORE_FAIL,
1653
                   "Error in storing"
1654
                   "volinfo");
1655
            goto out;
1656
        }
1657
    }
1658

1659
    ret = 0;
1660
out:
1661
    gf_msg_debug(this->name, 0, "Returning %d", ret);
1662
    return ret;
1663
}
1664

1665
int
1666
glusterd_check_gsync_running_local(char *primary, char *secondary,
1667
                                   char *conf_path, gf_boolean_t *is_run)
1668
{
1669
    int ret = -1;
1670
    int ret_status = 0;
1671
    gf_boolean_t is_template_in_use = _gf_false;
1672
    xlator_t *this = THIS;
1673

1674
    GF_ASSERT(primary);
1675
    GF_ASSERT(secondary);
1676
    GF_ASSERT(is_run);
1677

1678
    *is_run = _gf_false;
1679
    ret = gsync_status(primary, secondary, conf_path, &ret_status,
1680
                       &is_template_in_use);
1681
    if (ret == 0 && ret_status == 0)
1682
        *is_run = _gf_true;
1683
    else if (ret == -1) {
1684
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VALIDATE_FAILED,
1685
               GEOREP " validation failed");
1686
        goto out;
1687
    }
1688
    ret = 0;
1689
out:
1690
    gf_msg_debug(this->name, 0, "Returning %d", ret);
1691
    return ret;
1692
}
1693

1694
static int
1695
glusterd_store_secondary_in_info(glusterd_volinfo_t *volinfo, char *secondary,
1696
                                 char *host_uuid, char *secondary_voluuid,
1697
                                 char **op_errstr, gf_boolean_t is_force)
1698
{
1699
    int ret = 0;
1700
    int maxslv = 0;
1701
    char **linearr = NULL;
1702
    char *value = NULL;
1703
    char *secondarykey = NULL;
1704
    char *secondaryentry = NULL;
1705
    char key[32] = {
1706
        0,
1707
    };
1708
    int keylen;
1709
    char *t = NULL;
1710
    xlator_t *this = THIS;
1711
    struct secondary_vol_config secondary1 = {
1712
        {0},
1713
    };
1714

1715
    GF_ASSERT(volinfo);
1716
    GF_ASSERT(secondary);
1717
    GF_ASSERT(host_uuid);
1718
    GF_VALIDATE_OR_GOTO(this->name, secondary_voluuid, out);
1719

1720
    ret = glusterd_get_secondary(volinfo, secondary, &secondarykey);
1721
    switch (ret) {
1722
        case -2:
1723
            ret = -1;
1724
            goto out;
1725
        case -1:
1726
            break;
1727
        default:
1728
            if (!is_force)
1729
                GF_ASSERT(ret > 0);
1730
            ret = dict_get_str(volinfo->gsync_secondaries, secondarykey,
1731
                               &secondaryentry);
1732
            GF_ASSERT(ret == 0);
1733

1734
            /* same-name + same-uuid secondary entries should have been filtered
1735
             * out in glusterd_op_verify_gsync_start_options(), so we can
1736
             * assert an uuid mismatch
1737
             */
1738
            t = strtail(secondaryentry, host_uuid);
1739
            if (!is_force)
1740
                GF_ASSERT(!t || *t != ':');
1741

1742
            if (is_force) {
1743
                gf_msg_debug(this->name, 0,
1744
                             GEOREP
1745
                             " has already "
1746
                             "been invoked for the %s (primary) and "
1747
                             "%s (secondary). Allowing without saving "
1748
                             "info again due to force command.",
1749
                             volinfo->volname, secondary);
1750
                ret = 0;
1751
                goto out;
1752
            }
1753

1754
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVOKE_ERROR,
1755
                   GEOREP
1756
                   " has already been invoked for "
1757
                   "the %s (primary) and %s (secondary) from a different "
1758
                   "machine",
1759
                   volinfo->volname, secondary);
1760
            *op_errstr = gf_strdup(GEOREP
1761
                                   " already running in "
1762
                                   "another machine");
1763
            ret = -1;
1764
            goto out;
1765
    }
1766

1767
    ret = glusterd_urltransform_single(secondary, "normalize", &linearr);
1768
    if (ret == -1)
1769
        goto out;
1770

1771
    ret = gf_asprintf(&value, "%s:%s:%s", host_uuid, linearr[0],
1772
                      secondary_voluuid);
1773

1774
    glusterd_urltransform_free(linearr, 1);
1775
    if (ret == -1)
1776
        goto out;
1777

1778
    /* Given the secondary volume uuid, check and get any existing secondary */
1779
    memcpy(secondary1.secondary_voluuid, secondary_voluuid,
1780
           UUID_CANONICAL_FORM_LEN);
1781
    ret = dict_foreach(volinfo->gsync_secondaries,
1782
                       _get_secondary_idx_secondary_voluuid, &secondary1);
1783

1784
    if (ret == 0) { /* New secondary */
1785
        dict_foreach(volinfo->gsync_secondaries, _get_max_gsync_secondary_num,
1786
                     &maxslv);
1787
        keylen = snprintf(key, sizeof(key), "secondary%d", maxslv + 1);
1788

1789
        ret = dict_set_dynstrn(volinfo->gsync_secondaries, key, keylen, value);
1790
        if (ret) {
1791
            GF_FREE(value);
1792
            goto out;
1793
        }
1794
    } else if (ret == -1) { /* Existing secondary */
1795
        keylen = snprintf(key, sizeof(key), "secondary%d",
1796
                          secondary1.old_slvidx);
1797

1798
        gf_msg_debug(this->name, 0,
1799
                     "Replacing key:%s with new value"
1800
                     ":%s",
1801
                     key, value);
1802

1803
        /* Add new secondary's value, with the same secondary index */
1804
        ret = dict_set_dynstrn(volinfo->gsync_secondaries, key, keylen, value);
1805
        if (ret) {
1806
            GF_FREE(value);
1807
            goto out;
1808
        }
1809
    } else {
1810
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REMOTE_VOL_UUID_FAIL,
1811
               "_get_secondary_idx_secondary_voluuid failed!");
1812
        GF_FREE(value);
1813
        ret = -1;
1814
        goto out;
1815
    }
1816

1817
    ret = glusterd_store_volinfo(volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
1818
    if (ret) {
1819
        *op_errstr = gf_strdup(
1820
            "Failed to store the Volume "
1821
            "information");
1822
        goto out;
1823
    }
1824
    ret = 0;
1825
out:
1826
    return ret;
1827
}
1828

1829
static int
1830
glusterd_op_verify_gsync_start_options(glusterd_volinfo_t *volinfo,
1831
                                       char *secondary, char *conf_path,
1832
                                       char *statefile, char **op_errstr,
1833
                                       gf_boolean_t is_force)
1834
{
1835
    int ret = -1;
1836
    int ret_status = 0;
1837
    gf_boolean_t is_template_in_use = _gf_false;
1838
    char msg[2048] = {0};
1839
    uuid_t uuid = {0};
1840
    xlator_t *this = THIS;
1841
    struct stat stbuf = {
1842
        0,
1843
    };
1844
    char statefiledir[PATH_MAX] = {
1845
        0,
1846
    };
1847
    char *statedir = NULL;
1848

1849
    GF_ASSERT(volinfo);
1850
    GF_ASSERT(secondary);
1851
    GF_ASSERT(op_errstr);
1852
    GF_ASSERT(conf_path);
1853
    GF_ASSERT(this->private);
1854

1855
    if (GLUSTERD_STATUS_STARTED != volinfo->status) {
1856
        snprintf(msg, sizeof(msg),
1857
                 "Volume %s needs to be started "
1858
                 "before " GEOREP " start",
1859
                 volinfo->volname);
1860
        goto out;
1861
    }
1862

1863
    /* check session directory as statefile may not present
1864
     * during upgrade */
1865
    if (snprintf(statefiledir, sizeof(statefiledir), "%s", statefile) >=
1866
        sizeof(statefiledir)) {
1867
        snprintf(msg, sizeof(msg), "statefiledir truncated");
1868
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, "%s",
1869
               msg);
1870
        *op_errstr = gf_strdup(msg);
1871
        goto out;
1872
    }
1873
    statedir = dirname(statefiledir);
1874

1875
    ret = sys_lstat(statedir, &stbuf);
1876
    if (ret) {
1877
        snprintf(msg, sizeof(msg),
1878
                 "Session between %s and %s has"
1879
                 " not been created. Please create session and retry.",
1880
                 volinfo->volname, secondary);
1881
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED,
1882
               "%s statefile: %s", msg, statefile);
1883
        *op_errstr = gf_strdup(msg);
1884
        goto out;
1885
    }
1886

1887
    /* Check if the gsync secondary info is stored. If not
1888
     * session has not been created */
1889
    ret = glusterd_gsync_get_uuid(secondary, volinfo, uuid);
1890
    if (ret) {
1891
        snprintf(msg, sizeof(msg),
1892
                 "Session between %s and %s has"
1893
                 " not been created. Please create session and retry.",
1894
                 volinfo->volname, secondary);
1895
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SESSION_CREATE_ERROR, "%s",
1896
               msg);
1897
        goto out;
1898
    }
1899

1900
    /*Check if the gsync is already started in cmd. inited host
1901
     * If so initiate add it into the glusterd's priv*/
1902
    ret = gsync_status(volinfo->volname, secondary, conf_path, &ret_status,
1903
                       &is_template_in_use);
1904
    if (ret == 0) {
1905
        if ((ret_status == 0) && !is_force) {
1906
            snprintf(msg, sizeof(msg),
1907
                     GEOREP
1908
                     " session between"
1909
                     " %s & %s already started",
1910
                     volinfo->volname, secondary);
1911
            ret = -1;
1912
            goto out;
1913
        }
1914
    } else if (ret == -1) {
1915
        snprintf(msg, sizeof(msg),
1916
                 GEOREP
1917
                 " start option "
1918
                 "validation failed ");
1919
        goto out;
1920
    }
1921

1922
    if (is_template_in_use == _gf_true) {
1923
        snprintf(msg, sizeof(msg),
1924
                 GEOREP
1925
                 " start "
1926
                 "failed : pid-file entry missing "
1927
                 "in config file.");
1928
        ret = -1;
1929
        goto out;
1930
    }
1931

1932
    ret = glusterd_verify_gsyncd_spawn(volinfo->volname, secondary);
1933
    if (ret && !is_force) {
1934
        snprintf(msg, sizeof(msg), "Unable to spawn gsyncd");
1935
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_SPAWN_FAILED, "%s",
1936
               msg);
1937
    }
1938
out:
1939
    if (ret && (msg[0] != '\0')) {
1940
        *op_errstr = gf_strdup(msg);
1941
    }
1942
    gf_msg_debug(this->name, 0, "Returning %d", ret);
1943
    return ret;
1944
}
1945

1946
void
1947
glusterd_check_geo_rep_configured(glusterd_volinfo_t *volinfo,
1948
                                  gf_boolean_t *flag)
1949
{
1950
    GF_ASSERT(volinfo);
1951
    GF_ASSERT(flag);
1952

1953
    if (volinfo->gsync_secondaries->count)
1954
        *flag = _gf_true;
1955
    else
1956
        *flag = _gf_false;
1957

1958
    return;
1959
}
1960

1961
/*
1962
 * is_geo_rep_active:
1963
 *      This function reads the state_file and sets is_active to 1 if the
1964
 *      monitor status is neither "Stopped" or "Created"
1965
 *
1966
 * RETURN VALUE:
1967
 *       0: On successful read of state_file.
1968
 *      -1: error.
1969
 */
1970

1971
static int
1972
is_geo_rep_active(glusterd_volinfo_t *volinfo, char *secondary, char *conf_path,
1973
                  int *is_active)
1974
{
1975
    dict_t *confd = NULL;
1976
    char *statefile = NULL;
1977
    char *primary = NULL;
1978
    char monitor_status[PATH_MAX] = "";
1979
    int ret = -1;
1980
    xlator_t *this = THIS;
1981

1982
    primary = volinfo->volname;
1983

1984
    confd = dict_new();
1985
    if (!confd) {
1986
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_CREATE_FAIL,
1987
               "Not able to create dict.");
1988
        goto out;
1989
    }
1990

1991
    ret = glusterd_gsync_get_config(primary, secondary, conf_path, confd);
1992
    if (ret) {
1993
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_CONFIG_INFO_FAILED,
1994
               "Unable to get configuration data "
1995
               "for %s(primary), %s(secondary)",
1996
               primary, secondary);
1997
        ret = -1;
1998
        goto out;
1999
    }
2000

2001
    ret = dict_get_param(confd, "state_file", &statefile);
2002
    if (ret) {
2003
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2004
               "Unable to get state_file's name "
2005
               "for %s(primary), %s(secondary). Please check gsync "
2006
               "config file.",
2007
               primary, secondary);
2008
        ret = -1;
2009
        goto out;
2010
    }
2011

2012
    ret = glusterd_gsync_read_frm_status(statefile, monitor_status,
2013
                                         sizeof(monitor_status));
2014
    if (ret <= 0) {
2015
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STAT_FILE_READ_FAILED,
2016
               "Unable to read the status file for %s(primary), "
2017
               "%s(secondary)",
2018
               primary, secondary);
2019
        snprintf(monitor_status, sizeof(monitor_status), "defunct");
2020
    }
2021

2022
    if ((!strcmp(monitor_status, "Stopped")) ||
2023
        (!strcmp(monitor_status, "Created"))) {
2024
        *is_active = 0;
2025
    } else {
2026
        *is_active = 1;
2027
    }
2028
    ret = 0;
2029
out:
2030
    if (confd)
2031
        dict_unref(confd);
2032
    return ret;
2033
}
2034

2035
/*
2036
 * _get_secondary_status:
2037
 *      Called for each secondary in the volume from dict_foreach.
2038
 *      It calls is_geo_rep_active to get the monitor status.
2039
 *
2040
 * RETURN VALUE:
2041
 *      0: On successful read of state_file from is_geo_rep_active.
2042
 *         When it is found geo-rep is already active from previous calls.
2043
 *         When there is no secondary.
2044
 *     -1: On error.
2045
 */
2046

2047
int
2048
_get_secondary_status(dict_t *dict, char *key, data_t *value, void *data)
2049
{
2050
    gsync_status_param_t *param = NULL;
2051
    char *secondary = NULL;
2052
    char *secondary_url = NULL;
2053
    char *secondary_vol = NULL;
2054
    char *secondary_host = NULL;
2055
    char *errmsg = NULL;
2056
    char conf_path[PATH_MAX] = "";
2057
    int ret = -1;
2058
    glusterd_conf_t *priv = NULL;
2059
    xlator_t *this = THIS;
2060

2061
    param = (gsync_status_param_t *)data;
2062

2063
    GF_ASSERT(param);
2064
    GF_ASSERT(param->volinfo);
2065
    if (param->is_active) {
2066
        ret = 0;
2067
        goto out;
2068
    }
2069

2070
    priv = this->private;
2071
    if (priv == NULL) {
2072
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
2073
               "priv of glusterd not present");
2074
        goto out;
2075
    }
2076

2077
    secondary = strchr(value->data, ':');
2078
    if (!secondary) {
2079
        ret = 0;
2080
        goto out;
2081
    }
2082
    secondary++;
2083

2084
    ret = glusterd_get_secondary_info(secondary, &secondary_url,
2085
                                      &secondary_host, &secondary_vol, &errmsg);
2086
    if (ret) {
2087
        if (errmsg)
2088
            gf_msg(this->name, GF_LOG_ERROR, 0,
2089
                   GD_MSG_SECONDARYINFO_FETCH_ERROR,
2090
                   "Unable to fetch"
2091
                   " secondary details. Error: %s",
2092
                   errmsg);
2093
        else
2094
            gf_msg(this->name, GF_LOG_ERROR, 0,
2095
                   GD_MSG_SECONDARYINFO_FETCH_ERROR,
2096
                   "Unable to fetch secondary details.");
2097
        ret = -1;
2098
        goto out;
2099
    }
2100

2101
    ret = snprintf(conf_path, sizeof(conf_path) - 1,
2102
                   "%s/" GEOREP "/%s_%s_%s/gsyncd.conf", priv->workdir,
2103
                   param->volinfo->volname, secondary_host, secondary_vol);
2104
    if (ret < 0) {
2105
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_CONF_PATH_ASSIGN_FAILED,
2106
               "Unable to assign conf_path.");
2107
        ret = -1;
2108
        goto out;
2109
    }
2110
    conf_path[ret] = '\0';
2111

2112
    ret = is_geo_rep_active(param->volinfo, secondary, conf_path,
2113
                            &param->is_active);
2114
out:
2115
    if (errmsg)
2116
        GF_FREE(errmsg);
2117

2118
    if (secondary_vol)
2119
        GF_FREE(secondary_vol);
2120

2121
    if (secondary_url)
2122
        GF_FREE(secondary_url);
2123
    if (secondary_host)
2124
        GF_FREE(secondary_host);
2125

2126
    return ret;
2127
}
2128

2129
/* glusterd_check_geo_rep_running:
2130
 *          Checks if any geo-rep session is running for the volume.
2131
 *
2132
 *    RETURN VALUE:
2133
 *          Sets param.active to true if any geo-rep session is active.
2134
 *    This function sets op_errstr during some error and when any geo-rep
2135
 *    session is active. It is caller's responsibility to free op_errstr
2136
 *    in above cases.
2137
 */
2138

2139
int
2140
glusterd_check_geo_rep_running(gsync_status_param_t *param, char **op_errstr)
2141
{
2142
    char msg[2048] = {
2143
        0,
2144
    };
2145
    gf_boolean_t enabled = _gf_false;
2146
    int ret = 0;
2147

2148
    GF_ASSERT(param);
2149
    GF_ASSERT(param->volinfo);
2150
    GF_ASSERT(op_errstr);
2151

2152
    glusterd_check_geo_rep_configured(param->volinfo, &enabled);
2153

2154
    if (enabled) {
2155
        ret = dict_foreach(param->volinfo->gsync_secondaries,
2156
                           _get_secondary_status, param);
2157
        if (ret) {
2158
            gf_msg(THIS->name, GF_LOG_ERROR, 0,
2159
                   GD_MSG_SECONDARYINFO_FETCH_ERROR,
2160
                   "_get_secondary_satus failed");
2161
            snprintf(msg, sizeof(msg),
2162
                     GEOREP
2163
                     " Unable to"
2164
                     " get the status of active " GEOREP
2165
                     ""
2166
                     " session for the volume '%s'.\n"
2167
                     " Please check the log file for"
2168
                     " more info.",
2169
                     param->volinfo->volname);
2170
            *op_errstr = gf_strdup(msg);
2171
            ret = -1;
2172
            goto out;
2173
        }
2174

2175
        if (param->is_active) {
2176
            snprintf(msg, sizeof(msg),
2177
                     GEOREP
2178
                     " sessions"
2179
                     " are active for the volume %s.\nStop"
2180
                     " " GEOREP
2181
                     " sessions involved in this"
2182
                     " volume. Use 'volume " GEOREP
2183
                     " status' command for more info.",
2184
                     param->volinfo->volname);
2185
            *op_errstr = gf_strdup(msg);
2186
            goto out;
2187
        }
2188
    }
2189
out:
2190
    return ret;
2191
}
2192

2193
static int
2194
glusterd_op_verify_gsync_running(glusterd_volinfo_t *volinfo, char *secondary,
2195
                                 char *conf_path, char **op_errstr)
2196
{
2197
    int pfd = -1;
2198
    int ret = -1;
2199
    char msg[2048] = {0};
2200
    char pidfile[PATH_MAX] = {
2201
        0,
2202
    };
2203
    gf_boolean_t is_template_in_use = _gf_false;
2204
    xlator_t *this = THIS;
2205

2206
    GF_ASSERT(volinfo);
2207
    GF_ASSERT(secondary);
2208
    GF_ASSERT(conf_path);
2209
    GF_ASSERT(op_errstr);
2210

2211
    if (GLUSTERD_STATUS_STARTED != volinfo->status) {
2212
        snprintf(msg, sizeof(msg),
2213
                 "Volume %s needs to be started "
2214
                 "before " GEOREP " start",
2215
                 volinfo->volname);
2216
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_GEO_REP_START_FAILED,
2217
                "Volume is not in a started state, Volname=%s",
2218
                volinfo->volname, NULL);
2219

2220
        goto out;
2221
    }
2222

2223
    pfd = gsyncd_getpidfile(volinfo->volname, secondary, pidfile, conf_path,
2224
                            &is_template_in_use);
2225
    if (pfd == -2) {
2226
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VALIDATE_FAILED,
2227
               GEOREP " stop validation failed for %s & %s", volinfo->volname,
2228
               secondary);
2229
        ret = -1;
2230
        goto out;
2231
    }
2232
    if (gsync_status_byfd(pfd) == -1) {
2233
        snprintf(msg, sizeof(msg),
2234
                 GEOREP
2235
                 " session b/w %s & %s is "
2236
                 "not running on this node.",
2237
                 volinfo->volname, secondary);
2238
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SESSION_INACTIVE, "%s", msg);
2239
        ret = -1;
2240
        /* monitor gsyncd already dead */
2241
        goto out;
2242
    }
2243

2244
    if (is_template_in_use) {
2245
        snprintf(msg, sizeof(msg),
2246
                 "pid-file entry missing in "
2247
                 "the config file(%s).",
2248
                 conf_path);
2249
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PIDFILE_NOT_FOUND, "%s",
2250
               msg);
2251
        ret = -1;
2252
        goto out;
2253
    }
2254

2255
    if (pfd < 0)
2256
        goto out;
2257

2258
    ret = 0;
2259
out:
2260
    if (ret && (msg[0] != '\0')) {
2261
        *op_errstr = gf_strdup(msg);
2262
    }
2263
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2264
    return ret;
2265
}
2266

2267
static int
2268
glusterd_verify_gsync_status_opts(dict_t *dict, char **op_errstr)
2269
{
2270
    char *secondary = NULL;
2271
    char *volname = NULL;
2272
    char errmsg[PATH_MAX] = {
2273
        0,
2274
    };
2275
    glusterd_volinfo_t *volinfo = NULL;
2276
    int ret = 0;
2277
    char *conf_path = NULL;
2278
    char *secondary_url = NULL;
2279
    char *secondary_host = NULL;
2280
    char *secondary_vol = NULL;
2281
    glusterd_conf_t *priv = NULL;
2282
    xlator_t *this = THIS;
2283

2284
    priv = this->private;
2285
    if (priv == NULL) {
2286
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
2287
               "priv of glusterd not present");
2288
        *op_errstr = gf_strdup("glusterd defunct");
2289
        goto out;
2290
    }
2291

2292
    ret = dict_get_str(dict, "primary", &volname);
2293
    if (ret < 0) {
2294
        ret = 0;
2295
        goto out;
2296
    }
2297

2298
    ret = glusterd_volinfo_find(volname, &volinfo);
2299
    if (ret) {
2300
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOL_NOT_FOUND,
2301
               "volume name does not exist");
2302
        snprintf(errmsg, sizeof(errmsg),
2303
                 "Volume name %s does not"
2304
                 " exist",
2305
                 volname);
2306
        *op_errstr = gf_strdup(errmsg);
2307
        goto out;
2308
    }
2309

2310
    ret = dict_get_str(dict, "secondary", &secondary);
2311
    if (ret < 0) {
2312
        ret = 0;
2313
        goto out;
2314
    }
2315

2316
    ret = glusterd_get_secondary_details_confpath(
2317
        volinfo, dict, &secondary_url, &secondary_host, &secondary_vol,
2318
        &conf_path, op_errstr);
2319
    if (ret) {
2320
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARYINFO_FETCH_ERROR,
2321
               "Unable to fetch secondary or confpath details.");
2322
        ret = -1;
2323
        goto out;
2324
    }
2325

2326
out:
2327
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2328
    return ret;
2329
}
2330

2331
int
2332
glusterd_op_gsync_args_get(dict_t *dict, char **op_errstr, char **primary,
2333
                           char **secondary, char **host_uuid)
2334
{
2335
    int ret = -1;
2336
    xlator_t *this = THIS;
2337

2338
    GF_ASSERT(dict);
2339
    GF_ASSERT(op_errstr);
2340

2341
    if (primary) {
2342
        ret = dict_get_str(dict, "primary", primary);
2343
        if (ret < 0) {
2344
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
2345
                   "primary not found");
2346
            *op_errstr = gf_strdup("primary not found");
2347
            goto out;
2348
        }
2349
    }
2350

2351
    if (secondary) {
2352
        ret = dict_get_str(dict, "secondary", secondary);
2353
        if (ret < 0) {
2354
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
2355
                   "secondary not found");
2356
            *op_errstr = gf_strdup("secondary not found");
2357
            goto out;
2358
        }
2359
    }
2360

2361
    if (host_uuid) {
2362
        ret = dict_get_str(dict, "host-uuid", host_uuid);
2363
        if (ret < 0) {
2364
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
2365
                   "host_uuid not found");
2366
            *op_errstr = gf_strdup("host_uuid not found");
2367
            goto out;
2368
        }
2369
    }
2370

2371
    ret = 0;
2372
out:
2373
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2374
    return ret;
2375
}
2376

2377
int
2378
glusterd_op_stage_sys_exec(dict_t *dict, char **op_errstr)
2379
{
2380
    char errmsg[PATH_MAX] = "";
2381
    char *command = NULL;
2382
    char command_path[PATH_MAX] = "";
2383
    struct stat st = {
2384
        0,
2385
    };
2386
    int ret = -1;
2387
    glusterd_conf_t *conf = NULL;
2388
    xlator_t *this = THIS;
2389

2390
    conf = this->private;
2391
    GF_ASSERT(conf);
2392

2393
    if (conf->op_version < 2) {
2394
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNSUPPORTED_VERSION,
2395
               "Op Version not supported.");
2396
        snprintf(errmsg, sizeof(errmsg),
2397
                 "One or more nodes do not"
2398
                 " support the required op version.");
2399
        *op_errstr = gf_strdup(errmsg);
2400
        ret = -1;
2401
        goto out;
2402
    }
2403

2404
    ret = dict_get_str(dict, "command", &command);
2405
    if (ret) {
2406
        strcpy(errmsg, "internal error");
2407
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2408
               "Unable to get command from dict");
2409
        goto out;
2410
    }
2411

2412
    /* enforce local occurrence of the command */
2413
    if (strchr(command, '/')) {
2414
        strcpy(errmsg, "invalid command name");
2415
        ret = -1;
2416
        goto out;
2417
    }
2418

2419
    sprintf(command_path, GSYNCD_PREFIX "/peer_%s", command);
2420
    /* check if it's executable */
2421
    ret = sys_access(command_path, X_OK);
2422
    if (!ret)
2423
        /* check if it's a regular file */
2424
        ret = sys_stat(command_path, &st);
2425
    if (!ret && !S_ISREG(st.st_mode))
2426
        ret = -1;
2427

2428
out:
2429
    if (ret) {
2430
        if (errmsg[0] == '\0') {
2431
            if (command)
2432
                snprintf(errmsg, sizeof(errmsg),
2433
                         "gsync peer_%s command not found.", command);
2434
            else
2435
                snprintf(errmsg, sizeof(errmsg), "%s",
2436
                         "gsync peer command was not "
2437
                         "specified");
2438
        }
2439
        *op_errstr = gf_strdup(errmsg);
2440
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PEER_CMD_ERROR, "%s",
2441
               errmsg);
2442
    }
2443

2444
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2445
    return ret;
2446
}
2447

2448
int
2449
glusterd_op_stage_copy_file(dict_t *dict, char **op_errstr)
2450
{
2451
    char abs_filename[PATH_MAX] = "";
2452
    char errmsg[PATH_MAX] = "";
2453
    char *filename = NULL;
2454
    char *host_uuid = NULL;
2455
    char uuid_str[64] = {0};
2456
    int ret = -1;
2457
    glusterd_conf_t *priv = NULL;
2458
    struct stat stbuf = {
2459
        0,
2460
    };
2461
    xlator_t *this = THIS;
2462
    char workdir[PATH_MAX] = {
2463
        0,
2464
    };
2465
    char realpath_filename[PATH_MAX] = {
2466
        0,
2467
    };
2468
    char realpath_workdir[PATH_MAX] = {
2469
        0,
2470
    };
2471
    int32_t len = 0;
2472

2473
    priv = this->private;
2474
    if (priv == NULL) {
2475
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
2476
               "priv of glusterd not present");
2477
        *op_errstr = gf_strdup("glusterd defunct");
2478
        goto out;
2479
    }
2480

2481
    if (priv->op_version < 2) {
2482
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNSUPPORTED_VERSION,
2483
               "Op Version not supported.");
2484
        snprintf(errmsg, sizeof(errmsg),
2485
                 "One or more nodes do not"
2486
                 " support the required op version.");
2487
        *op_errstr = gf_strdup(errmsg);
2488
        ret = -1;
2489
        goto out;
2490
    }
2491

2492
    ret = dict_get_str(dict, "host-uuid", &host_uuid);
2493
    if (ret < 0) {
2494
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2495
               "Unable to fetch host-uuid from dict.");
2496
        goto out;
2497
    }
2498

2499
    uuid_utoa_r(MY_UUID, uuid_str);
2500
    if (!strcmp(uuid_str, host_uuid)) {
2501
        ret = dict_get_str(dict, "source", &filename);
2502
        if (ret < 0) {
2503
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2504
                   "Unable to fetch filename from dict.");
2505
            *op_errstr = gf_strdup("command unsuccessful");
2506
            goto out;
2507
        }
2508
        len = snprintf(abs_filename, sizeof(abs_filename), "%s/%s",
2509
                       priv->workdir, filename);
2510
        if ((len < 0) || (len >= sizeof(abs_filename))) {
2511
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
2512
            ret = -1;
2513
            goto out;
2514
        }
2515

2516
        if (!realpath(priv->workdir, realpath_workdir)) {
2517
            len = snprintf(errmsg, sizeof(errmsg),
2518
                           "Failed to "
2519
                           "get realpath of %s: %s",
2520
                           priv->workdir, strerror(errno));
2521
            if (len < 0) {
2522
                strcpy(errmsg, "<error>");
2523
            }
2524
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_REALPATH_GET_FAIL,
2525
                    "Realpath=%s, Reason=%s", priv->workdir, strerror(errno),
2526
                    NULL);
2527
            *op_errstr = gf_strdup(errmsg);
2528
            ret = -1;
2529
            goto out;
2530
        }
2531

2532
        if (!realpath(abs_filename, realpath_filename)) {
2533
            snprintf(errmsg, sizeof(errmsg),
2534
                     "Failed to get "
2535
                     "realpath of %s: %s",
2536
                     filename, strerror(errno));
2537
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_REALPATH_GET_FAIL,
2538
                    "Filename=%s, Reason=%s", filename, strerror(errno), NULL);
2539
            *op_errstr = gf_strdup(errmsg);
2540
            ret = -1;
2541
            goto out;
2542
        }
2543

2544
        /* Add Trailing slash to workdir, without slash strncmp
2545
           will succeed for /var/lib/glusterd_bad */
2546
        len = snprintf(workdir, sizeof(workdir), "%s/", realpath_workdir);
2547
        if ((len < 0) || (len >= sizeof(workdir))) {
2548
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_COPY_FAIL, NULL);
2549
            ret = -1;
2550
            goto out;
2551
        }
2552

2553
        /* Protect against file copy outside $workdir */
2554
        if (strncmp(workdir, realpath_filename, strlen(workdir))) {
2555
            len = snprintf(errmsg, sizeof(errmsg),
2556
                           "Source file"
2557
                           " is outside of %s directory",
2558
                           priv->workdir);
2559
            if (len < 0) {
2560
                strcpy(errmsg, "<error>");
2561
            }
2562
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_SRC_FILE_ERROR, errmsg,
2563
                    NULL);
2564
            *op_errstr = gf_strdup(errmsg);
2565
            ret = -1;
2566
            goto out;
2567
        }
2568

2569
        ret = sys_lstat(abs_filename, &stbuf);
2570
        if (ret) {
2571
            len = snprintf(errmsg, sizeof(errmsg),
2572
                           "Source file"
2573
                           " does not exist in %s",
2574
                           priv->workdir);
2575
            if (len < 0) {
2576
                strcpy(errmsg, "<error>");
2577
            }
2578
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_SRC_FILE_ERROR, errmsg,
2579
                    NULL);
2580
            *op_errstr = gf_strdup(errmsg);
2581
            goto out;
2582
        }
2583

2584
        if (!S_ISREG(stbuf.st_mode)) {
2585
            snprintf(errmsg, sizeof(errmsg),
2586
                     "Source file"
2587
                     " is not a regular file.");
2588
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_SRC_FILE_ERROR, errmsg,
2589
                    NULL);
2590
            *op_errstr = gf_strdup(errmsg);
2591
            ret = -1;
2592
            goto out;
2593
        }
2594
    }
2595

2596
    ret = 0;
2597
out:
2598
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2599
    return ret;
2600
}
2601

2602
int
2603
glusterd_get_statefile_name(glusterd_volinfo_t *volinfo, char *secondary,
2604
                            char *conf_path, char **statefile,
2605
                            gf_boolean_t *is_template_in_use)
2606
{
2607
    char *primary = NULL;
2608
    char *buf = NULL;
2609
    char *working_conf_path = NULL;
2610
    char temp_conf_path[PATH_MAX] = "";
2611
    dict_t *confd = NULL;
2612
    glusterd_conf_t *priv = NULL;
2613
    int ret = -1;
2614
    struct stat stbuf = {
2615
        0,
2616
    };
2617
    xlator_t *this = THIS;
2618
    int32_t len = 0;
2619

2620
    GF_ASSERT(this->private);
2621
    GF_ASSERT(volinfo);
2622
    GF_ASSERT(conf_path);
2623
    GF_ASSERT(is_template_in_use);
2624

2625
    primary = volinfo->volname;
2626

2627
    confd = dict_new();
2628
    if (!confd) {
2629
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_CREATE_FAIL,
2630
               "Unable to create new dict");
2631
        goto out;
2632
    }
2633

2634
    priv = THIS->private;
2635

2636
    len = snprintf(temp_conf_path, sizeof(temp_conf_path),
2637
                   "%s/" GSYNC_CONF_TEMPLATE, priv->workdir);
2638
    if ((len < 0) || (len >= sizeof(temp_conf_path))) {
2639
        goto out;
2640
    }
2641

2642
    ret = sys_lstat(conf_path, &stbuf);
2643
    if (!ret) {
2644
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_CONFIG_INFO,
2645
               "Using passed config template(%s).", conf_path);
2646
        working_conf_path = conf_path;
2647
    } else {
2648
        gf_msg(this->name, GF_LOG_WARNING, ENOENT, GD_MSG_FILE_OP_FAILED,
2649
               "Config file (%s) missing. Looking for template config"
2650
               " file (%s)",
2651
               conf_path, temp_conf_path);
2652
        ret = sys_lstat(temp_conf_path, &stbuf);
2653
        if (ret) {
2654
            gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
2655
                   "Template "
2656
                   "config file (%s) missing.",
2657
                   temp_conf_path);
2658
            goto out;
2659
        }
2660
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DEFAULT_TEMP_CONFIG,
2661
               "Using default config template(%s).", temp_conf_path);
2662
        working_conf_path = temp_conf_path;
2663
        *is_template_in_use = _gf_true;
2664
    }
2665

2666
fetch_data:
2667
    ret = glusterd_gsync_get_config(primary, secondary, working_conf_path,
2668
                                    confd);
2669
    if (ret) {
2670
        if (*is_template_in_use == _gf_false) {
2671
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_CONFIG_INFO_FAILED,
2672
                   "Unable to get configuration data "
2673
                   "for %s(primary), %s(secondary). "
2674
                   "Trying template config.",
2675
                   primary, secondary);
2676
            working_conf_path = temp_conf_path;
2677
            *is_template_in_use = _gf_true;
2678
            goto fetch_data;
2679
        } else {
2680
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_CONFIG_INFO_FAILED,
2681
                   "Unable to get configuration data "
2682
                   "for %s(primary), %s(secondary) from "
2683
                   "template config",
2684
                   primary, secondary);
2685
            goto out;
2686
        }
2687
    }
2688

2689
    ret = dict_get_param(confd, "state_file", &buf);
2690
    if (ret) {
2691
        if (*is_template_in_use == _gf_false) {
2692
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
2693
                   "Unable to get state_file's name. "
2694
                   "Trying template config.");
2695
            working_conf_path = temp_conf_path;
2696
            *is_template_in_use = _gf_true;
2697
            goto fetch_data;
2698
        } else {
2699
            gf_msg(this->name, GF_LOG_ERROR, 0,
2700
                   GD_MSG_GET_STATEFILE_NAME_FAILED,
2701
                   "Unable to get state_file's "
2702
                   "name from template.");
2703
            goto out;
2704
        }
2705
    }
2706

2707
    ret = 0;
2708
out:
2709
    if (buf) {
2710
        *statefile = gf_strdup(buf);
2711
        if (!*statefile)
2712
            ret = -1;
2713
    }
2714

2715
    if (confd)
2716
        dict_unref(confd);
2717

2718
    gf_msg_debug(this->name, 0, "Returning %d ", ret);
2719
    return ret;
2720
}
2721

2722
int
2723
glusterd_create_status_file(char *primary, char *secondary,
2724
                            char *secondary_host, char *secondary_vol,
2725
                            char *status)
2726
{
2727
    int ret = -1;
2728
    runner_t runner = {
2729
        0,
2730
    };
2731
    glusterd_conf_t *priv = NULL;
2732
    xlator_t *this = THIS;
2733

2734
    priv = this->private;
2735
    if (priv == NULL) {
2736
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
2737
               "priv of glusterd not present");
2738
        goto out;
2739
    }
2740

2741
    if (!status) {
2742
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STATUS_NULL, "Status Empty");
2743
        goto out;
2744
    }
2745
    gf_msg_debug(this->name, 0, "secondary = %s", secondary);
2746

2747
    runinit(&runner);
2748
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "--create", status, "-c",
2749
                    NULL);
2750
    runner_argprintf(&runner, "%s/" GEOREP "/%s_%s_%s/gsyncd.conf",
2751
                     priv->workdir, primary, secondary_host, secondary_vol);
2752
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);
2753
    runner_argprintf(&runner, ":%s", primary);
2754
    runner_add_args(&runner, secondary, NULL);
2755
    synclock_unlock(&priv->big_lock);
2756
    ret = runner_run(&runner);
2757
    synclock_lock(&priv->big_lock);
2758
    if (ret) {
2759
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STATUSFILE_CREATE_FAILED,
2760
               "Creating status file failed.");
2761
        ret = -1;
2762
        goto out;
2763
    }
2764

2765
    ret = 0;
2766
out:
2767
    gf_msg_debug(this->name, 0, "returning %d", ret);
2768
    return ret;
2769
}
2770

2771
static int
2772
glusterd_verify_secondary(char *volname, char *secondary_url,
2773
                          char *secondary_vol, int ssh_port, char **op_errstr,
2774
                          gf_boolean_t *is_force_blocker)
2775
{
2776
    int32_t ret = -1;
2777
    runner_t runner = {
2778
        0,
2779
    };
2780
    char log_file_path[PATH_MAX] = "";
2781
    char buf[PATH_MAX] = "";
2782
    char *tmp = NULL;
2783
    char *secondary_url_buf = NULL;
2784
    char *save_ptr = NULL;
2785
    char *secondary_user = NULL;
2786
    char *secondary_ip = NULL;
2787
    glusterd_conf_t *priv = NULL;
2788
    xlator_t *this = THIS;
2789
    char *af = NULL;
2790

2791
    priv = this->private;
2792
    GF_ASSERT(priv);
2793
    GF_ASSERT(volname);
2794
    GF_ASSERT(secondary_url);
2795
    GF_ASSERT(secondary_vol);
2796

2797
    /* Fetch the secondary_user and secondary_ip from the secondary_url.
2798
     * If the secondary_user is not present. Use "root"
2799
     */
2800
    if (strstr(secondary_url, "@")) {
2801
        secondary_url_buf = gf_strdup(secondary_url);
2802
        if (!secondary_url_buf) {
2803
            gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_STRDUP_FAILED,
2804
                    "Secondary_url=%s", secondary_url, NULL);
2805
            goto out;
2806
        }
2807

2808
        secondary_user = strtok_r(secondary_url_buf, "@", &save_ptr);
2809
        secondary_ip = strtok_r(NULL, "@", &save_ptr);
2810
    } else {
2811
        secondary_user = "root";
2812
        secondary_ip = secondary_url;
2813
    }
2814

2815
    if (!secondary_user || !secondary_ip) {
2816
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_URL_INVALID,
2817
               "Invalid secondary url.");
2818
        goto out;
2819
    }
2820

2821
    snprintf(log_file_path, sizeof(log_file_path), "%s/create_verify_log",
2822
             priv->logdir);
2823

2824
    runinit(&runner);
2825
    runner_add_args(&runner, GSYNCD_PREFIX "/gverify.sh", NULL);
2826
    runner_argprintf(&runner, "%s", volname);
2827
    runner_argprintf(&runner, "%s", secondary_user);
2828
    runner_argprintf(&runner, "%s", secondary_ip);
2829
    runner_argprintf(&runner, "%s", secondary_vol);
2830
    runner_argprintf(&runner, "%d", ssh_port);
2831
    runner_argprintf(&runner, "%s", log_file_path);
2832
    ret = dict_get_str(this->options, "transport.address-family", &af);
2833
    if (ret)
2834
        af = "-";
2835

2836
    runner_argprintf(&runner, "%s", af);
2837

2838
    gf_msg_debug(this->name, 0, "gverify Args = %s %s %s %s %s %s %s %s",
2839
                 runner.argv[0], runner.argv[1], runner.argv[2], runner.argv[3],
2840
                 runner.argv[4], runner.argv[5], runner.argv[6],
2841
                 runner.argv[7]);
2842
    runner_redir(&runner, STDOUT_FILENO, RUN_PIPE);
2843
    synclock_unlock(&priv->big_lock);
2844
    ret = runner_run(&runner);
2845
    synclock_lock(&priv->big_lock);
2846
    if (ret) {
2847
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_SECONDARY,
2848
               "Not a valid secondary");
2849
        ret = glusterd_gsync_read_frm_status(log_file_path, buf, sizeof(buf));
2850
        if (ret <= 0) {
2851
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_READ_ERROR,
2852
                   "Unable to read from %s", log_file_path);
2853
            goto out;
2854
        }
2855

2856
        /* Tokenize the error message from gverify.sh to figure out
2857
         * if the error is a force blocker or not. */
2858
        tmp = strtok_r(buf, "|", &save_ptr);
2859
        if (!tmp) {
2860
            ret = -1;
2861
            goto out;
2862
        }
2863
        if (!strcmp(tmp, "FORCE_BLOCKER"))
2864
            *is_force_blocker = 1;
2865
        else {
2866
            /* No FORCE_BLOCKER flag present so all that is
2867
             * present is the error message. */
2868
            *is_force_blocker = 0;
2869
            *op_errstr = gf_strdup(tmp);
2870
            ret = -1;
2871
            goto out;
2872
        }
2873

2874
        /* Copy rest of the error message to op_errstr */
2875
        tmp = strtok_r(NULL, "|", &save_ptr);
2876
        if (tmp)
2877
            *op_errstr = gf_strdup(tmp);
2878
        ret = -1;
2879
        goto out;
2880
    }
2881
    ret = 0;
2882
out:
2883
    GF_FREE(secondary_url_buf);
2884
    sys_unlink(log_file_path);
2885
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2886
    return ret;
2887
}
2888

2889
/** @secondary_ip remains unmodified */
2890
int
2891
glusterd_geo_rep_parse_secondary(char *secondary_url, char **hostname,
2892
                                 char **op_errstr)
2893
{
2894
    int ret = -1;
2895
    char *tmp = NULL;
2896
    char *save_ptr = NULL;
2897
    char *host = NULL;
2898
    char errmsg[PATH_MAX] = "";
2899
    char *saved_url = NULL;
2900
    xlator_t *this = THIS;
2901

2902
    GF_ASSERT(secondary_url);
2903
    GF_ASSERT(*secondary_url);
2904

2905
    saved_url = gf_strdup(secondary_url);
2906
    if (!saved_url)
2907
        goto out;
2908

2909
    /* Checking if hostname has user specified */
2910
    host = strstr(saved_url, "@");
2911
    if (!host) { /* no user specified */
2912
        if (hostname) {
2913
            *hostname = gf_strdup(saved_url);
2914
            if (!*hostname)
2915
                goto out;
2916
        }
2917

2918
        ret = 0;
2919
        goto out;
2920
    } else {
2921
        /* Moving the host past the '@' and checking if the
2922
         * actual hostname also has '@' */
2923
        host++;
2924
        if (strstr(host, "@")) {
2925
            gf_msg_debug(this->name, 0, "host = %s", host);
2926
            ret = snprintf(errmsg, sizeof(errmsg) - 1, "Invalid Hostname (%s).",
2927
                           host);
2928
            errmsg[ret] = '\0';
2929
            gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s",
2930
                   errmsg);
2931
            ret = -1;
2932
            if (op_errstr)
2933
                *op_errstr = gf_strdup(errmsg);
2934
            goto out;
2935
        }
2936

2937
        ret = -1;
2938

2939
        /**
2940
         * preliminary check for valid secondary format.
2941
         */
2942
        tmp = strtok_r(saved_url, "@", &save_ptr);
2943
        tmp = strtok_r(NULL, "@", &save_ptr);
2944
        if (!tmp)
2945
            goto out;
2946
        if (hostname) {
2947
            *hostname = gf_strdup(tmp);
2948
            if (!*hostname)
2949
                goto out;
2950
        }
2951
    }
2952

2953
    ret = 0;
2954
out:
2955
    GF_FREE(saved_url);
2956
    if (ret)
2957
        if (hostname)
2958
            GF_FREE(*hostname);
2959
    gf_msg_debug(this->name, 0, "Returning %d", ret);
2960
    return ret;
2961
}
2962

2963
/* Return -1 only if there is a match in volume uuid */
2964
static int
2965
get_secondaryhost_from_voluuid(dict_t *dict, char *key, data_t *value,
2966
                               void *data)
2967
{
2968
    char *secondary_info = NULL;
2969
    char *tmp = NULL;
2970
    char *secondary_host = NULL;
2971
    xlator_t *this = THIS;
2972
    struct secondary_vol_config *secondary_vol = NULL;
2973
    int i = 0;
2974
    int ret = -1;
2975

2976
    secondary_vol = data;
2977
    secondary_info = value->data;
2978

2979
    gf_msg_debug(this->name, 0, "secondary_info:%s !", secondary_info);
2980

2981
    if (!(secondary_info) || strlen(secondary_info) == 0) {
2982
        /* no secondaries present, peace  */
2983
        ret = 0;
2984
        goto out;
2985
    }
2986

2987
    /* secondary format:
2988
     * primary_node_uuid:ssh://secondary_host::secondary_vol:secondary_voluuid
2989
     */
2990
    while (i++ < 5) {
2991
        secondary_info = strchr(secondary_info, ':');
2992
        if (secondary_info)
2993
            secondary_info++;
2994
        else
2995
            break;
2996
    }
2997

2998
    if (!(secondary_info) || strlen(secondary_info) == 0) {
2999
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_VOL_PARSE_FAIL,
3000
               "secondary_info format is wrong!");
3001
        ret = -2;
3002
        goto out;
3003
    } else {
3004
        if (strcmp(secondary_info, secondary_vol->secondary_voluuid) == 0) {
3005
            ret = -1;
3006

3007
            /* get corresponding secondary host for reference*/
3008
            secondary_host = value->data;
3009
            secondary_host = strstr(secondary_host, "://");
3010
            if (secondary_host) {
3011
                secondary_host += 3;
3012
            } else {
3013
                gf_msg(this->name, GF_LOG_ERROR, 0,
3014
                       GD_MSG_SECONDARY_VOL_PARSE_FAIL,
3015
                       "Invalid secondary_host format!");
3016
                ret = -2;
3017
                goto out;
3018
            }
3019
            /* To go past username in non-root geo-rep session */
3020
            tmp = strchr(secondary_host, '@');
3021
            if (tmp) {
3022
                if ((tmp - secondary_host) >= LOGIN_NAME_MAX) {
3023
                    gf_msg(this->name, GF_LOG_ERROR, 0,
3024
                           GD_MSG_SECONDARY_VOL_PARSE_FAIL,
3025
                           "Invalid secondary user length in %s",
3026
                           secondary_host);
3027
                    ret = -2;
3028
                    goto out;
3029
                }
3030
                strncpy(secondary_vol->old_secuser, secondary_host,
3031
                        (tmp - secondary_host));
3032
                secondary_vol->old_secuser[(tmp - secondary_host) + 1] = '\0';
3033
                secondary_host = tmp + 1;
3034
            } else
3035
                strcpy(secondary_vol->old_secuser, "root");
3036

3037
            tmp = strchr(secondary_host, ':');
3038
            if (!tmp) {
3039
                gf_msg(this->name, GF_LOG_ERROR, 0,
3040
                       GD_MSG_SECONDARY_VOL_PARSE_FAIL,
3041
                       "Invalid secondary_host!");
3042
                ret = -2;
3043
                goto out;
3044
            }
3045

3046
            strncpy(secondary_vol->old_sechost, secondary_host,
3047
                    (tmp - secondary_host));
3048
            secondary_vol->old_sechost[(tmp - secondary_host) + 1] = '\0';
3049

3050
            goto out;
3051
        }
3052
    }
3053

3054
    ret = 0;
3055
out:
3056
    return ret;
3057
}
3058

3059
/* Given secondary host and secondary volume, check whether secondary volume
3060
 * uuid already present. If secondary volume uuid is present, get corresponding
3061
 * secondary host for reference */
3062
static int
3063
glusterd_get_secondaryhost_from_voluuid(glusterd_volinfo_t *volinfo,
3064
                                        char *secondary_host,
3065
                                        char *secondary_vol,
3066
                                        struct secondary_vol_config *secondary1)
3067
{
3068
    int ret = -1;
3069

3070
    GF_VALIDATE_OR_GOTO(THIS->name, volinfo, out);
3071

3072
    ret = dict_foreach(volinfo->gsync_secondaries,
3073
                       get_secondaryhost_from_voluuid, secondary1);
3074
out:
3075
    return ret;
3076
}
3077

3078
int
3079
glusterd_op_stage_gsync_create(dict_t *dict, char **op_errstr)
3080
{
3081
    char *down_peerstr = NULL;
3082
    char *secondary = NULL;
3083
    char *volname = NULL;
3084
    char *host_uuid = NULL;
3085
    char *statefile = NULL;
3086
    char *secondary_url = NULL;
3087
    char *secondary_host = NULL;
3088
    char *secondary_vol = NULL;
3089
    char *conf_path = NULL;
3090
    char errmsg[PATH_MAX] = "";
3091
    char common_pem_file[PATH_MAX] = "";
3092
    char hook_script[PATH_MAX] = "";
3093
    char uuid_str[64] = "";
3094
    int ret = -1;
3095
    int is_pem_push = -1;
3096
    int ssh_port = 22;
3097
    gf_boolean_t is_force = -1;
3098
    gf_boolean_t is_no_verify = -1;
3099
    gf_boolean_t is_force_blocker = -1;
3100
    gf_boolean_t is_template_in_use = _gf_false;
3101
    glusterd_conf_t *conf = NULL;
3102
    glusterd_volinfo_t *volinfo = NULL;
3103
    struct stat stbuf = {
3104
        0,
3105
    };
3106
    xlator_t *this = THIS;
3107
    struct secondary_vol_config secondary1 = {
3108
        {0},
3109
    };
3110
    char old_secondary_url[SECONDARY_URL_INFO_MAX] = {0};
3111
    char old_confpath[PATH_MAX] = {0};
3112
    gf_boolean_t is_running = _gf_false;
3113
    char *statedir = NULL;
3114
    char statefiledir[PATH_MAX] = {
3115
        0,
3116
    };
3117
    gf_boolean_t is_different_secondaryhost = _gf_false;
3118
    gf_boolean_t is_different_username = _gf_false;
3119
    char *secondary_user = NULL;
3120
    char *save_ptr = NULL;
3121
    char *secondary_url_buf = NULL;
3122
    int32_t len = 0;
3123

3124
    conf = this->private;
3125
    GF_ASSERT(conf);
3126

3127
    ret = glusterd_op_gsync_args_get(dict, op_errstr, &volname, &secondary,
3128
                                     &host_uuid);
3129
    if (ret) {
3130
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_ARG_FETCH_ERROR,
3131
               "Unable to fetch arguments");
3132
        gf_msg_debug(this->name, 0, "Returning %d", ret);
3133
        return -1;
3134
    }
3135

3136
    if (conf->op_version < 2) {
3137
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNSUPPORTED_VERSION,
3138
               "Op Version not supported.");
3139
        snprintf(errmsg, sizeof(errmsg),
3140
                 "One or more nodes do not"
3141
                 " support the required op version.");
3142
        *op_errstr = gf_strdup(errmsg);
3143
        ret = -1;
3144
        goto out;
3145
    }
3146

3147
    ret = glusterd_volinfo_find(volname, &volinfo);
3148
    if (ret) {
3149
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOL_NOT_FOUND,
3150
               "volume name does not exist");
3151
        snprintf(errmsg, sizeof(errmsg),
3152
                 "Volume name %s does not"
3153
                 " exist",
3154
                 volname);
3155
        goto out;
3156
    }
3157

3158
    ret = glusterd_get_secondary_details_confpath(
3159
        volinfo, dict, &secondary_url, &secondary_host, &secondary_vol,
3160
        &conf_path, op_errstr);
3161
    if (ret) {
3162
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARYINFO_FETCH_ERROR,
3163
               "Unable to fetch secondary or confpath details.");
3164
        ret = -1;
3165
        goto out;
3166
    }
3167

3168
    is_force = dict_get_str_boolean(dict, "force", _gf_false);
3169

3170
    uuid_utoa_r(MY_UUID, uuid_str);
3171
    if (!strcmp(uuid_str, host_uuid)) {
3172
        ret = glusterd_are_vol_all_peers_up(volinfo, &conf->peers,
3173
                                            &down_peerstr);
3174
        if ((ret == _gf_false) && !is_force) {
3175
            snprintf(errmsg, sizeof(errmsg),
3176
                     "Peer %s,"
3177
                     " which is a part of %s volume, is"
3178
                     " down. Please bring up the peer and"
3179
                     " retry.",
3180
                     down_peerstr, volinfo->volname);
3181
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PEER_DISCONNECTED, "%s",
3182
                   errmsg);
3183
            *op_errstr = gf_strdup(errmsg);
3184
            GF_FREE(down_peerstr);
3185
            down_peerstr = NULL;
3186
            gf_msg_debug(this->name, 0, "Returning %d", ret);
3187
            return -1;
3188
        } else if (ret == _gf_false) {
3189
            gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_PEER_DISCONNECTED,
3190
                   "Peer %s, which is a part of %s volume, is"
3191
                   " down. Force creating geo-rep session."
3192
                   " On bringing up the peer, re-run"
3193
                   " \"gluster system:: execute"
3194
                   " gsec_create\" and \"gluster volume"
3195
                   " geo-replication %s %s create push-pem"
3196
                   " force\"",
3197
                   down_peerstr, volinfo->volname, volinfo->volname, secondary);
3198
            GF_FREE(down_peerstr);
3199
            down_peerstr = NULL;
3200
        }
3201

3202
        ret = dict_get_int32(dict, "ssh_port", &ssh_port);
3203
        if (ret < 0 && ret != -ENOENT) {
3204
            snprintf(errmsg, sizeof(errmsg),
3205
                     "Fetching ssh_port failed while "
3206
                     "handling " GEOREP " options");
3207
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
3208
                   errmsg);
3209
            goto out;
3210
        }
3211

3212
        is_no_verify = dict_get_str_boolean(dict, "no_verify", _gf_false);
3213

3214
        if (!is_no_verify) {
3215
            /* Checking if secondary host is pingable, has proper passwordless
3216
             * ssh login setup, secondary volume is created, secondary vol is
3217
             * empty, and if it has enough memory and bypass in case of force if
3218
             * the error is not a force blocker */
3219
            ret = glusterd_verify_secondary(volname, secondary_url,
3220
                                            secondary_vol, ssh_port, op_errstr,
3221
                                            &is_force_blocker);
3222
            if (ret) {
3223
                if (is_force && !is_force_blocker) {
3224
                    gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_INVALID_SECONDARY,
3225
                           "%s is not a valid secondary "
3226
                           "volume. Error: %s. Force "
3227
                           "creating geo-rep"
3228
                           " session.",
3229
                           secondary, *op_errstr);
3230
                } else {
3231
                    gf_msg(this->name, GF_LOG_ERROR, 0,
3232
                           GD_MSG_INVALID_SECONDARY,
3233
                           "%s is not a valid secondary "
3234
                           "volume. Error: %s",
3235
                           secondary, *op_errstr);
3236
                    ret = -1;
3237

3238
                    goto out;
3239
                }
3240
            }
3241
        }
3242

3243
        ret = dict_get_int32(dict, "push_pem", &is_pem_push);
3244
        if (!ret && is_pem_push) {
3245
            ret = snprintf(common_pem_file, sizeof(common_pem_file),
3246
                           "%s" GLUSTERD_COMMON_PEM_PUB_FILE, conf->workdir);
3247
            if ((ret < 0) || (ret >= sizeof(common_pem_file))) {
3248
                ret = -1;
3249
                goto out;
3250
            }
3251

3252
            ret = snprintf(hook_script, sizeof(hook_script),
3253
                           "%s" GLUSTERD_CREATE_HOOK_SCRIPT, conf->workdir);
3254
            if ((ret < 0) || (ret >= sizeof(hook_script))) {
3255
                ret = -1;
3256
                goto out;
3257
            }
3258

3259
            ret = sys_lstat(common_pem_file, &stbuf);
3260
            if (ret) {
3261
                len = snprintf(errmsg, sizeof(errmsg),
3262
                               "%s"
3263
                               " required for push-pem is"
3264
                               " not present. Please run"
3265
                               " \"gluster system:: execute"
3266
                               " gsec_create\"",
3267
                               common_pem_file);
3268
                if (len < 0) {
3269
                    strcpy(errmsg, "<error>");
3270
                }
3271
                gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
3272
                       "%s", errmsg);
3273
                *op_errstr = gf_strdup(errmsg);
3274
                ret = -1;
3275
                goto out;
3276
            }
3277

3278
            ret = sys_lstat(hook_script, &stbuf);
3279
            if (ret) {
3280
                len = snprintf(errmsg, sizeof(errmsg),
3281
                               "The hook-script (%s) "
3282
                               "required for push-pem is not "
3283
                               "present. Please install the "
3284
                               "hook-script and retry",
3285
                               hook_script);
3286
                if (len < 0) {
3287
                    strcpy(errmsg, "<error>");
3288
                }
3289
                gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
3290
                       "%s", errmsg);
3291
                *op_errstr = gf_strdup(errmsg);
3292
                ret = -1;
3293
                goto out;
3294
            }
3295

3296
            if (!S_ISREG(stbuf.st_mode)) {
3297
                len = snprintf(errmsg, sizeof(errmsg),
3298
                               "%s"
3299
                               " required for push-pem is"
3300
                               " not a regular file. Please"
3301
                               " run \"gluster system:: "
3302
                               "execute gsec_create\"",
3303
                               common_pem_file);
3304
                if (len < 0) {
3305
                    strcpy(errmsg, "<error>");
3306
                }
3307
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REG_FILE_MISSING,
3308
                       "%s", errmsg);
3309
                ret = -1;
3310
                goto out;
3311
            }
3312
        }
3313
    }
3314

3315
    ret = glusterd_get_statefile_name(volinfo, secondary, conf_path, &statefile,
3316
                                      &is_template_in_use);
3317
    if (ret) {
3318
        if (!strstr(secondary, "::"))
3319
            snprintf(errmsg, sizeof(errmsg), "%s is not a valid secondary url.",
3320
                     secondary);
3321
        else
3322
            snprintf(errmsg, sizeof(errmsg),
3323
                     "Please check gsync "
3324
                     "config file. Unable to get statefile's name");
3325
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STATEFILE_NAME_NOT_FOUND,
3326
               "%s", errmsg);
3327
        ret = -1;
3328
        goto out;
3329
    }
3330

3331
    ret = dict_set_str(dict, "statefile", statefile);
3332
    if (ret) {
3333
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3334
               "Unable to store statefile path");
3335
        goto out;
3336
    }
3337

3338
    if (snprintf(statefiledir, sizeof(statefiledir), "%s", statefile) >=
3339
        sizeof(statefiledir)) {
3340
        snprintf(errmsg, sizeof(errmsg), "Failed copying statefiledir");
3341
        goto out;
3342
    }
3343
    statedir = dirname(statefiledir);
3344

3345
    ret = sys_lstat(statedir, &stbuf);
3346
    if (!ret && !is_force) {
3347
        snprintf(errmsg, sizeof(errmsg),
3348
                 "Session between %s"
3349
                 " and %s is already created.",
3350
                 volinfo->volname, secondary);
3351
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SESSION_ALREADY_EXIST, "%s",
3352
               errmsg);
3353
        ret = -1;
3354
        goto out;
3355
    } else if (!ret)
3356
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_FORCE_CREATE_SESSION,
3357
               "Session between %s and %s is already created. Force"
3358
               " creating again.",
3359
               volinfo->volname, secondary);
3360

3361
    ret = glusterd_get_secondary_voluuid(secondary_host, secondary_vol,
3362
                                         secondary1.secondary_voluuid);
3363
    if ((ret) || (strlen(secondary1.secondary_voluuid) == 0)) {
3364
        snprintf(errmsg, sizeof(errmsg), "Unable to get remote volume uuid.");
3365
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REMOTE_VOL_UUID_FAIL, "%s",
3366
               errmsg);
3367
        ret = -1;
3368
        goto out;
3369
    }
3370

3371
    ret = dict_set_dynstr_with_alloc(dict, "secondary_voluuid",
3372
                                     secondary1.secondary_voluuid);
3373
    if (ret) {
3374
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3375
               "Unable to set secondary volume uuid in the dict");
3376
        goto out;
3377
    }
3378

3379
    /* Check whether session is already created using secondary volume uuid */
3380
    ret = glusterd_get_secondaryhost_from_voluuid(volinfo, secondary_host,
3381
                                                  secondary_vol, &secondary1);
3382
    if (ret == -1) {
3383
        if (!is_force) {
3384
            snprintf(errmsg, sizeof(errmsg),
3385
                     "Session between %s"
3386
                     " and %s:%s is already created! Cannot create "
3387
                     "with new secondary:%s again!",
3388
                     volinfo->volname, secondary1.old_sechost, secondary_vol,
3389
                     secondary_host);
3390
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FORCE_CREATE_SESSION,
3391
                   "Session between"
3392
                   " %s and %s:%s is already created! "
3393
                   "Cannot create with new secondary:%s again!",
3394
                   volinfo->volname, secondary1.old_sechost, secondary_vol,
3395
                   secondary_host);
3396
            goto out;
3397
        }
3398

3399
        /* There is a remote possibility that secondary_host can be NULL when
3400
           control reaches here. Add a check so we wouldn't crash in next
3401
           line */
3402
        if (!secondary_host)
3403
            goto out;
3404

3405
        /* Now, check whether session is already started.If so, warn!*/
3406
        is_different_secondaryhost = (strcmp(secondary_host,
3407
                                             secondary1.old_sechost) != 0)
3408
                                         ? _gf_true
3409
                                         : _gf_false;
3410

3411
        if (strstr(secondary_url, "@")) {
3412
            secondary_url_buf = gf_strdup(secondary_url);
3413
            if (!secondary_url_buf) {
3414
                gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
3415
                       "Unable to allocate memory");
3416
                ret = -1;
3417
                goto out;
3418
            }
3419
            secondary_user = strtok_r(secondary_url_buf, "@", &save_ptr);
3420
        } else
3421
            secondary_user = "root";
3422
        is_different_username = (strcmp(secondary_user,
3423
                                        secondary1.old_secuser) != 0)
3424
                                    ? _gf_true
3425
                                    : _gf_false;
3426

3427
        /* Do the check, only if different secondary host/secondary user */
3428
        if (is_different_secondaryhost || is_different_username) {
3429
            len = snprintf(old_confpath, sizeof(old_confpath),
3430
                           "%s/" GEOREP "/%s_%s_%s/gsyncd.conf", conf->workdir,
3431
                           volinfo->volname, secondary1.old_sechost,
3432
                           secondary_vol);
3433
            if ((len < 0) || (len >= sizeof(old_confpath))) {
3434
                ret = -1;
3435
                goto out;
3436
            }
3437

3438
            /* construct old secondary url with (old) secondary host */
3439
            len = snprintf(old_secondary_url, sizeof(old_secondary_url),
3440
                           "%s::%s", secondary1.old_sechost, secondary_vol);
3441
            if ((len < 0) || (len >= sizeof(old_secondary_url))) {
3442
                ret = -1;
3443
                goto out;
3444
            }
3445

3446
            ret = glusterd_check_gsync_running_local(
3447
                volinfo->volname, old_secondary_url, old_confpath, &is_running);
3448
            if (_gf_true == is_running) {
3449
                (void)snprintf(errmsg, sizeof(errmsg),
3450
                               "Geo"
3451
                               "-replication session between %s and %s"
3452
                               " is still active. Please stop the "
3453
                               "session and retry.",
3454
                               volinfo->volname, old_secondary_url);
3455
                ret = -1;
3456
                goto out;
3457
            }
3458
        }
3459

3460
        ret = dict_set_dynstr_with_alloc(dict, "old_secondaryhost",
3461
                                         secondary1.old_sechost);
3462
        if (ret) {
3463
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3464
                   "Unable to set old_secondaryhost in the dict");
3465
            goto out;
3466
        }
3467

3468
        ret = dict_set_int32(dict, "existing_session", _gf_true);
3469
        if (ret) {
3470
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3471
                   "Unable to set existing_session in the dict");
3472
            goto out;
3473
        }
3474
    } else if (ret == -2) {
3475
        snprintf(errmsg, sizeof(errmsg),
3476
                 "get_secondaryhost_from_voluuid"
3477
                 " failed for %s::%s. Please check the glusterd logs.",
3478
                 secondary_host, secondary_vol);
3479
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_FORCE_CREATE_SESSION,
3480
               "get_secondaryhost_from_voluuid failed %s %s!!", secondary_host,
3481
               secondary_vol);
3482
        goto out;
3483
    }
3484

3485
    ret = glusterd_verify_gsyncd_spawn(volinfo->volname, secondary);
3486
    if (ret) {
3487
        snprintf(errmsg, sizeof(errmsg), "Unable to spawn gsyncd.");
3488
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_SPAWN_FAILED, "%s",
3489
               errmsg);
3490
        goto out;
3491
    }
3492

3493
    ret = 0;
3494
out:
3495

3496
    if (ret && errmsg[0] != '\0')
3497
        *op_errstr = gf_strdup(errmsg);
3498

3499
    if (secondary_url_buf)
3500
        GF_FREE(secondary_url_buf);
3501

3502
    return ret;
3503
}
3504

3505
/* pre-condition check for geo-rep pause/resume.
3506
 * Return: 0 on success
3507
 *        -1 on any check failed.
3508
 */
3509
static int
3510
gd_pause_resume_validation(int type, glusterd_volinfo_t *volinfo,
3511
                           char *secondary, char *statefile, char **op_errstr)
3512
{
3513
    int ret = 0;
3514
    char errmsg[PATH_MAX] = {
3515
        0,
3516
    };
3517
    char monitor_status[NAME_MAX] = {
3518
        0,
3519
    };
3520

3521
    GF_ASSERT(volinfo);
3522
    GF_ASSERT(secondary);
3523
    GF_ASSERT(statefile);
3524
    GF_ASSERT(op_errstr);
3525

3526
    ret = glusterd_gsync_read_frm_status(statefile, monitor_status,
3527
                                         sizeof(monitor_status));
3528
    if (ret <= 0) {
3529
        snprintf(errmsg, sizeof(errmsg),
3530
                 "Pause check Failed:"
3531
                 " Geo-rep session is not setup");
3532
        ret = -1;
3533
        goto out;
3534
    }
3535

3536
    if (type == GF_GSYNC_OPTION_TYPE_PAUSE &&
3537
        strstr(monitor_status, "Paused")) {
3538
        snprintf(errmsg, sizeof(errmsg),
3539
                 "Geo-replication"
3540
                 " session between %s and %s already Paused.",
3541
                 volinfo->volname, secondary);
3542
        ret = -1;
3543
        goto out;
3544
    }
3545
    if (type == GF_GSYNC_OPTION_TYPE_RESUME &&
3546
        !strstr(monitor_status, "Paused")) {
3547
        snprintf(errmsg, sizeof(errmsg),
3548
                 "Geo-replication"
3549
                 " session between %s and %s is not Paused.",
3550
                 volinfo->volname, secondary);
3551
        ret = -1;
3552
        goto out;
3553
    }
3554
    ret = 0;
3555
out:
3556
    if (ret && (errmsg[0] != '\0')) {
3557
        *op_errstr = gf_strdup(errmsg);
3558
    }
3559
    return ret;
3560
}
3561

3562
int
3563
glusterd_op_stage_gsync_set(dict_t *dict, char **op_errstr)
3564
{
3565
    int ret = 0;
3566
    int type = 0;
3567
    char *volname = NULL;
3568
    char *secondary = NULL;
3569
    char *secondary_url = NULL;
3570
    char *secondary_host = NULL;
3571
    char *secondary_vol = NULL;
3572
    char *down_peerstr = NULL;
3573
    char *statefile = NULL;
3574
    char statefiledir[PATH_MAX] = {
3575
        0,
3576
    };
3577
    char *statedir = NULL;
3578
    char *path_list = NULL;
3579
    char *conf_path = NULL;
3580
    glusterd_volinfo_t *volinfo = NULL;
3581
    char errmsg[PATH_MAX] = {
3582
        0,
3583
    };
3584
    dict_t *ctx = NULL;
3585
    gf_boolean_t is_force = 0;
3586
    gf_boolean_t is_running = _gf_false;
3587
    gf_boolean_t is_template_in_use = _gf_false;
3588
    uuid_t uuid = {0};
3589
    char uuid_str[64] = {0};
3590
    char *host_uuid = NULL;
3591
    xlator_t *this = THIS;
3592
    glusterd_conf_t *conf = NULL;
3593
    struct stat stbuf = {
3594
        0,
3595
    };
3596

3597
    conf = this->private;
3598
    GF_ASSERT(conf);
3599

3600
    ret = dict_get_int32(dict, "type", &type);
3601
    if (ret < 0) {
3602
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
3603
               "command type not found");
3604
        *op_errstr = gf_strdup("command unsuccessful");
3605
        goto out;
3606
    }
3607

3608
    if (type == GF_GSYNC_OPTION_TYPE_STATUS) {
3609
        ret = glusterd_verify_gsync_status_opts(dict, op_errstr);
3610
        goto out;
3611
    }
3612

3613
    ret = glusterd_op_gsync_args_get(dict, op_errstr, &volname, &secondary,
3614
                                     &host_uuid);
3615
    if (ret)
3616
        goto out;
3617

3618
    uuid_utoa_r(MY_UUID, uuid_str);
3619

3620
    if (conf->op_version < 2) {
3621
        snprintf(errmsg, sizeof(errmsg),
3622
                 "One or more nodes do not"
3623
                 " support the required op version.");
3624
        ret = -1;
3625
        goto out;
3626
    }
3627

3628
    ret = glusterd_volinfo_find(volname, &volinfo);
3629
    if (ret) {
3630
        snprintf(errmsg, sizeof(errmsg),
3631
                 "Volume name %s does not"
3632
                 " exist",
3633
                 volname);
3634
        goto out;
3635
    }
3636

3637
    ret = glusterd_get_secondary_details_confpath(
3638
        volinfo, dict, &secondary_url, &secondary_host, &secondary_vol,
3639
        &conf_path, op_errstr);
3640
    if (ret) {
3641
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARYINFO_FETCH_ERROR,
3642
               "Unable to fetch secondary or confpath details.");
3643
        ret = -1;
3644
        goto out;
3645
    }
3646

3647
    is_force = dict_get_str_boolean(dict, "force", _gf_false);
3648

3649
    ret = glusterd_get_statefile_name(volinfo, secondary, conf_path, &statefile,
3650
                                      &is_template_in_use);
3651
    if (ret) {
3652
        if (!strstr(secondary, "::")) {
3653
            snprintf(errmsg, sizeof(errmsg), "%s is not a valid secondary url.",
3654
                     secondary);
3655
            ret = -1;
3656
            goto out;
3657
        } else {
3658
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_URL_INVALID,
3659
                   "state_file entry missing in config file (%s)", conf_path);
3660

3661
            if ((type == GF_GSYNC_OPTION_TYPE_STOP) && is_force) {
3662
                gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_STOP_FORCE,
3663
                       "Allowing stop "
3664
                       "force to bypass missing statefile "
3665
                       "entry in config file (%s), and "
3666
                       "template file",
3667
                       conf_path);
3668
                ret = 0;
3669
            } else
3670
                goto out;
3671
        }
3672
    } else {
3673
        ret = dict_set_str(dict, "statefile", statefile);
3674
        if (ret) {
3675
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
3676
                   "Unable to store statefile path");
3677
            goto out;
3678
        }
3679
    }
3680

3681
    /* Allowing stop force to bypass the statefile check
3682
     * as this command acts as a fail safe method to stop geo-rep
3683
     * session. */
3684
    if (!((type == GF_GSYNC_OPTION_TYPE_STOP) && is_force)) {
3685
        /* check session directory as statefile may not present
3686
         * during upgrade */
3687
        if (snprintf(statefiledir, sizeof(statefiledir), "%s", statefile) >=
3688
            sizeof(statefiledir)) {
3689
            snprintf(errmsg, sizeof(errmsg), "Failed copying statefiledir");
3690
            ret = -1;
3691
            goto out;
3692
        }
3693
        statedir = dirname(statefiledir);
3694

3695
        ret = sys_lstat(statedir, &stbuf);
3696
        if (ret) {
3697
            snprintf(errmsg, sizeof(errmsg),
3698
                     "Geo-replication"
3699
                     " session between %s and %s does not exist.",
3700
                     volinfo->volname, secondary);
3701
            gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
3702
                   "%s. statefile = %s", errmsg, statefile);
3703
            ret = -1;
3704
            goto out;
3705
        }
3706
    }
3707

3708
    /* Check if all peers that are a part of the volume are up or not */
3709
    if ((type == GF_GSYNC_OPTION_TYPE_DELETE) ||
3710
        ((type == GF_GSYNC_OPTION_TYPE_STOP) && !is_force) ||
3711
        (type == GF_GSYNC_OPTION_TYPE_PAUSE) ||
3712
        (type == GF_GSYNC_OPTION_TYPE_RESUME)) {
3713
        if (!strcmp(uuid_str, host_uuid)) {
3714
            ret = glusterd_are_vol_all_peers_up(volinfo, &conf->peers,
3715
                                                &down_peerstr);
3716
            if (ret == _gf_false) {
3717
                snprintf(errmsg, sizeof(errmsg),
3718
                         "Peer %s,"
3719
                         " which is a part of %s volume, is"
3720
                         " down. Please bring up the peer and"
3721
                         " retry.",
3722
                         down_peerstr, volinfo->volname);
3723
                ret = -1;
3724
                GF_FREE(down_peerstr);
3725
                down_peerstr = NULL;
3726
                goto out;
3727
            }
3728
        }
3729
    }
3730

3731
    switch (type) {
3732
        case GF_GSYNC_OPTION_TYPE_START:
3733
            if (is_template_in_use) {
3734
                snprintf(errmsg, sizeof(errmsg),
3735
                         "state-file entry "
3736
                         "missing in the config file(%s).",
3737
                         conf_path);
3738
                ret = -1;
3739
                goto out;
3740
            }
3741

3742
            ret = glusterd_op_verify_gsync_start_options(
3743
                volinfo, secondary, conf_path, statefile, op_errstr, is_force);
3744
            if (ret)
3745
                goto out;
3746
            ctx = glusterd_op_get_ctx();
3747
            if (ctx) {
3748
                /* gsyncd does a fuse mount to start
3749
                 * the geo-rep session */
3750
                if (!glusterd_is_fuse_available()) {
3751
                    gf_msg("glusterd", GF_LOG_ERROR, errno,
3752
                           GD_MSG_GEO_REP_START_FAILED,
3753
                           "Unable "
3754
                           "to open /dev/fuse (%s), "
3755
                           "geo-replication start failed",
3756
                           strerror(errno));
3757
                    snprintf(errmsg, sizeof(errmsg), "fuse unavailable");
3758
                    ret = -1;
3759
                    goto out;
3760
                }
3761
            }
3762
            break;
3763

3764
        case GF_GSYNC_OPTION_TYPE_STOP:
3765
            if (!is_force) {
3766
                if (is_template_in_use) {
3767
                    snprintf(errmsg, sizeof(errmsg),
3768
                             "state-file entry missing in "
3769
                             "the config file(%s).",
3770
                             conf_path);
3771
                    ret = -1;
3772
                    goto out;
3773
                }
3774

3775
                ret = glusterd_op_verify_gsync_running(volinfo, secondary,
3776
                                                       conf_path, op_errstr);
3777
                if (ret) {
3778
                    ret = glusterd_get_local_brickpaths(volinfo, &path_list);
3779
                    if (!path_list && ret == -1)
3780
                        goto out;
3781
                }
3782

3783
                /* Check for geo-rep session is active or not for
3784
                 * configured user.*/
3785
                ret = glusterd_gsync_get_uuid(secondary, volinfo, uuid);
3786
                if (ret) {
3787
                    snprintf(errmsg, sizeof(errmsg),
3788
                             "Geo-replication session between %s "
3789
                             "and %s does not exist.",
3790
                             volinfo->volname, secondary);
3791
                    ret = -1;
3792
                    goto out;
3793
                }
3794
            }
3795
            break;
3796

3797
        case GF_GSYNC_OPTION_TYPE_PAUSE:
3798
        case GF_GSYNC_OPTION_TYPE_RESUME:
3799
            if (is_template_in_use) {
3800
                snprintf(errmsg, sizeof(errmsg),
3801
                         "state-file entry missing in "
3802
                         "the config file(%s).",
3803
                         conf_path);
3804
                ret = -1;
3805
                goto out;
3806
            }
3807

3808
            ret = glusterd_op_verify_gsync_running(volinfo, secondary,
3809
                                                   conf_path, op_errstr);
3810
            if (ret) {
3811
                ret = glusterd_get_local_brickpaths(volinfo, &path_list);
3812
                if (!path_list && ret == -1)
3813
                    goto out;
3814
            }
3815

3816
            /* Check for geo-rep session is active or not
3817
             * for configured user.*/
3818
            ret = glusterd_gsync_get_uuid(secondary, volinfo, uuid);
3819
            if (ret) {
3820
                snprintf(errmsg, sizeof(errmsg),
3821
                         "Geo-replication"
3822
                         " session between %s and %s does not exist.",
3823
                         volinfo->volname, secondary);
3824
                ret = -1;
3825
                goto out;
3826
            }
3827

3828
            if (!is_force) {
3829
                ret = gd_pause_resume_validation(type, volinfo, secondary,
3830
                                                 statefile, op_errstr);
3831
                if (ret) {
3832
                    ret = glusterd_get_local_brickpaths(volinfo, &path_list);
3833
                    if (!path_list && ret == -1)
3834
                        goto out;
3835
                }
3836
            }
3837
            break;
3838

3839
        case GF_GSYNC_OPTION_TYPE_CONFIG:
3840
            if (is_template_in_use) {
3841
                snprintf(errmsg, sizeof(errmsg),
3842
                         "state-file entry "
3843
                         "missing in the config file(%s).",
3844
                         conf_path);
3845
                ret = -1;
3846
                goto out;
3847
            }
3848

3849
            ret = gsync_verify_config_options(dict, op_errstr, volname);
3850
            goto out;
3851
            break;
3852

3853
        case GF_GSYNC_OPTION_TYPE_DELETE:
3854
            /* Check if the gsync session is still running
3855
             * If so ask the user to stop geo-replication first.*/
3856
            if (is_template_in_use) {
3857
                snprintf(errmsg, sizeof(errmsg),
3858
                         "state-file entry "
3859
                         "missing in the config file(%s).",
3860
                         conf_path);
3861
                ret = -1;
3862
                goto out;
3863
            }
3864

3865
            ret = glusterd_gsync_get_uuid(secondary, volinfo, uuid);
3866
            if (ret) {
3867
                snprintf(errmsg, sizeof(errmsg),
3868
                         "Geo-replication"
3869
                         " session between %s and %s does not exist.",
3870
                         volinfo->volname, secondary);
3871
                ret = -1;
3872
                goto out;
3873
            } else {
3874
                ret = glusterd_check_gsync_running_local(
3875
                    volinfo->volname, secondary, conf_path, &is_running);
3876
                if (_gf_true == is_running) {
3877
                    snprintf(errmsg, sizeof(errmsg),
3878
                             GEOREP
3879
                             " session between %s & %s is "
3880
                             "still active. Please stop the "
3881
                             "session and retry.",
3882
                             volinfo->volname, secondary);
3883
                    ret = -1;
3884
                    goto out;
3885
                }
3886
            }
3887

3888
            ret = glusterd_verify_gsyncd_spawn(volinfo->volname, secondary);
3889
            if (ret) {
3890
                snprintf(errmsg, sizeof(errmsg), "Unable to spawn gsyncd");
3891
            }
3892

3893
            break;
3894
    }
3895

3896
out:
3897

3898
    if (path_list)
3899
        GF_FREE(path_list);
3900

3901
    if (ret && errmsg[0] != '\0') {
3902
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_ERROR, "%s", errmsg);
3903
        *op_errstr = gf_strdup(errmsg);
3904
    }
3905

3906
    gf_msg_debug(this->name, 0, "Returning %d", ret);
3907
    return ret;
3908
}
3909

3910
static int
3911
gd_pause_or_resume_gsync(dict_t *dict, char *primary, char *secondary,
3912
                         char *secondary_host, char *secondary_vol,
3913
                         char *conf_path, char **op_errstr,
3914
                         gf_boolean_t is_pause)
3915
{
3916
    int32_t ret = 0;
3917
    int pfd = -1;
3918
    long pid = 0;
3919
    char pidfile[PATH_MAX] = {
3920
        0,
3921
    };
3922
    char errmsg[PATH_MAX] = "";
3923
    char buf[4096] = {
3924
        0,
3925
    };
3926
    gf_boolean_t is_template_in_use = _gf_false;
3927
    char monitor_status[NAME_MAX] = {
3928
        0,
3929
    };
3930
    char *statefile = NULL;
3931
    xlator_t *this = THIS;
3932

3933
    GF_ASSERT(dict);
3934
    GF_ASSERT(primary);
3935
    GF_ASSERT(secondary);
3936
    GF_ASSERT(secondary_host);
3937
    GF_ASSERT(secondary_vol);
3938
    GF_ASSERT(conf_path);
3939

3940
    pfd = gsyncd_getpidfile(primary, secondary, pidfile, conf_path,
3941
                            &is_template_in_use);
3942
    if (pfd == -2) {
3943
        snprintf(errmsg, sizeof(errmsg),
3944
                 "pid-file entry mising in config file and "
3945
                 "template config file.");
3946
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PIDFILE_NOT_FOUND, "%s",
3947
               errmsg);
3948
        *op_errstr = gf_strdup(errmsg);
3949
        ret = -1;
3950
        goto out;
3951
    }
3952

3953
    if (gsync_status_byfd(pfd) == -1) {
3954
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_ERROR,
3955
               "gsyncd b/w %s & %s is not running", primary, secondary);
3956
        /* monitor gsyncd already dead */
3957
        goto out;
3958
    }
3959

3960
    if (pfd < 0)
3961
        goto out;
3962

3963
    /* Prepare to update status file*/
3964
    ret = dict_get_str(dict, "statefile", &statefile);
3965
    if (ret) {
3966
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
3967
               "Pause/Resume Failed: Unable to fetch statefile path");
3968
        goto out;
3969
    }
3970
    ret = glusterd_gsync_read_frm_status(statefile, monitor_status,
3971
                                         sizeof(monitor_status));
3972
    if (ret <= 0) {
3973
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STAT_FILE_READ_FAILED,
3974
               "Pause/Resume Failed: "
3975
               "Unable to read status file for %s(primary)"
3976
               " %s(primary)",
3977
               primary, secondary);
3978
        goto out;
3979
    }
3980

3981
    ret = sys_read(pfd, buf, sizeof(buf) - 1);
3982
    if (ret > 0) {
3983
        buf[ret] = '\0';
3984
        pid = strtol(buf, NULL, 10);
3985
        if (is_pause) {
3986
            ret = kill(-pid, SIGSTOP);
3987
            if (ret) {
3988
                gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_PID_KILL_FAIL,
3989
                       "Failed"
3990
                       " to pause gsyncd. Error: %s",
3991
                       strerror(errno));
3992
                goto out;
3993
            }
3994
            /*On pause force, if status is already paused
3995
              do not update status again*/
3996
            if (strstr(monitor_status, "Paused"))
3997
                goto out;
3998

3999
            ret = glusterd_create_status_file(
4000
                primary, secondary, secondary_host, secondary_vol, "Paused");
4001
            if (ret) {
4002
                gf_msg(this->name, GF_LOG_ERROR, 0,
4003
                       GD_MSG_UPDATE_STATEFILE_FAILED,
4004
                       "Unable  to update state_file."
4005
                       " Error : %s",
4006
                       strerror(errno));
4007
                /* If status cannot be updated resume back */
4008
                if (kill(-pid, SIGCONT)) {
4009
                    snprintf(errmsg, sizeof(errmsg),
4010
                             "Pause successful but could "
4011
                             "not update status file. "
4012
                             "Please use 'resume force' to"
4013
                             " resume back and retry pause"
4014
                             " to reflect in status");
4015
                    gf_msg(this->name, GF_LOG_ERROR, errno,
4016
                           GD_MSG_PID_KILL_FAIL,
4017
                           "Resume back Failed. Error:"
4018
                           "%s",
4019
                           strerror(errno));
4020
                    *op_errstr = gf_strdup(errmsg);
4021
                }
4022
                goto out;
4023
            }
4024
        } else {
4025
            ret = glusterd_create_status_file(
4026
                primary, secondary, secondary_host, secondary_vol, "Started");
4027
            if (ret) {
4028
                gf_msg(this->name, GF_LOG_ERROR, 0,
4029
                       GD_MSG_UPDATE_STATEFILE_FAILED,
4030
                       "Resume Failed: Unable to update "
4031
                       "state_file. Error : %s",
4032
                       strerror(errno));
4033
                goto out;
4034
            }
4035
            ret = kill(-pid, SIGCONT);
4036
            if (ret) {
4037
                gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_PID_KILL_FAIL,
4038
                       "Resumed Failed: Unable to send"
4039
                       " SIGCONT. Error: %s",
4040
                       strerror(errno));
4041
                /* Process can't be resumed, update status
4042
                 * back to paused. */
4043
                ret = glusterd_create_status_file(primary, secondary,
4044
                                                  secondary_host, secondary_vol,
4045
                                                  monitor_status);
4046
                if (ret) {
4047
                    snprintf(errmsg, sizeof(errmsg),
4048
                             "Resume failed!!! Status "
4049
                             "inconsistent. Please use "
4050
                             "'resume force' to resume and"
4051
                             " reach consistent state");
4052
                    gf_msg(this->name, GF_LOG_ERROR, 0,
4053
                           GD_MSG_STATUS_UPDATE_FAILED,
4054
                           "Updating status back to paused"
4055
                           " Failed. Error: %s",
4056
                           strerror(errno));
4057
                    *op_errstr = gf_strdup(errmsg);
4058
                }
4059
                goto out;
4060
            }
4061
        }
4062
    }
4063
    ret = 0;
4064

4065
out:
4066
    sys_close(pfd);
4067
    /* coverity[INTEGER_OVERFLOW] */
4068
    return ret;
4069
}
4070

4071
static int
4072
stop_gsync(char *primary, char *secondary, char **msg, char *conf_path,
4073
           char **op_errstr, gf_boolean_t is_force)
4074
{
4075
    int32_t ret = 0;
4076
    int pfd = -1;
4077
    long pid = 0;
4078
    char pidfile[PATH_MAX] = {
4079
        0,
4080
    };
4081
    char errmsg[PATH_MAX] = "";
4082
    char buf[4096] = {
4083
        0,
4084
    };
4085
    int i = 0;
4086
    gf_boolean_t is_template_in_use = _gf_false;
4087
    xlator_t *this = THIS;
4088

4089
    pfd = gsyncd_getpidfile(primary, secondary, pidfile, conf_path,
4090
                            &is_template_in_use);
4091
    if (pfd == -2) {
4092
        snprintf(errmsg, sizeof(errmsg) - 1,
4093
                 "pid-file entry mising in config file and "
4094
                 "template config file.");
4095
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PIDFILE_NOT_FOUND, "%s",
4096
               errmsg);
4097
        *op_errstr = gf_strdup(errmsg);
4098
        ret = -1;
4099
        goto out;
4100
    }
4101
    if (gsync_status_byfd(pfd) == -1 && !is_force) {
4102
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_ERROR,
4103
               "gsyncd b/w %s & %s is not running", primary, secondary);
4104
        /* monitor gsyncd already dead */
4105
        goto out;
4106
    }
4107

4108
    if (pfd < 0)
4109
        goto out;
4110

4111
    ret = sys_read(pfd, buf, sizeof(buf) - 1);
4112
    if (ret > 0) {
4113
        buf[ret] = '\0';
4114
        pid = strtol(buf, NULL, 10);
4115
        ret = kill(-pid, SIGTERM);
4116
        if (ret && !is_force) {
4117
            gf_msg(this->name, GF_LOG_WARNING, errno, GD_MSG_PID_KILL_FAIL,
4118
                   "failed to kill gsyncd");
4119
            goto out;
4120
        }
4121
        for (i = 0; i < 20; i++) {
4122
            if (gsync_status_byfd(pfd) == -1) {
4123
                /* monitor gsyncd is dead but worker may
4124
                 * still be alive, give some more time
4125
                 * before SIGKILL (hack)
4126
                 */
4127
                gf_nanosleep(50000 * GF_US_IN_NS);
4128
                break;
4129
            }
4130
            gf_nanosleep(50000 * GF_US_IN_NS);
4131
        }
4132
        kill(-pid, SIGKILL);
4133
        sys_unlink(pidfile);
4134
    }
4135
    ret = 0;
4136

4137
out:
4138
    sys_close(pfd);
4139
    /* coverity[INTEGER_OVERFLOW] */
4140
    return ret;
4141
}
4142

4143
/*
4144
 * glusterd_gsync_op_already_set:
4145
 *      This function checks whether the op_value is same as in the
4146
 *      gsyncd.conf file.
4147
 *
4148
 * RETURN VALUE:
4149
 *      0 : op_value matches the conf file.
4150
 *      1 : op_value does not matches the conf file or op_param not
4151
 *          found in conf file.
4152
 *     -1 : error
4153
 */
4154

4155
int
4156
glusterd_gsync_op_already_set(char *primary, char *secondary, char *conf_path,
4157
                              char *op_name, char *op_value)
4158
{
4159
    dict_t *confd = NULL;
4160
    char *op_val_buf = NULL;
4161
    int32_t op_val_conf = 0;
4162
    int32_t op_val_cli = 0;
4163
    int32_t ret = -1;
4164
    gf_boolean_t is_bool = _gf_true;
4165
    xlator_t *this = THIS;
4166

4167
    confd = dict_new();
4168
    if (!confd) {
4169
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_CREATE_FAIL,
4170
               "Not able to create dict.");
4171
        return -1;
4172
    }
4173

4174
    ret = glusterd_gsync_get_config(primary, secondary, conf_path, confd);
4175
    if (ret) {
4176
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_CONFIG_INFO_FAILED,
4177
               "Unable to get configuration data for %s(primary), "
4178
               "%s(secondary)",
4179
               primary, secondary);
4180
        goto out;
4181
    }
4182

4183
    ret = dict_get_param(confd, op_name, &op_val_buf);
4184
    if (ret) {
4185
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4186
               "Unable to get op_value for %s(primary), %s(secondary). "
4187
               "Please check gsync config file.",
4188
               primary, secondary);
4189
        ret = 1;
4190
        goto out;
4191
    }
4192

4193
    gf_msg_debug(this->name, 0, "val_cli:%s  val_conf:%s", op_value,
4194
                 op_val_buf);
4195

4196
    if (!strcmp(op_val_buf, "true") || !strcmp(op_val_buf, "1") ||
4197
        !strcmp(op_val_buf, "yes")) {
4198
        op_val_conf = 1;
4199
    } else if (!strcmp(op_val_buf, "false") || !strcmp(op_val_buf, "0") ||
4200
               !strcmp(op_val_buf, "no")) {
4201
        op_val_conf = 0;
4202
    } else {
4203
        is_bool = _gf_false;
4204
    }
4205

4206
    if (is_bool) {
4207
        if (op_value && (!strcmp(op_value, "true") || !strcmp(op_value, "1") ||
4208
                         !strcmp(op_value, "yes"))) {
4209
            op_val_cli = 1;
4210
        } else {
4211
            op_val_cli = 0;
4212
        }
4213

4214
        if (op_val_cli == op_val_conf) {
4215
            ret = 0;
4216
            goto out;
4217
        }
4218
    } else {
4219
        if (op_value && !strcmp(op_val_buf, op_value)) {
4220
            ret = 0;
4221
            goto out;
4222
        }
4223
    }
4224

4225
    ret = 1;
4226

4227
out:
4228
    dict_unref(confd);
4229
    return ret;
4230
}
4231

4232
static int
4233
glusterd_gsync_configure(glusterd_volinfo_t *volinfo, char *secondary,
4234
                         char *path_list, dict_t *dict, dict_t *resp_dict,
4235
                         char **op_errstr)
4236
{
4237
    int32_t ret = -1;
4238
    char *op_name = NULL;
4239
    char *op_value = NULL;
4240
    runner_t runner = {
4241
        0,
4242
    };
4243
    glusterd_conf_t *priv = NULL;
4244
    char *subop = NULL;
4245
    char *primary = NULL;
4246
    char *conf_path = NULL;
4247
    char *secondary_host = NULL;
4248
    char *secondary_vol = NULL;
4249
    struct stat stbuf = {
4250
        0,
4251
    };
4252
    gf_boolean_t restart_required = _gf_true;
4253
    char **resopt = NULL;
4254
    gf_boolean_t op_already_set = _gf_false;
4255
    xlator_t *this = THIS;
4256

4257
    GF_ASSERT(secondary);
4258
    GF_ASSERT(op_errstr);
4259
    GF_ASSERT(dict);
4260
    GF_ASSERT(resp_dict);
4261

4262
    ret = dict_get_str(dict, "subop", &subop);
4263
    if (ret != 0)
4264
        goto out;
4265

4266
    if (strcmp(subop, "get") == 0 || strcmp(subop, "get-all") == 0) {
4267
        /* deferred to cli */
4268
        gf_msg_debug(this->name, 0, "Returning 0");
4269
        return 0;
4270
    }
4271

4272
    ret = dict_get_str(dict, "op_name", &op_name);
4273
    if (ret != 0)
4274
        goto out;
4275

4276
    if (strtail(subop, "set")) {
4277
        ret = dict_get_str(dict, "op_value", &op_value);
4278
        if (ret != 0)
4279
            goto out;
4280
    }
4281

4282
    priv = THIS->private;
4283
    if (priv == NULL) {
4284
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
4285
               "priv of glusterd not present");
4286
        *op_errstr = gf_strdup("glusterd defunct");
4287
        goto out;
4288
    }
4289

4290
    ret = dict_get_str(dict, "conf_path", &conf_path);
4291
    if (ret) {
4292
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4293
               "Unable to fetch conf file path.");
4294
        goto out;
4295
    }
4296

4297
    primary = "";
4298
    runinit(&runner);
4299
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
4300
    runner_argprintf(&runner, "%s", conf_path);
4301
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);
4302
    if (volinfo) {
4303
        primary = volinfo->volname;
4304
        runner_argprintf(&runner, ":%s", primary);
4305
    }
4306
    runner_add_arg(&runner, secondary);
4307
    runner_argprintf(&runner, "--config-%s", subop);
4308
    runner_add_arg(&runner, op_name);
4309
    if (op_value) {
4310
        runner_argprintf(&runner, "--value=%s", op_value);
4311
    }
4312

4313
    if (strcmp(op_name, "checkpoint") != 0 && strtail(subop, "set")) {
4314
        ret = glusterd_gsync_op_already_set(primary, secondary, conf_path,
4315
                                            op_name, op_value);
4316
        if (ret == -1) {
4317
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GSYNCD_OP_SET_FAILED,
4318
                   "glusterd_gsync_op_already_set failed.");
4319
            gf_asprintf(op_errstr,
4320
                        GEOREP
4321
                        " config-%s failed for "
4322
                        "%s %s",
4323
                        subop, primary, secondary);
4324
            goto out;
4325
        }
4326
        if (ret == 0) {
4327
            gf_msg_debug(this->name, 0, "op_value is already set");
4328
            op_already_set = _gf_true;
4329
            goto out;
4330
        }
4331
    }
4332

4333
    synclock_unlock(&priv->big_lock);
4334
    ret = runner_run(&runner);
4335
    synclock_lock(&priv->big_lock);
4336
    if (ret) {
4337
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GSYNCD_ERROR,
4338
               "gsyncd failed to %s %s option for "
4339
               "%s %s peers",
4340
               subop, op_name, primary, secondary);
4341

4342
        gf_asprintf(op_errstr, GEOREP " config-%s failed for %s %s", subop,
4343
                    primary, secondary);
4344

4345
        goto out;
4346
    }
4347

4348
    if ((!strcmp(op_name, "state_file")) && (op_value)) {
4349
        ret = sys_lstat(op_value, &stbuf);
4350
        if (ret) {
4351
            ret = dict_get_str(dict, "secondary_host", &secondary_host);
4352
            if (ret) {
4353
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4354
                       "Unable to fetch secondary host.");
4355
                goto out;
4356
            }
4357

4358
            ret = dict_get_str(dict, "secondary_vol", &secondary_vol);
4359
            if (ret) {
4360
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4361
                       "Unable to fetch secondary volume name.");
4362
                goto out;
4363
            }
4364

4365
            ret = glusterd_create_status_file(volinfo->volname, secondary,
4366
                                              secondary_host, secondary_vol,
4367
                                              "Switching Status "
4368
                                              "File");
4369
            if (ret || sys_lstat(op_value, &stbuf)) {
4370
                gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED,
4371
                       "Unable to "
4372
                       "create %s. Error : %s",
4373
                       op_value, strerror(errno));
4374
                ret = -1;
4375
                goto out;
4376
            }
4377
        }
4378
    }
4379

4380
    ret = 0;
4381
    gf_asprintf(op_errstr, "config-%s successful", subop);
4382

4383
out:
4384
    if (!ret && volinfo && !op_already_set) {
4385
        for (resopt = gsync_no_restart_opts; *resopt; resopt++) {
4386
            restart_required = _gf_true;
4387
            if (!strcmp((*resopt), op_name)) {
4388
                restart_required = _gf_false;
4389
                break;
4390
            }
4391
        }
4392

4393
        if (restart_required) {
4394
            ret = glusterd_check_restart_gsync_session(
4395
                volinfo, secondary, resp_dict, path_list, conf_path, 0);
4396
            if (ret)
4397
                *op_errstr = gf_strdup("internal error");
4398
        }
4399
    }
4400

4401
    gf_msg_debug(this->name, 0, "Returning %d", ret);
4402
    return ret;
4403
}
4404

4405
int
4406
glusterd_gsync_read_frm_status(char *path, char *buf, size_t blen)
4407
{
4408
    int ret = 0;
4409
    int status_fd = -1;
4410
    xlator_t *this = THIS;
4411

4412
    GF_ASSERT(path);
4413
    GF_ASSERT(buf);
4414
    status_fd = open(path, O_RDONLY);
4415
    if (status_fd == -1) {
4416
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED,
4417
               "Unable to read gsyncd status file %s", path);
4418
        return -1;
4419
    }
4420
    ret = sys_read(status_fd, buf, blen - 1);
4421

4422
    if (ret > 0) {
4423
        buf[ret] = '\0';
4424
        size_t len = strnlen(buf, ret);
4425
        /* Ensure there is a NUL byte and that it's not the first.  */
4426
        if (len == 0 || len == blen - 1) {
4427
            ret = -1;
4428
        } else {
4429
            char *p = buf + len - 1;
4430
            while (isspace(*p))
4431
                *p-- = '\0';
4432
        }
4433
    } else if (ret == 0)
4434
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_ERROR,
4435
               "Status file of gsyncd is empty");
4436
    else /* ret < 0 */
4437
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_ERROR,
4438
               "Status file of gsyncd is corrupt");
4439

4440
    sys_close(status_fd);
4441
    return ret;
4442
}
4443

4444
static int
4445
dict_get_param(dict_t *dict, char *key, char **param)
4446
{
4447
    char *dk = NULL;
4448
    char *s = NULL;
4449
    char x = '\0';
4450
    int ret = 0;
4451

4452
    if (dict_get_str(dict, key, param) == 0)
4453
        return 0;
4454

4455
    dk = gf_strdup(key);
4456
    if (!dk)
4457
        return -1;
4458

4459
    s = strpbrk(dk, "-_");
4460
    if (!s) {
4461
        ret = -1;
4462
        goto out;
4463
    }
4464
    x = (*s == '-') ? '_' : '-';
4465
    *s++ = x;
4466
    while ((s = strpbrk(s, "-_")))
4467
        *s++ = x;
4468

4469
    ret = dict_get_str(dict, dk, param);
4470
out:
4471
    GF_FREE(dk);
4472
    return ret;
4473
}
4474

4475
int
4476
glusterd_fetch_values_from_config(char *primary, char *secondary,
4477
                                  char *confpath, dict_t *confd,
4478
                                  char **statefile,
4479
                                  char **georep_session_wrkng_dir,
4480
                                  char **socketfile)
4481
{
4482
    int ret = 0;
4483
    xlator_t *this = THIS;
4484

4485
    ret = glusterd_gsync_get_config(primary, secondary, confpath, confd);
4486
    if (ret) {
4487
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_CONFIG_INFO_FAILED,
4488
               "Unable to get configuration data for %s(primary), "
4489
               "%s(secondary)",
4490
               primary, secondary);
4491
        goto out;
4492
    }
4493

4494
    if (statefile) {
4495
        ret = dict_get_param(confd, "state_file", statefile);
4496
        if (ret) {
4497
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4498
                   "Unable to get state_file's name "
4499
                   "for %s(primary), %s(secondary). "
4500
                   "Please check gsync config file.",
4501
                   primary, secondary);
4502
            goto out;
4503
        }
4504
    }
4505

4506
    if (georep_session_wrkng_dir) {
4507
        ret = dict_get_param(confd, "georep_session_working_dir",
4508
                             georep_session_wrkng_dir);
4509
        if (ret) {
4510
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4511
                   "Unable to get geo-rep session's "
4512
                   "working directory name for %s(primary), "
4513
                   "%s(secondary). Please check gsync config file.",
4514
                   primary, secondary);
4515
            goto out;
4516
        }
4517
    }
4518

4519
    if (socketfile) {
4520
        ret = dict_get_param(confd, "state_socket_unencoded", socketfile);
4521
        if (ret) {
4522
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
4523
                   "Unable to get socket file's name "
4524
                   "for %s(primary), %s(secondary). "
4525
                   "Please check gsync config file.",
4526
                   primary, secondary);
4527
            goto out;
4528
        }
4529
    }
4530

4531
    ret = 0;
4532
out:
4533
    gf_msg_debug(this->name, 0, "Returning %d", ret);
4534
    return ret;
4535
}
4536

4537
int
4538
glusterd_read_status_file(glusterd_volinfo_t *volinfo, char *secondary,
4539
                          char *conf_path, dict_t *dict, char *node)
4540
{
4541
    char temp_conf_path[PATH_MAX] = "";
4542
    char *working_conf_path = NULL;
4543
    char *georep_session_wrkng_dir = NULL;
4544
    char *primary = NULL;
4545
    char sts_val_name[1024] = "";
4546
    char monitor_status[NAME_MAX] = "";
4547
    char *statefile = NULL;
4548
    char *socketfile = NULL;
4549
    dict_t *confd = NULL;
4550
    char *secondarykey = NULL;
4551
    char *secondaryentry = NULL;
4552
    char *secondaryuser = NULL;
4553
    char *saveptr = NULL;
4554
    char *temp = NULL;
4555
    char *temp_inp = NULL;
4556
    char *brick_host_uuid = NULL;
4557
    int brick_host_uuid_length = 0;
4558
    int gsync_count = 0;
4559
    int ret = 0;
4560
    glusterd_brickinfo_t *brickinfo = NULL;
4561
    gf_gsync_status_t *sts_val = NULL;
4562
    gf_boolean_t is_template_in_use = _gf_false;
4563
    glusterd_conf_t *priv = NULL;
4564
    struct stat stbuf = {
4565
        0,
4566
    };
4567
    xlator_t *this = THIS;
4568
    int32_t len = 0;
4569

4570
    priv = this->private;
4571
    GF_ASSERT(priv);
4572
    GF_ASSERT(volinfo);
4573
    GF_ASSERT(conf_path);
4574

4575
    primary = volinfo->volname;
4576

4577
    confd = dict_new();
4578
    if (!confd) {
4579
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_CREATE_FAIL,
4580
               "Not able to create dict.");
4581
        ret = -1;
4582
        goto out;
4583
    }
4584

4585
    len = snprintf(temp_conf_path, sizeof(temp_conf_path),
4586
                   "%s/" GSYNC_CONF_TEMPLATE, priv->workdir);
4587
    if ((len < 0) || (len >= sizeof(temp_conf_path))) {
4588
        ret = -1;
4589
        goto out;
4590
    }
4591

4592
    ret = sys_lstat(conf_path, &stbuf);
4593
    if (!ret) {
4594
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_CONFIG_INFO,
4595
               "Using passed config template(%s).", conf_path);
4596
        working_conf_path = conf_path;
4597
    } else {
4598
        gf_msg(this->name, GF_LOG_WARNING, ENOENT, GD_MSG_FILE_OP_FAILED,
4599
               "Config file (%s) missing. Looking for template "
4600
               "config file (%s)",
4601
               conf_path, temp_conf_path);
4602
        ret = sys_lstat(temp_conf_path, &stbuf);
4603
        if (ret) {
4604
            gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
4605
                   "Template "
4606
                   "config file (%s) missing.",
4607
                   temp_conf_path);
4608
            goto out;
4609
        }
4610
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DEFAULT_TEMP_CONFIG,
4611
               "Using default config template(%s).", temp_conf_path);
4612
        working_conf_path = temp_conf_path;
4613
        is_template_in_use = _gf_true;
4614
    }
4615

4616
fetch_data:
4617
    ret = glusterd_fetch_values_from_config(
4618
        primary, secondary, working_conf_path, confd, &statefile,
4619
        &georep_session_wrkng_dir, &socketfile);
4620
    if (ret) {
4621
        if (is_template_in_use == _gf_false) {
4622
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FETCH_CONFIG_VAL_FAILED,
4623
                   "Unable to fetch config values "
4624
                   "for %s(primary), %s(secondary). "
4625
                   "Trying default config template",
4626
                   primary, secondary);
4627
            working_conf_path = temp_conf_path;
4628
            is_template_in_use = _gf_true;
4629
            goto fetch_data;
4630
        } else {
4631
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FETCH_CONFIG_VAL_FAILED,
4632
                   "Unable to "
4633
                   "fetch config values for %s(primary), "
4634
                   "%s(secondary)",
4635
                   primary, secondary);
4636
            goto out;
4637
        }
4638
    }
4639

4640
    ret = glusterd_gsync_read_frm_status(statefile, monitor_status,
4641
                                         sizeof(monitor_status));
4642
    if (ret <= 0) {
4643
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STAT_FILE_READ_FAILED,
4644
               "Unable to read the status file for %s(primary), "
4645
               "%s(secondary) statefile: %s",
4646
               primary, secondary, statefile);
4647
        snprintf(monitor_status, sizeof(monitor_status), "defunct");
4648
    }
4649

4650
    ret = dict_get_int32(dict, "gsync-count", &gsync_count);
4651
    if (ret)
4652
        gsync_count = 0;
4653

4654
    cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
4655
    {
4656
        if (gf_uuid_compare(brickinfo->uuid, MY_UUID))
4657
            continue;
4658

4659
        sts_val = GF_CALLOC(1, sizeof(gf_gsync_status_t),
4660
                            gf_common_mt_gsync_status_t);
4661
        if (!sts_val) {
4662
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
4663
                   "Out Of Memory");
4664
            goto out;
4665
        }
4666

4667
        /* Secondary Key */
4668
        ret = glusterd_get_secondary(volinfo, secondary, &secondarykey);
4669
        if (ret < 0) {
4670
            GF_FREE(sts_val);
4671
            goto out;
4672
        }
4673
        memcpy(sts_val->secondarykey, secondarykey, strlen(secondarykey));
4674
        sts_val->secondarykey[strlen(secondarykey)] = '\0';
4675

4676
        /* Primary Volume */
4677
        memcpy(sts_val->primary, primary, strlen(primary));
4678
        sts_val->primary[strlen(primary)] = '\0';
4679

4680
        /* Primary Brick Node */
4681
        memcpy(sts_val->node, brickinfo->hostname, strlen(brickinfo->hostname));
4682
        sts_val->node[strlen(brickinfo->hostname)] = '\0';
4683

4684
        /* Primary Brick Path */
4685
        memcpy(sts_val->brick, brickinfo->path, strlen(brickinfo->path));
4686
        sts_val->brick[strlen(brickinfo->path)] = '\0';
4687

4688
        /* Brick Host UUID */
4689
        brick_host_uuid = uuid_utoa(brickinfo->uuid);
4690
        brick_host_uuid_length = strlen(brick_host_uuid);
4691
        memcpy(sts_val->brick_host_uuid, brick_host_uuid,
4692
               brick_host_uuid_length);
4693
        sts_val->brick_host_uuid[brick_host_uuid_length] = '\0';
4694

4695
        /* Secondary */
4696
        memcpy(sts_val->secondary, secondary, strlen(secondary));
4697
        sts_val->secondary[strlen(secondary)] = '\0';
4698

4699
        snprintf(sts_val->secondary_node, sizeof(sts_val->secondary_node),
4700
                 "N/A");
4701

4702
        snprintf(sts_val->worker_status, sizeof(sts_val->worker_status), "N/A");
4703

4704
        snprintf(sts_val->crawl_status, sizeof(sts_val->crawl_status), "N/A");
4705

4706
        snprintf(sts_val->last_synced, sizeof(sts_val->last_synced), "N/A");
4707

4708
        snprintf(sts_val->last_synced_utc, sizeof(sts_val->last_synced_utc),
4709
                 "N/A");
4710

4711
        snprintf(sts_val->entry, sizeof(sts_val->entry), "N/A");
4712

4713
        snprintf(sts_val->data, sizeof(sts_val->data), "N/A");
4714

4715
        snprintf(sts_val->meta, sizeof(sts_val->meta), "N/A");
4716

4717
        snprintf(sts_val->failures, sizeof(sts_val->failures), "N/A");
4718

4719
        snprintf(sts_val->checkpoint_time, sizeof(sts_val->checkpoint_time),
4720
                 "N/A");
4721

4722
        snprintf(sts_val->checkpoint_time_utc,
4723
                 sizeof(sts_val->checkpoint_time_utc), "N/A");
4724

4725
        snprintf(sts_val->checkpoint_completed,
4726
                 sizeof(sts_val->checkpoint_completed), "N/A");
4727

4728
        snprintf(sts_val->checkpoint_completion_time,
4729
                 sizeof(sts_val->checkpoint_completion_time), "N/A");
4730

4731
        snprintf(sts_val->checkpoint_completion_time_utc,
4732
                 sizeof(sts_val->checkpoint_completion_time_utc), "N/A");
4733

4734
        /* Get all the other values from Gsyncd */
4735
        ret = glusterd_gsync_get_status(primary, secondary, conf_path,
4736
                                        brickinfo->path, sts_val);
4737

4738
        if (ret) {
4739
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_STATUS_DATA_FAIL,
4740
                   "Unable to get status data "
4741
                   "for %s(primary), %s(secondary), %s(brick)",
4742
                   primary, secondary, brickinfo->path);
4743
            ret = -1;
4744
            goto out;
4745
        }
4746

4747
        if (is_template_in_use) {
4748
            snprintf(sts_val->worker_status, sizeof(sts_val->worker_status),
4749
                     "Config Corrupted");
4750
        }
4751

4752
        ret = dict_get_str(volinfo->gsync_secondaries, secondarykey,
4753
                           &secondaryentry);
4754
        if (ret < 0) {
4755
            GF_FREE(sts_val);
4756
            goto out;
4757
        }
4758

4759
        memcpy(sts_val->session_secondary, secondaryentry,
4760
               strlen(secondaryentry));
4761
        sts_val->session_secondary[strlen(secondaryentry)] = '\0';
4762

4763
        temp_inp = gf_strdup(secondaryentry);
4764
        if (!temp_inp)
4765
            goto out;
4766

4767
        if (strstr(temp_inp, "@") == NULL) {
4768
            secondaryuser = "root";
4769
        } else {
4770
            temp = strtok_r(temp_inp, "//", &saveptr);
4771
            temp = strtok_r(NULL, "/", &saveptr);
4772
            secondaryuser = strtok_r(temp, "@", &saveptr);
4773
        }
4774
        memcpy(sts_val->secondary_user, secondaryuser, strlen(secondaryuser));
4775
        sts_val->secondary_user[strlen(secondaryuser)] = '\0';
4776

4777
        snprintf(sts_val_name, sizeof(sts_val_name), "status_value%d",
4778
                 gsync_count);
4779
        ret = dict_set_bin(dict, sts_val_name, sts_val,
4780
                           sizeof(gf_gsync_status_t));
4781
        if (ret) {
4782
            GF_FREE(sts_val);
4783
            goto out;
4784
        }
4785

4786
        gsync_count++;
4787
        sts_val = NULL;
4788
    }
4789

4790
    ret = dict_set_int32(dict, "gsync-count", gsync_count);
4791

4792
out:
4793
    GF_FREE(temp_inp);
4794
    if (confd)
4795
        dict_unref(confd);
4796

4797
    return ret;
4798
}
4799

4800
int
4801
glusterd_check_restart_gsync_session(glusterd_volinfo_t *volinfo,
4802
                                     char *secondary, dict_t *resp_dict,
4803
                                     char *path_list, char *conf_path,
4804
                                     gf_boolean_t is_force)
4805
{
4806
    int ret = 0;
4807
    char *status_msg = NULL;
4808
    gf_boolean_t is_running = _gf_false;
4809
    char *op_errstr = NULL;
4810
    char *key = NULL;
4811
    xlator_t *this = THIS;
4812

4813
    GF_ASSERT(volinfo);
4814
    GF_ASSERT(secondary);
4815

4816
    key = secondary;
4817

4818
    ret = glusterd_check_gsync_running_local(volinfo->volname, secondary,
4819
                                             conf_path, &is_running);
4820
    if (!ret && (_gf_true != is_running))
4821
        /* gsynd not running, nothing to do */
4822
        goto out;
4823

4824
    ret = stop_gsync(volinfo->volname, secondary, &status_msg, conf_path,
4825
                     &op_errstr, is_force);
4826
    if (ret == 0 && status_msg)
4827
        ret = dict_set_str(resp_dict, "gsync-status", status_msg);
4828
    if (ret == 0) {
4829
        dict_del(volinfo->gsync_active_secondaries, key);
4830
        ret = glusterd_start_gsync(volinfo, secondary, path_list, conf_path,
4831
                                   uuid_utoa(MY_UUID), NULL, _gf_false);
4832
        if (!ret) {
4833
            /* Add secondary to the dict indicating geo-rep session is
4834
             * running.*/
4835
            ret = dict_set_dynstr_with_alloc(volinfo->gsync_active_secondaries,
4836
                                             key, "running");
4837
            if (ret) {
4838
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
4839
                       "Unable to set"
4840
                       " key:%s value:running in dict. But "
4841
                       "the config succeeded.",
4842
                       key);
4843
                goto out;
4844
            }
4845
        }
4846
    }
4847

4848
out:
4849
    gf_msg_debug(this->name, 0, "Returning %d", ret);
4850
    if (op_errstr)
4851
        GF_FREE(op_errstr);
4852
    return ret;
4853
}
4854

4855
static int32_t
4856
glusterd_marker_changelog_create_volfile(glusterd_volinfo_t *volinfo)
4857
{
4858
    int32_t ret = 0;
4859

4860
    ret = glusterd_create_volfiles_and_notify_services(volinfo);
4861
    if (ret) {
4862
        gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_VOLFILE_CREATE_FAIL,
4863
               "Unable to create volfile for setting of marker "
4864
               "while '" GEOREP " start'");
4865
        ret = -1;
4866
        goto out;
4867
    }
4868

4869
    ret = glusterd_store_volinfo(volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
4870
    if (ret)
4871
        goto out;
4872

4873
    if (GLUSTERD_STATUS_STARTED == volinfo->status) {
4874
        ret = glusterd_svcs_manager(volinfo);
4875
        goto out;
4876
    }
4877
    ret = 0;
4878
out:
4879
    return ret;
4880
}
4881

4882
static int
4883
glusterd_set_gsync_knob(glusterd_volinfo_t *volinfo, char *key, int *vc)
4884
{
4885
    int ret = -1;
4886
    int conf_enabled = _gf_false;
4887
    xlator_t *this = THIS;
4888

4889
    conf_enabled = glusterd_volinfo_get_boolean(volinfo, key);
4890
    if (conf_enabled == -1) {
4891
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GET_KEY_FAILED,
4892
               "failed to get key %s from volinfo", key);
4893
        goto out;
4894
    }
4895

4896
    ret = 0;
4897
    if (conf_enabled == _gf_false) {
4898
        *vc = 1;
4899
        ret = glusterd_gsync_volinfo_dict_set(volinfo, key, "on");
4900
    }
4901

4902
out:
4903
    gf_msg_debug(this->name, 0, "Returning %d", ret);
4904
    return ret;
4905
}
4906

4907
static int
4908
glusterd_set_gsync_confs(glusterd_volinfo_t *volinfo)
4909
{
4910
    int ret = -1;
4911
    int volfile_changed = 0;
4912

4913
    ret = glusterd_set_gsync_knob(volinfo, VKEY_MARKER_XTIME, &volfile_changed);
4914
    if (ret)
4915
        goto out;
4916

4917
    /**
4918
     * enable ignore-pid-check blindly as it could be needed for
4919
     * cascading setups.
4920
     */
4921
    ret = glusterd_set_gsync_knob(volinfo, VKEY_MARKER_XTIME_FORCE,
4922
                                  &volfile_changed);
4923
    if (ret)
4924
        goto out;
4925

4926
    ret = glusterd_set_gsync_knob(volinfo, VKEY_CHANGELOG, &volfile_changed);
4927
    if (ret)
4928
        goto out;
4929

4930
    if (volfile_changed)
4931
        ret = glusterd_marker_changelog_create_volfile(volinfo);
4932

4933
out:
4934
    return ret;
4935
}
4936

4937
static int
4938
glusterd_get_gsync_status_mst_slv(glusterd_volinfo_t *volinfo, char *secondary,
4939
                                  char *conf_path, dict_t *rsp_dict, char *node)
4940
{
4941
    char *statefile = NULL;
4942
    uuid_t uuid = {
4943
        0,
4944
    };
4945
    int ret = 0;
4946
    gf_boolean_t is_template_in_use = _gf_false;
4947
    struct stat stbuf = {
4948
        0,
4949
    };
4950
    xlator_t *this = THIS;
4951

4952
    GF_ASSERT(volinfo);
4953
    GF_ASSERT(secondary);
4954

4955
    ret = glusterd_gsync_get_uuid(secondary, volinfo, uuid);
4956
    if (ret) {
4957
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_SESSION_INACTIVE,
4958
               "geo-replication status %s %s : session is not "
4959
               "active",
4960
               volinfo->volname, secondary);
4961

4962
        ret = glusterd_get_statefile_name(volinfo, secondary, conf_path,
4963
                                          &statefile, &is_template_in_use);
4964
        if (ret) {
4965
            if (!strstr(secondary, "::"))
4966
                gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_SECONDARY_URL_INVALID,
4967
                       "%s is not a valid secondary url.", secondary);
4968
            else
4969
                gf_msg(this->name, GF_LOG_INFO, 0,
4970
                       GD_MSG_GET_STATEFILE_NAME_FAILED,
4971
                       "Unable to get statefile's name");
4972
            ret = 0;
4973
            goto out;
4974
        }
4975

4976
        ret = sys_lstat(statefile, &stbuf);
4977
        if (ret) {
4978
            gf_msg(this->name, GF_LOG_INFO, ENOENT, GD_MSG_FILE_OP_FAILED,
4979
                   "%s statefile not present.", statefile);
4980
            ret = 0;
4981
            goto out;
4982
        }
4983
    }
4984

4985
    ret = glusterd_read_status_file(volinfo, secondary, conf_path, rsp_dict,
4986
                                    node);
4987
out:
4988
    if (statefile)
4989
        GF_FREE(statefile);
4990

4991
    gf_msg_debug(this->name, 0, "Returning with %d", ret);
4992
    return ret;
4993
}
4994

4995
int
4996
glusterd_get_gsync_status_mst(glusterd_volinfo_t *volinfo, dict_t *rsp_dict,
4997
                              char *node)
4998
{
4999
    glusterd_gsync_status_temp_t param = {
5000
        0,
5001
    };
5002

5003
    GF_ASSERT(volinfo);
5004

5005
    param.rsp_dict = rsp_dict;
5006
    param.volinfo = volinfo;
5007
    param.node = node;
5008
    dict_foreach(volinfo->gsync_secondaries, _get_status_mst_slv, &param);
5009

5010
    return 0;
5011
}
5012

5013
static int
5014
glusterd_get_gsync_status_all(dict_t *rsp_dict, char *node)
5015
{
5016
    int32_t ret = 0;
5017
    glusterd_conf_t *priv = NULL;
5018
    glusterd_volinfo_t *volinfo = NULL;
5019
    xlator_t *this = THIS;
5020

5021
    priv = this->private;
5022

5023
    GF_ASSERT(priv);
5024

5025
    cds_list_for_each_entry(volinfo, &priv->volumes, vol_list)
5026
    {
5027
        ret = glusterd_get_gsync_status_mst(volinfo, rsp_dict, node);
5028
        if (ret)
5029
            goto out;
5030
    }
5031

5032
out:
5033
    gf_msg_debug(this->name, 0, "Returning with %d", ret);
5034
    return ret;
5035
}
5036

5037
static int
5038
glusterd_get_gsync_status(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
5039
{
5040
    char *secondary = NULL;
5041
    char *volname = NULL;
5042
    char *conf_path = NULL;
5043
    char errmsg[PATH_MAX] = {
5044
        0,
5045
    };
5046
    glusterd_volinfo_t *volinfo = NULL;
5047
    int ret = 0;
5048
    char *my_hostname = gf_gethostname();
5049
    xlator_t *this = THIS;
5050

5051
    ret = dict_get_str(dict, "primary", &volname);
5052
    if (ret < 0) {
5053
        ret = glusterd_get_gsync_status_all(rsp_dict, my_hostname);
5054
        goto out;
5055
    }
5056

5057
    ret = glusterd_volinfo_find(volname, &volinfo);
5058
    if (ret) {
5059
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOL_NOT_FOUND,
5060
               "volume name does not exist");
5061
        snprintf(errmsg, sizeof(errmsg),
5062
                 "Volume name %s does not"
5063
                 " exist",
5064
                 volname);
5065
        *op_errstr = gf_strdup(errmsg);
5066
        goto out;
5067
    }
5068

5069
    ret = dict_get_str(dict, "secondary", &secondary);
5070
    if (ret < 0) {
5071
        ret = glusterd_get_gsync_status_mst(volinfo, rsp_dict, my_hostname);
5072
        goto out;
5073
    }
5074

5075
    ret = dict_get_str(dict, "conf_path", &conf_path);
5076
    if (ret) {
5077
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5078
               "Unable to fetch conf file path.");
5079
        goto out;
5080
    }
5081

5082
    ret = glusterd_get_gsync_status_mst_slv(volinfo, secondary, conf_path,
5083
                                            rsp_dict, my_hostname);
5084

5085
out:
5086
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5087
    return ret;
5088
}
5089

5090
static int
5091
glusterd_gsync_delete(glusterd_volinfo_t *volinfo, char *secondary,
5092
                      char *secondary_host, char *secondary_vol,
5093
                      char *path_list, dict_t *dict, dict_t *resp_dict,
5094
                      char **op_errstr)
5095
{
5096
    int32_t ret = -1;
5097
    runner_t runner = {
5098
        0,
5099
    };
5100
    glusterd_conf_t *priv = NULL;
5101
    char *primary = NULL;
5102
    char *gl_workdir = NULL;
5103
    char geo_rep_dir[PATH_MAX] = "";
5104
    char *conf_path = NULL;
5105
    xlator_t *this = THIS;
5106
    uint32_t reset_sync_time = _gf_false;
5107

5108
    GF_ASSERT(secondary);
5109
    GF_ASSERT(secondary_host);
5110
    GF_ASSERT(secondary_vol);
5111
    GF_ASSERT(op_errstr);
5112
    GF_ASSERT(dict);
5113
    GF_ASSERT(resp_dict);
5114

5115
    priv = this->private;
5116
    if (priv == NULL) {
5117
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
5118
               "priv of glusterd not present");
5119
        *op_errstr = gf_strdup("glusterd defunct");
5120
        goto out;
5121
    }
5122

5123
    ret = dict_get_str(dict, "conf_path", &conf_path);
5124
    if (ret) {
5125
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5126
               "Unable to fetch conf file path.");
5127
        goto out;
5128
    }
5129

5130
    gl_workdir = priv->workdir;
5131
    primary = "";
5132
    runinit(&runner);
5133
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "--delete", "-c", NULL);
5134
    runner_argprintf(&runner, "%s", conf_path);
5135
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);
5136

5137
    runner_argprintf(&runner, "--path-list=%s", path_list);
5138

5139
    ret = dict_get_uint32(dict, "reset-sync-time", &reset_sync_time);
5140
    if (!ret && reset_sync_time) {
5141
        runner_add_args(&runner, "--reset-sync-time", NULL);
5142
    }
5143

5144
    if (volinfo) {
5145
        primary = volinfo->volname;
5146
        runner_argprintf(&runner, ":%s", primary);
5147
    }
5148
    runner_add_arg(&runner, secondary);
5149
    runner_redir(&runner, STDOUT_FILENO, RUN_PIPE);
5150
    synclock_unlock(&priv->big_lock);
5151
    ret = runner_run(&runner);
5152
    synclock_lock(&priv->big_lock);
5153
    if (ret) {
5154
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SESSION_DEL_FAILED,
5155
               "gsyncd failed to delete session info for %s and "
5156
               "%s peers",
5157
               primary, secondary);
5158

5159
        gf_asprintf(op_errstr,
5160
                    "gsyncd failed to "
5161
                    "delete session info for %s and %s peers",
5162
                    primary, secondary);
5163

5164
        goto out;
5165
    }
5166

5167
    ret = snprintf(geo_rep_dir, sizeof(geo_rep_dir) - 1,
5168
                   "%s/" GEOREP "/%s_%s_%s", gl_workdir, volinfo->volname,
5169
                   secondary_host, secondary_vol);
5170
    geo_rep_dir[ret] = '\0';
5171

5172
    ret = sys_rmdir(geo_rep_dir);
5173
    if (ret) {
5174
        if (errno == ENOENT)
5175
            gf_msg_debug(this->name, 0, "Geo Rep Dir(%s) Not Present.",
5176
                         geo_rep_dir);
5177
        else {
5178
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
5179
                   "Unable to delete Geo Rep Dir(%s). Error: %s", geo_rep_dir,
5180
                   strerror(errno));
5181
            goto out;
5182
        }
5183
    }
5184

5185
    ret = 0;
5186

5187
    gf_asprintf(op_errstr, "delete successful");
5188

5189
out:
5190
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5191
    return ret;
5192
}
5193

5194
int
5195
glusterd_op_sys_exec(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
5196
{
5197
    char buf[PATH_MAX] = "";
5198
    char cmd_arg_name[PATH_MAX] = "";
5199
    char output_name[PATH_MAX] = "";
5200
    char errmsg[PATH_MAX] = "";
5201
    char *ptr = NULL;
5202
    char *bufp = NULL;
5203
    char *command = NULL;
5204
    char **cmd_args = NULL;
5205
    int ret = -1;
5206
    int i = -1;
5207
    int cmd_args_count = 0;
5208
    int output_count = 0;
5209
    glusterd_conf_t *priv = NULL;
5210
    runner_t runner = {
5211
        0,
5212
    };
5213
    xlator_t *this = THIS;
5214

5215
    GF_ASSERT(dict);
5216
    GF_ASSERT(op_errstr);
5217
    GF_ASSERT(rsp_dict);
5218

5219
    priv = this->private;
5220
    if (priv == NULL) {
5221
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
5222
               "priv of glusterd not present");
5223
        *op_errstr = gf_strdup("glusterd defunct");
5224
        goto out;
5225
    }
5226

5227
    ret = dict_get_str(dict, "command", &command);
5228
    if (ret) {
5229
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5230
               "Unable to get command from dict");
5231
        goto out;
5232
    }
5233

5234
    ret = dict_get_int32(dict, "cmd_args_count", &cmd_args_count);
5235
    if (ret)
5236
        gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DICT_GET_FAILED,
5237
               "No cmd_args_count");
5238

5239
    if (cmd_args_count) {
5240
        cmd_args = GF_CALLOC(cmd_args_count, sizeof(char *), gf_common_mt_char);
5241
        if (!cmd_args) {
5242
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
5243
                   "Unable to calloc. Errno = %s", strerror(errno));
5244
            goto out;
5245
        }
5246

5247
        for (i = 1; i <= cmd_args_count; i++) {
5248
            snprintf(cmd_arg_name, sizeof(cmd_arg_name), "cmd_arg_%d", i);
5249
            ret = dict_get_str(dict, cmd_arg_name, &cmd_args[i - 1]);
5250
            if (ret) {
5251
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5252
                       "Unable to get"
5253
                       " %s in dict",
5254
                       cmd_arg_name);
5255
                goto out;
5256
            }
5257
        }
5258
    }
5259

5260
    runinit(&runner);
5261
    runner_argprintf(&runner, GSYNCD_PREFIX "/peer_%s", command);
5262
    for (i = 0; i < cmd_args_count; i++)
5263
        runner_add_arg(&runner, cmd_args[i]);
5264
    runner_redir(&runner, STDOUT_FILENO, RUN_PIPE);
5265
    synclock_unlock(&priv->big_lock);
5266
    ret = runner_start(&runner);
5267
    if (ret == -1) {
5268
        snprintf(errmsg, sizeof(errmsg),
5269
                 "Unable to "
5270
                 "execute command. Error : %s",
5271
                 strerror(errno));
5272
        *op_errstr = gf_strdup(errmsg);
5273
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_CMD_EXEC_FAIL, "%s", errmsg);
5274
        ret = -1;
5275
        synclock_lock(&priv->big_lock);
5276
        goto out;
5277
    }
5278

5279
    do {
5280
        ptr = fgets(buf, sizeof(buf), runner_chio(&runner, STDOUT_FILENO));
5281
        if (ptr) {
5282
            ret = dict_get_int32(rsp_dict, "output_count", &output_count);
5283
            if (ret)
5284
                output_count = 1;
5285
            else
5286
                output_count++;
5287
            snprintf(output_name, sizeof(output_name), "output_%d",
5288
                     output_count);
5289
            if (buf[strlen(buf) - 1] == '\n')
5290
                buf[strlen(buf) - 1] = '\0';
5291
            bufp = gf_strdup(buf);
5292
            if (!bufp)
5293
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STRDUP_FAILED,
5294
                       "gf_strdup failed.");
5295
            ret = dict_set_dynstr(rsp_dict, output_name, bufp);
5296
            if (ret) {
5297
                GF_FREE(bufp);
5298
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5299
                       "output set "
5300
                       "failed.");
5301
            }
5302
            ret = dict_set_int32(rsp_dict, "output_count", output_count);
5303
            if (ret)
5304
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5305
                       "output_count "
5306
                       "set failed.");
5307
        }
5308
    } while (ptr);
5309

5310
    ret = runner_end(&runner);
5311
    if (ret) {
5312
        snprintf(errmsg, sizeof(errmsg),
5313
                 "Unable to "
5314
                 "end. Error : %s",
5315
                 strerror(errno));
5316
        *op_errstr = gf_strdup(errmsg);
5317
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNABLE_TO_END, "%s", errmsg);
5318
        ret = -1;
5319
        synclock_lock(&priv->big_lock);
5320
        goto out;
5321
    }
5322
    synclock_lock(&priv->big_lock);
5323

5324
    ret = 0;
5325
out:
5326
    if (cmd_args) {
5327
        GF_FREE(cmd_args);
5328
        cmd_args = NULL;
5329
    }
5330

5331
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5332
    return ret;
5333
}
5334

5335
int
5336
glusterd_op_copy_file(dict_t *dict, char **op_errstr)
5337
{
5338
    char abs_filename[PATH_MAX] = "";
5339
    char errmsg[PATH_MAX] = "";
5340
    char *filename = NULL;
5341
    char *host_uuid = NULL;
5342
    char uuid_str[64] = {0};
5343
    char *contents = NULL;
5344
    char buf[4096] = "";
5345
    int ret = -1;
5346
    int fd = -1;
5347
    int bytes_writen = 0;
5348
    int bytes_read = 0;
5349
    int contents_size = -1;
5350
    int file_mode = -1;
5351
    glusterd_conf_t *priv = NULL;
5352
    struct stat stbuf = {
5353
        0,
5354
    };
5355
    gf_boolean_t free_contents = _gf_true;
5356
    xlator_t *this = THIS;
5357
    int32_t len = 0;
5358

5359
    priv = this->private;
5360
    if (priv == NULL) {
5361
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GLUSTERD_PRIV_NOT_FOUND,
5362
               "priv of glusterd not present");
5363
        *op_errstr = gf_strdup("glusterd defunct");
5364
        goto out;
5365
    }
5366

5367
    ret = dict_get_str(dict, "host-uuid", &host_uuid);
5368
    if (ret < 0)
5369
        goto out;
5370

5371
    ret = dict_get_str(dict, "source", &filename);
5372
    if (ret < 0) {
5373
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5374
               "Unable to fetch filename from dict.");
5375
        *op_errstr = gf_strdup("command unsuccessful");
5376
        goto out;
5377
    }
5378
    len = snprintf(abs_filename, sizeof(abs_filename), "%s/%s", priv->workdir,
5379
                   filename);
5380
    if ((len < 0) || (len >= sizeof(abs_filename))) {
5381
        ret = -1;
5382
        goto out;
5383
    }
5384

5385
    uuid_utoa_r(MY_UUID, uuid_str);
5386
    if (!strcmp(uuid_str, host_uuid)) {
5387
        ret = sys_lstat(abs_filename, &stbuf);
5388
        if (ret) {
5389
            len = snprintf(errmsg, sizeof(errmsg),
5390
                           "Source file "
5391
                           "does not exist in %s",
5392
                           priv->workdir);
5393
            if (len < 0) {
5394
                strcpy(errmsg, "<error>");
5395
            }
5396
            *op_errstr = gf_strdup(errmsg);
5397
            gf_msg(this->name, GF_LOG_ERROR, ENOENT, GD_MSG_FILE_OP_FAILED,
5398
                   "%s", errmsg);
5399
            goto out;
5400
        }
5401

5402
        contents = GF_CALLOC(1, stbuf.st_size + 1, gf_common_mt_char);
5403
        if (!contents) {
5404
            snprintf(errmsg, sizeof(errmsg), "Unable to allocate memory");
5405
            *op_errstr = gf_strdup(errmsg);
5406
            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, "%s",
5407
                   errmsg);
5408
            ret = -1;
5409
            goto out;
5410
        }
5411

5412
        fd = open(abs_filename, O_RDONLY);
5413
        if (fd < 0) {
5414
            len = snprintf(errmsg, sizeof(errmsg), "Unable to open %s",
5415
                           abs_filename);
5416
            if (len < 0) {
5417
                strcpy(errmsg, "<error>");
5418
            }
5419
            *op_errstr = gf_strdup(errmsg);
5420
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, "%s",
5421
                   errmsg);
5422
            ret = -1;
5423
            goto out;
5424
        }
5425

5426
        do {
5427
            ret = sys_read(fd, buf, sizeof(buf) - 1);
5428
            if (ret > 0) {
5429
                buf[ret] = '\0';
5430
                memcpy(contents + bytes_read, buf, ret);
5431
                bytes_read += ret;
5432
            }
5433
        } while (ret > 0);
5434

5435
        if (bytes_read != stbuf.st_size) {
5436
            len = snprintf(errmsg, sizeof(errmsg),
5437
                           "Unable to read all the data from %s", abs_filename);
5438
            if (len < 0) {
5439
                strcpy(errmsg, "<error>");
5440
            }
5441
            *op_errstr = gf_strdup(errmsg);
5442
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_READ_ERROR, "%s",
5443
                   errmsg);
5444
            ret = -1;
5445
            goto out;
5446
        }
5447

5448
        ret = dict_set_int32(dict, "contents_size", stbuf.st_size);
5449
        if (ret) {
5450
            snprintf(errmsg, sizeof(errmsg),
5451
                     "Unable to set"
5452
                     " contents size in dict.");
5453
            *op_errstr = gf_strdup(errmsg);
5454
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "%s",
5455
                   errmsg);
5456
            goto out;
5457
        }
5458

5459
        ret = dict_set_int32(dict, "file_mode", (int32_t)stbuf.st_mode);
5460
        if (ret) {
5461
            snprintf(errmsg, sizeof(errmsg),
5462
                     "Unable to set"
5463
                     " file mode in dict.");
5464
            *op_errstr = gf_strdup(errmsg);
5465
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "%s",
5466
                   errmsg);
5467
            goto out;
5468
        }
5469

5470
        ret = dict_set_bin(dict, "common_pem_contents", contents,
5471
                           stbuf.st_size);
5472
        if (ret) {
5473
            snprintf(errmsg, sizeof(errmsg),
5474
                     "Unable to set"
5475
                     " pem contents in dict.");
5476
            *op_errstr = gf_strdup(errmsg);
5477
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "%s",
5478
                   errmsg);
5479
            goto out;
5480
        }
5481
        free_contents = _gf_false;
5482
    } else {
5483
        free_contents = _gf_false;
5484
        ret = dict_get_bin(dict, "common_pem_contents", (void **)&contents);
5485
        if (ret) {
5486
            snprintf(errmsg, sizeof(errmsg),
5487
                     "Unable to get"
5488
                     " pem contents in dict.");
5489
            *op_errstr = gf_strdup(errmsg);
5490
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
5491
                   errmsg);
5492
            goto out;
5493
        }
5494
        ret = dict_get_int32(dict, "contents_size", &contents_size);
5495
        if (ret) {
5496
            snprintf(errmsg, sizeof(errmsg),
5497
                     "Unable to set"
5498
                     " contents size in dict.");
5499
            *op_errstr = gf_strdup(errmsg);
5500
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
5501
                   errmsg);
5502
            goto out;
5503
        }
5504

5505
        ret = dict_get_int32(dict, "file_mode", &file_mode);
5506
        if (ret) {
5507
            snprintf(errmsg, sizeof(errmsg),
5508
                     "Unable to get"
5509
                     " file mode in dict.");
5510
            *op_errstr = gf_strdup(errmsg);
5511
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
5512
                   errmsg);
5513
            goto out;
5514
        }
5515

5516
        fd = open(abs_filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
5517
        if (fd < 0) {
5518
            len = snprintf(errmsg, sizeof(errmsg), "Unable to open %s",
5519
                           abs_filename);
5520
            if (len < 0) {
5521
                strcpy(errmsg, "<error>");
5522
            }
5523
            *op_errstr = gf_strdup(errmsg);
5524
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, "%s",
5525
                   errmsg);
5526
            ret = -1;
5527
            goto out;
5528
        }
5529

5530
        bytes_writen = sys_write(fd, contents, contents_size);
5531

5532
        if (bytes_writen != contents_size) {
5533
            len = snprintf(errmsg, sizeof(errmsg), "Failed to write to %s",
5534
                           abs_filename);
5535
            if (len < 0) {
5536
                strcpy(errmsg, "<error>");
5537
            }
5538
            *op_errstr = gf_strdup(errmsg);
5539
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, "%s",
5540
                   errmsg);
5541
            ret = -1;
5542
            goto out;
5543
        }
5544

5545
        sys_fchmod(fd, file_mode);
5546
    }
5547

5548
    ret = 0;
5549
out:
5550
    if (fd != -1)
5551
        sys_close(fd);
5552

5553
    if (free_contents)
5554
        GF_FREE(contents);
5555

5556
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5557
    return ret;
5558
}
5559

5560
int
5561
glusterd_op_gsync_set(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
5562
{
5563
    int32_t ret = -1;
5564
    int32_t type = -1;
5565
    char *host_uuid = NULL;
5566
    char *secondary = NULL;
5567
    char *secondary_url = NULL;
5568
    char *secondary_vol = NULL;
5569
    char *secondary_host = NULL;
5570
    char *volname = NULL;
5571
    char *path_list = NULL;
5572
    glusterd_volinfo_t *volinfo = NULL;
5573
    glusterd_conf_t *priv = NULL;
5574
    gf_boolean_t is_force = _gf_false;
5575
    char *status_msg = NULL;
5576
    gf_boolean_t is_running = _gf_false;
5577
    char *conf_path = NULL;
5578
    char *key = NULL;
5579
    xlator_t *this = THIS;
5580

5581
    priv = this->private;
5582
    GF_ASSERT(priv);
5583
    GF_ASSERT(dict);
5584
    GF_ASSERT(op_errstr);
5585
    GF_ASSERT(rsp_dict);
5586

5587
    ret = dict_get_int32(dict, "type", &type);
5588
    if (ret < 0)
5589
        goto out;
5590

5591
    ret = dict_get_str(dict, "host-uuid", &host_uuid);
5592
    if (ret < 0)
5593
        goto out;
5594

5595
    if (type == GF_GSYNC_OPTION_TYPE_STATUS) {
5596
        ret = glusterd_get_gsync_status(dict, op_errstr, rsp_dict);
5597
        goto out;
5598
    }
5599

5600
    ret = dict_get_str(dict, "secondary", &secondary);
5601
    if (ret < 0)
5602
        goto out;
5603

5604
    key = secondary;
5605

5606
    ret = dict_get_str(dict, "secondary_url", &secondary_url);
5607
    if (ret) {
5608
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5609
               "Unable to fetch secondary url.");
5610
        goto out;
5611
    }
5612

5613
    ret = dict_get_str(dict, "secondary_host", &secondary_host);
5614
    if (ret) {
5615
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5616
               "Unable to fetch secondary hostname.");
5617
        goto out;
5618
    }
5619

5620
    ret = dict_get_str(dict, "secondary_vol", &secondary_vol);
5621
    if (ret) {
5622
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5623
               "Unable to fetch secondary volume name.");
5624
        goto out;
5625
    }
5626

5627
    ret = dict_get_str(dict, "conf_path", &conf_path);
5628
    if (ret) {
5629
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5630
               "Unable to fetch conf file path.");
5631
        goto out;
5632
    }
5633

5634
    if (dict_get_str(dict, "primary", &volname) == 0) {
5635
        ret = glusterd_volinfo_find(volname, &volinfo);
5636
        if (ret) {
5637
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_DICT_GET_FAILED,
5638
                   "Volinfo for"
5639
                   " %s (primary) not found",
5640
                   volname);
5641
            goto out;
5642
        }
5643

5644
        ret = glusterd_get_local_brickpaths(volinfo, &path_list);
5645
        if (!path_list && ret == -1)
5646
            goto out;
5647
    }
5648

5649
    if (type == GF_GSYNC_OPTION_TYPE_CONFIG) {
5650
        ret = glusterd_gsync_configure(volinfo, secondary, path_list, dict,
5651
                                       rsp_dict, op_errstr);
5652
        if (!ret) {
5653
            ret = dict_set_str(rsp_dict, "conf_path", conf_path);
5654
            if (ret) {
5655
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5656
                       "Unable to store conf_file_path.");
5657
                goto out;
5658
            }
5659
        }
5660
        goto out;
5661
    }
5662

5663
    if (type == GF_GSYNC_OPTION_TYPE_DELETE) {
5664
        ret = glusterd_remove_secondary_in_info(volinfo, secondary, op_errstr);
5665
        if (ret && !is_force && path_list)
5666
            goto out;
5667

5668
        ret = glusterd_gsync_delete(volinfo, secondary, secondary_host,
5669
                                    secondary_vol, path_list, dict, rsp_dict,
5670
                                    op_errstr);
5671
        goto out;
5672
    }
5673

5674
    if (!volinfo) {
5675
        ret = -1;
5676
        goto out;
5677
    }
5678

5679
    is_force = dict_get_str_boolean(dict, "force", _gf_false);
5680

5681
    if (type == GF_GSYNC_OPTION_TYPE_START) {
5682
        /* Add secondary to the dict indicating geo-rep session is running*/
5683
        ret = dict_set_dynstr_with_alloc(volinfo->gsync_active_secondaries, key,
5684
                                         "running");
5685
        if (ret) {
5686
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5687
                   "Unable to set key:%s"
5688
                   " value:running in the dict",
5689
                   key);
5690
            goto out;
5691
        }
5692

5693
        /* If secondary volume uuid is not present in gsync_secondaries
5694
         * update it*/
5695
        ret = glusterd_update_secondary_voluuid_secondaryinfo(volinfo);
5696
        if (ret) {
5697
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_REMOTE_VOL_UUID_FAIL,
5698
                   "Error in updating"
5699
                   " secondary volume uuid for old secondary info");
5700
            goto out;
5701
        }
5702

5703
        ret = glusterd_start_gsync(volinfo, secondary, path_list, conf_path,
5704
                                   host_uuid, op_errstr, _gf_false);
5705

5706
        /* Delete added secondary in the dict if start fails*/
5707
        if (ret)
5708
            dict_del(volinfo->gsync_active_secondaries, key);
5709
    }
5710

5711
    if (type == GF_GSYNC_OPTION_TYPE_STOP ||
5712
        type == GF_GSYNC_OPTION_TYPE_PAUSE ||
5713
        type == GF_GSYNC_OPTION_TYPE_RESUME) {
5714
        ret = glusterd_check_gsync_running_local(volinfo->volname, secondary,
5715
                                                 conf_path, &is_running);
5716
        if (!ret && !is_force && path_list && (_gf_true != is_running)) {
5717
            gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GSYNCD_OP_SET_FAILED,
5718
                   GEOREP
5719
                   " is not "
5720
                   "set up for %s(primary) and %s(secondary)",
5721
                   volname, secondary);
5722
            *op_errstr = gf_strdup(GEOREP " is not set up");
5723
            goto out;
5724
        }
5725

5726
        if (type == GF_GSYNC_OPTION_TYPE_PAUSE) {
5727
            ret = gd_pause_or_resume_gsync(dict, volname, secondary,
5728
                                           secondary_host, secondary_vol,
5729
                                           conf_path, op_errstr, _gf_true);
5730
            if (ret)
5731
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PAUSE_FAILED,
5732
                       GEOREP " Pause Failed");
5733
            else
5734
                dict_del(volinfo->gsync_active_secondaries, key);
5735

5736
        } else if (type == GF_GSYNC_OPTION_TYPE_RESUME) {
5737
            /* Add secondary to the dict indicating geo-rep session is
5738
             * running*/
5739
            ret = dict_set_dynstr_with_alloc(volinfo->gsync_active_secondaries,
5740
                                             key, "running");
5741
            if (ret) {
5742
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5743
                       "Unable to set "
5744
                       "key:%s value:running in dict",
5745
                       key);
5746
                goto out;
5747
            }
5748

5749
            ret = gd_pause_or_resume_gsync(dict, volname, secondary,
5750
                                           secondary_host, secondary_vol,
5751
                                           conf_path, op_errstr, _gf_false);
5752
            if (ret) {
5753
                gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_RESUME_FAILED,
5754
                       GEOREP " Resume Failed");
5755
                dict_del(volinfo->gsync_active_secondaries, key);
5756
            }
5757
        } else {
5758
            ret = stop_gsync(volname, secondary, &status_msg, conf_path,
5759
                             op_errstr, is_force);
5760

5761
            if (ret == 0 && status_msg)
5762
                ret = dict_set_str(rsp_dict, "gsync-status", status_msg);
5763
            if (!ret) {
5764
                ret = glusterd_create_status_file(volinfo->volname, secondary,
5765
                                                  secondary_host, secondary_vol,
5766
                                                  "Stopped");
5767
                if (ret) {
5768
                    gf_msg(this->name, GF_LOG_ERROR, 0,
5769
                           GD_MSG_UPDATE_STATEFILE_FAILED,
5770
                           "Unable to update state_file. "
5771
                           "Error : %s",
5772
                           strerror(errno));
5773
                }
5774
                dict_del(volinfo->gsync_active_secondaries, key);
5775
            }
5776
        }
5777
    }
5778

5779
out:
5780
    if (path_list) {
5781
        GF_FREE(path_list);
5782
        path_list = NULL;
5783
    }
5784

5785
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5786
    return ret;
5787
}
5788

5789
int
5790
glusterd_get_secondary_details_confpath(glusterd_volinfo_t *volinfo,
5791
                                        dict_t *dict, char **secondary_url,
5792
                                        char **secondary_host,
5793
                                        char **secondary_vol, char **conf_path,
5794
                                        char **op_errstr)
5795
{
5796
    int ret = -1;
5797
    char confpath[PATH_MAX] = "";
5798
    glusterd_conf_t *priv = NULL;
5799
    char *secondary = NULL;
5800
    xlator_t *this = THIS;
5801

5802
    priv = this->private;
5803
    GF_ASSERT(priv);
5804

5805
    ret = dict_get_str(dict, "secondary", &secondary);
5806
    if (ret || !secondary) {
5807
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED,
5808
               "Unable to fetch secondary from dict");
5809
        ret = -1;
5810
        goto out;
5811
    }
5812

5813
    ret = glusterd_get_secondary_info(secondary, secondary_url, secondary_host,
5814
                                      secondary_vol, op_errstr);
5815
    if (ret) {
5816
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARYINFO_FETCH_ERROR,
5817
               "Unable to fetch secondary details.");
5818
        ret = -1;
5819
        goto out;
5820
    }
5821

5822
    ret = dict_set_str(dict, "secondary_url", *secondary_url);
5823
    if (ret) {
5824
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5825
               "Unable to store secondary IP.");
5826
        goto out;
5827
    }
5828

5829
    ret = dict_set_str(dict, "secondary_host", *secondary_host);
5830
    if (ret) {
5831
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5832
               "Unable to store secondary hostname");
5833
        goto out;
5834
    }
5835

5836
    ret = dict_set_str(dict, "secondary_vol", *secondary_vol);
5837
    if (ret) {
5838
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5839
               "Unable to store secondary volume name.");
5840
        goto out;
5841
    }
5842

5843
    ret = snprintf(confpath, sizeof(confpath) - 1,
5844
                   "%s/" GEOREP "/%s_%s_%s/gsyncd.conf", priv->workdir,
5845
                   volinfo->volname, *secondary_host, *secondary_vol);
5846
    confpath[ret] = '\0';
5847
    *conf_path = gf_strdup(confpath);
5848
    if (!(*conf_path)) {
5849
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_STRDUP_FAILED,
5850
               "Unable to gf_strdup. Error: %s", strerror(errno));
5851
        ret = -1;
5852
        goto out;
5853
    }
5854

5855
    ret = dict_set_str(dict, "conf_path", *conf_path);
5856
    if (ret) {
5857
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
5858
               "Unable to store conf_path");
5859
        goto out;
5860
    }
5861

5862
out:
5863
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5864
    return ret;
5865
}
5866

5867
int
5868
glusterd_get_secondary_info(char *secondary, char **secondary_url,
5869
                            char **hostname, char **secondary_vol,
5870
                            char **op_errstr)
5871
{
5872
    char *tmp = NULL;
5873
    char *save_ptr = NULL;
5874
    char **linearr = NULL;
5875
    int32_t ret = -1;
5876
    char errmsg[PATH_MAX] = "";
5877
    xlator_t *this = THIS;
5878

5879
    ret = glusterd_urltransform_single(secondary, "normalize", &linearr);
5880
    if ((ret == -1) || (linearr[0] == NULL)) {
5881
        ret = snprintf(errmsg, sizeof(errmsg) - 1, "Invalid Url: %s",
5882
                       secondary);
5883
        errmsg[ret] = '\0';
5884
        *op_errstr = gf_strdup(errmsg);
5885
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NORMALIZE_URL_FAIL,
5886
               "Failed to normalize url");
5887
        goto out;
5888
    }
5889

5890
    tmp = strtok_r(linearr[0], "/", &save_ptr);
5891
    tmp = strtok_r(NULL, "/", &save_ptr);
5892
    secondary = NULL;
5893
    if (tmp != NULL) {
5894
        secondary = strtok_r(tmp, ":", &save_ptr);
5895
    }
5896
    if (secondary) {
5897
        ret = glusterd_geo_rep_parse_secondary(secondary, hostname, op_errstr);
5898
        if (ret) {
5899
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_URL_INVALID,
5900
                   "Invalid secondary url: %s", *op_errstr);
5901
            goto out;
5902
        }
5903
        gf_msg_debug(this->name, 0, "Hostname : %s", *hostname);
5904

5905
        *secondary_url = gf_strdup(secondary);
5906
        if (!*secondary_url) {
5907
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STRDUP_FAILED,
5908
                   "Failed to gf_strdup");
5909
            ret = -1;
5910
            goto out;
5911
        }
5912
        gf_msg_debug(this->name, 0, "Secondary URL : %s", *secondary_url);
5913
        ret = 0;
5914
    } else {
5915
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
5916
               "Invalid secondary name");
5917
        goto out;
5918
    }
5919

5920
    secondary = strtok_r(NULL, ":", &save_ptr);
5921
    if (secondary) {
5922
        *secondary_vol = gf_strdup(secondary);
5923
        if (!*secondary_vol) {
5924
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STRDUP_FAILED,
5925
                   "Failed to gf_strdup");
5926
            ret = -1;
5927
            GF_FREE(*secondary_url);
5928
            goto out;
5929
        }
5930
        gf_msg_debug(this->name, 0, "Secondary Vol : %s", *secondary_vol);
5931
        ret = 0;
5932
    } else {
5933
        gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
5934
               "Invalid secondary name");
5935
        goto out;
5936
    }
5937

5938
out:
5939
    if (linearr)
5940
        glusterd_urltransform_free(linearr, 1);
5941
    gf_msg_debug(this->name, 0, "Returning %d", ret);
5942
    return ret;
5943
}
5944

5945
static void
5946
runinit_gsyncd_setrx(runner_t *runner, char *conf_path)
5947
{
5948
    runinit(runner);
5949
    runner_add_args(runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
5950
    runner_argprintf(runner, "%s", conf_path);
5951
    runner_add_arg(runner, "--config-set-rx");
5952
}
5953

5954
static int
5955
glusterd_check_gsync_present(int *valid_state)
5956
{
5957
    char buff[PATH_MAX] = {
5958
        0,
5959
    };
5960
    runner_t runner = {
5961
        0,
5962
    };
5963
    char *ptr = NULL;
5964
    int ret = 0;
5965

5966
    runinit(&runner);
5967
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "--version", NULL);
5968
    runner_redir(&runner, STDOUT_FILENO, RUN_PIPE);
5969
    ret = runner_start(&runner);
5970
    if (ret == -1) {
5971
        if (errno == ENOENT) {
5972
            gf_msg("glusterd", GF_LOG_INFO, ENOENT, GD_MSG_MODULE_NOT_INSTALLED,
5973
                   GEOREP
5974
                   " module "
5975
                   "not installed in the system");
5976
            *valid_state = 0;
5977
        } else {
5978
            gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_MODULE_ERROR,
5979
                   GEOREP " module not working as desired");
5980
            *valid_state = -1;
5981
        }
5982
        goto out;
5983
    }
5984

5985
    ptr = fgets(buff, sizeof(buff), runner_chio(&runner, STDOUT_FILENO));
5986
    if (ptr) {
5987
        if (!strstr(buff, "gsyncd")) {
5988
            ret = -1;
5989
            gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_MODULE_ERROR,
5990
                   GEOREP " module not working as desired");
5991
            *valid_state = -1;
5992
            goto out;
5993
        }
5994
    } else {
5995
        ret = -1;
5996
        gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_MODULE_ERROR,
5997
               GEOREP " module not working as desired");
5998
        *valid_state = -1;
5999
        goto out;
6000
    }
6001

6002
    ret = 0;
6003
out:
6004

6005
    runner_end(&runner);
6006

6007
    gf_msg_debug("glusterd", 0, "Returning %d", ret);
6008
    return ret;
6009
}
6010

6011
static int
6012
create_conf_file(glusterd_conf_t *conf, char *conf_path)
6013
#define RUN_GSYNCD_CMD                                                         \
6014
    do {                                                                       \
6015
        ret = runner_run_reuse(&runner);                                       \
6016
        if (ret == -1) {                                                       \
6017
            runner_log(&runner, "glusterd", GF_LOG_ERROR, "command failed");   \
6018
            runner_end(&runner);                                               \
6019
            goto out;                                                          \
6020
        }                                                                      \
6021
        runner_end(&runner);                                                   \
6022
    } while (0)
6023
{
6024
    int ret = 0;
6025
    runner_t runner = {
6026
        0,
6027
    };
6028
    char georepdir[PATH_MAX] = {
6029
        0,
6030
    };
6031
    int valid_state = 0;
6032

6033
    valid_state = -1;
6034
    ret = glusterd_check_gsync_present(&valid_state);
6035
    if (-1 == ret) {
6036
        ret = valid_state;
6037
        goto out;
6038
    }
6039

6040
    ret = snprintf(georepdir, sizeof(georepdir) - 1, "%s/" GEOREP,
6041
                   conf->workdir);
6042
    georepdir[ret] = '\0';
6043

6044
    /************
6045
     * primary pre-configuration
6046
     ************/
6047

6048
    /* remote-gsyncd */
6049
    runinit_gsyncd_setrx(&runner, conf_path);
6050
    runner_add_args(&runner, "remote-gsyncd", GSYNCD_PREFIX "/gsyncd", ".", ".",
6051
                    NULL);
6052
    RUN_GSYNCD_CMD;
6053

6054
    runinit_gsyncd_setrx(&runner, conf_path);
6055
    runner_add_args(&runner, "remote-gsyncd", "/nonexistent/gsyncd", ".",
6056
                    "^ssh:", NULL);
6057
    RUN_GSYNCD_CMD;
6058

6059
    /* gluster-command-dir */
6060
    runinit_gsyncd_setrx(&runner, conf_path);
6061
    runner_add_args(&runner, "gluster-command-dir", SBIN_DIR "/", ".", ".",
6062
                    NULL);
6063
    RUN_GSYNCD_CMD;
6064

6065
    /* gluster-params */
6066
    runinit_gsyncd_setrx(&runner, conf_path);
6067
    runner_add_args(&runner, "gluster-params", "aux-gfid-mount acl", ".", ".",
6068
                    NULL);
6069
    RUN_GSYNCD_CMD;
6070

6071
    /* ssh-command */
6072
    runinit_gsyncd_setrx(&runner, conf_path);
6073
    runner_add_arg(&runner, "ssh-command");
6074
    runner_argprintf(&runner,
6075
                     "ssh -oPasswordAuthentication=no "
6076
                     "-oStrictHostKeyChecking=no "
6077
                     "-i %s/secret.pem",
6078
                     georepdir);
6079
    runner_add_args(&runner, ".", ".", NULL);
6080
    RUN_GSYNCD_CMD;
6081

6082
    /* ssh-command tar */
6083
    runinit_gsyncd_setrx(&runner, conf_path);
6084
    runner_add_arg(&runner, "ssh-command-tar");
6085
    runner_argprintf(&runner,
6086
                     "ssh -oPasswordAuthentication=no "
6087
                     "-oStrictHostKeyChecking=no "
6088
                     "-i %s/tar_ssh.pem",
6089
                     georepdir);
6090
    runner_add_args(&runner, ".", ".", NULL);
6091
    RUN_GSYNCD_CMD;
6092

6093
    /* pid-file */
6094
    runinit_gsyncd_setrx(&runner, conf_path);
6095
    runner_add_arg(&runner, "pid-file");
6096
    runner_argprintf(
6097
        &runner, "%s/${primaryvol}_${remotehost}_${secondaryvol}/monitor.pid",
6098
        georepdir);
6099
    runner_add_args(&runner, ".", ".", NULL);
6100
    RUN_GSYNCD_CMD;
6101

6102
    /* geo-rep-working-dir */
6103
    runinit_gsyncd_setrx(&runner, conf_path);
6104
    runner_add_arg(&runner, "georep-session-working-dir");
6105
    runner_argprintf(&runner, "%s/${primaryvol}_${remotehost}_${secondaryvol}/",
6106
                     georepdir);
6107
    runner_add_args(&runner, ".", ".", NULL);
6108
    RUN_GSYNCD_CMD;
6109

6110
    /* state-file */
6111
    runinit_gsyncd_setrx(&runner, conf_path);
6112
    runner_add_arg(&runner, "state-file");
6113
    runner_argprintf(
6114
        &runner,
6115
        "%s/${primaryvol}_${remotehost}_${secondaryvol}/monitor.status",
6116
        georepdir);
6117
    runner_add_args(&runner, ".", ".", NULL);
6118
    RUN_GSYNCD_CMD;
6119

6120
    /* state-detail-file */
6121
    runinit_gsyncd_setrx(&runner, conf_path);
6122
    runner_add_arg(&runner, "state-detail-file");
6123
    runner_argprintf(&runner,
6124
                     "%s/${primaryvol}_${remotehost}_${secondaryvol}/"
6125
                     "${eSecondary}-detail.status",
6126
                     georepdir);
6127
    runner_add_args(&runner, ".", ".", NULL);
6128
    RUN_GSYNCD_CMD;
6129

6130
    /* state-socket */
6131
    runinit_gsyncd_setrx(&runner, conf_path);
6132
    runner_add_arg(&runner, "state-socket-unencoded");
6133
    runner_argprintf(
6134
        &runner,
6135
        "%s/${primaryvol}_${remotehost}_${secondaryvol}/${eSecondary}.socket",
6136
        georepdir);
6137
    runner_add_args(&runner, ".", ".", NULL);
6138
    RUN_GSYNCD_CMD;
6139

6140
    /* socketdir */
6141
    runinit_gsyncd_setrx(&runner, conf_path);
6142
    runner_add_args(&runner, "socketdir", GLUSTERD_SOCK_DIR, ".", ".", NULL);
6143
    RUN_GSYNCD_CMD;
6144

6145
    /* log-file */
6146
    runinit_gsyncd_setrx(&runner, conf_path);
6147
    runner_add_arg(&runner, "log-file");
6148
    runner_argprintf(&runner, "%s/%s/${primaryvol}/${eSecondary}.log",
6149
                     conf->logdir, GEOREP);
6150
    runner_add_args(&runner, ".", ".", NULL);
6151
    RUN_GSYNCD_CMD;
6152

6153
    /* changelog-log-file */
6154
    runinit_gsyncd_setrx(&runner, conf_path);
6155
    runner_add_arg(&runner, "changelog-log-file");
6156
    runner_argprintf(&runner,
6157
                     "%s/%s/${primaryvol}/${eSecondary}${local_id}-changes.log",
6158
                     conf->logdir, GEOREP);
6159
    runner_add_args(&runner, ".", ".", NULL);
6160
    RUN_GSYNCD_CMD;
6161

6162
    /* gluster-log-file */
6163
    runinit_gsyncd_setrx(&runner, conf_path);
6164
    runner_add_arg(&runner, "gluster-log-file");
6165
    runner_argprintf(&runner,
6166
                     "%s/%s/${primaryvol}/${eSecondary}${local_id}.gluster.log",
6167
                     conf->logdir, GEOREP);
6168
    runner_add_args(&runner, ".", ".", NULL);
6169
    RUN_GSYNCD_CMD;
6170

6171
    /* ignore-deletes */
6172
    runinit_gsyncd_setrx(&runner, conf_path);
6173
    runner_add_args(&runner, "ignore-deletes", "false", ".", ".", NULL);
6174
    RUN_GSYNCD_CMD;
6175

6176
    /* special-sync-mode */
6177
    runinit_gsyncd_setrx(&runner, conf_path);
6178
    runner_add_args(&runner, "special-sync-mode", "partial", ".", ".", NULL);
6179
    RUN_GSYNCD_CMD;
6180

6181
    /* change-detector == changelog */
6182
    runinit_gsyncd_setrx(&runner, conf_path);
6183
    runner_add_args(&runner, "change-detector", "changelog", ".", ".", NULL);
6184
    RUN_GSYNCD_CMD;
6185

6186
    runinit_gsyncd_setrx(&runner, conf_path);
6187
    runner_add_arg(&runner, "working-dir");
6188
    runner_argprintf(&runner, "%s/${primaryvol}/${eSecondary}",
6189
                     DEFAULT_GLUSTERFSD_MISC_DIRETORY);
6190
    runner_add_args(&runner, ".", ".", NULL);
6191
    RUN_GSYNCD_CMD;
6192

6193
    /************
6194
     * secondary pre-configuration
6195
     ************/
6196

6197
    /* secondary-gluster-command-dir */
6198
    runinit_gsyncd_setrx(&runner, conf_path);
6199
    runner_add_args(&runner, "secondary-gluster-command-dir", SBIN_DIR "/", ".",
6200
                    NULL);
6201
    RUN_GSYNCD_CMD;
6202

6203
    /* gluster-params */
6204
    runinit_gsyncd_setrx(&runner, conf_path);
6205
    runner_add_args(&runner, "gluster-params", "aux-gfid-mount acl", ".", NULL);
6206
    RUN_GSYNCD_CMD;
6207

6208
    /* log-file */
6209
    runinit_gsyncd_setrx(&runner, conf_path);
6210
    runner_add_arg(&runner, "log-file");
6211
    runner_argprintf(
6212
        &runner,
6213
        "%s/%s-secondaries/"
6214
        "${session_owner}:${local_node}${local_id}.${secondaryvol}."
6215
        "log",
6216
        conf->logdir, GEOREP);
6217
    runner_add_args(&runner, ".", ".", NULL);
6218
    RUN_GSYNCD_CMD;
6219

6220
    /* MountBroker log-file */
6221
    runinit_gsyncd_setrx(&runner, conf_path);
6222
    runner_add_arg(&runner, "log-file-mbr");
6223
    runner_argprintf(
6224
        &runner,
6225
        "%s/%s-secondaries/mbr/"
6226
        "${session_owner}:${local_node}${local_id}.${secondaryvol}."
6227
        "log",
6228
        conf->logdir, GEOREP);
6229
    runner_add_args(&runner, ".", ".", NULL);
6230
    RUN_GSYNCD_CMD;
6231

6232
    /* gluster-log-file */
6233
    runinit_gsyncd_setrx(&runner, conf_path);
6234
    runner_add_arg(&runner, "gluster-log-file");
6235
    runner_argprintf(
6236
        &runner,
6237
        "%s/%s-secondaries/"
6238
        "${session_owner}:${local_node}${local_id}.${secondaryvol}."
6239
        "gluster.log",
6240
        conf->logdir, GEOREP);
6241
    runner_add_args(&runner, ".", ".", NULL);
6242
    RUN_GSYNCD_CMD;
6243

6244
out:
6245
    return ret ? -1 : 0;
6246
}
6247

6248
static int
6249
glusterd_create_essential_dir_files(glusterd_volinfo_t *volinfo, dict_t *dict,
6250
                                    char *secondary, char *secondary_host,
6251
                                    char *secondary_vol, char **op_errstr)
6252
{
6253
    int ret = -1;
6254
    char *conf_path = NULL;
6255
    char *statefile = NULL;
6256
    char buf[PATH_MAX] = "";
6257
    char errmsg[PATH_MAX] = "";
6258
    glusterd_conf_t *conf = NULL;
6259
    struct stat stbuf = {
6260
        0,
6261
    };
6262
    xlator_t *this = THIS;
6263
    int32_t len = 0;
6264

6265
    conf = this->private;
6266

6267
    ret = dict_get_str(dict, "conf_path", &conf_path);
6268
    if (ret) {
6269
        snprintf(errmsg, sizeof(errmsg), "Unable to fetch conf file path.");
6270
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6271
               errmsg);
6272
        goto out;
6273
    }
6274

6275
    ret = dict_get_str(dict, "statefile", &statefile);
6276
    if (ret) {
6277
        snprintf(errmsg, sizeof(errmsg), "Unable to fetch statefile path.");
6278
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6279
               errmsg);
6280
        goto out;
6281
    }
6282

6283
    ret = snprintf(buf, sizeof(buf), "%s/" GEOREP "/%s_%s_%s", conf->workdir,
6284
                   volinfo->volname, secondary_host, secondary_vol);
6285
    if ((ret < 0) || (ret >= sizeof(buf))) {
6286
        ret = -1;
6287
        goto out;
6288
    }
6289
    ret = mkdir_p(buf, 0755, _gf_true);
6290
    if (ret) {
6291
        len = snprintf(errmsg, sizeof(errmsg),
6292
                       "Unable to create %s"
6293
                       ". Error : %s",
6294
                       buf, strerror(errno));
6295
        if (len < 0) {
6296
            strcpy(errmsg, "<error>");
6297
        }
6298
        *op_errstr = gf_strdup(errmsg);
6299
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, "%s",
6300
               errmsg);
6301
        goto out;
6302
    }
6303

6304
    ret = snprintf(buf, PATH_MAX, "%s/" GEOREP "/%s", conf->logdir,
6305
                   volinfo->volname);
6306
    if ((ret < 0) || (ret >= PATH_MAX)) {
6307
        ret = -1;
6308
        goto out;
6309
    }
6310
    ret = mkdir_p(buf, 0755, _gf_true);
6311
    if (ret) {
6312
        len = snprintf(errmsg, sizeof(errmsg),
6313
                       "Unable to create %s"
6314
                       ". Error : %s",
6315
                       buf, strerror(errno));
6316
        if (len < 0) {
6317
            strcpy(errmsg, "<error>");
6318
        }
6319
        *op_errstr = gf_strdup(errmsg);
6320
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, "%s",
6321
               errmsg);
6322
        goto out;
6323
    }
6324

6325
    ret = sys_lstat(conf_path, &stbuf);
6326
    if (!ret) {
6327
        gf_msg_debug(this->name, 0,
6328
                     "Session already running."
6329
                     " Not creating config file again.");
6330
    } else {
6331
        ret = create_conf_file(conf, conf_path);
6332
        if (ret || sys_lstat(conf_path, &stbuf)) {
6333
            snprintf(errmsg, sizeof(errmsg),
6334
                     "Failed to create"
6335
                     " config file(%s).",
6336
                     conf_path);
6337
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, "%s",
6338
                   errmsg);
6339
            goto out;
6340
        }
6341
    }
6342

6343
    ret = sys_lstat(statefile, &stbuf);
6344
    if (!ret) {
6345
        gf_msg_debug(this->name, 0,
6346
                     "Session already running."
6347
                     " Not creating status file again.");
6348
        goto out;
6349
    } else {
6350
        ret = glusterd_create_status_file(volinfo->volname, secondary,
6351
                                          secondary_host, secondary_vol,
6352
                                          "Created");
6353
        if (ret || sys_lstat(statefile, &stbuf)) {
6354
            snprintf(errmsg, sizeof(errmsg),
6355
                     "Unable to create %s"
6356
                     ". Error : %s",
6357
                     statefile, strerror(errno));
6358
            *op_errstr = gf_strdup(errmsg);
6359
            gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, "%s",
6360
                   errmsg);
6361
            ret = -1;
6362
            goto out;
6363
        }
6364
    }
6365

6366
out:
6367
    gf_msg_debug(this->name, 0, "Returning %d", ret);
6368
    return ret;
6369
}
6370

6371
int
6372
glusterd_op_gsync_create(dict_t *dict, char **op_errstr, dict_t *rsp_dict)
6373
{
6374
    char common_pem_file[PATH_MAX] = "";
6375
    char errmsg[PATH_MAX] = {
6376
        0,
6377
    };
6378
    char hooks_args[PATH_MAX] = "";
6379
    char uuid_str[64] = "";
6380
    char *host_uuid = NULL;
6381
    char *secondary_url = NULL;
6382
    char *secondary_url_buf = NULL;
6383
    char *secondary_user = NULL;
6384
    char *secondary_ip = NULL;
6385
    char *save_ptr = NULL;
6386
    char *secondary_host = NULL;
6387
    char *secondary_vol = NULL;
6388
    char *arg_buf = NULL;
6389
    char *volname = NULL;
6390
    char *secondary = NULL;
6391
    int32_t ret = -1;
6392
    int32_t is_pem_push = -1;
6393
    int32_t ssh_port = 22;
6394
    gf_boolean_t is_force = -1;
6395
    glusterd_conf_t *conf = NULL;
6396
    glusterd_volinfo_t *volinfo = NULL;
6397
    xlator_t *this = THIS;
6398
    char old_working_dir[PATH_MAX] = {0};
6399
    char new_working_dir[PATH_MAX] = {0};
6400
    char *secondary_voluuid = NULL;
6401
    char *old_secondaryhost = NULL;
6402
    gf_boolean_t is_existing_session = _gf_false;
6403
    int32_t len = 0;
6404

6405
    conf = this->private;
6406
    GF_ASSERT(conf);
6407
    GF_ASSERT(dict);
6408
    GF_ASSERT(op_errstr);
6409

6410
    ret = glusterd_op_gsync_args_get(dict, op_errstr, &volname, &secondary,
6411
                                     &host_uuid);
6412
    if (ret)
6413
        goto out;
6414

6415
    len = snprintf(common_pem_file, sizeof(common_pem_file),
6416
                   "%s" GLUSTERD_COMMON_PEM_PUB_FILE, conf->workdir);
6417
    if ((len < 0) || (len >= sizeof(common_pem_file))) {
6418
        ret = -1;
6419
        goto out;
6420
    }
6421

6422
    ret = glusterd_volinfo_find(volname, &volinfo);
6423
    if (ret) {
6424
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_FOUND,
6425
               "Volinfo for %s (primary) not found", volname);
6426
        goto out;
6427
    }
6428

6429
    ret = dict_get_str(dict, "secondary_vol", &secondary_vol);
6430
    if (ret) {
6431
        snprintf(errmsg, sizeof(errmsg),
6432
                 "Unable to fetch secondary volume name.");
6433
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6434
               errmsg);
6435
        goto out;
6436
    }
6437

6438
    ret = dict_get_str(dict, "secondary_url", &secondary_url);
6439
    if (ret) {
6440
        snprintf(errmsg, sizeof(errmsg), "Unable to fetch secondary IP.");
6441
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6442
               errmsg);
6443
        ret = -1;
6444
        goto out;
6445
    }
6446

6447
    /* Fetch the secondary_user and secondary_ip from the secondary_url.
6448
     * If the secondary_user is not present. Use "root"
6449
     */
6450
    if (strstr(secondary_url, "@")) {
6451
        secondary_url_buf = gf_strdup(secondary_url);
6452
        if (!secondary_url_buf) {
6453
            ret = -1;
6454
            goto out;
6455
        }
6456
        secondary_user = strtok_r(secondary_url, "@", &save_ptr);
6457
        secondary_ip = strtok_r(NULL, "@", &save_ptr);
6458
    } else {
6459
        secondary_user = "root";
6460
        secondary_ip = secondary_url;
6461
    }
6462

6463
    if (!secondary_user || !secondary_ip) {
6464
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARY_URL_INVALID,
6465
               "Invalid secondary url.");
6466
        ret = -1;
6467
        goto out;
6468
    }
6469

6470
    ret = dict_get_str(dict, "secondary_host", &secondary_host);
6471
    if (ret) {
6472
        snprintf(errmsg, sizeof(errmsg), "Unable to fetch secondary host");
6473
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6474
               errmsg);
6475
        ret = -1;
6476
        goto out;
6477
    }
6478

6479
    ret = dict_get_int32(dict, "ssh_port", &ssh_port);
6480
    if (ret < 0 && ret != -ENOENT) {
6481
        snprintf(errmsg, sizeof(errmsg), "Fetching ssh_port failed");
6482
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6483
               errmsg);
6484
        ret = -1;
6485
        goto out;
6486
    }
6487

6488
    is_force = dict_get_str_boolean(dict, "force", _gf_false);
6489

6490
    uuid_utoa_r(MY_UUID, uuid_str);
6491
    if (!strcmp(uuid_str, host_uuid)) {
6492
        ret = dict_get_int32(dict, "push_pem", &is_pem_push);
6493
        if (!ret && is_pem_push) {
6494
            gf_msg_debug(this->name, 0,
6495
                         "Trying to setup"
6496
                         " pem files in secondary");
6497
            is_pem_push = 1;
6498
        } else
6499
            is_pem_push = 0;
6500

6501
        len = snprintf(hooks_args, sizeof(hooks_args),
6502
                       "is_push_pem=%d,pub_file=%s,secondary_user=%s,"
6503
                       "secondary_ip=%s,secondary_vol=%s,ssh_port=%d",
6504
                       is_pem_push, common_pem_file, secondary_user,
6505
                       secondary_ip, secondary_vol, ssh_port);
6506
        if ((len < 0) || (len >= sizeof(hooks_args))) {
6507
            ret = -1;
6508
            goto out;
6509
        }
6510
    } else
6511
        snprintf(hooks_args, sizeof(hooks_args),
6512
                 "This argument will stop the hooks script");
6513

6514
    arg_buf = gf_strdup(hooks_args);
6515
    if (!arg_buf) {
6516
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STRDUP_FAILED,
6517
               "Failed to gf_strdup");
6518
        if (is_force) {
6519
            ret = 0;
6520
            goto create_essentials;
6521
        }
6522
        ret = -1;
6523
        goto out;
6524
    }
6525

6526
    ret = dict_set_str(dict, "hooks_args", arg_buf);
6527
    if (ret) {
6528
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
6529
               "Failed to set hooks_args in dict.");
6530
        if (is_force) {
6531
            ret = 0;
6532
            goto create_essentials;
6533
        }
6534
        goto out;
6535
    }
6536

6537
create_essentials:
6538
    /* Fetch secondary volume uuid, to get stored in volume info. */
6539
    ret = dict_get_str(dict, "secondary_voluuid", &secondary_voluuid);
6540
    if (ret) {
6541
        snprintf(errmsg, sizeof(errmsg),
6542
                 "Unable to fetch secondary volume uuid from dict");
6543
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6544
               errmsg);
6545
        ret = -1;
6546
        goto out;
6547
    }
6548

6549
    is_existing_session = dict_get_str_boolean(dict, "existing_session",
6550
                                               _gf_false);
6551
    if (is_existing_session) {
6552
        ret = dict_get_str(dict, "old_secondaryhost", &old_secondaryhost);
6553
        if (ret) {
6554
            snprintf(errmsg, sizeof(errmsg),
6555
                     "Unable to fetch old_secondaryhost");
6556
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "%s",
6557
                   errmsg);
6558
            ret = -1;
6559
            goto out;
6560
        }
6561

6562
        /* Rename existing geo-rep session with new Secondary Host */
6563
        ret = snprintf(old_working_dir, sizeof(old_working_dir) - 1,
6564
                       "%s/" GEOREP "/%s_%s_%s", conf->workdir,
6565
                       volinfo->volname, old_secondaryhost, secondary_vol);
6566

6567
        ret = snprintf(new_working_dir, sizeof(new_working_dir) - 1,
6568
                       "%s/" GEOREP "/%s_%s_%s", conf->workdir,
6569
                       volinfo->volname, secondary_host, secondary_vol);
6570

6571
        ret = sys_rename(old_working_dir, new_working_dir);
6572
        if (!ret) {
6573
            gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_FORCE_CREATE_SESSION,
6574
                   "rename of old working dir %s to "
6575
                   "new working dir %s is done! ",
6576
                   old_working_dir, new_working_dir);
6577
        } else {
6578
            if (errno == ENOENT) {
6579
                /* log error, but proceed with directory
6580
                 * creation below */
6581
                gf_msg_debug(this->name, 0,
6582
                             "old_working_dir(%s) "
6583
                             "not present.",
6584
                             old_working_dir);
6585
            } else {
6586
                len = snprintf(errmsg, sizeof(errmsg),
6587
                               "rename of old working dir %s "
6588
                               "to new working dir %s "
6589
                               "failed! Error: %s",
6590
                               old_working_dir, new_working_dir,
6591
                               strerror(errno));
6592
                if (len < 0) {
6593
                    strcpy(errmsg, "<error>");
6594
                }
6595
                gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_FORCE_CREATE_SESSION,
6596
                       "rename of old working dir %s to "
6597
                       "new working dir %s failed! Error: %s!",
6598
                       old_working_dir, new_working_dir, strerror(errno));
6599

6600
                ret = -1;
6601
                goto out;
6602
            }
6603
        }
6604
    }
6605

6606
    ret = glusterd_create_essential_dir_files(
6607
        volinfo, dict, secondary, secondary_host, secondary_vol, op_errstr);
6608
    if (ret)
6609
        goto out;
6610

6611
    ret = glusterd_store_secondary_in_info(
6612
        volinfo, secondary, host_uuid, secondary_voluuid, op_errstr, is_force);
6613
    if (ret) {
6614
        snprintf(errmsg, sizeof(errmsg),
6615
                 "Unable to store"
6616
                 " secondary info.");
6617
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SECONDARYINFO_STORE_ERROR,
6618
               "%s", errmsg);
6619
        goto out;
6620
    }
6621

6622
    /* Enable marker and changelog */
6623
    ret = glusterd_set_gsync_confs(volinfo);
6624
    if (ret != 0) {
6625
        gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_MARKER_START_FAIL,
6626
               "marker/changelog"
6627
               " start failed");
6628
        snprintf(errmsg, sizeof(errmsg), "Index initialization failed");
6629

6630
        ret = -1;
6631
        goto out;
6632
    }
6633

6634
out:
6635
    if (ret && errmsg[0] != '\0') {
6636
        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_GSYNCD_ERROR, "%s", errmsg);
6637
        *op_errstr = gf_strdup(errmsg);
6638
    }
6639

6640
    GF_FREE(secondary_url_buf);
6641
    gf_msg_debug(this->name, 0, "Returning %d", ret);
6642
    return ret;
6643
}
6644

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.