glusterfs

Форк
0
/
common-utils.c 
4387 строк · 102.8 Кб
1
/*
2
  Copyright (c) 2008-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

11
#ifdef HAVE_BACKTRACE
12
#include <execinfo.h>
13
#else
14
#include "execinfo_compat.h"
15
#endif
16

17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <string.h>
20
#include <ctype.h>
21
#include <errno.h>
22
#include <limits.h>
23
#include <netdb.h>
24
#include <unistd.h>
25
#include <time.h>
26
#include <locale.h>
27
#include <sys/socket.h>
28
#include <netinet/in.h>
29
#include <arpa/inet.h>
30
#include <signal.h>
31
#include <assert.h>
32
#include <libgen.h> /* for dirname() */
33
#include <grp.h>
34

35
#if defined(GF_BSD_HOST_OS) || defined(GF_DARWIN_HOST_OS)
36
#include <sys/sysctl.h>
37
#endif
38
#ifdef HAVE_SYNCFS_SYS
39
#include <sys/syscall.h>
40
#endif
41

42
#include "glusterfs/compat-errno.h"
43
#include "glusterfs/common-utils.h"
44
#include "glusterfs/revision.h"
45
#include "glusterfs/glusterfs.h"
46
#include "glusterfs/stack.h"
47
#include "glusterfs/syscall.h"
48
#define XXH_INLINE_ALL
49
#include "xxhash.h"
50
#include <ifaddrs.h>
51
#include "glusterfs/libglusterfs-messages.h"
52
#include "glusterfs/glusterfs-acl.h"
53
#ifdef __FreeBSD__
54
#include <pthread_np.h>
55
#undef BIT_SET
56
#endif
57

58
#if defined(HAVE_LIBXXHASH)
59
#define XXH64_FMT PRIx64
60
#else /* use from contrib */
61
#define XXH64_FMT "llx"
62
#endif /* HAVE_LIBXXHASH */
63

64
#ifndef AI_ADDRCONFIG
65
#define AI_ADDRCONFIG 0
66
#endif /* AI_ADDRCONFIG */
67

68
#if OPENSSL_VERSION_NUMBER >= 0x030000000  // 3.0.0
69
#include <openssl/evp.h>
70
#endif
71

72
char *vol_type_str[] = {
73
    "Distribute",
74
    "Stripe [NOT SUPPORTED from v6.0]",
75
    "Replicate",
76
    "Striped-Replicate [NOT SUPPORTED from v6.0]",
77
    "Disperse",
78
    "Tier [NOT SUPPORTED from v6.0]",
79
    "Distributed-Stripe [NOT SUPPORTED from v6.0]",
80
    "Distributed-Replicate",
81
    "Distributed-Striped-Replicate [NOT SUPPORTED from v6.0]",
82
    "Distributed-Disperse",
83
};
84

85
gf_boolean_t gf_signal_on_assert = false;
86

87
typedef int32_t (*rw_op_t)(int32_t fd, char *buf, int32_t size);
88
typedef int32_t (*rwv_op_t)(int32_t fd, const struct iovec *buf, int32_t size);
89

90
char *xattrs_to_heal[] = {"user.",
91
                          POSIX_ACL_ACCESS_XATTR,
92
                          POSIX_ACL_DEFAULT_XATTR,
93
                          QUOTA_LIMIT_KEY,
94
                          QUOTA_LIMIT_OBJECTS_KEY,
95
                          GF_SELINUX_XATTR_KEY,
96
                          GF_XATTR_MDATA_KEY,
97
                          NULL};
98

99
static gf_boolean_t
100
gf_ports_reserved(char *blocked_port, unsigned char *ports, uint32_t ceiling);
101

102
void
103
gf_assert(void)
104
{
105
    if (gf_signal_on_assert) {
106
        raise(SIGCONT);
107
    }
108
}
109

110
void
111
gf_xxh64_wrapper(const unsigned char *data, size_t const len,
112
                 unsigned long long const seed, char *xxh64)
113
{
114
    unsigned short i = 0;
115
    const unsigned short lim = GF_XXH64_DIGEST_LENGTH * 2 + 1;
116
    XXH64_hash_t hash = 0;
117
    XXH64_canonical_t c_hash = {
118
        {
119
            0,
120
        },
121
    };
122
    const uint8_t *p = (const uint8_t *)&c_hash;
123

124
    hash = XXH64(data, len, seed);
125
    XXH64_canonicalFromHash(&c_hash, hash);
126

127
    for (i = 0; i < GF_XXH64_DIGEST_LENGTH; i++)
128
        snprintf(xxh64 + i * 2, lim - i * 2, "%02x", p[i]);
129
}
130

131
/**
132
 * This function takes following arguments
133
 * @this: xlator
134
 * @gfid: The gfid which has to be filled
135
 * @hash: the 8 byte hash which has to be filled inside the gfid
136
 * @index: the array element of the uuid_t structure (which is
137
 *         a array of unsigned char) from where the 8 bytes of
138
 *         the hash has to be filled. Since uuid_t contains 16
139
 *        char elements in the array, each byte of the hash has
140
 *        to be filled in one array element.
141
 *
142
 * This function is called twice for 2 hashes (of 8 byte each) to
143
 * be filled in the gfid.
144
 *
145
 * The for loop in this function actually is doing these 2 things
146
 * for each hash
147
 *
148
 * 1) One of the hashes
149
 *      tmp[0] = (hash_2 >> 56) & 0xff;
150
 *      tmp[1] = (hash_2 >> 48) & 0xff;
151
 *      tmp[2] = (hash_2 >> 40) & 0xff;
152
 *      tmp[3] = (hash_2 >> 32) & 0xff;
153
 *      tmp[4] = (hash_2 >> 24) & 0xff;
154
 *      tmp[5] = (hash_2 >> 16) & 0xff;
155
 *      tmp[6] = (hash_2 >> 8) & 0xff;
156
 *      tmp[7] = (hash_2) & 0xff;
157
 *
158
 * 2) The other hash:
159
 *      tmp[8] = (hash_1 >> 56) & 0xff;
160
 *      tmp[9] = (hash_1 >> 48) & 0xff;
161
 *      tmp[10] = (hash_1 >> 40) & 0xff;
162
 *      tmp[11] = (hash_1 >> 32) & 0xff;
163
 *      tmp[12] = (hash_1 >> 24) & 0xff;
164
 *      tmp[13] = (hash_1 >> 16) & 0xff;
165
 *      tmp[14] = (hash_1 >> 8) & 0xff;
166
 *      tmp[15] = (hash_1) & 0xff;
167
 **/
168
static int
169
gf_gfid_from_xxh64(xlator_t *this, uuid_t gfid, XXH64_hash_t hash,
170
                   unsigned short index)
171
{
172
    int ret = -1;
173
    int i = -1;
174

175
    if ((index != 0) && (index != 8)) {
176
        gf_msg_callingfn("gfid-from-xxh64", GF_LOG_WARNING, 0,
177
                         LG_MSG_INDEX_NOT_FOUND,
178
                         "index can only be either 0 or 8, as this"
179
                         "function's purpose is to encode a 8 byte "
180
                         "hash inside the gfid (index: %d)",
181
                         index);
182
        goto out;
183
    }
184

185
    for (i = 0; i < sizeof(hash); i++) {
186
        /*
187
         * As of now the below statement is equivalent of this.
188
         * gfid[index+i] = (hash >> (64 - (8 * (i+1)))) & 0xff;
189
         */
190
        gfid[index + i] = (hash >> ((sizeof(hash) * 8) - (8 * (i + 1)))) &
191
                          (0xff);
192
    }
193

194
    ret = 0;
195

196
out:
197
    return ret;
198
}
199

200
/**
201
 * This function does the same thing as gf_xxh64_wrapper. But gf_xxh64_wrapper
202
 * does not return anything and in this xlator there is a need for both the
203
 * actual hash and the canonicalized form of the hash.
204
 *
205
 * To summarize:
206
 * - XXH64_hash_t is needed as return because, those bytes which contain the
207
 *   hash can be used for different purposes as needed. One example is
208
 *   to have those bytes copied into the uuid_t structure to be used as gfid
209
 * - xxh64 string is needed because, it can be used as the key for generating
210
 *   the next hash (and any other purpose which might require canonical form
211
 *   of the hash).
212
 **/
213
XXH64_hash_t
214
gf_xxh64_hash_wrapper(const unsigned char *data, size_t const len,
215
                      unsigned long long const seed, char *xxh64)
216
{
217
    unsigned short i = 0;
218
    const unsigned short lim = GF_XXH64_DIGEST_LENGTH * 2 + 1;
219
    XXH64_hash_t hash = 0;
220
    XXH64_canonical_t c_hash = {
221
        {
222
            0,
223
        },
224
    };
225
    const uint8_t *p = (const uint8_t *)&c_hash;
226

227
    hash = XXH64(data, len, seed);
228
    XXH64_canonicalFromHash(&c_hash, hash);
229

230
    for (i = 0; i < GF_XXH64_DIGEST_LENGTH; i++)
231
        snprintf(xxh64 + i * 2, lim - i * 2, "%02x", p[i]);
232

233
    return hash;
234
}
235

236
/**
237
 * This is the algorithm followed for generating new gfid
238
 * 1) generate xxh64 hash using snapname and original gfid of the object
239
 * 2) Using the canonicalized form of above hash as the key, generate
240
 *    another hash
241
 * 3) Combine both of the  8 byte hashes to generate a 16 byte uuid_t type
242
 * 4) Use the above uuid as the gfid
243
 *
244
 * Each byte of the hash is stored separately in different elements of the
245
 * character array represented by uuid_t
246
 * Ex: tmp[0] = (hash_2 >> 56) & 0xFF
247
 *     This saves the most significant byte of hash_2 in tmp[0]
248
 *     tmp[1] = (hash_2 >> 48) & 0xFF
249
 *     This saves next most significant byte of hash_2 in tmp[1]
250
 *     .
251
 *     .
252
 *     So on.
253
 *     tmp[0] - tmp[7] holds the contents of hash_2
254
 *     tmp[8] - tmp[15] hold the conents of hash_1
255
 *
256
 * The hash generated (i.e. of type XXH64_hash_t) is 8 bytes long. And for
257
 * gfid 16 byte uuid is needed. Hecne the 2 hashes are combined to form
258
 * one 16 byte entity.
259
 **/
260
int
261
gf_gfid_generate_from_xxh64(uuid_t gfid, char *key)
262
{
263
    char xxh64_1[GF_XXH64_DIGEST_LENGTH * 2 + 1] = {
264
        0,
265
    };
266
    char xxh64_2[GF_XXH64_DIGEST_LENGTH * 2 + 1] = {
267
        0,
268
    };
269
    XXH64_hash_t hash_1 = 0;
270
    XXH64_hash_t hash_2 = 0;
271
    int ret = -1;
272
    xlator_t *this = THIS;
273

274
    hash_1 = gf_xxh64_hash_wrapper((unsigned char *)key, strlen(key),
275
                                   GF_XXHSUM64_DEFAULT_SEED, xxh64_1);
276

277
    hash_2 = gf_xxh64_hash_wrapper((unsigned char *)xxh64_1, strlen(xxh64_1),
278
                                   GF_XXHSUM64_DEFAULT_SEED, xxh64_2);
279

280
    /* hash_2 is saved in 1st 8 elements of uuid_t char array */
281
    if (gf_gfid_from_xxh64(this, gfid, hash_2, 0)) {
282
        gf_msg_callingfn(this->name, GF_LOG_WARNING, 0,
283
                         LG_MSG_XXH64_TO_GFID_FAILED,
284
                         "failed to encode the hash %" XXH64_FMT
285
                         " into the 1st half of gfid",
286
                         hash_2);
287
        goto out;
288
    }
289

290
    /* hash_1 is saved in the remaining 8 elements of uuid_t */
291
    if (gf_gfid_from_xxh64(this, gfid, hash_1, 8)) {
292
        gf_msg_callingfn(this->name, GF_LOG_WARNING, 0,
293
                         LG_MSG_XXH64_TO_GFID_FAILED,
294
                         "failed to encode the hash %" XXH64_FMT
295
                         " into the 2nd half of gfid",
296
                         hash_1);
297
        goto out;
298
    }
299

300
    gf_msg_debug(this->name, 0,
301
                 "gfid generated is %s (hash1: %" XXH64_FMT
302
                 ") "
303
                 "hash2: %" XXH64_FMT ", xxh64_1: %s xxh64_2: %s",
304
                 uuid_utoa(gfid), hash_1, hash_2, xxh64_1, xxh64_2);
305

306
    ret = 0;
307

308
out:
309
    return ret;
310
}
311

312
/* works similar to mkdir(1) -p.
313
 */
314
int
315
mkdir_p(char *path, mode_t mode, gf_boolean_t allow_symlinks)
316
{
317
    int i = 0;
318
    int ret = -1;
319
    char dir[PATH_MAX] = {
320
        0,
321
    };
322
    struct stat stbuf = {
323
        0,
324
    };
325

326
    const int path_len = min(strlen(path), PATH_MAX - 1);
327

328
    snprintf(dir, path_len + 1, "%s", path);
329

330
    i = (dir[0] == '/') ? 1 : 0;
331
    do {
332
        if (path[i] != '/' && path[i] != '\0')
333
            continue;
334

335
        dir[i] = '\0';
336
        ret = sys_mkdir(dir, mode);
337
        if (ret && errno != EEXIST) {
338
            gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, NULL);
339
            goto out;
340
        }
341

342
        if (ret && errno == EEXIST && !allow_symlinks) {
343
            ret = sys_lstat(dir, &stbuf);
344
            if (ret)
345
                goto out;
346

347
            if (S_ISLNK(stbuf.st_mode)) {
348
                ret = -1;
349
                gf_smsg("", GF_LOG_ERROR, 0, LG_MSG_DIR_IS_SYMLINK, "dir=%s",
350
                        dir, NULL);
351
                goto out;
352
            }
353
        }
354
        dir[i] = '/';
355

356
    } while (path[i++] != '\0');
357

358
    ret = sys_stat(dir, &stbuf);
359
    if (ret || !S_ISDIR(stbuf.st_mode)) {
360
        if (ret == 0)
361
            errno = 0;
362
        ret = -1;
363
        gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED,
364
                "possibly some of the components"
365
                " were not directories",
366
                NULL);
367
        goto out;
368
    }
369

370
    ret = 0;
371
out:
372

373
    return ret;
374
}
375

376
int
377
gf_lstat_dir(const char *path, struct stat *stbuf_in)
378
{
379
    int ret = -1;
380
    struct stat stbuf = {
381
        0,
382
    };
383

384
    if (path == NULL) {
385
        errno = EINVAL;
386
        goto out;
387
    }
388

389
    ret = sys_lstat(path, &stbuf);
390
    if (ret)
391
        goto out;
392

393
    if (!S_ISDIR(stbuf.st_mode)) {
394
        errno = ENOTDIR;
395
        ret = -1;
396
        goto out;
397
    }
398
    ret = 0;
399

400
out:
401
    if (!ret && stbuf_in)
402
        *stbuf_in = stbuf;
403

404
    return ret;
405
}
406

407
int
408
log_base2(unsigned long x)
409
{
410
    int val = 0;
411

412
    while (x > 1) {
413
        x /= 2;
414
        val++;
415
    }
416

417
    return val;
418
}
419

420
/**
421
 * gf_rev_dns_lookup -- Perform a reverse DNS lookup on the IP address.
422
 *
423
 * @ip: The IP address to perform a reverse lookup on
424
 *
425
 * @return: success: Allocated string containing the hostname
426
 *          failure: NULL
427
 */
428
char *
429
gf_rev_dns_lookup(const char *ip)
430
{
431
    char *fqdn = NULL;
432
    int ret = 0;
433

434
    GF_VALIDATE_OR_GOTO("resolver", ip, out);
435

436
    /* Get the FQDN */
437
    ret = gf_get_hostname_from_ip((char *)ip, &fqdn);
438
    if (ret != 0) {
439
        gf_smsg("resolver", GF_LOG_INFO, errno, LG_MSG_RESOLVE_HOSTNAME_FAILED,
440
                "hostname=%s", ip, NULL);
441
    }
442
out:
443
    return fqdn;
444
}
445

446
struct xldump {
447
    int lineno;
448
};
449

450
/* to catch any format discrepencies that may arise in code */
451
static int
452
nprintf(struct xldump *dump, const char *fmt, ...)
453
    __attribute__((__format__(__printf__, 2, 3)));
454
static int
455
nprintf(struct xldump *dump, const char *fmt, ...)
456
{
457
    va_list ap;
458
    char *msg = NULL;
459
    char header[32];
460
    int ret = 0;
461

462
    ret = snprintf(header, 32, "%3d:", ++dump->lineno);
463
    if (ret < 0)
464
        goto out;
465

466
    va_start(ap, fmt);
467
    ret = vasprintf(&msg, fmt, ap);
468
    va_end(ap);
469
    if (-1 == ret)
470
        goto out;
471

472
    /* NOTE: No ret value from gf_msg_plain, so unable to compute printed
473
     * characters. The return value from nprintf is not used, so for now
474
     * living with it */
475
    gf_msg_plain(GF_LOG_WARNING, "%s %s", header, msg);
476

477
out:
478
    FREE(msg);
479
    return 0;
480
}
481

482
static int
483
xldump_options(dict_t *this, char *key, data_t *value, void *d)
484
{
485
    nprintf(d, "    option %s %s", key, value->data);
486
    return 0;
487
}
488

489
static void
490
xldump_subvolumes(xlator_t *this, void *d)
491
{
492
    xlator_list_t *subv = NULL;
493
    int len = 0;
494
    char *subvstr = NULL;
495

496
    if (!this->children)
497
        return;
498

499
    for (subv = this->children; subv; subv = subv->next)
500
        len += (strlen(subv->xlator->name) + 1);
501

502
    subvstr = GF_MALLOC(len, gf_common_mt_strdup);
503

504
    len = 0;
505
    for (subv = this->children; subv; subv = subv->next)
506
        len += sprintf(subvstr + len, "%s%s", subv->xlator->name,
507
                       subv->next ? " " : "");
508

509
    nprintf(d, "    subvolumes %s", subvstr);
510

511
    GF_FREE(subvstr);
512
}
513

514
static void
515
xldump(xlator_t *each, void *d)
516
{
517
    nprintf(d, "volume %s", each->name);
518
    nprintf(d, "    type %s", each->type);
519
    dict_foreach(each->options, xldump_options, d);
520

521
    xldump_subvolumes(each, d);
522

523
    nprintf(d, "end-volume");
524
    nprintf(d, " ");
525
}
526

527
void
528
gf_log_dump_graph(FILE *specfp, glusterfs_graph_t *graph)
529
{
530
    struct xldump xld = {
531
        0,
532
    };
533

534
    gf_msg_plain(GF_LOG_WARNING, "Final graph:");
535
    gf_msg_plain(GF_LOG_WARNING,
536
                 "+---------------------------------------"
537
                 "---------------------------------------+");
538

539
    xlator_foreach_depth_first(graph->top, xldump, &xld);
540

541
    gf_msg_plain(GF_LOG_WARNING,
542
                 "+---------------------------------------"
543
                 "---------------------------------------+");
544
}
545

546
static void
547
gf_dump_config_flags(void)
548
{
549
    gf_msg_plain_nomem(GF_LOG_ALERT, "configuration details:");
550

551
/* have argp */
552
#ifdef HAVE_ARGP
553
    gf_msg_plain_nomem(GF_LOG_ALERT, "argp 1");
554
#endif
555

556
/* ifdef if found backtrace */
557
#ifdef HAVE_BACKTRACE
558
    gf_msg_plain_nomem(GF_LOG_ALERT, "backtrace 1");
559
#endif
560

561
/* Berkeley-DB version has cursor->get() */
562
#ifdef HAVE_BDB_CURSOR_GET
563
    gf_msg_plain_nomem(GF_LOG_ALERT, "bdb->cursor->get 1");
564
#endif
565

566
/* Define to 1 if you have the <db.h> header file. */
567
#ifdef HAVE_DB_H
568
    gf_msg_plain_nomem(GF_LOG_ALERT, "db.h 1");
569
#endif
570

571
/* Define to 1 if you have the <dlfcn.h> header file. */
572
#ifdef HAVE_DLFCN_H
573
    gf_msg_plain_nomem(GF_LOG_ALERT, "dlfcn 1");
574
#endif
575

576
/* define if fdatasync exists */
577
#ifdef HAVE_FDATASYNC
578
    gf_msg_plain_nomem(GF_LOG_ALERT, "fdatasync 1");
579
#endif
580

581
/* Define to 1 if you have the `pthread' library (-lpthread). */
582
#ifdef HAVE_LIBPTHREAD
583
    gf_msg_plain_nomem(GF_LOG_ALERT, "libpthread 1");
584
#endif
585

586
/* define if llistxattr exists */
587
#ifdef HAVE_LLISTXATTR
588
    gf_msg_plain_nomem(GF_LOG_ALERT, "llistxattr 1");
589
#endif
590

591
/* define if found setfsuid setfsgid */
592
#ifdef HAVE_SET_FSID
593
    gf_msg_plain_nomem(GF_LOG_ALERT, "setfsid 1");
594
#endif
595

596
/* Define to 1 if you have the <sys/epoll.h> header file. */
597
#ifdef HAVE_SYS_EPOLL_H
598
    gf_msg_plain_nomem(GF_LOG_ALERT, "epoll.h 1");
599
#endif
600

601
/* Define to 1 if you have the <sys/extattr.h> header file. */
602
#ifdef HAVE_SYS_EXTATTR_H
603
    gf_msg_plain_nomem(GF_LOG_ALERT, "extattr.h 1");
604
#endif
605

606
/* Define to 1 if you have the <sys/xattr.h> header file. */
607
#ifdef HAVE_SYS_XATTR_H
608
    gf_msg_plain_nomem(GF_LOG_ALERT, "xattr.h 1");
609
#endif
610

611
/* define if found st_atim.tv_nsec */
612
#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
613
    gf_msg_plain_nomem(GF_LOG_ALERT, "st_atim.tv_nsec 1");
614
#endif
615

616
/* define if found st_atimespec.tv_nsec */
617
#ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
618
    gf_msg_plain_nomem(GF_LOG_ALERT, "st_atimespec.tv_nsec 1");
619
#endif
620

621
/* Define to the full name and version of this package. */
622
#ifdef PACKAGE_STRING
623
    gf_msg_plain_nomem(GF_LOG_ALERT, "package-string: " PACKAGE_STRING);
624
#endif
625

626
    return;
627
}
628

629
/* Obtain a backtrace and print it to the log */
630
void
631
gf_print_trace(int32_t signum, glusterfs_ctx_t *ctx)
632
{
633
    char msg[1024] = {
634
        0,
635
    };
636
    char timestr[GF_TIMESTR_SIZE] = {
637
        0,
638
    };
639
    call_stack_t *stack = NULL;
640

641
    /* Now every gf_log call will just write to a buffer and when the
642
     * buffer becomes full, its written to the log-file. Suppose the process
643
     * crashes and prints the backtrace in the log-file, then the previous
644
     * log information will still be in the buffer itself. So flush the
645
     * contents of the buffer to the log file before printing the backtrace
646
     * which helps in debugging.
647
     */
648
    gf_log_flush(ctx);
649

650
    gf_log_disable_suppression_before_exit(ctx);
651

652
    if (!ctx || ctx->log.logger != gf_logger_glusterlog)
653
        goto skip_print_trace;
654

655
#ifdef GF_LINUX_HOST_OS
656
    gf_log_disable_syslog(ctx);
657
#endif
658

659
    /* Pending frames, (if any), list them in order */
660
    gf_msg_plain_nomem(GF_LOG_ALERT, "pending frames:");
661
    {
662
        /* FIXME: traversing stacks outside pool->lock */
663
        list_for_each_entry(stack, &ctx->pool->all_frames, all_frames)
664
        {
665
            if (stack->type == GF_OP_TYPE_FOP)
666
                sprintf(msg, "frame : type(%d) op(%s)", stack->type,
667
                        gf_fop_list[stack->op]);
668
            else
669
                sprintf(msg, "frame : type(%d) op(%d)", stack->type, stack->op);
670

671
            gf_msg_plain_nomem(GF_LOG_ALERT, msg);
672
        }
673
    }
674

675
    sprintf(msg, "patchset: %s", GLUSTERFS_REPOSITORY_REVISION);
676
    gf_msg_plain_nomem(GF_LOG_ALERT, msg);
677

678
    sprintf(msg, "signal received: %d", signum);
679
    gf_msg_plain_nomem(GF_LOG_ALERT, msg);
680
    {
681
        /* Dump the timestamp of the crash too, so the previous logs
682
           can be related */
683
        gf_time_fmt_FT(timestr, sizeof timestr, gf_time());
684
        gf_msg_plain_nomem(GF_LOG_ALERT, "time of crash: ");
685
        gf_msg_plain_nomem(GF_LOG_ALERT, timestr);
686
    }
687

688
    gf_dump_config_flags();
689
    gf_msg_backtrace_nomem(GF_LOG_ALERT, 200);
690
    sprintf(msg, "---------");
691
    gf_msg_plain_nomem(GF_LOG_ALERT, msg);
692

693
#ifdef GF_LINUX_HOST_OS
694
    gf_log_enable_syslog(ctx);
695
#endif
696
skip_print_trace:
697
    /* Send a signal to terminate the process */
698
    signal(signum, SIG_DFL);
699
    raise(signum);
700
}
701

702
void
703
trap(void)
704
{
705
}
706

707
char *
708
gf_trim(char *string)
709
{
710
    register char *s, *t;
711

712
    if (string == NULL) {
713
        return NULL;
714
    }
715

716
    for (s = string; isspace(*s); s++)
717
        ;
718

719
    if (*s == 0)
720
        return s;
721

722
    t = s + strlen(s) - 1;
723
    while (t > s && isspace(*t))
724
        t--;
725
    *++t = '\0';
726

727
    return s;
728
}
729

730
int
731
gf_strstr(const char *str, const char *delim, const char *match)
732
{
733
    char *tmp = NULL;
734
    char *save_ptr = NULL;
735
    char *tmp_str = NULL;
736

737
    int ret = 0;
738

739
    tmp_str = strdup(str);
740

741
    if (str == NULL || delim == NULL || match == NULL || tmp_str == NULL) {
742
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
743
                         "argument invalid");
744
        ret = -1;
745
        goto out;
746
    }
747

748
    tmp = strtok_r(tmp_str, delim, &save_ptr);
749

750
    while (tmp) {
751
        ret = strcmp(tmp, match);
752

753
        if (ret == 0)
754
            break;
755

756
        tmp = strtok_r(NULL, delim, &save_ptr);
757
    }
758

759
out:
760
    free(tmp_str);
761

762
    return ret;
763
}
764

765
int
766
gf_string2time(const char *str, time_t *n)
767
{
768
    unsigned long value = 0;
769
    char *tail = NULL;
770
    int old_errno = 0;
771
    const char *s = NULL;
772

773
    if (str == NULL || n == NULL) {
774
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
775
                         "argument invalid");
776
        errno = EINVAL;
777
        return -1;
778
    }
779

780
    for (s = str; *s != '\0'; s++) {
781
        if (isspace(*s))
782
            continue;
783
        if (*s == '-')
784
            return -1;
785
        break;
786
    }
787

788
    old_errno = errno;
789
    errno = 0;
790
    value = strtol(str, &tail, 0);
791
    if (str == tail)
792
        errno = EINVAL;
793

794
    if (errno == ERANGE || errno == EINVAL)
795
        return -1;
796

797
    if (errno == 0)
798
        errno = old_errno;
799

800
    if (((tail[0] == '\0') || ((tail[0] == 's') && (tail[1] == '\0')) ||
801
         ((tail[0] == 's') && (tail[1] == 'e') && (tail[2] == 'c') &&
802
          (tail[3] == '\0'))))
803
        goto out;
804

805
    else if (((tail[0] == 'm') && (tail[1] == '\0')) ||
806
             ((tail[0] == 'm') && (tail[1] == 'i') && (tail[2] == 'n') &&
807
              (tail[3] == '\0'))) {
808
        value = value * GF_MINUTE_IN_SECONDS;
809
        goto out;
810
    }
811

812
    else if (((tail[0] == 'h') && (tail[1] == '\0')) ||
813
             ((tail[0] == 'h') && (tail[1] == 'r') && (tail[2] == '\0'))) {
814
        value = value * GF_HOUR_IN_SECONDS;
815
        goto out;
816
    }
817

818
    else if (((tail[0] == 'd') && (tail[1] == '\0')) ||
819
             ((tail[0] == 'd') && (tail[1] == 'a') && (tail[2] == 'y') &&
820
              (tail[3] == 's') && (tail[4] == '\0'))) {
821
        value = value * GF_DAY_IN_SECONDS;
822
        goto out;
823
    }
824

825
    else if (((tail[0] == 'w') && (tail[1] == '\0')) ||
826
             ((tail[0] == 'w') && (tail[1] == 'k') && (tail[2] == '\0'))) {
827
        value = value * GF_WEEK_IN_SECONDS;
828
        goto out;
829
    } else {
830
        return -1;
831
    }
832

833
out:
834
    *n = value;
835

836
    return 0;
837
}
838

839
int
840
gf_string2percent(const char *str, double *n)
841
{
842
    double value = 0;
843
    char *tail = NULL;
844
    int old_errno = 0;
845
    const char *s = NULL;
846

847
    if (str == NULL || n == NULL) {
848
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
849
                         "argument invalid");
850
        errno = EINVAL;
851
        return -1;
852
    }
853

854
    for (s = str; *s != '\0'; s++) {
855
        if (isspace(*s))
856
            continue;
857
        if (*s == '-')
858
            return -1;
859
        break;
860
    }
861

862
    old_errno = errno;
863
    errno = 0;
864
    value = strtod(str, &tail);
865
    if (str == tail)
866
        errno = EINVAL;
867

868
    if (errno == ERANGE || errno == EINVAL)
869
        return -1;
870

871
    if (errno == 0)
872
        errno = old_errno;
873

874
    if (!((tail[0] == '\0') || ((tail[0] == '%') && (tail[1] == '\0'))))
875
        return -1;
876

877
    *n = value;
878

879
    return 0;
880
}
881

882
static int
883
_gf_string2long(const char *str, long *n, int base)
884
{
885
    long value = 0;
886
    char *tail = NULL;
887
    int old_errno = 0;
888

889
    if (str == NULL || n == NULL) {
890
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
891
                         "argument invalid");
892
        errno = EINVAL;
893
        return -1;
894
    }
895

896
    old_errno = errno;
897
    errno = 0;
898
    value = strtol(str, &tail, base);
899
    if ((str == tail) || (*tail != 0)) {
900
        errno = EINVAL;
901
        return -1;
902
    }
903

904
    if (errno == ERANGE || errno == EINVAL)
905
        return -1;
906

907
    if (errno == 0)
908
        errno = old_errno;
909

910
    *n = value;
911

912
    return 0;
913
}
914

915
static int
916
_gf_string2ulong(const char *str, unsigned long *n, int base)
917
{
918
    unsigned long value = 0;
919
    char *tail = NULL;
920
    int old_errno = 0;
921
    const char *s = NULL;
922

923
    if (str == NULL || n == NULL) {
924
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
925
                         "argument invalid");
926
        errno = EINVAL;
927
        return -1;
928
    }
929

930
    for (s = str; *s != '\0'; s++) {
931
        if (isspace(*s))
932
            continue;
933
        if (*s == '-')
934
            return -1;
935
        break;
936
    }
937

938
    old_errno = errno;
939
    errno = 0;
940
    value = strtoul(str, &tail, base);
941
    if (str == tail)
942
        errno = EINVAL;
943

944
    if (errno == ERANGE || errno == EINVAL)
945
        return -1;
946

947
    if (errno == 0)
948
        errno = old_errno;
949

950
    if (tail[0] != '\0')
951
        return -1;
952

953
    *n = value;
954

955
    return 0;
956
}
957

958
static int
959
_gf_string2uint(const char *str, unsigned int *n, int base)
960
{
961
    unsigned long value = 0;
962
    char *tail = NULL;
963
    int old_errno = 0;
964
    const char *s = NULL;
965

966
    if (str == NULL || n == NULL) {
967
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
968
                         "argument invalid");
969
        errno = EINVAL;
970
        return -1;
971
    }
972

973
    for (s = str; *s != '\0'; s++) {
974
        if (isspace(*s))
975
            continue;
976
        if (*s == '-')
977
            return -1;
978
        break;
979
    }
980

981
    old_errno = errno;
982
    errno = 0;
983
    value = strtoul(str, &tail, base);
984
    if (str == tail)
985
        errno = EINVAL;
986

987
    if (errno == ERANGE || errno == EINVAL)
988
        return -1;
989

990
    if (errno == 0)
991
        errno = old_errno;
992

993
    if (tail[0] != '\0')
994
        return -1;
995

996
    *n = (unsigned int)value;
997

998
    return 0;
999
}
1000

1001
static int
1002
_gf_string2double(const char *str, double *n)
1003
{
1004
    double value = 0.0;
1005
    char *tail = NULL;
1006
    int old_errno = 0;
1007

1008
    if (str == NULL || n == NULL) {
1009
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1010
                         "argument invalid");
1011
        errno = EINVAL;
1012
        return -1;
1013
    }
1014

1015
    old_errno = errno;
1016
    errno = 0;
1017
    value = strtod(str, &tail);
1018
    if (str == tail)
1019
        errno = EINVAL;
1020

1021
    if (errno == ERANGE || errno == EINVAL)
1022
        return -1;
1023

1024
    if (errno == 0)
1025
        errno = old_errno;
1026

1027
    if (tail[0] != '\0')
1028
        return -1;
1029

1030
    *n = value;
1031

1032
    return 0;
1033
}
1034

1035
static int
1036
_gf_string2longlong(const char *str, long long *n, int base)
1037
{
1038
    long long value = 0;
1039
    char *tail = NULL;
1040
    int old_errno = 0;
1041

1042
    if (str == NULL || n == NULL) {
1043
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1044
                         "argument invalid");
1045
        errno = EINVAL;
1046
        return -1;
1047
    }
1048

1049
    old_errno = errno;
1050
    errno = 0;
1051
    value = strtoll(str, &tail, base);
1052
    if (str == tail)
1053
        errno = EINVAL;
1054

1055
    if (errno == ERANGE || errno == EINVAL)
1056
        return -1;
1057

1058
    if (errno == 0)
1059
        errno = old_errno;
1060

1061
    if (tail[0] != '\0')
1062
        return -1;
1063

1064
    *n = value;
1065

1066
    return 0;
1067
}
1068

1069
static int
1070
_gf_string2ulonglong(const char *str, unsigned long long *n, int base)
1071
{
1072
    unsigned long long value = 0;
1073
    char *tail = NULL;
1074
    int old_errno = 0;
1075
    const char *s = NULL;
1076

1077
    if (str == NULL || n == NULL) {
1078
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1079
                         "argument invalid");
1080
        errno = EINVAL;
1081
        return -1;
1082
    }
1083

1084
    for (s = str; *s != '\0'; s++) {
1085
        if (isspace(*s))
1086
            continue;
1087
        if (*s == '-')
1088
            return -1;
1089
        break;
1090
    }
1091

1092
    old_errno = errno;
1093
    errno = 0;
1094
    value = strtoull(str, &tail, base);
1095
    if (str == tail)
1096
        errno = EINVAL;
1097

1098
    if (errno == ERANGE || errno == EINVAL)
1099
        return -1;
1100

1101
    if (errno == 0)
1102
        errno = old_errno;
1103

1104
    if (tail[0] != '\0')
1105
        return -1;
1106

1107
    *n = value;
1108

1109
    return 0;
1110
}
1111

1112
int
1113
gf_string2long(const char *str, long *n)
1114
{
1115
    return _gf_string2long(str, n, 0);
1116
}
1117

1118
int
1119
gf_string2ulong(const char *str, unsigned long *n)
1120
{
1121
    return _gf_string2ulong(str, n, 0);
1122
}
1123

1124
int
1125
gf_string2int(const char *str, int *n)
1126
{
1127
    long l = 0;
1128
    int ret = 0;
1129

1130
    ret = _gf_string2long(str, &l, 0);
1131

1132
    *n = l;
1133
    return ret;
1134
}
1135

1136
int
1137
gf_string2uint(const char *str, unsigned int *n)
1138
{
1139
    return _gf_string2uint(str, n, 0);
1140
}
1141

1142
int
1143
gf_string2double(const char *str, double *n)
1144
{
1145
    return _gf_string2double(str, n);
1146
}
1147

1148
int
1149
gf_string2longlong(const char *str, long long *n)
1150
{
1151
    return _gf_string2longlong(str, n, 0);
1152
}
1153

1154
int
1155
gf_string2ulonglong(const char *str, unsigned long long *n)
1156
{
1157
    return _gf_string2ulonglong(str, n, 0);
1158
}
1159

1160
int
1161
gf_string2int8(const char *str, int8_t *n)
1162
{
1163
    long l = 0L;
1164
    int rv = 0;
1165

1166
    rv = _gf_string2long(str, &l, 0);
1167
    if (rv != 0)
1168
        return rv;
1169

1170
    if ((l >= INT8_MIN) && (l <= INT8_MAX)) {
1171
        *n = (int8_t)l;
1172
        return 0;
1173
    }
1174

1175
    errno = ERANGE;
1176
    return -1;
1177
}
1178

1179
int
1180
gf_string2int16(const char *str, int16_t *n)
1181
{
1182
    long l = 0L;
1183
    int rv = 0;
1184

1185
    rv = _gf_string2long(str, &l, 0);
1186
    if (rv != 0)
1187
        return rv;
1188

1189
    if ((l >= INT16_MIN) && (l <= INT16_MAX)) {
1190
        *n = (int16_t)l;
1191
        return 0;
1192
    }
1193

1194
    errno = ERANGE;
1195
    return -1;
1196
}
1197

1198
int
1199
gf_string2int32(const char *str, int32_t *n)
1200
{
1201
    long l = 0L;
1202
    int rv = 0;
1203

1204
    rv = _gf_string2long(str, &l, 0);
1205
    if (rv != 0)
1206
        return rv;
1207

1208
    if ((l >= INT32_MIN) && (l <= INT32_MAX)) {
1209
        *n = (int32_t)l;
1210
        return 0;
1211
    }
1212

1213
    errno = ERANGE;
1214
    return -1;
1215
}
1216

1217
int
1218
gf_string2int64(const char *str, int64_t *n)
1219
{
1220
    long long l = 0LL;
1221
    int rv = 0;
1222

1223
    rv = _gf_string2longlong(str, &l, 0);
1224
    if (rv != 0)
1225
        return rv;
1226

1227
    *n = (int64_t)l;
1228
    return 0;
1229
}
1230

1231
int
1232
gf_string2uint8(const char *str, uint8_t *n)
1233
{
1234
    unsigned long l = 0L;
1235
    int rv = 0;
1236

1237
    rv = _gf_string2ulong(str, &l, 0);
1238
    if (rv != 0)
1239
        return rv;
1240

1241
    if (l <= UINT8_MAX) {
1242
        *n = (uint8_t)l;
1243
        return 0;
1244
    }
1245

1246
    errno = ERANGE;
1247
    return -1;
1248
}
1249

1250
int
1251
gf_string2uint16(const char *str, uint16_t *n)
1252
{
1253
    unsigned long l = 0L;
1254
    int rv = 0;
1255

1256
    rv = _gf_string2ulong(str, &l, 0);
1257
    if (rv != 0)
1258
        return rv;
1259

1260
    if (l <= UINT16_MAX) {
1261
        *n = (uint16_t)l;
1262
        return 0;
1263
    }
1264

1265
    errno = ERANGE;
1266
    return -1;
1267
}
1268

1269
int
1270
gf_string2uint32(const char *str, uint32_t *n)
1271
{
1272
    unsigned long l = 0L;
1273
    int rv = 0;
1274

1275
    rv = _gf_string2ulong(str, &l, 0);
1276
    if (rv != 0)
1277
        return rv;
1278

1279
    if (l <= UINT32_MAX) {
1280
        *n = (uint32_t)l;
1281
        return 0;
1282
    }
1283

1284
    errno = ERANGE;
1285
    return -1;
1286
}
1287

1288
int
1289
gf_string2uint64(const char *str, uint64_t *n)
1290
{
1291
    unsigned long long l = 0ULL;
1292
    int rv = 0;
1293

1294
    rv = _gf_string2ulonglong(str, &l, 0);
1295
    if (rv != 0)
1296
        return rv;
1297

1298
    if (l <= UINT64_MAX) {
1299
        *n = (uint64_t)l;
1300
        return 0;
1301
    }
1302

1303
    errno = ERANGE;
1304
    return -1;
1305
}
1306

1307
int
1308
gf_string2ulong_base10(const char *str, unsigned long *n)
1309
{
1310
    return _gf_string2ulong(str, n, 10);
1311
}
1312

1313
int
1314
gf_string2uint_base10(const char *str, unsigned int *n)
1315
{
1316
    return _gf_string2uint(str, n, 10);
1317
}
1318

1319
int
1320
gf_string2uint8_base10(const char *str, uint8_t *n)
1321
{
1322
    unsigned long l = 0L;
1323
    int rv = 0;
1324

1325
    rv = _gf_string2ulong(str, &l, 10);
1326
    if (rv != 0)
1327
        return rv;
1328

1329
    if (l <= UINT8_MAX) {
1330
        *n = (uint8_t)l;
1331
        return 0;
1332
    }
1333

1334
    errno = ERANGE;
1335
    return -1;
1336
}
1337

1338
int
1339
gf_string2uint16_base10(const char *str, uint16_t *n)
1340
{
1341
    unsigned long l = 0L;
1342
    int rv = 0;
1343

1344
    rv = _gf_string2ulong(str, &l, 10);
1345
    if (rv != 0)
1346
        return rv;
1347

1348
    if (l <= UINT16_MAX) {
1349
        *n = (uint16_t)l;
1350
        return 0;
1351
    }
1352

1353
    errno = ERANGE;
1354
    return -1;
1355
}
1356

1357
int
1358
gf_string2uint32_base10(const char *str, uint32_t *n)
1359
{
1360
    unsigned long l = 0L;
1361
    int rv = 0;
1362

1363
    rv = _gf_string2ulong(str, &l, 10);
1364
    if (rv != 0)
1365
        return rv;
1366

1367
    if (l <= UINT32_MAX) {
1368
        *n = (uint32_t)l;
1369
        return 0;
1370
    }
1371

1372
    errno = ERANGE;
1373
    return -1;
1374
}
1375

1376
int
1377
gf_string2uint64_base10(const char *str, uint64_t *n)
1378
{
1379
    unsigned long long l = 0ULL;
1380
    int rv = 0;
1381

1382
    rv = _gf_string2ulonglong(str, &l, 10);
1383
    if (rv != 0)
1384
        return rv;
1385

1386
    if (l <= UINT64_MAX) {
1387
        *n = (uint64_t)l;
1388
        return 0;
1389
    }
1390

1391
    errno = ERANGE;
1392
    return -1;
1393
}
1394

1395
char *
1396
gf_uint64_2human_readable(uint64_t n)
1397
{
1398
    int ret = 0;
1399
    char *str = NULL;
1400

1401
    if (n >= GF_UNIT_PB) {
1402
        ret = gf_asprintf(&str, "%.1lfPB", ((double)n) / GF_UNIT_PB);
1403
        if (ret < 0)
1404
            goto err;
1405
    } else if (n >= GF_UNIT_TB) {
1406
        ret = gf_asprintf(&str, "%.1lfTB", ((double)n) / GF_UNIT_TB);
1407
        if (ret < 0)
1408
            goto err;
1409
    } else if (n >= GF_UNIT_GB) {
1410
        ret = gf_asprintf(&str, "%.1lfGB", ((double)n) / GF_UNIT_GB);
1411
        if (ret < 0)
1412
            goto err;
1413
    } else if (n >= GF_UNIT_MB) {
1414
        ret = gf_asprintf(&str, "%.1lfMB", ((double)n) / GF_UNIT_MB);
1415
        if (ret < 0)
1416
            goto err;
1417
    } else if (n >= GF_UNIT_KB) {
1418
        ret = gf_asprintf(&str, "%.1lfKB", ((double)n) / GF_UNIT_KB);
1419
        if (ret < 0)
1420
            goto err;
1421
    } else {
1422
        ret = gf_asprintf(&str, "%" PRIu64 "Bytes", n);
1423
        if (ret < 0)
1424
            goto err;
1425
    }
1426
    return str;
1427
err:
1428
    return NULL;
1429
}
1430

1431
int
1432
gf_string2bytesize_range(const char *str, uint64_t *n, uint64_t umax)
1433
{
1434
    double value = 0.0;
1435
    int64_t int_value = 0;
1436
    uint64_t unit = 0;
1437
    int64_t max = 0;
1438
    char *tail = NULL;
1439
    int old_errno = 0;
1440
    const char *s = NULL;
1441
    gf_boolean_t fraction = _gf_false;
1442

1443
    if (str == NULL || n == NULL) {
1444
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1445
                         "argument invalid");
1446
        errno = EINVAL;
1447
        return -1;
1448
    }
1449

1450
    max = umax & 0x7fffffffffffffffLL;
1451

1452
    for (s = str; *s != '\0'; s++) {
1453
        if (isspace(*s))
1454
            continue;
1455
        if (*s == '-')
1456
            return -1;
1457
        break;
1458
    }
1459

1460
    if (strrchr(str, '.'))
1461
        fraction = _gf_true;
1462

1463
    old_errno = errno;
1464
    errno = 0;
1465
    if (fraction)
1466
        value = strtod(str, &tail);
1467
    else
1468
        int_value = strtoll(str, &tail, 10);
1469

1470
    if (str == tail)
1471
        errno = EINVAL;
1472

1473
    if (errno == ERANGE || errno == EINVAL)
1474
        return -1;
1475

1476
    if (errno == 0)
1477
        errno = old_errno;
1478

1479
    if (tail[0] != '\0') {
1480
        if (strcasecmp(tail, GF_UNIT_KB_STRING) == 0)
1481
            unit = GF_UNIT_KB;
1482
        else if (strcasecmp(tail, GF_UNIT_MB_STRING) == 0)
1483
            unit = GF_UNIT_MB;
1484
        else if (strcasecmp(tail, GF_UNIT_GB_STRING) == 0)
1485
            unit = GF_UNIT_GB;
1486
        else if (strcasecmp(tail, GF_UNIT_TB_STRING) == 0)
1487
            unit = GF_UNIT_TB;
1488
        else if (strcasecmp(tail, GF_UNIT_PB_STRING) == 0)
1489
            unit = GF_UNIT_PB;
1490
        else if (strcasecmp(tail, GF_UNIT_B_STRING) != 0)
1491
            return -1;
1492

1493
        if (unit > 0) {
1494
            if (fraction)
1495
                value *= unit;
1496
            else
1497
                int_value *= unit;
1498
        }
1499
    }
1500

1501
    if (fraction) {
1502
        if ((max - value) < 0) {
1503
            errno = ERANGE;
1504
            return -1;
1505
        }
1506
        *n = (uint64_t)value;
1507
    } else {
1508
        if ((max - int_value) < 0) {
1509
            errno = ERANGE;
1510
            return -1;
1511
        }
1512
        *n = int_value;
1513
    }
1514

1515
    return 0;
1516
}
1517

1518
int
1519
gf_string2bytesize_uint64(const char *str, uint64_t *n)
1520
{
1521
    return gf_string2bytesize_range(str, n, UINT64_MAX);
1522
}
1523

1524
int
1525
gf_string2bytesize_int64(const char *str, int64_t *n)
1526
{
1527
    uint64_t u64 = 0;
1528
    int ret = 0;
1529

1530
    ret = gf_string2bytesize_range(str, &u64, INT64_MAX);
1531
    *n = (int64_t)u64;
1532
    return ret;
1533
}
1534

1535
int
1536
gf_string2percent_or_bytesize(const char *str, double *n,
1537
                              gf_boolean_t *is_percent)
1538
{
1539
    double value = 0ULL;
1540
    char *tail = NULL;
1541
    int old_errno = 0;
1542
    const char *s = NULL;
1543

1544
    if (str == NULL || n == NULL) {
1545
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1546
                         "argument invalid");
1547
        errno = EINVAL;
1548
        return -1;
1549
    }
1550

1551
    for (s = str; *s != '\0'; s++) {
1552
        if (isspace(*s))
1553
            continue;
1554
        if (*s == '-')
1555
            return -1;
1556
        break;
1557
    }
1558

1559
    old_errno = errno;
1560
    errno = 0;
1561
    value = strtod(str, &tail);
1562
    if (str == tail)
1563
        errno = EINVAL;
1564

1565
    if (errno == ERANGE || errno == EINVAL)
1566
        return -1;
1567

1568
    if (errno == 0)
1569
        errno = old_errno;
1570

1571
    /*Maximum accepted value for 64 bit OS will be (2^14 -1)PB*/
1572
    if (tail[0] != '\0') {
1573
        if (strcasecmp(tail, GF_UNIT_KB_STRING) == 0)
1574
            value *= GF_UNIT_KB;
1575
        else if (strcasecmp(tail, GF_UNIT_MB_STRING) == 0)
1576
            value *= GF_UNIT_MB;
1577
        else if (strcasecmp(tail, GF_UNIT_GB_STRING) == 0)
1578
            value *= GF_UNIT_GB;
1579
        else if (strcasecmp(tail, GF_UNIT_TB_STRING) == 0)
1580
            value *= GF_UNIT_TB;
1581
        else if (strcasecmp(tail, GF_UNIT_PB_STRING) == 0)
1582
            value *= GF_UNIT_PB;
1583
        else if (strcasecmp(tail, GF_UNIT_PERCENT_STRING) == 0)
1584
            *is_percent = _gf_true;
1585
        else
1586
            return -1;
1587
    }
1588

1589
    /* Error out if we cannot store the value in uint64 */
1590
    if ((UINT64_MAX - value) < 0) {
1591
        errno = ERANGE;
1592
        return -1;
1593
    }
1594

1595
    *n = value;
1596

1597
    return 0;
1598
}
1599

1600
int64_t
1601
gf_str_to_long_long(const char *number)
1602
{
1603
    int64_t unit = 1;
1604
    int64_t ret = 0;
1605
    char *endptr = NULL;
1606
    if (!number)
1607
        return 0;
1608

1609
    ret = strtoll(number, &endptr, 0);
1610

1611
    if (endptr) {
1612
        switch (*endptr) {
1613
            case 'G':
1614
            case 'g':
1615
                if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b'))
1616
                    unit = 1024 * 1024 * 1024;
1617
                break;
1618
            case 'M':
1619
            case 'm':
1620
                if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b'))
1621
                    unit = 1024 * 1024;
1622
                break;
1623
            case 'K':
1624
            case 'k':
1625
                if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b'))
1626
                    unit = 1024;
1627
                break;
1628
            case '%':
1629
                unit = 1;
1630
                break;
1631
            default:
1632
                unit = 1;
1633
                break;
1634
        }
1635
    }
1636
    return ret * unit;
1637
}
1638

1639
int
1640
gf_string2boolean(const char *str, gf_boolean_t *b)
1641
{
1642
    if (str == NULL) {
1643
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1644
                         "argument invalid");
1645
        return -1;
1646
    }
1647

1648
    if ((strcasecmp(str, "1") == 0) || (strcasecmp(str, "on") == 0) ||
1649
        (strcasecmp(str, "yes") == 0) || (strcasecmp(str, "true") == 0) ||
1650
        (strcasecmp(str, "enable") == 0)) {
1651
        *b = _gf_true;
1652
        return 0;
1653
    }
1654

1655
    if ((strcasecmp(str, "0") == 0) || (strcasecmp(str, "off") == 0) ||
1656
        (strcasecmp(str, "no") == 0) || (strcasecmp(str, "false") == 0) ||
1657
        (strcasecmp(str, "disable") == 0)) {
1658
        *b = _gf_false;
1659
        return 0;
1660
    }
1661

1662
    return -1;
1663
}
1664

1665
int
1666
gf_strn2boolean(const char *str, const int len, gf_boolean_t *b)
1667
{
1668
    if (str == NULL) {
1669
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1670
                         "argument invalid");
1671
        return -1;
1672
    }
1673

1674
    switch (len) {
1675
        case 1:
1676
            if (strcasecmp(str, "1") == 0) {
1677
                *b = _gf_true;
1678
                return 0;
1679
            } else if (strcasecmp(str, "0") == 0) {
1680
                *b = _gf_false;
1681
                return 0;
1682
            }
1683
            break;
1684
        case 2:
1685
            if (strcasecmp(str, "on") == 0) {
1686
                *b = _gf_true;
1687
                return 0;
1688
            } else if (strcasecmp(str, "no") == 0) {
1689
                *b = _gf_false;
1690
                return 0;
1691
            }
1692
            break;
1693
        case 3:
1694
            if (strcasecmp(str, "yes") == 0) {
1695
                *b = _gf_true;
1696
                return 0;
1697
            } else if (strcasecmp(str, "off") == 0) {
1698
                *b = _gf_false;
1699
                return 0;
1700
            }
1701
            break;
1702
        case 4:
1703
            if (strcasecmp(str, "true") == 0) {
1704
                *b = _gf_true;
1705
                return 0;
1706
            }
1707
            break;
1708
        case 5:
1709
            if (strcasecmp(str, "false") == 0) {
1710
                *b = _gf_false;
1711
                return 0;
1712
            }
1713
            break;
1714
        case 6:
1715
            if (strcasecmp(str, "enable") == 0) {
1716
                *b = _gf_true;
1717
                return 0;
1718
            }
1719
            break;
1720
        case 7:
1721
            if (strcasecmp(str, "disable") == 0) {
1722
                *b = _gf_false;
1723
                return 0;
1724
            }
1725
            break;
1726
        default:
1727
            return -1;
1728
            break;
1729
    }
1730
    return -1;
1731
}
1732

1733
/**
1734
 * gf_is_ip_in_net -- Checks if an IP Address is in a network.
1735
 *                    A network should be specified by something like
1736
 *                    '10.5.153.0/24' (in CIDR notation).
1737
 *
1738
 * @result : Sets to true if the IP is in the network
1739
 * @ip_str : The IP to check
1740
 * @network: The network to check the IP against.
1741
 *
1742
 * @return: success: _gf_true
1743
 *          failure: _gf_false
1744
 *
1745
 * Whenever this function is modified, please modify
1746
 * tests/utils/ip-in-cidr.c as well.
1747
 */
1748
gf_boolean_t
1749
gf_is_ip_in_net(const char *network, const char *ip_str)
1750
{
1751
    /* A buffer big enough for any socket address. */
1752
    uint8_t net_buff[sizeof(struct sockaddr_storage) + 1];
1753
    uint8_t ip_buff[sizeof(struct sockaddr_storage) + 1];
1754
    int32_t size;
1755
    uint8_t mask;
1756
    int ret = -EINVAL;
1757
    int family = AF_INET;
1758

1759
    GF_ASSERT(network);
1760
    GF_ASSERT(ip_str);
1761

1762
    if (strchr(network, ':'))
1763
        family = AF_INET6;
1764
    else if (strchr(network, '.'))
1765
        family = AF_INET;
1766
    else {
1767
        goto out;
1768
    }
1769

1770
    size = inet_net_pton(family, network, net_buff, sizeof(net_buff));
1771
    if (size < 0) {
1772
        GF_LOG_E("common-utils", LG_MSG_INET_NET_PTON_FAILED(errno));
1773
        goto out;
1774
    }
1775
    ret = inet_pton(family, ip_str, &ip_buff);
1776
    if (ret < 0) {
1777
        gf_smsg("common-utils", GF_LOG_ERROR, errno, LG_MSG_INET_PTON_FAILED,
1778
                NULL);
1779
        goto out;
1780
    }
1781

1782
    mask = (0xff00 >> (size & 7)) & 0xff;
1783
    size /= 8;
1784
    net_buff[size] &= mask;
1785
    ip_buff[size] &= mask;
1786

1787
    return memcmp(net_buff, ip_buff, size + 1) == 0;
1788
out:
1789
    return _gf_false;
1790
}
1791

1792
char *
1793
strtail(char *str, const char *pattern)
1794
{
1795
    int i = 0;
1796

1797
    for (i = 0; str[i] == pattern[i] && str[i]; i++)
1798
        ;
1799

1800
    if (pattern[i] == '\0')
1801
        return str + i;
1802

1803
    return NULL;
1804
}
1805

1806
void
1807
skipwhite(char **s)
1808
{
1809
    while (isspace(**s))
1810
        (*s)++;
1811
}
1812

1813
char *
1814
nwstrtail(char *str, char *pattern)
1815
{
1816
    for (;;) {
1817
        skipwhite(&str);
1818
        skipwhite(&pattern);
1819

1820
        if (*str != *pattern || !*str)
1821
            break;
1822

1823
        str++;
1824
        pattern++;
1825
    }
1826

1827
    return *pattern ? NULL : str;
1828
}
1829

1830
/**
1831
 * token_iter_init -- initialize tokenization
1832
 *
1833
 * @str: string to be tokenized
1834
 * @sep: token separator character
1835
 * @tit: pointer to iteration state
1836
 *
1837
 * @return: token string
1838
 *
1839
 * The returned token string and tit are
1840
 * not to be used directly, but through
1841
 * next_token().
1842
 */
1843
char *
1844
token_iter_init(char *str, char sep, token_iter_t *tit)
1845
{
1846
    tit->end = str + strlen(str);
1847
    tit->sep = sep;
1848

1849
    return str;
1850
}
1851

1852
/**
1853
 * next_token -- fetch next token in tokenization
1854
 * inited by token_iter_init().
1855
 *
1856
 * @tokenp: pointer to token
1857
 * @tit:    pointer to iteration state
1858
 *
1859
 * @return: true if iteration ends, else false
1860
 *
1861
 * The token pointed by @tokenp can be used
1862
 * after a call to next_token(). When next_token()
1863
 * returns true the iteration is to be stopped
1864
 * and the string with which the tokenization
1865
 * was inited (see token_iter_init() is restored,
1866
 * apart from dropped tokens (see drop_token()).
1867
 */
1868
gf_boolean_t
1869
next_token(char **tokenp, token_iter_t *tit)
1870
{
1871
    char *cursor = NULL;
1872
    gf_boolean_t is_last = _gf_false;
1873

1874
    for (cursor = *tokenp; *cursor; cursor++)
1875
        ;
1876
    if (cursor < tit->end) {
1877
        /*
1878
         * We detect that in between current token and end a zero
1879
         * marker has already been inserted. This means that the
1880
         * token has already been returned. We restore the
1881
         * separator and move ahead.
1882
         */
1883
        *cursor = tit->sep;
1884
        *tokenp = cursor + 1;
1885
    }
1886

1887
    for (cursor = *tokenp; *cursor && *cursor != tit->sep; cursor++)
1888
        ;
1889
    /* If the cursor ended up on a zero byte, then it's the last token. */
1890
    is_last = !*cursor;
1891
    /* Zero-terminate the token. */
1892
    *cursor = 0;
1893

1894
    return is_last;
1895
}
1896

1897
/*
1898
 * drop_token -- drop a token during iterated calls of next_token().
1899
 *
1900
 * Sample program that uses these functions to tokenize
1901
 * a comma-separated first argument while dropping the
1902
 * rest of the arguments if they occur as token:
1903
 *
1904
 * #include <stdio.h>
1905
 * #include <stdlib.h>
1906
 * #include <string.h>
1907
 * #include "glusterfs/common-utils.h"
1908
 *
1909
 * int
1910
 * main (int argc, char **argv)
1911
 * {
1912
 *         char *buf;
1913
 *         char *token;
1914
 *         token_iter_t tit;
1915
 *         int i;
1916
 *         gf_boolean_t iter_end;
1917
 *
1918
 *         if (argc <= 1)
1919
 *                 abort();
1920
 *
1921
 *         buf = strdup (argv[1]);
1922
 *         if (!buf)
1923
 *                 abort();
1924
 *
1925
 *         for (token = token_iter_init (buf, ',', &tit) ;;) {
1926
 *                 iter_end = next_token (&token, &tit);
1927
 *                 printf("found token: '%s'\n", token);
1928
 *                 for (i = 2; i < argc; i++) {
1929
 *                         if (strcmp (argv[i], token) == 0) {
1930
 *                                 printf ("%s\n", "dropping token!");
1931
 *                                 drop_token (token, &tit);
1932
 *                                 break;
1933
 *                          }
1934
 *                 }
1935
 *                 if (iter_end)
1936
 *                         break;
1937
 *         }
1938
 *
1939
 *         printf ("finally: '%s'\n", buf);
1940
 *
1941
 *         return 0;
1942
 * }
1943
 */
1944
void
1945
drop_token(char *token, token_iter_t *tit)
1946
{
1947
    char *cursor = NULL;
1948

1949
    for (cursor = token; *cursor; cursor++)
1950
        ;
1951
    if (cursor < tit->end) {
1952
        /*
1953
         * We detect a zero inserted by next_token().
1954
         * Step the cursor and copy what comes after
1955
         * to token.
1956
         */
1957
        for (cursor++; cursor < tit->end; *token++ = *cursor++)
1958
            ;
1959
    }
1960

1961
    /*
1962
     * Zero out the remainder of the buffer.
1963
     * It would be enough to insert just a single zero,
1964
     * but we continue 'till the end to have cleaner
1965
     * memory content.
1966
     */
1967
    for (cursor = token; cursor < tit->end; *cursor++ = 0)
1968
        ;
1969

1970
    /* Adjust the end to point to the new terminating zero. */
1971
    tit->end = token;
1972
}
1973

1974
/* Syntax formed according to RFC 1912 (RFC 1123 & 952 are more restrictive)  *
1975
   <hname> ::= <gen-name>*["."<gen-name>]                                     *
1976
   <gen-name> ::= <let-or-digit> <[*[<let-or-digit-or-hyphen>]<let-or-digit>] */
1977
char
1978
valid_host_name(char *address, int length)
1979
{
1980
    int i = 0;
1981
    int str_len = 0;
1982
    char ret = 1;
1983
    char *dup_addr = NULL;
1984
    char *temp_str = NULL;
1985
    char *save_ptr = NULL;
1986

1987
    if ((length > _POSIX_HOST_NAME_MAX) || (length < 1)) {
1988
        ret = 0;
1989
        goto out;
1990
    }
1991

1992
    dup_addr = gf_strndup(address, length);
1993
    if (!dup_addr) {
1994
        ret = 0;
1995
        goto out;
1996
    }
1997

1998
    if (!isalnum(dup_addr[length - 1]) && (dup_addr[length - 1] != '*')) {
1999
        ret = 0;
2000
        goto out;
2001
    }
2002

2003
    /* Check for consecutive dots, which is invalid in a hostname and is
2004
     * ignored by strtok()
2005
     */
2006
    if (strstr(dup_addr, "..")) {
2007
        ret = 0;
2008
        goto out;
2009
    }
2010

2011
    /* gen-name */
2012
    temp_str = strtok_r(dup_addr, ".", &save_ptr);
2013
    do {
2014
        str_len = strlen(temp_str);
2015

2016
        if (!isalnum(temp_str[0]) || !isalnum(temp_str[str_len - 1])) {
2017
            ret = 0;
2018
            goto out;
2019
        }
2020
        for (i = 1; i < str_len; i++) {
2021
            if (!isalnum(temp_str[i]) && (temp_str[i] != '-')) {
2022
                ret = 0;
2023
                goto out;
2024
            }
2025
        }
2026
    } while ((temp_str = strtok_r(NULL, ".", &save_ptr)));
2027

2028
out:
2029
    GF_FREE(dup_addr);
2030
    return ret;
2031
}
2032

2033
/*  Matches all ipv4 address, if wildcard_acc is true  '*' wildcard pattern for*
2034
  subnets is considered as valid strings as well */
2035
char
2036
valid_ipv4_address(char *address, int length, gf_boolean_t wildcard_acc)
2037
{
2038
    int octets = 0;
2039
    int value = 0;
2040
    char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL;
2041
    char ret = 1;
2042
    int is_wildcard = 0;
2043

2044
    tmp = gf_strndup(address, length);
2045

2046
    /*
2047
     * To prevent cases where last character is '.' and which have
2048
     * consecutive dots like ".." as strtok ignore consecutive
2049
     * delimiters.
2050
     */
2051
    if (length <= 0 || (strstr(address, "..")) ||
2052
        (!isdigit(tmp[length - 1]) && (tmp[length - 1] != '*'))) {
2053
        ret = 0;
2054
        goto out;
2055
    }
2056

2057
    prev = strtok_r(tmp, ".", &ptr);
2058

2059
    while (prev != NULL) {
2060
        octets++;
2061
        if (wildcard_acc && !strcmp(prev, "*")) {
2062
            is_wildcard = 1;
2063
        } else {
2064
            value = strtol(prev, &endptr, 10);
2065
            if ((value > 255) || (value < 0) ||
2066
                (endptr != NULL && *endptr != '\0')) {
2067
                ret = 0;
2068
                goto out;
2069
            }
2070
        }
2071
        prev = strtok_r(NULL, ".", &ptr);
2072
    }
2073

2074
    if ((octets > 4) || (octets < 4 && !is_wildcard)) {
2075
        ret = 0;
2076
    }
2077

2078
out:
2079
    GF_FREE(tmp);
2080
    return ret;
2081
}
2082

2083
static char
2084
valid_cidr_address(char *cidr_address, unsigned int len,
2085
                   gf_boolean_t wildcard_acc)
2086
{
2087
    unsigned int net_mask = 0;
2088
    char *temp = NULL, *cidr_str = NULL;
2089

2090
    cidr_str = strdupa(cidr_address);
2091
    temp = strstr(cidr_str, "/");
2092
    if (temp == NULL)
2093
        return 0; /* Since Invalid cidr ip address we return 0 */
2094

2095
    *temp = '\0';
2096
    temp++;
2097
    net_mask = (unsigned int)atoi(temp);
2098

2099
    if (net_mask > 32 || net_mask < 1)
2100
        return 0; /* Since Invalid cidr ip address we return 0*/
2101

2102
    return valid_ipv4_address(cidr_str, len, wildcard_acc);
2103
}
2104

2105
char
2106
valid_ipv6_address(char *address, int length, gf_boolean_t wildcard_acc)
2107
{
2108
    int hex_numbers = 0;
2109
    int value = 0;
2110
    int i = 0;
2111
    char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL;
2112
    char ret = 1;
2113
    int is_wildcard = 0;
2114
    int is_compressed = 0;
2115

2116
    tmp = gf_strndup(address, length);
2117

2118
    /* Check for '%' for link local addresses */
2119
    endptr = strchr(tmp, '%');
2120
    if (endptr) {
2121
        *endptr = '\0';
2122
        length = strlen(tmp);
2123
        endptr = NULL;
2124
    }
2125

2126
    /* Check for compressed form */
2127
    if (length <= 0 || tmp[length - 1] == ':') {
2128
        ret = 0;
2129
        goto out;
2130
    }
2131
    for (i = 0; i < (length - 1); i++) {
2132
        if (tmp[i] == ':' && tmp[i + 1] == ':') {
2133
            if (is_compressed == 0)
2134
                is_compressed = 1;
2135
            else {
2136
                ret = 0;
2137
                goto out;
2138
            }
2139
        }
2140
    }
2141

2142
    prev = strtok_r(tmp, ":", &ptr);
2143

2144
    while (prev != NULL) {
2145
        hex_numbers++;
2146
        if (wildcard_acc && !strcmp(prev, "*")) {
2147
            is_wildcard = 1;
2148
        } else {
2149
            value = strtol(prev, &endptr, 16);
2150
            if ((value > 0xffff) || (value < 0) ||
2151
                (endptr != NULL && *endptr != '\0')) {
2152
                ret = 0;
2153
                goto out;
2154
            }
2155
        }
2156
        prev = strtok_r(NULL, ":", &ptr);
2157
    }
2158

2159
    if ((hex_numbers > 8) ||
2160
        (hex_numbers < 8 && !is_wildcard && !is_compressed)) {
2161
        ret = 0;
2162
    }
2163

2164
out:
2165
    GF_FREE(tmp);
2166
    return ret;
2167
}
2168

2169
char
2170
valid_internet_address(char *address, gf_boolean_t wildcard_acc,
2171
                       gf_boolean_t cidr)
2172
{
2173
    char ret = 0;
2174
    int length = 0;
2175

2176
    if (address == NULL) {
2177
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
2178
                         "argument invalid");
2179
        goto out;
2180
    }
2181

2182
    length = strlen(address);
2183
    if (length == 0)
2184
        goto out;
2185

2186
    if (cidr && valid_cidr_address(address, length, wildcard_acc)) {
2187
        ret = 1;
2188
    }
2189

2190
    if (valid_ipv4_address(address, length, wildcard_acc) ||
2191
        valid_ipv6_address(address, length, wildcard_acc) ||
2192
        valid_host_name(address, length))
2193
        ret = 1;
2194

2195
out:
2196
    return ret;
2197
}
2198

2199
/*
2200
 * Check if both have same network address.
2201
 * Extract the network address from the sockaddr(s) addr by applying the
2202
 * network mask. If they match, return boolean _gf_true, _gf_false otherwise.
2203
 *
2204
 * (x == y) <=> (x ^ y == 0)
2205
 * (x & y) ^ (x & z) <=> x & (y ^ z)
2206
 *
2207
 * ((ip1 & mask) == (ip2 & mask)) <=> ((mask & (ip1 ^ ip2)) == 0)
2208
 */
2209
gf_boolean_t
2210
mask_match(const uint32_t a, const uint32_t b, const uint32_t m)
2211
{
2212
    return (((a ^ b) & m) == 0);
2213
}
2214

2215
/*Thread safe conversion function*/
2216
char *
2217
uuid_utoa(uuid_t uuid)
2218
{
2219
    char *uuid_buffer = glusterfs_uuid_buf_get();
2220
    gf_uuid_unparse(uuid, uuid_buffer);
2221
    return uuid_buffer;
2222
}
2223

2224
/*Re-entrant conversion function*/
2225
char *
2226
uuid_utoa_r(uuid_t uuid, char *dst)
2227
{
2228
    if (!dst)
2229
        return NULL;
2230
    gf_uuid_unparse(uuid, dst);
2231
    return dst;
2232
}
2233

2234
/*Thread safe conversion function*/
2235
char *
2236
lkowner_utoa(gf_lkowner_t *lkowner)
2237
{
2238
    char *lkowner_buffer = glusterfs_lkowner_buf_get();
2239
    lkowner_unparse(lkowner, lkowner_buffer, GF_LKOWNER_BUF_SIZE);
2240
    return lkowner_buffer;
2241
}
2242

2243
gf_boolean_t
2244
is_valid_lease_id(const char *lease_id)
2245
{
2246
    int i = 0;
2247
    gf_boolean_t valid = _gf_false;
2248

2249
    for (i = 0; i < LEASE_ID_SIZE; i++) {
2250
        if (lease_id[i] != 0) {
2251
            valid = _gf_true;
2252
            goto out;
2253
        }
2254
    }
2255
out:
2256
    return valid;
2257
}
2258

2259
/* Lease_id can be a either in printable or non printable binary
2260
 * format. This function can be used to print any lease_id.
2261
 *
2262
 * This function returns a pointer to a buf, containing the ascii
2263
 * representation of the value in lease_id, in the following format:
2264
 * 4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum
2265
 *
2266
 * Eg: If lease_id = "lid1-clnt1" the printable string would be:
2267
 * 6c69-6431-2d63-6c6e-7431-0000-0000-0000
2268
 *
2269
 * Note: The pointer returned should not be stored for further use, as any
2270
 * subsequent call to this function will override the same buffer.
2271
 */
2272
char *
2273
leaseid_utoa(const char *lease_id)
2274
{
2275
    char *buf = NULL;
2276
    int i = 0;
2277
    int j = 0;
2278

2279
    buf = glusterfs_leaseid_buf_get();
2280
    if (!buf)
2281
        goto out;
2282

2283
    for (i = 0; i < LEASE_ID_SIZE; i++) {
2284
        if (i && !(i % 2)) {
2285
            buf[j] = '-';
2286
            j++;
2287
        }
2288
        sprintf(&buf[j], "%02hhx", lease_id[i]);
2289
        j += 2;
2290
        if (j == GF_LEASE_ID_BUF_SIZE)
2291
            break;
2292
    }
2293
    buf[GF_LEASE_ID_BUF_SIZE - 1] = '\0';
2294
out:
2295
    return buf;
2296
}
2297

2298
char *
2299
gf_leaseid_get(void)
2300
{
2301
    return glusterfs_leaseid_buf_get();
2302
}
2303

2304
char *
2305
gf_existing_leaseid(void)
2306
{
2307
    return glusterfs_leaseid_exist();
2308
}
2309

2310
/*
2311
 * rounds up nr to power of two. If nr is already a power of two, just returns
2312
 * nr
2313
 */
2314

2315
int32_t
2316
gf_roundup_power_of_two(int32_t nr)
2317
{
2318
    int32_t result = 1;
2319

2320
    if (nr < 0) {
2321
        gf_smsg("common-utils", GF_LOG_WARNING, 0, LG_MSG_NEGATIVE_NUM_PASSED,
2322
                NULL);
2323
        result = -1;
2324
        goto out;
2325
    }
2326

2327
    while (result < nr)
2328
        result *= 2;
2329

2330
out:
2331
    return result;
2332
}
2333

2334
/*
2335
 * rounds up nr to next power of two. If nr is already a power of two, next
2336
 * power of two is returned.
2337
 */
2338

2339
int32_t
2340
gf_roundup_next_power_of_two(int32_t nr)
2341
{
2342
    int32_t result = 1;
2343

2344
    if (nr < 0) {
2345
        gf_smsg("common-utils", GF_LOG_WARNING, 0, LG_MSG_NEGATIVE_NUM_PASSED,
2346
                NULL);
2347
        result = -1;
2348
        goto out;
2349
    }
2350

2351
    while (result <= nr)
2352
        result *= 2;
2353

2354
out:
2355
    return result;
2356
}
2357

2358
char *
2359
get_host_name(char *word, char **host)
2360
{
2361
    char *delimiter = NULL;
2362
    delimiter = strrchr(word, ':');
2363
    if (delimiter)
2364
        *delimiter = '\0';
2365
    else
2366
        return NULL;
2367
    *host = word;
2368
    return *host;
2369
}
2370

2371
void
2372
gf_path_strip_trailing_slashes(char *path)
2373
{
2374
    int i = 0;
2375
    int len = 0;
2376

2377
    if (!path)
2378
        return;
2379

2380
    len = strlen(path);
2381
    for (i = len - 1; i > 0; i--) {
2382
        if (path[i] != '/')
2383
            break;
2384
    }
2385

2386
    if (i < (len - 1))
2387
        path[i + 1] = '\0';
2388

2389
    return;
2390
}
2391

2392
uint64_t
2393
get_mem_size(void)
2394
{
2395
    uint64_t memsize = -1;
2396

2397
#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS
2398

2399
    uint64_t page_size = 0;
2400
    uint64_t num_pages = 0;
2401

2402
    page_size = sysconf(_SC_PAGESIZE);
2403
    num_pages = sysconf(_SC_PHYS_PAGES);
2404

2405
    memsize = page_size * num_pages;
2406
#endif
2407

2408
#if defined GF_DARWIN_HOST_OS || defined __FreeBSD__
2409

2410
    size_t len = sizeof(memsize);
2411
    int name[] = {CTL_HW, HW_PHYSMEM};
2412

2413
    sysctl(name, 2, &memsize, &len, NULL, 0);
2414
#endif
2415

2416
#if defined __NetBSD__
2417

2418
    size_t len = sizeof(memsize);
2419
    int name64[] = {CTL_HW, HW_PHYSMEM64};
2420

2421
    sysctl(name64, 2, &memsize, &len, NULL, 0);
2422
    if (memsize == -1)
2423
        sysctl(name64, 2, &memsize, &len, NULL, 0);
2424
#endif
2425
    return memsize;
2426
}
2427

2428
int
2429
gf_canonicalize_path(char *path)
2430
{
2431
    int ret = -1;
2432
    int path_len = 0;
2433
    int dir_path_len = 0;
2434
    char *tmppath = NULL;
2435
    char *dir = NULL;
2436
    char *tmpstr = NULL;
2437
    int pathlen;
2438

2439
    if (!path || *path != '/')
2440
        goto out;
2441

2442
    if (!strcmp(path, "/"))
2443
        return 0;
2444

2445
    pathlen = strlen(path);
2446
    tmppath = gf_strndup(path, pathlen);
2447
    if (!tmppath)
2448
        goto out;
2449

2450
    /* Strip the extra slashes and return */
2451
    bzero(path, pathlen);
2452
    path[0] = '/';
2453
    dir = strtok_r(tmppath, "/", &tmpstr);
2454

2455
    while (dir) {
2456
        dir_path_len = strlen(dir);
2457
        memcpy((path + path_len + 1), dir, dir_path_len);
2458
        path_len += dir_path_len + 1;
2459
        dir = strtok_r(NULL, "/", &tmpstr);
2460
        if (dir) {
2461
            path[path_len] = '/';
2462
        }
2463
    }
2464
    path[path_len] = '\0';
2465
    ret = 0;
2466

2467
out:
2468
    if (ret)
2469
        gf_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_PATH_ERROR, NULL);
2470

2471
    GF_FREE(tmppath);
2472

2473
    return ret;
2474
}
2475

2476
char *
2477
generate_glusterfs_ctx_id(void)
2478
{
2479
    uuid_t ctxid;
2480
    char *tmp = NULL;
2481

2482
    gf_uuid_generate(ctxid);
2483
    tmp = uuid_utoa(ctxid);
2484

2485
    return gf_strndup(tmp, UUID_CANONICAL_FORM_LEN);
2486
}
2487

2488
static char *
2489
gf_get_reserved_ports(void)
2490
{
2491
    char *ports_info = NULL;
2492
#if defined GF_LINUX_HOST_OS
2493
    int proc_fd = -1;
2494
    char *proc_file = "/proc/sys/net/ipv4/ip_local_reserved_ports";
2495
    char buffer[4096] = {
2496
        0,
2497
    };
2498
    int32_t ret = -1;
2499

2500
    proc_fd = open(proc_file, O_RDONLY);
2501
    if (proc_fd == -1) {
2502
        /* What should be done in this case? error out from here
2503
         * and thus stop the glusterfs process from starting or
2504
         * continue with older method of using any of the available
2505
         * port? For now 2nd option is considered.
2506
         */
2507
        gf_smsg("glusterfs", GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,
2508
                " /proc/sys/net/ipv4/ip_local_reserved_ports", NULL);
2509
        goto out;
2510
    }
2511

2512
    ret = sys_read(proc_fd, buffer, sizeof(buffer) - 1);
2513
    if (ret < 0) {
2514
        gf_smsg("glusterfs", GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,
2515
                "file=%s", proc_file, NULL);
2516
        goto out;
2517
    }
2518

2519
    buffer[ret] = '\0';
2520
    ports_info = gf_strndup(buffer, ret);
2521

2522
out:
2523
    if (proc_fd != -1)
2524
        sys_close(proc_fd);
2525
#endif /* GF_LINUX_HOST_OS */
2526
    return ports_info;
2527
}
2528

2529
int
2530
gf_process_reserved_ports(unsigned char *ports, uint32_t ceiling)
2531
{
2532
    int ret = -1;
2533

2534
    memset(ports, 0, GF_PORT_ARRAY_SIZE);
2535

2536
#if defined GF_LINUX_HOST_OS
2537
    char *ports_info = NULL;
2538
    char *tmp = NULL;
2539
    char *blocked_port = NULL;
2540

2541
    ports_info = gf_get_reserved_ports();
2542
    if (!ports_info) {
2543
        gf_smsg("glusterfs", GF_LOG_WARNING, 0, LG_MSG_RESERVED_PORTS_ERROR,
2544
                NULL);
2545
        goto out;
2546
    }
2547

2548
    blocked_port = strtok_r(ports_info, ",\n", &tmp);
2549

2550
    while (blocked_port) {
2551
        gf_ports_reserved(blocked_port, ports, ceiling);
2552
        blocked_port = strtok_r(NULL, ",\n", &tmp);
2553
    }
2554

2555
    ret = 0;
2556

2557
out:
2558
    GF_FREE(ports_info);
2559

2560
#else  /* FIXME: Non Linux Host */
2561
    ret = 0;
2562
#endif /* GF_LINUX_HOST_OS */
2563

2564
    return ret;
2565
}
2566

2567
gf_boolean_t
2568
gf_ports_reserved(char *blocked_port, unsigned char *ports, uint32_t ceiling)
2569
{
2570
    gf_boolean_t result = _gf_false;
2571
    char *range_port = NULL;
2572
    int32_t tmp_port1 = -1;
2573
    int32_t tmp_port2 = -1;
2574

2575
    if (strstr(blocked_port, "-") == NULL) {
2576
        /* get rid of the new line character*/
2577
        if (blocked_port[strlen(blocked_port) - 1] == '\n')
2578
            blocked_port[strlen(blocked_port) - 1] = '\0';
2579
        if (gf_string2int32(blocked_port, &tmp_port1) == 0) {
2580
            if (tmp_port1 > GF_PORT_MAX || tmp_port1 < 0) {
2581
                gf_smsg("glusterfs-socket", GF_LOG_WARNING, 0,
2582
                        LG_MSG_INVALID_PORT, "port=%d", tmp_port1, NULL);
2583
                result = _gf_true;
2584
                goto out;
2585
            } else {
2586
                gf_msg_debug("glusterfs", 0,
2587
                             "blocking port "
2588
                             "%d",
2589
                             tmp_port1);
2590
                BIT_SET(ports, tmp_port1);
2591
            }
2592
        } else {
2593
            gf_smsg("glusterfs-socket", GF_LOG_WARNING, 0, LG_MSG_INVALID_PORT,
2594
                    "port=%s", blocked_port, NULL);
2595
            result = _gf_true;
2596
            goto out;
2597
        }
2598
    } else {
2599
        range_port = strtok(blocked_port, "-");
2600
        if (!range_port) {
2601
            result = _gf_true;
2602
            goto out;
2603
        }
2604
        if (gf_string2int32(range_port, &tmp_port1) == 0) {
2605
            if (tmp_port1 > ceiling)
2606
                tmp_port1 = ceiling;
2607
            if (tmp_port1 < 0)
2608
                tmp_port1 = 0;
2609
        }
2610
        range_port = strtok(NULL, "-");
2611
        if (!range_port) {
2612
            result = _gf_true;
2613
            goto out;
2614
        }
2615
        /* get rid of the new line character*/
2616
        if (range_port[strlen(range_port) - 1] == '\n')
2617
            range_port[strlen(range_port) - 1] = '\0';
2618
        if (gf_string2int32(range_port, &tmp_port2) == 0) {
2619
            if (tmp_port2 > ceiling)
2620
                tmp_port2 = ceiling;
2621
            if (tmp_port2 < 0)
2622
                tmp_port2 = 0;
2623
        }
2624
        gf_msg_debug("glusterfs", 0, "lower: %d, higher: %d", tmp_port1,
2625
                     tmp_port2);
2626
        for (; tmp_port1 <= tmp_port2; tmp_port1++)
2627
            BIT_SET(ports, tmp_port1);
2628
    }
2629

2630
out:
2631
    return result;
2632
}
2633

2634
/* Takes in client ip{v4,v6} and returns associated hostname, if any
2635
 * Also, allocates memory for the hostname.
2636
 * Returns: 0 for success, -1 for failure
2637
 */
2638
int
2639
gf_get_hostname_from_ip(char *client_ip, char **hostname)
2640
{
2641
    int ret = -1;
2642
    struct sockaddr *client_sockaddr = NULL;
2643
    struct sockaddr_in client_sock_in = {0};
2644
    struct sockaddr_in6 client_sock_in6 = {0};
2645
    char client_hostname[NI_MAXHOST] = {0};
2646
    char *client_ip_copy = NULL;
2647
    char *tmp = NULL;
2648
    char *ip = NULL;
2649
    size_t addr_sz = 0;
2650
    int ip_len;
2651

2652
    if (!client_ip)
2653
        goto out;
2654

2655
    ip_len = strlen(client_ip);
2656
    /* if ipv4, reverse lookup the hostname to
2657
     * allow FQDN based rpc authentication
2658
     */
2659
    if (!valid_ipv6_address(client_ip, ip_len, 0) &&
2660
        !valid_ipv4_address(client_ip, ip_len, 0)) {
2661
        /* most times, we get a.b.c.d:port form, so check that */
2662
        client_ip_copy = gf_strndup(client_ip, ip_len);
2663
        if (!client_ip_copy)
2664
            goto out;
2665

2666
        ip = strtok_r(client_ip_copy, ":", &tmp);
2667
    } else {
2668
        ip = client_ip;
2669
    }
2670

2671
    ip_len = strlen(ip);
2672
    if (valid_ipv4_address(ip, ip_len, 0) == _gf_true) {
2673
        client_sockaddr = (struct sockaddr *)&client_sock_in;
2674
        addr_sz = sizeof(client_sock_in);
2675
        client_sock_in.sin_family = AF_INET;
2676
        ret = inet_pton(AF_INET, ip, (void *)&client_sock_in.sin_addr.s_addr);
2677

2678
    } else if (valid_ipv6_address(ip, ip_len, 0) == _gf_true) {
2679
        client_sockaddr = (struct sockaddr *)&client_sock_in6;
2680
        addr_sz = sizeof(client_sock_in6);
2681

2682
        client_sock_in6.sin6_family = AF_INET6;
2683
        ret = inet_pton(AF_INET6, ip, (void *)&client_sock_in6.sin6_addr);
2684
    } else {
2685
        goto out;
2686
    }
2687

2688
    if (ret != 1) {
2689
        ret = -1;
2690
        goto out;
2691
    }
2692

2693
    /* You cannot just use sizeof (*client_sockaddr), as per the man page
2694
     * the (getnameinfo) size must be the size of the underlying sockaddr
2695
     * struct e.g. sockaddr_in6 or sockaddr_in.  Failure to do so will
2696
     * break IPv6 hostname resolution (IPv4 will work only because
2697
     * the sockaddr_in struct happens to be of the correct size).
2698
     */
2699
    ret = getnameinfo(client_sockaddr, addr_sz, client_hostname,
2700
                      sizeof(client_hostname), NULL, 0, 0);
2701
    if (ret) {
2702
        gf_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED,
2703
                "ip=%s", client_ip, "ret=%s", gai_strerror(ret), NULL);
2704
        ret = -1;
2705
        goto out;
2706
    }
2707

2708
    *hostname = gf_strdup((char *)client_hostname);
2709
out:
2710
    if (client_ip_copy)
2711
        GF_FREE(client_ip_copy);
2712

2713
    return ret;
2714
}
2715

2716
gf_boolean_t
2717
gf_interface_search(char *ip)
2718
{
2719
    int32_t ret = -1;
2720
    gf_boolean_t found = _gf_false;
2721
    struct ifaddrs *ifaddr, *ifa;
2722
    int family;
2723
    char host[NI_MAXHOST];
2724
    xlator_t *this = NULL;
2725
    char *pct = NULL;
2726

2727
    this = THIS;
2728

2729
    ret = getifaddrs(&ifaddr);
2730

2731
    if (ret != 0) {
2732
        gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETIFADDRS_FAILED, "ret=%s",
2733
                gai_strerror(ret), NULL);
2734
        goto out;
2735
    }
2736

2737
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
2738
        if (!ifa->ifa_addr) {
2739
            /*
2740
             * This seemingly happens if an interface hasn't
2741
             * been bound to a particular protocol (seen with
2742
             * TUN devices).
2743
             */
2744
            continue;
2745
        }
2746
        family = ifa->ifa_addr->sa_family;
2747

2748
        if (family != AF_INET && family != AF_INET6)
2749
            continue;
2750

2751
        ret = getnameinfo(ifa->ifa_addr,
2752
                          (family == AF_INET) ? sizeof(struct sockaddr_in)
2753
                                              : sizeof(struct sockaddr_in6),
2754
                          host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
2755

2756
        if (ret != 0) {
2757
            gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED,
2758
                    "ret=%s", gai_strerror(ret), NULL);
2759
            goto out;
2760
        }
2761

2762
        /*
2763
         * Sometimes the address comes back as addr%eth0 or
2764
         * similar.  Since % is an invalid character, we can
2765
         * strip it out with confidence that doing so won't
2766
         * harm anything.
2767
         */
2768
        pct = index(host, '%');
2769
        if (pct) {
2770
            *pct = '\0';
2771
        }
2772

2773
        if (strncmp(ip, host, NI_MAXHOST) == 0) {
2774
            gf_msg_debug(this->name, 0,
2775
                         "%s is local address at "
2776
                         "interface %s",
2777
                         ip, ifa->ifa_name);
2778
            found = _gf_true;
2779
            goto out;
2780
        }
2781
    }
2782
out:
2783
    if (ifaddr)
2784
        freeifaddrs(ifaddr);
2785
    return found;
2786
}
2787

2788
static char *
2789
get_ip_from_addrinfo(struct addrinfo *addr, char **ip)
2790
{
2791
    char buf[64];
2792
    void *in_addr = NULL;
2793
    struct sockaddr_in *s4 = NULL;
2794
    struct sockaddr_in6 *s6 = NULL;
2795

2796
    switch (addr->ai_family) {
2797
        case AF_INET:
2798
            s4 = (struct sockaddr_in *)addr->ai_addr;
2799
            in_addr = &s4->sin_addr;
2800
            break;
2801

2802
        case AF_INET6:
2803
            s6 = (struct sockaddr_in6 *)addr->ai_addr;
2804
            in_addr = &s6->sin6_addr;
2805
            break;
2806

2807
        default:
2808
            gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_INVALID_FAMILY, NULL);
2809
            return NULL;
2810
    }
2811

2812
    if (!inet_ntop(addr->ai_family, in_addr, buf, sizeof(buf))) {
2813
        gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_CONVERSION_FAILED, NULL);
2814
        return NULL;
2815
    }
2816

2817
    *ip = gf_strdup(buf);
2818
    return *ip;
2819
}
2820

2821
gf_boolean_t
2822
gf_is_loopback_localhost(const struct sockaddr *sa, char *hostname)
2823
{
2824
    GF_ASSERT(sa);
2825

2826
    gf_boolean_t is_local = _gf_false;
2827
    const struct in_addr *addr4 = NULL;
2828
    const struct in6_addr *addr6 = NULL;
2829
    uint8_t *ap = NULL;
2830
    struct in6_addr loopbackaddr6 = IN6ADDR_LOOPBACK_INIT;
2831

2832
    switch (sa->sa_family) {
2833
        case AF_INET:
2834
            addr4 = &(((struct sockaddr_in *)sa)->sin_addr);
2835
            ap = (uint8_t *)&addr4->s_addr;
2836
            if (ap[0] == 127)
2837
                is_local = _gf_true;
2838
            break;
2839

2840
        case AF_INET6:
2841
            addr6 = &(((struct sockaddr_in6 *)sa)->sin6_addr);
2842
            if (memcmp(addr6, &loopbackaddr6, sizeof(loopbackaddr6)) == 0)
2843
                is_local = _gf_true;
2844
            break;
2845

2846
        default:
2847
            if (hostname)
2848
                gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_INVALID_FAMILY,
2849
                        "family=%d", sa->sa_family, "hostname=%s", hostname,
2850
                        NULL);
2851
            break;
2852
    }
2853

2854
    return is_local;
2855
}
2856

2857
gf_boolean_t
2858
gf_is_local_addr(char *hostname)
2859
{
2860
    int32_t ret = -1;
2861
    struct addrinfo *result = NULL;
2862
    struct addrinfo *res = NULL;
2863
    gf_boolean_t found = _gf_false;
2864
    char *ip = NULL;
2865
    xlator_t *this = NULL;
2866
    struct addrinfo hints;
2867

2868
    this = THIS;
2869

2870
    memset(&hints, 0, sizeof(hints));
2871
    /*
2872
     * Removing AI_ADDRCONFIG from default_hints
2873
     * for being able to use link local ipv6 addresses
2874
     */
2875
    hints.ai_family = AF_UNSPEC;
2876

2877
    ret = getaddrinfo(hostname, NULL, &hints, &result);
2878

2879
    if (ret != 0) {
2880
        gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETADDRINFO_FAILED,
2881
                "ret=%s", gai_strerror(ret), NULL);
2882
        goto out;
2883
    }
2884

2885
    for (res = result; res != NULL; res = res->ai_next) {
2886
        get_ip_from_addrinfo(res, &ip);
2887
        gf_msg_debug(this->name, 0, "%s ", (ip ? ip : "<unknown>"));
2888

2889
        if (ip) {
2890
            found = (gf_is_loopback_localhost(res->ai_addr, hostname) ||
2891
                     gf_interface_search(ip));
2892
        }
2893
        if (found) {
2894
            GF_FREE(ip);
2895
            goto out;
2896
        }
2897
        GF_FREE(ip);
2898
        /* the above free will not set ip to NULL, and hence, there is
2899
           double free possible as the loop continues. set ip to NULL. */
2900
        ip = NULL;
2901
    }
2902

2903
out:
2904
    if (result)
2905
        freeaddrinfo(result);
2906

2907
    if (!found)
2908
        gf_msg_debug(this->name, 0, "%s is not local", hostname);
2909

2910
    return found;
2911
}
2912

2913
gf_boolean_t
2914
gf_is_same_address(char *name1, char *name2)
2915
{
2916
    struct addrinfo *addr1 = NULL;
2917
    struct addrinfo *addr2 = NULL;
2918
    struct addrinfo *p = NULL;
2919
    struct addrinfo *q = NULL;
2920
    gf_boolean_t ret = _gf_false;
2921
    int gai_err = 0;
2922
    struct addrinfo hints;
2923

2924
    memset(&hints, 0, sizeof(hints));
2925
    hints.ai_family = AF_UNSPEC;
2926

2927
    gai_err = getaddrinfo(name1, NULL, &hints, &addr1);
2928
    if (gai_err != 0) {
2929
        gf_smsg(name1, GF_LOG_WARNING, 0, LG_MSG_GETADDRINFO_FAILED, "error=%s",
2930
                gai_strerror(gai_err), NULL);
2931
        goto out;
2932
    }
2933

2934
    gai_err = getaddrinfo(name2, NULL, &hints, &addr2);
2935
    if (gai_err != 0) {
2936
        gf_smsg(name2, GF_LOG_WARNING, 0, LG_MSG_GETADDRINFO_FAILED, "error=%s",
2937
                gai_strerror(gai_err), NULL);
2938
        goto out;
2939
    }
2940

2941
    for (p = addr1; p; p = p->ai_next) {
2942
        for (q = addr2; q; q = q->ai_next) {
2943
            if (p->ai_addrlen != q->ai_addrlen) {
2944
                continue;
2945
            }
2946
            if (memcmp(p->ai_addr, q->ai_addr, p->ai_addrlen)) {
2947
                continue;
2948
            }
2949
            ret = _gf_true;
2950
            goto out;
2951
        }
2952
    }
2953

2954
out:
2955
    if (addr1) {
2956
        freeaddrinfo(addr1);
2957
    }
2958
    if (addr2) {
2959
        freeaddrinfo(addr2);
2960
    }
2961
    return ret;
2962
}
2963

2964
/*
2965
 * Processes list of volfile servers.
2966
 * Format: <host1>:<port1> <host2>:<port2>...
2967
 */
2968
int
2969
gf_process_getspec_servers_list(cmd_args_t *cmd_args, const char *servers_list)
2970
{
2971
    char *tmp = NULL;
2972
    char *address = NULL;
2973
    char *host = NULL;
2974
    char *last_colon = NULL;
2975
    char *save_ptr = NULL;
2976
    int port = 0;
2977
    int ret = -1;
2978

2979
    tmp = gf_strdup(servers_list);
2980
    if (!tmp) {
2981
        errno = ENOMEM;
2982
        goto out;
2983
    }
2984

2985
    address = strtok_r(tmp, " ", &save_ptr);
2986
    if (!address) {
2987
        errno = EINVAL;
2988
        goto out;
2989
    }
2990

2991
    while (1) {
2992
        last_colon = strrchr(address, ':');
2993
        if (!last_colon) {
2994
            errno = EINVAL;
2995
            ret = -1;
2996
            break;
2997
        }
2998
        *last_colon = '\0';
2999
        host = address;
3000
        port = atoi(last_colon + 1);
3001
        if (port <= 0) {
3002
            errno = EINVAL;
3003
            ret = -1;
3004
            break;
3005
        }
3006
        ret = gf_set_volfile_server_common(cmd_args, host,
3007
                                           GF_DEFAULT_VOLFILE_TRANSPORT, port);
3008
        if (ret && errno != EEXIST) {
3009
            break;
3010
        }
3011
        address = strtok_r(NULL, " ", &save_ptr);
3012
        if (!address) {
3013
            errno = 0;
3014
            ret = 0;
3015
            break;
3016
        }
3017
    }
3018

3019
out:
3020
    if (tmp) {
3021
        GF_FREE(tmp);
3022
    }
3023

3024
    return ret;
3025
}
3026

3027
int
3028
gf_set_volfile_server_common(cmd_args_t *cmd_args, const char *host,
3029
                             const char *transport, int port)
3030
{
3031
    server_cmdline_t *server = NULL;
3032
    server_cmdline_t *tmp = NULL;
3033
    char *duphost = NULL;
3034
    int ret = -1;
3035

3036
    GF_VALIDATE_OR_GOTO(THIS->name, cmd_args, out);
3037
    GF_VALIDATE_OR_GOTO(THIS->name, host, out);
3038
    GF_VALIDATE_OR_GOTO(THIS->name, transport, out);
3039

3040
    server = GF_CALLOC(1, sizeof(server_cmdline_t),
3041
                       gf_common_mt_server_cmdline_t);
3042
    if (!server) {
3043
        errno = ENOMEM;
3044
        goto out;
3045
    }
3046

3047
    INIT_LIST_HEAD(&server->list);
3048
    server->port = port;
3049

3050
    duphost = gf_strdup(host);
3051
    if (!duphost) {
3052
        errno = ENOMEM;
3053
        goto out;
3054
    }
3055

3056
    char *lastptr = rindex(duphost, ':');
3057
    if (lastptr) {
3058
        *lastptr = '\0';
3059
        long port_argument = strtol(lastptr + 1, NULL, 0);
3060
        if (!port_argument) {
3061
            port_argument = port;
3062
        }
3063
        server->port = port_argument;
3064
    }
3065
    server->volfile_server = gf_strdup(duphost);
3066
    if (!server->volfile_server) {
3067
        errno = ENOMEM;
3068
        goto out;
3069
    }
3070

3071
    server->transport = gf_strdup(transport);
3072
    if (!server->transport) {
3073
        errno = ENOMEM;
3074
        goto out;
3075
    }
3076

3077
    if (!cmd_args->volfile_server) {
3078
        cmd_args->volfile_server = server->volfile_server;
3079
        cmd_args->volfile_server_transport = server->transport;
3080
        cmd_args->volfile_server_port = server->port;
3081
        cmd_args->curr_server = server;
3082
    }
3083

3084
    list_for_each_entry(tmp, &cmd_args->volfile_servers, list)
3085
    {
3086
        if ((!strcmp(tmp->volfile_server, server->volfile_server) &&
3087
             !strcmp(tmp->transport, server->transport) &&
3088
             (tmp->port == server->port))) {
3089
            /* Duplicate option given, log and ignore */
3090
            gf_smsg("gluster", GF_LOG_INFO, EEXIST, LG_MSG_DUPLICATE_ENTRY,
3091
                    NULL);
3092
            ret = 0;
3093
            goto out;
3094
        }
3095
    }
3096

3097
    list_add_tail(&server->list, &cmd_args->volfile_servers);
3098

3099
    ret = 0;
3100
out:
3101
    if (-1 == ret) {
3102
        if (server) {
3103
            GF_FREE(server->volfile_server);
3104
            GF_FREE(server->transport);
3105
            GF_FREE(server);
3106
        }
3107
    }
3108
    if (duphost)
3109
        GF_FREE(duphost);
3110

3111
    return ret;
3112
}
3113

3114
/* Sets log file path from user provided arguments */
3115
int
3116
gf_set_log_file_path(cmd_args_t *cmd_args, glusterfs_ctx_t *ctx)
3117
{
3118
    int i = 0;
3119
    int j = 0;
3120
    int ret = 0;
3121
    int tmp_len = 0;
3122
    char tmp_str[1024] = {
3123
        0,
3124
    };
3125

3126
    if (!cmd_args)
3127
        goto done;
3128

3129
    if (cmd_args->mount_point) {
3130
        j = 0;
3131
        i = 0;
3132
        if (cmd_args->mount_point[0] == '/')
3133
            i = 1;
3134
        for (; i < strlen(cmd_args->mount_point); i++, j++) {
3135
            tmp_str[j] = cmd_args->mount_point[i];
3136
            if (cmd_args->mount_point[i] == '/')
3137
                tmp_str[j] = '-';
3138
        }
3139

3140
        ret = gf_asprintf(&cmd_args->log_file,
3141
                          DEFAULT_LOG_FILE_DIRECTORY "/%s.log", tmp_str);
3142
        if (ret > 0)
3143
            ret = 0;
3144
        goto done;
3145
    }
3146

3147
    if (ctx && GF_GLUSTERD_PROCESS == ctx->process_mode) {
3148
        ret = gf_asprintf(&cmd_args->log_file,
3149
                          DEFAULT_LOG_FILE_DIRECTORY "/%s.log", GLUSTERD_NAME);
3150
        if (ret > 0)
3151
            ret = 0;
3152

3153
        goto done;
3154
    }
3155

3156
    if (cmd_args->volfile) {
3157
        j = 0;
3158
        i = 0;
3159
        if (cmd_args->volfile[0] == '/')
3160
            i = 1;
3161
        for (; i < strlen(cmd_args->volfile); i++, j++) {
3162
            tmp_str[j] = cmd_args->volfile[i];
3163
            if (cmd_args->volfile[i] == '/')
3164
                tmp_str[j] = '-';
3165
        }
3166
        ret = gf_asprintf(&cmd_args->log_file,
3167
                          DEFAULT_LOG_FILE_DIRECTORY "/%s.log", tmp_str);
3168
        if (ret > 0)
3169
            ret = 0;
3170
        goto done;
3171
    }
3172

3173
    if (cmd_args->volfile_server) {
3174
        if (strncmp(cmd_args->volfile_server_transport, "unix", 4) == 0) {
3175
            if (cmd_args->volfile_server[0] == '/')
3176
                i = 1;
3177
            tmp_len = strlen(cmd_args->volfile_server);
3178
            for (j = 0; i < tmp_len; i++, j++) {
3179
                tmp_str[j] = cmd_args->volfile_server[i];
3180
                if (cmd_args->volfile_server[i] == '/')
3181
                    tmp_str[j] = '-';
3182
            }
3183
            ret = gf_asprintf(&cmd_args->log_file, "%s/%s-%s-%d.log",
3184
                              DEFAULT_LOG_FILE_DIRECTORY, tmp_str,
3185
                              cmd_args->volfile_id, getpid());
3186
        } else {
3187
            ret = gf_asprintf(&cmd_args->log_file, "%s/%s-%s-%d.log",
3188
                              DEFAULT_LOG_FILE_DIRECTORY,
3189
                              cmd_args->volfile_server, cmd_args->volfile_id,
3190
                              getpid());
3191
        }
3192
        if (ret > 0)
3193
            ret = 0;
3194
    }
3195
done:
3196
    return ret;
3197
}
3198

3199
int
3200
gf_thread_cleanup_xint(pthread_t thread)
3201
{
3202
    int ret = 0;
3203
    void *res = NULL;
3204

3205
    ret = pthread_cancel(thread);
3206
    if (ret != 0)
3207
        goto error_return;
3208

3209
    ret = pthread_join(thread, &res);
3210
    if (ret != 0)
3211
        goto error_return;
3212

3213
    if (res != PTHREAD_CANCELED)
3214
        goto error_return;
3215

3216
    ret = 0;
3217

3218
error_return:
3219
    return ret;
3220
}
3221

3222
static void
3223
gf_thread_set_vname(pthread_t thread, const char *name, va_list args)
3224
{
3225
    char thread_name[GF_THREAD_NAME_LIMIT];
3226
    int ret;
3227

3228
    /* Initialize the thread name with the prefix (not NULL terminated). */
3229
    memcpy(thread_name, GF_THREAD_NAME_PREFIX,
3230
           sizeof(GF_THREAD_NAME_PREFIX) - 1);
3231

3232
    ret = vsnprintf(thread_name + sizeof(GF_THREAD_NAME_PREFIX) - 1,
3233
                    sizeof(thread_name) - sizeof(GF_THREAD_NAME_PREFIX) + 1,
3234
                    name, args);
3235
    if (ret < 0) {
3236
        gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_PTHREAD_NAMING_FAILED,
3237
                "name=%s", name, NULL);
3238
        return;
3239
    }
3240

3241
    if (ret >= sizeof(thread_name)) {
3242
        gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_THREAD_NAME_TOO_LONG,
3243
                "name=%s", thread_name, NULL);
3244
    }
3245

3246
    ret = __gf_thread_set_name(thread, thread_name);
3247

3248
    if (ret != 0) {
3249
        gf_smsg(THIS->name, GF_LOG_WARNING, ret, LG_MSG_SET_THREAD_FAILED,
3250
                "name=%s", thread_name, NULL);
3251
    }
3252
}
3253

3254
void
3255
gf_thread_set_name(pthread_t thread, const char *name, ...)
3256
{
3257
    va_list args;
3258

3259
    va_start(args, name);
3260
    gf_thread_set_vname(thread, name, args);
3261
    va_end(args);
3262
}
3263

3264
static int
3265
gf_thread_vcreate(pthread_t *thread, const pthread_attr_t *attr,
3266
                  void *(*start_routine)(void *), void *arg, const char *name,
3267
                  va_list args)
3268
{
3269
    sigset_t set, old;
3270
    int ret;
3271

3272
    sigemptyset(&old);
3273
    sigfillset(&set);
3274
    sigdelset(&set, SIGSEGV);
3275
    sigdelset(&set, SIGBUS);
3276
    sigdelset(&set, SIGILL);
3277
    sigdelset(&set, SIGSYS);
3278
    sigdelset(&set, SIGFPE);
3279
    sigdelset(&set, SIGABRT);
3280
    sigdelset(&set, SIGCONT);
3281

3282
    pthread_sigmask(SIG_BLOCK, &set, &old);
3283

3284
    ret = pthread_create(thread, attr, start_routine, arg);
3285
    if (ret != 0) {
3286
        gf_smsg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_THREAD_CREATE_FAILED,
3287
                NULL);
3288
        ret = -1;
3289
    } else if (name != NULL) {
3290
        gf_thread_set_vname(*thread, name, args);
3291
    }
3292

3293
    pthread_sigmask(SIG_SETMASK, &old, NULL);
3294

3295
    return ret;
3296
}
3297

3298
int
3299
gf_thread_create(pthread_t *thread, const pthread_attr_t *attr,
3300
                 void *(*start_routine)(void *), void *arg, const char *name,
3301
                 ...)
3302
{
3303
    va_list args;
3304
    int ret;
3305

3306
    va_start(args, name);
3307
    ret = gf_thread_vcreate(thread, attr, start_routine, arg, name, args);
3308
    va_end(args);
3309

3310
    return ret;
3311
}
3312

3313
int
3314
gf_thread_create_detached(pthread_t *thread, void *(*start_routine)(void *),
3315
                          void *arg, const char *name, ...)
3316
{
3317
    pthread_attr_t attr;
3318
    va_list args;
3319
    int ret = -1;
3320

3321
    ret = pthread_attr_init(&attr);
3322
    if (ret) {
3323
        gf_smsg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_PTHREAD_ATTR_INIT_FAILED,
3324
                NULL);
3325
        return -1;
3326
    }
3327

3328
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3329

3330
    va_start(args, name);
3331
    ret = gf_thread_vcreate(thread, &attr, start_routine, arg, name, args);
3332
    va_end(args);
3333

3334
    pthread_attr_destroy(&attr);
3335

3336
    return ret;
3337
}
3338

3339
/* Below function is use to check at runtime if pid is running */
3340

3341
static gf_boolean_t
3342
gf_is_pid_running(int pid)
3343
{
3344
#ifdef __FreeBSD__
3345
    int ret = -1;
3346

3347
    ret = sys_kill(pid, 0);
3348
    if (ret < 0) {
3349
        return _gf_false;
3350
    }
3351
#else
3352
    char fname[32] = {
3353
        0,
3354
    };
3355
    int fd = -1;
3356

3357
    snprintf(fname, sizeof(fname), "/proc/%d/cmdline", pid);
3358

3359
    fd = sys_open(fname, O_RDONLY, 0);
3360
    if (fd < 0) {
3361
        return _gf_false;
3362
    }
3363

3364
    sys_close(fd);
3365
#endif
3366
    return _gf_true;
3367
}
3368

3369
gf_boolean_t
3370
gf_is_service_running(char *pidfile, int *pid)
3371
{
3372
    FILE *file = NULL;
3373
    gf_boolean_t running = _gf_false;
3374
    int ret = 0;
3375
    int fno = 0;
3376

3377
    file = fopen(pidfile, "r+");
3378
    if (!file) {
3379
        goto out;
3380
    }
3381

3382
    fno = fileno(file);
3383
    ret = lockf(fno, F_TEST, 0);
3384
    if (ret == -1) {
3385
        running = _gf_true;
3386
    }
3387

3388
    ret = fscanf(file, "%d", pid);
3389
    if (ret <= 0) {
3390
        gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, "pidfile=%s",
3391
                pidfile, NULL);
3392
        *pid = -1;
3393
        running = _gf_false;
3394
        goto out;
3395
    }
3396

3397
    running = gf_is_pid_running(*pid);
3398
out:
3399
    if (file)
3400
        fclose(file);
3401
    return running;
3402
}
3403

3404
/*
3405
 * gf_set_timestamp:
3406
 *      It sets the mtime and atime of 'dest' file as of 'src'.
3407
 */
3408

3409
int
3410
gf_set_timestamp(const char *src, const char *dest)
3411
{
3412
    struct stat sb = {
3413
        0,
3414
    };
3415
#if defined(HAVE_UTIMENSAT)
3416
    struct timespec new_time[2] = {{
3417
                                       0,
3418
                                   },
3419
                                   {
3420
                                       0,
3421
                                   }};
3422
#else
3423
    struct timeval new_time[2] = {{
3424
                                      0,
3425
                                  },
3426
                                  {
3427
                                      0,
3428
                                  }};
3429
#endif
3430
    int ret = 0;
3431
    xlator_t *this = NULL;
3432

3433
    this = THIS;
3434
    GF_ASSERT(this);
3435
    GF_ASSERT(src);
3436
    GF_ASSERT(dest);
3437

3438
    ret = sys_stat(src, &sb);
3439
    if (ret) {
3440
        gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_FILE_STAT_FAILED,
3441
                "stat=%s", src, NULL);
3442
        goto out;
3443
    }
3444
    /* The granularity is nano seconds if `utimensat()` is available,
3445
     * and micro seconds otherwise.
3446
     */
3447
#if defined(HAVE_UTIMENSAT)
3448
    new_time[0].tv_sec = sb.st_atime;
3449
    new_time[0].tv_nsec = ST_ATIM_NSEC(&sb);
3450

3451
    new_time[1].tv_sec = sb.st_mtime;
3452
    new_time[1].tv_nsec = ST_MTIM_NSEC(&sb);
3453

3454
    /* dirfd = 0 is ignored because `dest` is an absolute path. */
3455
    ret = sys_utimensat(AT_FDCWD, dest, new_time, AT_SYMLINK_NOFOLLOW);
3456
    if (ret) {
3457
        gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMENSAT_FAILED,
3458
                "dest=%s", dest, NULL);
3459
    }
3460
#else
3461
    new_time[0].tv_sec = sb.st_atime;
3462
    new_time[0].tv_usec = ST_ATIM_NSEC(&sb) / 1000;
3463

3464
    new_time[1].tv_sec = sb.st_mtime;
3465
    new_time[1].tv_usec = ST_MTIM_NSEC(&sb) / 1000;
3466

3467
    ret = sys_utimes(dest, new_time);
3468
    if (ret) {
3469
        gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMES_FAILED,
3470
                "dest=%s", dest, NULL);
3471
    }
3472
#endif
3473
out:
3474
    return ret;
3475
}
3476

3477
static void
3478
gf_backtrace_end(char *buf, size_t frames)
3479
{
3480
    size_t pos = 0;
3481

3482
    if (!buf)
3483
        return;
3484

3485
    pos = strlen(buf);
3486

3487
    frames = min(frames, GF_BACKTRACE_LEN - pos - 1);
3488

3489
    if (0 == frames)
3490
        return;
3491

3492
    memset(buf + pos, ')', frames);
3493
    buf[pos + frames] = '\0';
3494
}
3495

3496
/*Returns bytes written*/
3497
static int
3498
gf_backtrace_append(char *buf, size_t pos, char *framestr)
3499
{
3500
    if (pos >= GF_BACKTRACE_LEN)
3501
        return -1;
3502
    return snprintf(buf + pos, GF_BACKTRACE_LEN - pos, "(--> %s ", framestr);
3503
}
3504

3505
static int
3506
gf_backtrace_fillframes(char *buf)
3507
{
3508
    void *array[GF_BACKTRACE_FRAME_COUNT];
3509
    size_t frames = 0;
3510
    FILE *fp = NULL;
3511
    char callingfn[GF_BACKTRACE_FRAME_COUNT - 2][1024] = {
3512
        {0},
3513
    };
3514
    int ret = -1;
3515
    int fd = -1;
3516
    size_t idx = 0;
3517
    size_t pos = 0;
3518
    size_t inc = 0;
3519
    char tmpl[] = "/tmp/glfs-bt-XXXXXX";
3520

3521
    frames = backtrace(array, GF_BACKTRACE_FRAME_COUNT);
3522
    if (!frames)
3523
        return -1;
3524

3525
    /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */
3526
    fd = mkstemp(tmpl);
3527
    if (fd == -1)
3528
        return -1;
3529

3530
    /* Calling unlink so that when the file is closed or program
3531
     * terminates the temporary file is deleted.
3532
     */
3533
    ret = sys_unlink(tmpl);
3534
    if (ret < 0) {
3535
        gf_smsg(THIS->name, GF_LOG_INFO, 0, LG_MSG_FILE_DELETE_FAILED,
3536
                "temporary_file=%s", tmpl, NULL);
3537
    }
3538

3539
    /*The most recent two frames are the calling function and
3540
     * gf_backtrace_save, which we can infer.*/
3541

3542
    backtrace_symbols_fd(&array[2], frames - 2, fd);
3543

3544
    fp = fdopen(fd, "r");
3545
    if (!fp) {
3546
        sys_close(fd);
3547
        goto out;
3548
    }
3549

3550
    ret = fseek(fp, 0L, SEEK_SET);
3551
    if (ret)
3552
        goto out;
3553

3554
    pos = 0;
3555
    for (idx = 0; idx < frames - 2; idx++) {
3556
        ret = fscanf(fp, "%1023s", callingfn[idx]);
3557
        if (ret == EOF)
3558
            break;
3559
        inc = gf_backtrace_append(buf, pos, callingfn[idx]);
3560
        if (inc == -1)
3561
            break;
3562
        pos += inc;
3563
    }
3564
    gf_backtrace_end(buf, idx);
3565

3566
out:
3567
    if (fp)
3568
        fclose(fp);
3569

3570
    return (idx > 0) ? 0 : -1;
3571
}
3572

3573
/* Optionally takes @buf to save backtrace.  If @buf is NULL, uses the
3574
 * pre-allocated ctx->btbuf to avoid allocating memory while printing
3575
 * backtrace.
3576
 * TODO: This API doesn't provide flexibility in terms of no. of frames
3577
 * of the backtrace is being saved in the buffer. Deferring fixing it
3578
 * when there is a real-use for that.*/
3579

3580
char *
3581
gf_backtrace_save(char *buf)
3582
{
3583
    char *bt = NULL;
3584

3585
    if (!buf) {
3586
        bt = THIS->ctx->btbuf;
3587
        GF_ASSERT(bt);
3588

3589
    } else {
3590
        bt = buf;
3591
    }
3592

3593
    if ((0 == gf_backtrace_fillframes(bt)))
3594
        return bt;
3595

3596
    gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_BACKTRACE_SAVE_FAILED, NULL);
3597
    return NULL;
3598
}
3599

3600
gf_loglevel_t
3601
fop_log_level(glusterfs_fop_t fop, int op_errno)
3602
{
3603
    /* if gfid doesn't exist ESTALE comes */
3604
    if (op_errno == ENOENT || op_errno == ESTALE)
3605
        return GF_LOG_DEBUG;
3606

3607
    if ((fop == GF_FOP_ENTRYLK) || (fop == GF_FOP_FENTRYLK) ||
3608
        (fop == GF_FOP_FINODELK) || (fop == GF_FOP_INODELK) ||
3609
        (fop == GF_FOP_LK)) {
3610
        /*
3611
         * if non-blocking lock fails EAGAIN comes
3612
         * if locks xlator is not loaded ENOSYS comes
3613
         */
3614
        if (op_errno == EAGAIN || op_errno == ENOSYS)
3615
            return GF_LOG_DEBUG;
3616
    }
3617

3618
    if ((fop == GF_FOP_GETXATTR) || (fop == GF_FOP_FGETXATTR)) {
3619
        if (op_errno == ENOTSUP || op_errno == ENODATA)
3620
            return GF_LOG_DEBUG;
3621
    }
3622

3623
    if ((fop == GF_FOP_SETXATTR) || (fop == GF_FOP_FSETXATTR) ||
3624
        (fop == GF_FOP_REMOVEXATTR) || (fop == GF_FOP_FREMOVEXATTR)) {
3625
        if (op_errno == ENOTSUP)
3626
            return GF_LOG_DEBUG;
3627
    }
3628

3629
    if (fop == GF_FOP_MKNOD || fop == GF_FOP_MKDIR)
3630
        if (op_errno == EEXIST)
3631
            return GF_LOG_DEBUG;
3632

3633
    if (fop == GF_FOP_SEEK) {
3634
#ifdef HAVE_SEEK_HOLE
3635
        if (op_errno == ENXIO) {
3636
            return GF_LOG_DEBUG;
3637
        }
3638
#else
3639
        return GF_LOG_DEBUG;
3640
#endif
3641
    }
3642

3643
    return GF_LOG_ERROR;
3644
}
3645

3646
/* This is an utility function which will recursively delete
3647
 * a folder and its contents.
3648
 *
3649
 * @param delete_path folder to be deleted.
3650
 *
3651
 * @return 0 on success and -1 on failure.
3652
 */
3653
int
3654
recursive_rmdir(const char *delete_path)
3655
{
3656
    int ret = -1;
3657
    char path[PATH_MAX] = {
3658
        0,
3659
    };
3660
    struct stat st = {
3661
        0,
3662
    };
3663
    DIR *dir = NULL;
3664
    struct dirent *entry = NULL;
3665
    struct dirent scratch[2] = {
3666
        {
3667
            0,
3668
        },
3669
    };
3670
    xlator_t *this = NULL;
3671

3672
    this = THIS;
3673
    GF_ASSERT(this);
3674
    GF_VALIDATE_OR_GOTO(this->name, delete_path, out);
3675

3676
    dir = sys_opendir(delete_path);
3677
    if (!dir) {
3678
        gf_msg_debug(this->name, errno, "Failed to open directory %s.",
3679
                     delete_path);
3680
        ret = 0;
3681
        goto out;
3682
    }
3683

3684
    while ((entry = sys_readdir(dir, scratch))) {
3685
        if (gf_irrelevant_entry(entry))
3686
            continue;
3687
        snprintf(path, PATH_MAX, "%s/%s", delete_path, entry->d_name);
3688
        ret = sys_lstat(path, &st);
3689
        if (ret == -1) {
3690
            gf_msg_debug(this->name, errno, "Failed to stat entry %s", path);
3691
            (void)sys_closedir(dir);
3692
            goto out;
3693
        }
3694

3695
        if (S_ISDIR(st.st_mode))
3696
            ret = recursive_rmdir(path);
3697
        else
3698
            ret = sys_unlink(path);
3699

3700
        if (ret) {
3701
            gf_msg_debug(this->name, errno, " Failed to remove %s.", path);
3702
        }
3703

3704
        gf_msg_debug(this->name, 0, "%s %s",
3705
                     ret ? "Failed to remove" : "Removed", entry->d_name);
3706
    }
3707

3708
    ret = sys_closedir(dir);
3709
    if (ret) {
3710
        gf_msg_debug(this->name, errno, "Failed to close dir %s", delete_path);
3711
    }
3712

3713
    ret = sys_rmdir(delete_path);
3714
    if (ret) {
3715
        gf_msg_debug(this->name, errno, "Failed to rmdir: %s", delete_path);
3716
    }
3717

3718
out:
3719
    return ret;
3720
}
3721
/*
3722
 * Input: Array of strings 'array' terminating in NULL
3723
 *        string 'elem' to be searched in the array
3724
 *
3725
 * Output: Index of the element in the array if found, '-1' otherwise
3726
 */
3727
int
3728
gf_get_index_by_elem(char **array, char *elem)
3729
{
3730
    int i = 0;
3731

3732
    for (i = 0; array[i]; i++) {
3733
        if (strcmp(elem, array[i]) == 0)
3734
            return i;
3735
    }
3736

3737
    return -1;
3738
}
3739

3740
static int
3741
get_pathinfo_host(char *pathinfo, char *hostname, size_t size)
3742
{
3743
    char *start = NULL;
3744
    char *end = NULL;
3745
    int ret = -1;
3746
    int i = 0;
3747

3748
    if (!pathinfo)
3749
        goto out;
3750

3751
    start = strchr(pathinfo, ':');
3752
    if (!start)
3753
        goto out;
3754

3755
    end = strrchr(pathinfo, ':');
3756
    if (start == end)
3757
        goto out;
3758

3759
    memset(hostname, 0, size);
3760
    i = 0;
3761
    while (++start != end)
3762
        hostname[i++] = *start;
3763
    ret = 0;
3764
out:
3765
    return ret;
3766
}
3767

3768
/*Note: 'pathinfo' should be gathered only from one brick*/
3769
int
3770
glusterfs_is_local_pathinfo(char *pathinfo, gf_boolean_t *is_local)
3771
{
3772
    int ret = 0;
3773
    char pathinfohost[1024] = {0};
3774

3775
    *is_local = _gf_false;
3776
    ret = get_pathinfo_host(pathinfo, pathinfohost, sizeof(pathinfohost));
3777
    if (ret == 0) {
3778
        if (!strcmp(gf_gethostname(), pathinfohost))
3779
            *is_local = _gf_true;
3780
    }
3781
    return ret;
3782
}
3783

3784
ssize_t
3785
gf_nread(int fd, void *buf, size_t count)
3786
{
3787
    ssize_t ret = 0;
3788
    ssize_t read_bytes = 0;
3789

3790
    for (read_bytes = 0; read_bytes < count; read_bytes += ret) {
3791
        ret = sys_read(fd, buf + read_bytes, count - read_bytes);
3792
        if (ret == 0) {
3793
            break;
3794
        } else if (ret < 0) {
3795
            if (errno == EINTR)
3796
                ret = 0;
3797
            else
3798
                goto out;
3799
        }
3800
    }
3801

3802
    ret = read_bytes;
3803
out:
3804
    return ret;
3805
}
3806

3807
ssize_t
3808
gf_nwrite(int fd, const void *buf, size_t count)
3809
{
3810
    ssize_t ret = 0;
3811
    ssize_t written = 0;
3812

3813
    for (written = 0; written != count; written += ret) {
3814
        ret = sys_write(fd, buf + written, count - written);
3815
        if (ret < 0) {
3816
            if (errno == EINTR)
3817
                ret = 0;
3818
            else
3819
                goto out;
3820
        }
3821
    }
3822

3823
    ret = written;
3824
out:
3825
    return ret;
3826
}
3827

3828
void
3829
gf_free_mig_locks(lock_migration_info_t *locks)
3830
{
3831
    lock_migration_info_t *current = NULL;
3832
    lock_migration_info_t *temp = NULL;
3833

3834
    if (!locks)
3835
        return;
3836

3837
    if (list_empty(&locks->list))
3838
        return;
3839

3840
    list_for_each_entry_safe(current, temp, &locks->list, list)
3841
    {
3842
        list_del_init(&current->list);
3843
        GF_FREE(current->client_uid);
3844
        GF_FREE(current);
3845
    }
3846
}
3847

3848
void
3849
_mask_cancellation(void)
3850
{
3851
    (void)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
3852
}
3853

3854
void
3855
_unmask_cancellation(void)
3856
{
3857
    (void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
3858
}
3859

3860
const char *
3861
fop_enum_to_pri_string(glusterfs_fop_t fop)
3862
{
3863
    switch (fop) {
3864
        case GF_FOP_OPEN:
3865
        case GF_FOP_STAT:
3866
        case GF_FOP_FSTAT:
3867
        case GF_FOP_LOOKUP:
3868
        case GF_FOP_ACCESS:
3869
        case GF_FOP_READLINK:
3870
        case GF_FOP_OPENDIR:
3871
        case GF_FOP_STATFS:
3872
        case GF_FOP_READDIR:
3873
        case GF_FOP_READDIRP:
3874
        case GF_FOP_GETACTIVELK:
3875
        case GF_FOP_SETACTIVELK:
3876
        case GF_FOP_ICREATE:
3877
        case GF_FOP_NAMELINK:
3878
            return "HIGH";
3879

3880
        case GF_FOP_CREATE:
3881
        case GF_FOP_FLUSH:
3882
        case GF_FOP_LK:
3883
        case GF_FOP_INODELK:
3884
        case GF_FOP_FINODELK:
3885
        case GF_FOP_ENTRYLK:
3886
        case GF_FOP_FENTRYLK:
3887
        case GF_FOP_UNLINK:
3888
        case GF_FOP_SETATTR:
3889
        case GF_FOP_FSETATTR:
3890
        case GF_FOP_MKNOD:
3891
        case GF_FOP_MKDIR:
3892
        case GF_FOP_RMDIR:
3893
        case GF_FOP_SYMLINK:
3894
        case GF_FOP_RENAME:
3895
        case GF_FOP_LINK:
3896
        case GF_FOP_SETXATTR:
3897
        case GF_FOP_GETXATTR:
3898
        case GF_FOP_FGETXATTR:
3899
        case GF_FOP_FSETXATTR:
3900
        case GF_FOP_REMOVEXATTR:
3901
        case GF_FOP_FREMOVEXATTR:
3902
        case GF_FOP_IPC:
3903
        case GF_FOP_LEASE:
3904
            return "NORMAL";
3905

3906
        case GF_FOP_READ:
3907
        case GF_FOP_WRITE:
3908
        case GF_FOP_FSYNC:
3909
        case GF_FOP_TRUNCATE:
3910
        case GF_FOP_FTRUNCATE:
3911
        case GF_FOP_FSYNCDIR:
3912
        case GF_FOP_XATTROP:
3913
        case GF_FOP_FXATTROP:
3914
        case GF_FOP_RCHECKSUM:
3915
        case GF_FOP_ZEROFILL:
3916
        case GF_FOP_FALLOCATE:
3917
        case GF_FOP_SEEK:
3918
            return "LOW";
3919

3920
        case GF_FOP_NULL:
3921
        case GF_FOP_FORGET:
3922
        case GF_FOP_RELEASE:
3923
        case GF_FOP_RELEASEDIR:
3924
        case GF_FOP_GETSPEC:
3925
        case GF_FOP_MAXVALUE:
3926
        case GF_FOP_DISCARD:
3927
            return "LEAST";
3928
        default:
3929
            return "UNKNOWN";
3930
    }
3931
}
3932

3933
const char *
3934
gf_inode_type_to_str(ia_type_t type)
3935
{
3936
    static const char *const str_ia_type[] = {
3937
        "UNKNOWN",      "REGULAR FILE",     "DIRECTORY", "LINK",
3938
        "BLOCK DEVICE", "CHARACTER DEVICE", "PIPE",      "SOCKET"};
3939
    return str_ia_type[type];
3940
}
3941

3942
gf_boolean_t
3943
gf_is_zero_filled_stat(struct iatt *buf)
3944
{
3945
    if (!buf)
3946
        return 1;
3947

3948
    /* Do not use st_dev because it is transformed to store the xlator id
3949
     * in place of the device number. Do not use st_ino because by this time
3950
     * we've already mapped the root ino to 1 so it is not guaranteed to be
3951
     * 0.
3952
     */
3953
    if ((buf->ia_nlink == 0) && (buf->ia_ctime == 0))
3954
        return 1;
3955

3956
    return 0;
3957
}
3958

3959
gf_boolean_t
3960
gf_is_valid_xattr_namespace(char *key)
3961
{
3962
    static char *xattr_namespaces[] = {"trusted.", "system.", "user.",
3963
                                       "security.", NULL};
3964
    int i = 0;
3965

3966
    for (i = 0; xattr_namespaces[i]; i++) {
3967
        if (strncmp(key, xattr_namespaces[i], strlen(xattr_namespaces[i])) == 0)
3968
            return _gf_true;
3969
    }
3970

3971
    return _gf_false;
3972
}
3973

3974
ino_t
3975
gfid_to_ino(uuid_t gfid)
3976
{
3977
    ino_t ino = 0;
3978
    int32_t i;
3979

3980
    for (i = 8; i < 16; i++) {
3981
        ino <<= 8;
3982
        ino += (uint8_t)gfid[i];
3983
    }
3984

3985
    return ino;
3986
}
3987

3988
int
3989
gf_bits_count(uint64_t n)
3990
{
3991
    int val = 0;
3992
#if defined(__GNUC__) || defined(__clang__)
3993
    val = __builtin_popcountll(n);
3994
#else
3995
    n -= (n >> 1) & 0x5555555555555555ULL;
3996
    n = ((n >> 2) & 0x3333333333333333ULL) + (n & 0x3333333333333333ULL);
3997
    n = (n + (n >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
3998
    n += n >> 8;
3999
    n += n >> 16;
4000
    n += n >> 32;
4001
    val = n & 0xFF;
4002
#endif
4003
    return val;
4004
}
4005

4006
int
4007
gf_bits_index(uint64_t n)
4008
{
4009
#if defined(__GNUC__) || defined(__clang__)
4010
    return __builtin_ffsll(n) - 1;
4011
#else
4012
    return ffsll(n) - 1;
4013
#endif
4014
}
4015

4016
const char *
4017
gf_fop_string(glusterfs_fop_t fop)
4018
{
4019
    if ((fop > GF_FOP_NULL) && (fop < GF_FOP_MAXVALUE))
4020
        return gf_fop_list[fop];
4021
    return "INVALID";
4022
}
4023

4024
int
4025
gf_fop_int(char *fop)
4026
{
4027
    int i = 0;
4028

4029
    for (i = GF_FOP_NULL + 1; i < GF_FOP_MAXVALUE; i++) {
4030
        if (strcasecmp(fop, gf_fop_list[i]) == 0)
4031
            return i;
4032
    }
4033
    return -1;
4034
}
4035

4036
int
4037
close_fds_except_custom(int *fdv, size_t count, void *prm,
4038
                        void closer(int fd, void *prm))
4039
{
4040
    int i = 0;
4041
    size_t j = 0;
4042
    gf_boolean_t should_close = _gf_true;
4043
#ifdef GF_LINUX_HOST_OS
4044
    DIR *d = NULL;
4045
    struct dirent *de = NULL;
4046
    struct dirent scratch[2] = {
4047
        {
4048
            0,
4049
        },
4050
    };
4051
    char *e = NULL;
4052

4053
    d = sys_opendir("/proc/self/fd");
4054
    if (!d)
4055
        return -1;
4056

4057
    for (;;) {
4058
        should_close = _gf_true;
4059

4060
        errno = 0;
4061
        de = sys_readdir(d, scratch);
4062
        if (!de || errno != 0)
4063
            break;
4064
        i = strtoul(de->d_name, &e, 10);
4065
        if (*e != '\0' || i == dirfd(d))
4066
            continue;
4067

4068
        for (j = 0; j < count; j++) {
4069
            if (i == fdv[j]) {
4070
                should_close = _gf_false;
4071
                break;
4072
            }
4073
        }
4074
        if (should_close)
4075
            closer(i, prm);
4076
    }
4077
    sys_closedir(d);
4078
#else  /* !GF_LINUX_HOST_OS */
4079
    struct rlimit rl;
4080
    int ret = -1;
4081

4082
    ret = getrlimit(RLIMIT_NOFILE, &rl);
4083
    if (ret)
4084
        return ret;
4085

4086
    for (i = 0; i < rl.rlim_cur; i++) {
4087
        should_close = _gf_true;
4088
        for (j = 0; j < count; j++) {
4089
            if (i == fdv[j]) {
4090
                should_close = _gf_false;
4091
                break;
4092
            }
4093
        }
4094
        if (should_close)
4095
            closer(i, prm);
4096
    }
4097
#endif /* !GF_LINUX_HOST_OS */
4098
    return 0;
4099
}
4100

4101
static void
4102
closer_close(int fd, void *prm)
4103
{
4104
    sys_close(fd);
4105
}
4106

4107
int
4108
close_fds_except(int *fdv, size_t count)
4109
{
4110
    return close_fds_except_custom(fdv, count, NULL, closer_close);
4111
}
4112

4113
/**
4114
 * gf_getgrouplist - get list of groups to which a user belongs
4115
 *
4116
 * A convenience wrapper for getgrouplist(3).
4117
 *
4118
 * @param user - same as in getgrouplist(3)
4119
 * @param group - same as in getgrouplist(3)
4120
 * @param groups - pointer to a gid_t pointer
4121
 *
4122
 * gf_getgrouplist allocates a gid_t buffer which is big enough to
4123
 * hold the list of auxiliary group ids for user, up to the GF_MAX_AUX_GROUPS
4124
 * threshold. Upon successful invocation groups will be pointed to that buffer.
4125
 *
4126
 * @return success: the number of auxiliary group ids retrieved
4127
 *         failure: -1
4128
 */
4129
int
4130
gf_getgrouplist(const char *user, gid_t group, gid_t **groups)
4131
{
4132
    int ret = -1;
4133
    int ngroups = SMALL_GROUP_COUNT;
4134

4135
    *groups = GF_CALLOC(sizeof(gid_t), ngroups, gf_common_mt_groups_t);
4136
    if (!*groups)
4137
        return -1;
4138

4139
    /*
4140
     * We are running getgrouplist() in a loop until we succeed (or hit
4141
     * certain exit conditions, see the comments below). This is because
4142
     * the indicated number of auxiliary groups that we obtain in case of
4143
     * the failure of the first invocation is not guaranteed to keep its
4144
     * validity upon the next invocation with a gid buffer of that size.
4145
     */
4146
    for (;;) {
4147
        int ngroups_old = ngroups;
4148
        ret = getgrouplist(user, group, *groups, &ngroups);
4149
        if (ret != -1)
4150
            break;
4151

4152
        if (ngroups >= GF_MAX_AUX_GROUPS) {
4153
            /*
4154
             * This should not happen as GF_MAX_AUX_GROUPS is set
4155
             * to the max value of number of supported auxiliary
4156
             * groups across all platforms supported by GlusterFS.
4157
             * However, if it still happened some way, we wouldn't
4158
             * care about the incompleteness of the result, we'd
4159
             * just go on with what we got.
4160
             */
4161
            return GF_MAX_AUX_GROUPS;
4162
        } else if (ngroups <= ngroups_old) {
4163
            /*
4164
             * There is an edge case that getgrouplist() fails but
4165
             * ngroups remains the same. This is actually not
4166
             * specified in getgrouplist(3), but implementations
4167
             * can do this upon internal failure[1]. To avoid
4168
             * falling into an infinite loop when this happens, we
4169
             * break the loop if the getgrouplist call failed
4170
             * without an increase in the indicated group number.
4171
             *
4172
             * [1]
4173
             * https://sourceware.org/git/?p=glibc.git;a=blob;f=grp/initgroups.c;hb=refs/heads/release/2.25/master#l168
4174
             */
4175
            GF_FREE(*groups);
4176
            return -1;
4177
        }
4178

4179
        *groups = GF_REALLOC(*groups, ngroups * sizeof(gid_t));
4180
        if (!*groups)
4181
            return -1;
4182
    }
4183
    return ret;
4184
}
4185

4186
int
4187
glusterfs_compute_sha256(const unsigned char *content, size_t size,
4188
                         char *sha256_hash)
4189
{
4190
#if OPENSSL_VERSION_NUMBER >= 0x030000000  // 3.0.0
4191

4192
    EVP_Digest((const unsigned char *)(content), size,
4193
               (unsigned char *)sha256_hash, NULL, EVP_sha256(), NULL);
4194
#else
4195
    SHA256_CTX sha256;
4196

4197
    SHA256_Init(&sha256);
4198
    SHA256_Update(&sha256, (const unsigned char *)(content), size);
4199
    SHA256_Final((unsigned char *)sha256_hash, &sha256);
4200

4201
#endif
4202
    return 0;
4203
}
4204

4205
/* * Safe wrapper function for strncpy.
4206
 * This wrapper makes sure that when there is no null byte among the first n in
4207
 * source srting for strncpy function call, the string placed in dest will be
4208
 * null-terminated.
4209
 */
4210

4211
char *
4212
gf_strncpy(char *dest, const char *src, const size_t dest_size)
4213
{
4214
    strncpy(dest, src, dest_size - 1);
4215
    dest[dest_size - 1] = '\0';
4216
    return dest;
4217
}
4218

4219
xlator_cmdline_option_t *
4220
find_xlator_option_in_cmd_args_t(const char *option_name, cmd_args_t *args)
4221
{
4222
    xlator_cmdline_option_t *pos = NULL;
4223
    xlator_cmdline_option_t *tmp = NULL;
4224

4225
    list_for_each_entry_safe(pos, tmp, &args->xlator_options, cmd_args)
4226
    {
4227
        if (strcmp(pos->key, option_name) == 0)
4228
            return pos;
4229
    }
4230
    return NULL;
4231
}
4232

4233
int
4234
gf_d_type_from_ia_type(ia_type_t type)
4235
{
4236
    switch (type) {
4237
        case IA_IFDIR:
4238
            return DT_DIR;
4239
        case IA_IFCHR:
4240
            return DT_CHR;
4241
        case IA_IFBLK:
4242
            return DT_BLK;
4243
        case IA_IFIFO:
4244
            return DT_FIFO;
4245
        case IA_IFLNK:
4246
            return DT_LNK;
4247
        case IA_IFREG:
4248
            return DT_REG;
4249
        case IA_IFSOCK:
4250
            return DT_SOCK;
4251
        default:
4252
            return DT_UNKNOWN;
4253
    }
4254
}
4255

4256
int
4257
gf_nanosleep(uint64_t nsec)
4258
{
4259
    struct timespec req;
4260
    struct timespec rem;
4261
    int ret = -1;
4262

4263
    req.tv_sec = nsec / GF_SEC_IN_NS;
4264
    req.tv_nsec = nsec % GF_SEC_IN_NS;
4265

4266
    do {
4267
        ret = nanosleep(&req, &rem);
4268
        req = rem;
4269
    } while (ret == -1 && errno == EINTR);
4270

4271
    return ret;
4272
}
4273

4274
int
4275
gf_pipe(int fd[2], int flags)
4276
{
4277
    int ret = 0;
4278
#if defined(HAVE_PIPE2)
4279
    ret = pipe2(fd, flags);
4280
#else  /* not HAVE_PIPE2 */
4281
    ret = pipe(fd);
4282
    if (ret < 0)
4283
        return ret;
4284
    if (flags) {
4285
        ret = fcntl(fd[0], F_SETFL, (fcntl(fd[0], F_GETFL) | flags));
4286
        if (ret < 0)
4287
            goto out;
4288
        ret = fcntl(fd[1], F_SETFL, (fcntl(fd[1], F_GETFL) | flags));
4289
        if (ret < 0)
4290
            goto out;
4291
    }
4292
out:
4293
    if (ret < 0) {
4294
        close(fd[0]);
4295
        close(fd[1]);
4296
    }
4297
#endif /* HAVE_PIPE2 */
4298
    return ret;
4299
}
4300

4301
char **
4302
get_xattrs_to_heal(void)
4303
{
4304
    return xattrs_to_heal;
4305
}
4306

4307
char *
4308
gf_gethostname(void)
4309
{
4310
    return global_ctx->hostname;
4311
}
4312

4313
#ifndef GF_DARWIN_HOST_OS
4314

4315
void
4316
gf_set_nofile(rlim_t high, rlim_t low)
4317
{
4318
    int n, ret = -1;
4319
    struct rlimit lim;
4320
    rlim_t r[2] = {high, low};
4321

4322
    for (n = 0; n < 2; n++)
4323
        if (r[n] != 0) {
4324
            lim.rlim_cur = r[n];
4325
            lim.rlim_max = r[n];
4326
            ret = setrlimit(RLIMIT_NOFILE, &lim);
4327
            if (ret == 0)
4328
                break;
4329
        }
4330

4331
    if (ret)
4332
        GF_LOG_W(THIS->name, LG_MSG_NOFILE_FAILED(high, low));
4333
}
4334

4335
#endif /* not GF_DARWIN_HOST_OS */
4336

4337
/* Like sys_unlink() but tolerate ENOENT. */
4338

4339
gf_boolean_t
4340
gf_unlink(const char *path)
4341
{
4342
    int ret = 0;
4343

4344
    GF_ASSERT(path);
4345
    ret = sys_unlink(path);
4346

4347
    if (ret && errno != ENOENT) {
4348
        GF_LOG_W(THIS->name, LG_MSG_UNLINK_FAILED(path));
4349
        return _gf_false;
4350
    }
4351
    return _gf_true;
4352
}
4353

4354
int
4355
gf_rebalance_thread_count(char *str, char **errmsg)
4356
{
4357
    int count = 0, lim = sysconf(_SC_NPROCESSORS_ONLN);
4358

4359
    /* An option should be one of lazy|normal|aggressive or
4360
       a number from 1 to the number of cores in the machine. */
4361

4362
    if (!strcasecmp(str, "lazy"))
4363
        return 1;
4364
    else if (!strcasecmp(str, "normal"))
4365
        return 2;
4366
    else if (!strcasecmp(str, "aggressive"))
4367
        return max(lim - 4, 4);
4368
    else if (gf_string2int(str, &count) == 0) {
4369
        if (count > 0 && count <= lim)
4370
            return count;
4371
        else {
4372
            if (gf_asprintf(errmsg,
4373
                            "number of rebalance threads should be "
4374
                            "in range from 1 to %d, not %d",
4375
                            lim, count) < 0)
4376
                *errmsg = NULL;
4377
            return -1;
4378
        }
4379
    }
4380
    if (gf_asprintf(errmsg,
4381
                    "number of rebalance threads should "
4382
                    "be {lazy|normal|aggressive} or a number in "
4383
                    "range from 1 to %d, not %s",
4384
                    lim, str) < 0)
4385
        *errmsg = NULL;
4386
    return -1;
4387
}
4388

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

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

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

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