glusterfs
4387 строк · 102.8 Кб
1/*
2Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3This file is part of GlusterFS.
4
5This file is licensed to you under your choice of the GNU Lesser
6General Public License, version 3 or any later version (LGPLv3 or
7later), or the GNU General Public License, version 2 (GPLv2), in all
8cases 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
72char *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
85gf_boolean_t gf_signal_on_assert = false;
86
87typedef int32_t (*rw_op_t)(int32_t fd, char *buf, int32_t size);
88typedef int32_t (*rwv_op_t)(int32_t fd, const struct iovec *buf, int32_t size);
89
90char *xattrs_to_heal[] = {"user.",
91POSIX_ACL_ACCESS_XATTR,
92POSIX_ACL_DEFAULT_XATTR,
93QUOTA_LIMIT_KEY,
94QUOTA_LIMIT_OBJECTS_KEY,
95GF_SELINUX_XATTR_KEY,
96GF_XATTR_MDATA_KEY,
97NULL};
98
99static gf_boolean_t
100gf_ports_reserved(char *blocked_port, unsigned char *ports, uint32_t ceiling);
101
102void
103gf_assert(void)
104{
105if (gf_signal_on_assert) {
106raise(SIGCONT);
107}
108}
109
110void
111gf_xxh64_wrapper(const unsigned char *data, size_t const len,
112unsigned long long const seed, char *xxh64)
113{
114unsigned short i = 0;
115const unsigned short lim = GF_XXH64_DIGEST_LENGTH * 2 + 1;
116XXH64_hash_t hash = 0;
117XXH64_canonical_t c_hash = {
118{
1190,
120},
121};
122const uint8_t *p = (const uint8_t *)&c_hash;
123
124hash = XXH64(data, len, seed);
125XXH64_canonicalFromHash(&c_hash, hash);
126
127for (i = 0; i < GF_XXH64_DIGEST_LENGTH; i++)
128snprintf(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**/
168static int
169gf_gfid_from_xxh64(xlator_t *this, uuid_t gfid, XXH64_hash_t hash,
170unsigned short index)
171{
172int ret = -1;
173int i = -1;
174
175if ((index != 0) && (index != 8)) {
176gf_msg_callingfn("gfid-from-xxh64", GF_LOG_WARNING, 0,
177LG_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)",
181index);
182goto out;
183}
184
185for (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*/
190gfid[index + i] = (hash >> ((sizeof(hash) * 8) - (8 * (i + 1)))) &
191(0xff);
192}
193
194ret = 0;
195
196out:
197return 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**/
213XXH64_hash_t
214gf_xxh64_hash_wrapper(const unsigned char *data, size_t const len,
215unsigned long long const seed, char *xxh64)
216{
217unsigned short i = 0;
218const unsigned short lim = GF_XXH64_DIGEST_LENGTH * 2 + 1;
219XXH64_hash_t hash = 0;
220XXH64_canonical_t c_hash = {
221{
2220,
223},
224};
225const uint8_t *p = (const uint8_t *)&c_hash;
226
227hash = XXH64(data, len, seed);
228XXH64_canonicalFromHash(&c_hash, hash);
229
230for (i = 0; i < GF_XXH64_DIGEST_LENGTH; i++)
231snprintf(xxh64 + i * 2, lim - i * 2, "%02x", p[i]);
232
233return 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**/
260int
261gf_gfid_generate_from_xxh64(uuid_t gfid, char *key)
262{
263char xxh64_1[GF_XXH64_DIGEST_LENGTH * 2 + 1] = {
2640,
265};
266char xxh64_2[GF_XXH64_DIGEST_LENGTH * 2 + 1] = {
2670,
268};
269XXH64_hash_t hash_1 = 0;
270XXH64_hash_t hash_2 = 0;
271int ret = -1;
272xlator_t *this = THIS;
273
274hash_1 = gf_xxh64_hash_wrapper((unsigned char *)key, strlen(key),
275GF_XXHSUM64_DEFAULT_SEED, xxh64_1);
276
277hash_2 = gf_xxh64_hash_wrapper((unsigned char *)xxh64_1, strlen(xxh64_1),
278GF_XXHSUM64_DEFAULT_SEED, xxh64_2);
279
280/* hash_2 is saved in 1st 8 elements of uuid_t char array */
281if (gf_gfid_from_xxh64(this, gfid, hash_2, 0)) {
282gf_msg_callingfn(this->name, GF_LOG_WARNING, 0,
283LG_MSG_XXH64_TO_GFID_FAILED,
284"failed to encode the hash %" XXH64_FMT
285" into the 1st half of gfid",
286hash_2);
287goto out;
288}
289
290/* hash_1 is saved in the remaining 8 elements of uuid_t */
291if (gf_gfid_from_xxh64(this, gfid, hash_1, 8)) {
292gf_msg_callingfn(this->name, GF_LOG_WARNING, 0,
293LG_MSG_XXH64_TO_GFID_FAILED,
294"failed to encode the hash %" XXH64_FMT
295" into the 2nd half of gfid",
296hash_1);
297goto out;
298}
299
300gf_msg_debug(this->name, 0,
301"gfid generated is %s (hash1: %" XXH64_FMT
302") "
303"hash2: %" XXH64_FMT ", xxh64_1: %s xxh64_2: %s",
304uuid_utoa(gfid), hash_1, hash_2, xxh64_1, xxh64_2);
305
306ret = 0;
307
308out:
309return ret;
310}
311
312/* works similar to mkdir(1) -p.
313*/
314int
315mkdir_p(char *path, mode_t mode, gf_boolean_t allow_symlinks)
316{
317int i = 0;
318int ret = -1;
319char dir[PATH_MAX] = {
3200,
321};
322struct stat stbuf = {
3230,
324};
325
326const int path_len = min(strlen(path), PATH_MAX - 1);
327
328snprintf(dir, path_len + 1, "%s", path);
329
330i = (dir[0] == '/') ? 1 : 0;
331do {
332if (path[i] != '/' && path[i] != '\0')
333continue;
334
335dir[i] = '\0';
336ret = sys_mkdir(dir, mode);
337if (ret && errno != EEXIST) {
338gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, NULL);
339goto out;
340}
341
342if (ret && errno == EEXIST && !allow_symlinks) {
343ret = sys_lstat(dir, &stbuf);
344if (ret)
345goto out;
346
347if (S_ISLNK(stbuf.st_mode)) {
348ret = -1;
349gf_smsg("", GF_LOG_ERROR, 0, LG_MSG_DIR_IS_SYMLINK, "dir=%s",
350dir, NULL);
351goto out;
352}
353}
354dir[i] = '/';
355
356} while (path[i++] != '\0');
357
358ret = sys_stat(dir, &stbuf);
359if (ret || !S_ISDIR(stbuf.st_mode)) {
360if (ret == 0)
361errno = 0;
362ret = -1;
363gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED,
364"possibly some of the components"
365" were not directories",
366NULL);
367goto out;
368}
369
370ret = 0;
371out:
372
373return ret;
374}
375
376int
377gf_lstat_dir(const char *path, struct stat *stbuf_in)
378{
379int ret = -1;
380struct stat stbuf = {
3810,
382};
383
384if (path == NULL) {
385errno = EINVAL;
386goto out;
387}
388
389ret = sys_lstat(path, &stbuf);
390if (ret)
391goto out;
392
393if (!S_ISDIR(stbuf.st_mode)) {
394errno = ENOTDIR;
395ret = -1;
396goto out;
397}
398ret = 0;
399
400out:
401if (!ret && stbuf_in)
402*stbuf_in = stbuf;
403
404return ret;
405}
406
407int
408log_base2(unsigned long x)
409{
410int val = 0;
411
412while (x > 1) {
413x /= 2;
414val++;
415}
416
417return 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*/
428char *
429gf_rev_dns_lookup(const char *ip)
430{
431char *fqdn = NULL;
432int ret = 0;
433
434GF_VALIDATE_OR_GOTO("resolver", ip, out);
435
436/* Get the FQDN */
437ret = gf_get_hostname_from_ip((char *)ip, &fqdn);
438if (ret != 0) {
439gf_smsg("resolver", GF_LOG_INFO, errno, LG_MSG_RESOLVE_HOSTNAME_FAILED,
440"hostname=%s", ip, NULL);
441}
442out:
443return fqdn;
444}
445
446struct xldump {
447int lineno;
448};
449
450/* to catch any format discrepencies that may arise in code */
451static int
452nprintf(struct xldump *dump, const char *fmt, ...)
453__attribute__((__format__(__printf__, 2, 3)));
454static int
455nprintf(struct xldump *dump, const char *fmt, ...)
456{
457va_list ap;
458char *msg = NULL;
459char header[32];
460int ret = 0;
461
462ret = snprintf(header, 32, "%3d:", ++dump->lineno);
463if (ret < 0)
464goto out;
465
466va_start(ap, fmt);
467ret = vasprintf(&msg, fmt, ap);
468va_end(ap);
469if (-1 == ret)
470goto 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 */
475gf_msg_plain(GF_LOG_WARNING, "%s %s", header, msg);
476
477out:
478FREE(msg);
479return 0;
480}
481
482static int
483xldump_options(dict_t *this, char *key, data_t *value, void *d)
484{
485nprintf(d, " option %s %s", key, value->data);
486return 0;
487}
488
489static void
490xldump_subvolumes(xlator_t *this, void *d)
491{
492xlator_list_t *subv = NULL;
493int len = 0;
494char *subvstr = NULL;
495
496if (!this->children)
497return;
498
499for (subv = this->children; subv; subv = subv->next)
500len += (strlen(subv->xlator->name) + 1);
501
502subvstr = GF_MALLOC(len, gf_common_mt_strdup);
503
504len = 0;
505for (subv = this->children; subv; subv = subv->next)
506len += sprintf(subvstr + len, "%s%s", subv->xlator->name,
507subv->next ? " " : "");
508
509nprintf(d, " subvolumes %s", subvstr);
510
511GF_FREE(subvstr);
512}
513
514static void
515xldump(xlator_t *each, void *d)
516{
517nprintf(d, "volume %s", each->name);
518nprintf(d, " type %s", each->type);
519dict_foreach(each->options, xldump_options, d);
520
521xldump_subvolumes(each, d);
522
523nprintf(d, "end-volume");
524nprintf(d, " ");
525}
526
527void
528gf_log_dump_graph(FILE *specfp, glusterfs_graph_t *graph)
529{
530struct xldump xld = {
5310,
532};
533
534gf_msg_plain(GF_LOG_WARNING, "Final graph:");
535gf_msg_plain(GF_LOG_WARNING,
536"+---------------------------------------"
537"---------------------------------------+");
538
539xlator_foreach_depth_first(graph->top, xldump, &xld);
540
541gf_msg_plain(GF_LOG_WARNING,
542"+---------------------------------------"
543"---------------------------------------+");
544}
545
546static void
547gf_dump_config_flags(void)
548{
549gf_msg_plain_nomem(GF_LOG_ALERT, "configuration details:");
550
551/* have argp */
552#ifdef HAVE_ARGP
553gf_msg_plain_nomem(GF_LOG_ALERT, "argp 1");
554#endif
555
556/* ifdef if found backtrace */
557#ifdef HAVE_BACKTRACE
558gf_msg_plain_nomem(GF_LOG_ALERT, "backtrace 1");
559#endif
560
561/* Berkeley-DB version has cursor->get() */
562#ifdef HAVE_BDB_CURSOR_GET
563gf_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
568gf_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
573gf_msg_plain_nomem(GF_LOG_ALERT, "dlfcn 1");
574#endif
575
576/* define if fdatasync exists */
577#ifdef HAVE_FDATASYNC
578gf_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
583gf_msg_plain_nomem(GF_LOG_ALERT, "libpthread 1");
584#endif
585
586/* define if llistxattr exists */
587#ifdef HAVE_LLISTXATTR
588gf_msg_plain_nomem(GF_LOG_ALERT, "llistxattr 1");
589#endif
590
591/* define if found setfsuid setfsgid */
592#ifdef HAVE_SET_FSID
593gf_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
598gf_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
603gf_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
608gf_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
613gf_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
618gf_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
623gf_msg_plain_nomem(GF_LOG_ALERT, "package-string: " PACKAGE_STRING);
624#endif
625
626return;
627}
628
629/* Obtain a backtrace and print it to the log */
630void
631gf_print_trace(int32_t signum, glusterfs_ctx_t *ctx)
632{
633char msg[1024] = {
6340,
635};
636char timestr[GF_TIMESTR_SIZE] = {
6370,
638};
639call_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*/
648gf_log_flush(ctx);
649
650gf_log_disable_suppression_before_exit(ctx);
651
652if (!ctx || ctx->log.logger != gf_logger_glusterlog)
653goto skip_print_trace;
654
655#ifdef GF_LINUX_HOST_OS
656gf_log_disable_syslog(ctx);
657#endif
658
659/* Pending frames, (if any), list them in order */
660gf_msg_plain_nomem(GF_LOG_ALERT, "pending frames:");
661{
662/* FIXME: traversing stacks outside pool->lock */
663list_for_each_entry(stack, &ctx->pool->all_frames, all_frames)
664{
665if (stack->type == GF_OP_TYPE_FOP)
666sprintf(msg, "frame : type(%d) op(%s)", stack->type,
667gf_fop_list[stack->op]);
668else
669sprintf(msg, "frame : type(%d) op(%d)", stack->type, stack->op);
670
671gf_msg_plain_nomem(GF_LOG_ALERT, msg);
672}
673}
674
675sprintf(msg, "patchset: %s", GLUSTERFS_REPOSITORY_REVISION);
676gf_msg_plain_nomem(GF_LOG_ALERT, msg);
677
678sprintf(msg, "signal received: %d", signum);
679gf_msg_plain_nomem(GF_LOG_ALERT, msg);
680{
681/* Dump the timestamp of the crash too, so the previous logs
682can be related */
683gf_time_fmt_FT(timestr, sizeof timestr, gf_time());
684gf_msg_plain_nomem(GF_LOG_ALERT, "time of crash: ");
685gf_msg_plain_nomem(GF_LOG_ALERT, timestr);
686}
687
688gf_dump_config_flags();
689gf_msg_backtrace_nomem(GF_LOG_ALERT, 200);
690sprintf(msg, "---------");
691gf_msg_plain_nomem(GF_LOG_ALERT, msg);
692
693#ifdef GF_LINUX_HOST_OS
694gf_log_enable_syslog(ctx);
695#endif
696skip_print_trace:
697/* Send a signal to terminate the process */
698signal(signum, SIG_DFL);
699raise(signum);
700}
701
702void
703trap(void)
704{
705}
706
707char *
708gf_trim(char *string)
709{
710register char *s, *t;
711
712if (string == NULL) {
713return NULL;
714}
715
716for (s = string; isspace(*s); s++)
717;
718
719if (*s == 0)
720return s;
721
722t = s + strlen(s) - 1;
723while (t > s && isspace(*t))
724t--;
725*++t = '\0';
726
727return s;
728}
729
730int
731gf_strstr(const char *str, const char *delim, const char *match)
732{
733char *tmp = NULL;
734char *save_ptr = NULL;
735char *tmp_str = NULL;
736
737int ret = 0;
738
739tmp_str = strdup(str);
740
741if (str == NULL || delim == NULL || match == NULL || tmp_str == NULL) {
742gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
743"argument invalid");
744ret = -1;
745goto out;
746}
747
748tmp = strtok_r(tmp_str, delim, &save_ptr);
749
750while (tmp) {
751ret = strcmp(tmp, match);
752
753if (ret == 0)
754break;
755
756tmp = strtok_r(NULL, delim, &save_ptr);
757}
758
759out:
760free(tmp_str);
761
762return ret;
763}
764
765int
766gf_string2time(const char *str, time_t *n)
767{
768unsigned long value = 0;
769char *tail = NULL;
770int old_errno = 0;
771const char *s = NULL;
772
773if (str == NULL || n == NULL) {
774gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
775"argument invalid");
776errno = EINVAL;
777return -1;
778}
779
780for (s = str; *s != '\0'; s++) {
781if (isspace(*s))
782continue;
783if (*s == '-')
784return -1;
785break;
786}
787
788old_errno = errno;
789errno = 0;
790value = strtol(str, &tail, 0);
791if (str == tail)
792errno = EINVAL;
793
794if (errno == ERANGE || errno == EINVAL)
795return -1;
796
797if (errno == 0)
798errno = old_errno;
799
800if (((tail[0] == '\0') || ((tail[0] == 's') && (tail[1] == '\0')) ||
801((tail[0] == 's') && (tail[1] == 'e') && (tail[2] == 'c') &&
802(tail[3] == '\0'))))
803goto out;
804
805else if (((tail[0] == 'm') && (tail[1] == '\0')) ||
806((tail[0] == 'm') && (tail[1] == 'i') && (tail[2] == 'n') &&
807(tail[3] == '\0'))) {
808value = value * GF_MINUTE_IN_SECONDS;
809goto out;
810}
811
812else if (((tail[0] == 'h') && (tail[1] == '\0')) ||
813((tail[0] == 'h') && (tail[1] == 'r') && (tail[2] == '\0'))) {
814value = value * GF_HOUR_IN_SECONDS;
815goto out;
816}
817
818else if (((tail[0] == 'd') && (tail[1] == '\0')) ||
819((tail[0] == 'd') && (tail[1] == 'a') && (tail[2] == 'y') &&
820(tail[3] == 's') && (tail[4] == '\0'))) {
821value = value * GF_DAY_IN_SECONDS;
822goto out;
823}
824
825else if (((tail[0] == 'w') && (tail[1] == '\0')) ||
826((tail[0] == 'w') && (tail[1] == 'k') && (tail[2] == '\0'))) {
827value = value * GF_WEEK_IN_SECONDS;
828goto out;
829} else {
830return -1;
831}
832
833out:
834*n = value;
835
836return 0;
837}
838
839int
840gf_string2percent(const char *str, double *n)
841{
842double value = 0;
843char *tail = NULL;
844int old_errno = 0;
845const char *s = NULL;
846
847if (str == NULL || n == NULL) {
848gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
849"argument invalid");
850errno = EINVAL;
851return -1;
852}
853
854for (s = str; *s != '\0'; s++) {
855if (isspace(*s))
856continue;
857if (*s == '-')
858return -1;
859break;
860}
861
862old_errno = errno;
863errno = 0;
864value = strtod(str, &tail);
865if (str == tail)
866errno = EINVAL;
867
868if (errno == ERANGE || errno == EINVAL)
869return -1;
870
871if (errno == 0)
872errno = old_errno;
873
874if (!((tail[0] == '\0') || ((tail[0] == '%') && (tail[1] == '\0'))))
875return -1;
876
877*n = value;
878
879return 0;
880}
881
882static int
883_gf_string2long(const char *str, long *n, int base)
884{
885long value = 0;
886char *tail = NULL;
887int old_errno = 0;
888
889if (str == NULL || n == NULL) {
890gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
891"argument invalid");
892errno = EINVAL;
893return -1;
894}
895
896old_errno = errno;
897errno = 0;
898value = strtol(str, &tail, base);
899if ((str == tail) || (*tail != 0)) {
900errno = EINVAL;
901return -1;
902}
903
904if (errno == ERANGE || errno == EINVAL)
905return -1;
906
907if (errno == 0)
908errno = old_errno;
909
910*n = value;
911
912return 0;
913}
914
915static int
916_gf_string2ulong(const char *str, unsigned long *n, int base)
917{
918unsigned long value = 0;
919char *tail = NULL;
920int old_errno = 0;
921const char *s = NULL;
922
923if (str == NULL || n == NULL) {
924gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
925"argument invalid");
926errno = EINVAL;
927return -1;
928}
929
930for (s = str; *s != '\0'; s++) {
931if (isspace(*s))
932continue;
933if (*s == '-')
934return -1;
935break;
936}
937
938old_errno = errno;
939errno = 0;
940value = strtoul(str, &tail, base);
941if (str == tail)
942errno = EINVAL;
943
944if (errno == ERANGE || errno == EINVAL)
945return -1;
946
947if (errno == 0)
948errno = old_errno;
949
950if (tail[0] != '\0')
951return -1;
952
953*n = value;
954
955return 0;
956}
957
958static int
959_gf_string2uint(const char *str, unsigned int *n, int base)
960{
961unsigned long value = 0;
962char *tail = NULL;
963int old_errno = 0;
964const char *s = NULL;
965
966if (str == NULL || n == NULL) {
967gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
968"argument invalid");
969errno = EINVAL;
970return -1;
971}
972
973for (s = str; *s != '\0'; s++) {
974if (isspace(*s))
975continue;
976if (*s == '-')
977return -1;
978break;
979}
980
981old_errno = errno;
982errno = 0;
983value = strtoul(str, &tail, base);
984if (str == tail)
985errno = EINVAL;
986
987if (errno == ERANGE || errno == EINVAL)
988return -1;
989
990if (errno == 0)
991errno = old_errno;
992
993if (tail[0] != '\0')
994return -1;
995
996*n = (unsigned int)value;
997
998return 0;
999}
1000
1001static int
1002_gf_string2double(const char *str, double *n)
1003{
1004double value = 0.0;
1005char *tail = NULL;
1006int old_errno = 0;
1007
1008if (str == NULL || n == NULL) {
1009gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1010"argument invalid");
1011errno = EINVAL;
1012return -1;
1013}
1014
1015old_errno = errno;
1016errno = 0;
1017value = strtod(str, &tail);
1018if (str == tail)
1019errno = EINVAL;
1020
1021if (errno == ERANGE || errno == EINVAL)
1022return -1;
1023
1024if (errno == 0)
1025errno = old_errno;
1026
1027if (tail[0] != '\0')
1028return -1;
1029
1030*n = value;
1031
1032return 0;
1033}
1034
1035static int
1036_gf_string2longlong(const char *str, long long *n, int base)
1037{
1038long long value = 0;
1039char *tail = NULL;
1040int old_errno = 0;
1041
1042if (str == NULL || n == NULL) {
1043gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1044"argument invalid");
1045errno = EINVAL;
1046return -1;
1047}
1048
1049old_errno = errno;
1050errno = 0;
1051value = strtoll(str, &tail, base);
1052if (str == tail)
1053errno = EINVAL;
1054
1055if (errno == ERANGE || errno == EINVAL)
1056return -1;
1057
1058if (errno == 0)
1059errno = old_errno;
1060
1061if (tail[0] != '\0')
1062return -1;
1063
1064*n = value;
1065
1066return 0;
1067}
1068
1069static int
1070_gf_string2ulonglong(const char *str, unsigned long long *n, int base)
1071{
1072unsigned long long value = 0;
1073char *tail = NULL;
1074int old_errno = 0;
1075const char *s = NULL;
1076
1077if (str == NULL || n == NULL) {
1078gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1079"argument invalid");
1080errno = EINVAL;
1081return -1;
1082}
1083
1084for (s = str; *s != '\0'; s++) {
1085if (isspace(*s))
1086continue;
1087if (*s == '-')
1088return -1;
1089break;
1090}
1091
1092old_errno = errno;
1093errno = 0;
1094value = strtoull(str, &tail, base);
1095if (str == tail)
1096errno = EINVAL;
1097
1098if (errno == ERANGE || errno == EINVAL)
1099return -1;
1100
1101if (errno == 0)
1102errno = old_errno;
1103
1104if (tail[0] != '\0')
1105return -1;
1106
1107*n = value;
1108
1109return 0;
1110}
1111
1112int
1113gf_string2long(const char *str, long *n)
1114{
1115return _gf_string2long(str, n, 0);
1116}
1117
1118int
1119gf_string2ulong(const char *str, unsigned long *n)
1120{
1121return _gf_string2ulong(str, n, 0);
1122}
1123
1124int
1125gf_string2int(const char *str, int *n)
1126{
1127long l = 0;
1128int ret = 0;
1129
1130ret = _gf_string2long(str, &l, 0);
1131
1132*n = l;
1133return ret;
1134}
1135
1136int
1137gf_string2uint(const char *str, unsigned int *n)
1138{
1139return _gf_string2uint(str, n, 0);
1140}
1141
1142int
1143gf_string2double(const char *str, double *n)
1144{
1145return _gf_string2double(str, n);
1146}
1147
1148int
1149gf_string2longlong(const char *str, long long *n)
1150{
1151return _gf_string2longlong(str, n, 0);
1152}
1153
1154int
1155gf_string2ulonglong(const char *str, unsigned long long *n)
1156{
1157return _gf_string2ulonglong(str, n, 0);
1158}
1159
1160int
1161gf_string2int8(const char *str, int8_t *n)
1162{
1163long l = 0L;
1164int rv = 0;
1165
1166rv = _gf_string2long(str, &l, 0);
1167if (rv != 0)
1168return rv;
1169
1170if ((l >= INT8_MIN) && (l <= INT8_MAX)) {
1171*n = (int8_t)l;
1172return 0;
1173}
1174
1175errno = ERANGE;
1176return -1;
1177}
1178
1179int
1180gf_string2int16(const char *str, int16_t *n)
1181{
1182long l = 0L;
1183int rv = 0;
1184
1185rv = _gf_string2long(str, &l, 0);
1186if (rv != 0)
1187return rv;
1188
1189if ((l >= INT16_MIN) && (l <= INT16_MAX)) {
1190*n = (int16_t)l;
1191return 0;
1192}
1193
1194errno = ERANGE;
1195return -1;
1196}
1197
1198int
1199gf_string2int32(const char *str, int32_t *n)
1200{
1201long l = 0L;
1202int rv = 0;
1203
1204rv = _gf_string2long(str, &l, 0);
1205if (rv != 0)
1206return rv;
1207
1208if ((l >= INT32_MIN) && (l <= INT32_MAX)) {
1209*n = (int32_t)l;
1210return 0;
1211}
1212
1213errno = ERANGE;
1214return -1;
1215}
1216
1217int
1218gf_string2int64(const char *str, int64_t *n)
1219{
1220long long l = 0LL;
1221int rv = 0;
1222
1223rv = _gf_string2longlong(str, &l, 0);
1224if (rv != 0)
1225return rv;
1226
1227*n = (int64_t)l;
1228return 0;
1229}
1230
1231int
1232gf_string2uint8(const char *str, uint8_t *n)
1233{
1234unsigned long l = 0L;
1235int rv = 0;
1236
1237rv = _gf_string2ulong(str, &l, 0);
1238if (rv != 0)
1239return rv;
1240
1241if (l <= UINT8_MAX) {
1242*n = (uint8_t)l;
1243return 0;
1244}
1245
1246errno = ERANGE;
1247return -1;
1248}
1249
1250int
1251gf_string2uint16(const char *str, uint16_t *n)
1252{
1253unsigned long l = 0L;
1254int rv = 0;
1255
1256rv = _gf_string2ulong(str, &l, 0);
1257if (rv != 0)
1258return rv;
1259
1260if (l <= UINT16_MAX) {
1261*n = (uint16_t)l;
1262return 0;
1263}
1264
1265errno = ERANGE;
1266return -1;
1267}
1268
1269int
1270gf_string2uint32(const char *str, uint32_t *n)
1271{
1272unsigned long l = 0L;
1273int rv = 0;
1274
1275rv = _gf_string2ulong(str, &l, 0);
1276if (rv != 0)
1277return rv;
1278
1279if (l <= UINT32_MAX) {
1280*n = (uint32_t)l;
1281return 0;
1282}
1283
1284errno = ERANGE;
1285return -1;
1286}
1287
1288int
1289gf_string2uint64(const char *str, uint64_t *n)
1290{
1291unsigned long long l = 0ULL;
1292int rv = 0;
1293
1294rv = _gf_string2ulonglong(str, &l, 0);
1295if (rv != 0)
1296return rv;
1297
1298if (l <= UINT64_MAX) {
1299*n = (uint64_t)l;
1300return 0;
1301}
1302
1303errno = ERANGE;
1304return -1;
1305}
1306
1307int
1308gf_string2ulong_base10(const char *str, unsigned long *n)
1309{
1310return _gf_string2ulong(str, n, 10);
1311}
1312
1313int
1314gf_string2uint_base10(const char *str, unsigned int *n)
1315{
1316return _gf_string2uint(str, n, 10);
1317}
1318
1319int
1320gf_string2uint8_base10(const char *str, uint8_t *n)
1321{
1322unsigned long l = 0L;
1323int rv = 0;
1324
1325rv = _gf_string2ulong(str, &l, 10);
1326if (rv != 0)
1327return rv;
1328
1329if (l <= UINT8_MAX) {
1330*n = (uint8_t)l;
1331return 0;
1332}
1333
1334errno = ERANGE;
1335return -1;
1336}
1337
1338int
1339gf_string2uint16_base10(const char *str, uint16_t *n)
1340{
1341unsigned long l = 0L;
1342int rv = 0;
1343
1344rv = _gf_string2ulong(str, &l, 10);
1345if (rv != 0)
1346return rv;
1347
1348if (l <= UINT16_MAX) {
1349*n = (uint16_t)l;
1350return 0;
1351}
1352
1353errno = ERANGE;
1354return -1;
1355}
1356
1357int
1358gf_string2uint32_base10(const char *str, uint32_t *n)
1359{
1360unsigned long l = 0L;
1361int rv = 0;
1362
1363rv = _gf_string2ulong(str, &l, 10);
1364if (rv != 0)
1365return rv;
1366
1367if (l <= UINT32_MAX) {
1368*n = (uint32_t)l;
1369return 0;
1370}
1371
1372errno = ERANGE;
1373return -1;
1374}
1375
1376int
1377gf_string2uint64_base10(const char *str, uint64_t *n)
1378{
1379unsigned long long l = 0ULL;
1380int rv = 0;
1381
1382rv = _gf_string2ulonglong(str, &l, 10);
1383if (rv != 0)
1384return rv;
1385
1386if (l <= UINT64_MAX) {
1387*n = (uint64_t)l;
1388return 0;
1389}
1390
1391errno = ERANGE;
1392return -1;
1393}
1394
1395char *
1396gf_uint64_2human_readable(uint64_t n)
1397{
1398int ret = 0;
1399char *str = NULL;
1400
1401if (n >= GF_UNIT_PB) {
1402ret = gf_asprintf(&str, "%.1lfPB", ((double)n) / GF_UNIT_PB);
1403if (ret < 0)
1404goto err;
1405} else if (n >= GF_UNIT_TB) {
1406ret = gf_asprintf(&str, "%.1lfTB", ((double)n) / GF_UNIT_TB);
1407if (ret < 0)
1408goto err;
1409} else if (n >= GF_UNIT_GB) {
1410ret = gf_asprintf(&str, "%.1lfGB", ((double)n) / GF_UNIT_GB);
1411if (ret < 0)
1412goto err;
1413} else if (n >= GF_UNIT_MB) {
1414ret = gf_asprintf(&str, "%.1lfMB", ((double)n) / GF_UNIT_MB);
1415if (ret < 0)
1416goto err;
1417} else if (n >= GF_UNIT_KB) {
1418ret = gf_asprintf(&str, "%.1lfKB", ((double)n) / GF_UNIT_KB);
1419if (ret < 0)
1420goto err;
1421} else {
1422ret = gf_asprintf(&str, "%" PRIu64 "Bytes", n);
1423if (ret < 0)
1424goto err;
1425}
1426return str;
1427err:
1428return NULL;
1429}
1430
1431int
1432gf_string2bytesize_range(const char *str, uint64_t *n, uint64_t umax)
1433{
1434double value = 0.0;
1435int64_t int_value = 0;
1436uint64_t unit = 0;
1437int64_t max = 0;
1438char *tail = NULL;
1439int old_errno = 0;
1440const char *s = NULL;
1441gf_boolean_t fraction = _gf_false;
1442
1443if (str == NULL || n == NULL) {
1444gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1445"argument invalid");
1446errno = EINVAL;
1447return -1;
1448}
1449
1450max = umax & 0x7fffffffffffffffLL;
1451
1452for (s = str; *s != '\0'; s++) {
1453if (isspace(*s))
1454continue;
1455if (*s == '-')
1456return -1;
1457break;
1458}
1459
1460if (strrchr(str, '.'))
1461fraction = _gf_true;
1462
1463old_errno = errno;
1464errno = 0;
1465if (fraction)
1466value = strtod(str, &tail);
1467else
1468int_value = strtoll(str, &tail, 10);
1469
1470if (str == tail)
1471errno = EINVAL;
1472
1473if (errno == ERANGE || errno == EINVAL)
1474return -1;
1475
1476if (errno == 0)
1477errno = old_errno;
1478
1479if (tail[0] != '\0') {
1480if (strcasecmp(tail, GF_UNIT_KB_STRING) == 0)
1481unit = GF_UNIT_KB;
1482else if (strcasecmp(tail, GF_UNIT_MB_STRING) == 0)
1483unit = GF_UNIT_MB;
1484else if (strcasecmp(tail, GF_UNIT_GB_STRING) == 0)
1485unit = GF_UNIT_GB;
1486else if (strcasecmp(tail, GF_UNIT_TB_STRING) == 0)
1487unit = GF_UNIT_TB;
1488else if (strcasecmp(tail, GF_UNIT_PB_STRING) == 0)
1489unit = GF_UNIT_PB;
1490else if (strcasecmp(tail, GF_UNIT_B_STRING) != 0)
1491return -1;
1492
1493if (unit > 0) {
1494if (fraction)
1495value *= unit;
1496else
1497int_value *= unit;
1498}
1499}
1500
1501if (fraction) {
1502if ((max - value) < 0) {
1503errno = ERANGE;
1504return -1;
1505}
1506*n = (uint64_t)value;
1507} else {
1508if ((max - int_value) < 0) {
1509errno = ERANGE;
1510return -1;
1511}
1512*n = int_value;
1513}
1514
1515return 0;
1516}
1517
1518int
1519gf_string2bytesize_uint64(const char *str, uint64_t *n)
1520{
1521return gf_string2bytesize_range(str, n, UINT64_MAX);
1522}
1523
1524int
1525gf_string2bytesize_int64(const char *str, int64_t *n)
1526{
1527uint64_t u64 = 0;
1528int ret = 0;
1529
1530ret = gf_string2bytesize_range(str, &u64, INT64_MAX);
1531*n = (int64_t)u64;
1532return ret;
1533}
1534
1535int
1536gf_string2percent_or_bytesize(const char *str, double *n,
1537gf_boolean_t *is_percent)
1538{
1539double value = 0ULL;
1540char *tail = NULL;
1541int old_errno = 0;
1542const char *s = NULL;
1543
1544if (str == NULL || n == NULL) {
1545gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1546"argument invalid");
1547errno = EINVAL;
1548return -1;
1549}
1550
1551for (s = str; *s != '\0'; s++) {
1552if (isspace(*s))
1553continue;
1554if (*s == '-')
1555return -1;
1556break;
1557}
1558
1559old_errno = errno;
1560errno = 0;
1561value = strtod(str, &tail);
1562if (str == tail)
1563errno = EINVAL;
1564
1565if (errno == ERANGE || errno == EINVAL)
1566return -1;
1567
1568if (errno == 0)
1569errno = old_errno;
1570
1571/*Maximum accepted value for 64 bit OS will be (2^14 -1)PB*/
1572if (tail[0] != '\0') {
1573if (strcasecmp(tail, GF_UNIT_KB_STRING) == 0)
1574value *= GF_UNIT_KB;
1575else if (strcasecmp(tail, GF_UNIT_MB_STRING) == 0)
1576value *= GF_UNIT_MB;
1577else if (strcasecmp(tail, GF_UNIT_GB_STRING) == 0)
1578value *= GF_UNIT_GB;
1579else if (strcasecmp(tail, GF_UNIT_TB_STRING) == 0)
1580value *= GF_UNIT_TB;
1581else if (strcasecmp(tail, GF_UNIT_PB_STRING) == 0)
1582value *= GF_UNIT_PB;
1583else if (strcasecmp(tail, GF_UNIT_PERCENT_STRING) == 0)
1584*is_percent = _gf_true;
1585else
1586return -1;
1587}
1588
1589/* Error out if we cannot store the value in uint64 */
1590if ((UINT64_MAX - value) < 0) {
1591errno = ERANGE;
1592return -1;
1593}
1594
1595*n = value;
1596
1597return 0;
1598}
1599
1600int64_t
1601gf_str_to_long_long(const char *number)
1602{
1603int64_t unit = 1;
1604int64_t ret = 0;
1605char *endptr = NULL;
1606if (!number)
1607return 0;
1608
1609ret = strtoll(number, &endptr, 0);
1610
1611if (endptr) {
1612switch (*endptr) {
1613case 'G':
1614case 'g':
1615if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b'))
1616unit = 1024 * 1024 * 1024;
1617break;
1618case 'M':
1619case 'm':
1620if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b'))
1621unit = 1024 * 1024;
1622break;
1623case 'K':
1624case 'k':
1625if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b'))
1626unit = 1024;
1627break;
1628case '%':
1629unit = 1;
1630break;
1631default:
1632unit = 1;
1633break;
1634}
1635}
1636return ret * unit;
1637}
1638
1639int
1640gf_string2boolean(const char *str, gf_boolean_t *b)
1641{
1642if (str == NULL) {
1643gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1644"argument invalid");
1645return -1;
1646}
1647
1648if ((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;
1652return 0;
1653}
1654
1655if ((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;
1659return 0;
1660}
1661
1662return -1;
1663}
1664
1665int
1666gf_strn2boolean(const char *str, const int len, gf_boolean_t *b)
1667{
1668if (str == NULL) {
1669gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1670"argument invalid");
1671return -1;
1672}
1673
1674switch (len) {
1675case 1:
1676if (strcasecmp(str, "1") == 0) {
1677*b = _gf_true;
1678return 0;
1679} else if (strcasecmp(str, "0") == 0) {
1680*b = _gf_false;
1681return 0;
1682}
1683break;
1684case 2:
1685if (strcasecmp(str, "on") == 0) {
1686*b = _gf_true;
1687return 0;
1688} else if (strcasecmp(str, "no") == 0) {
1689*b = _gf_false;
1690return 0;
1691}
1692break;
1693case 3:
1694if (strcasecmp(str, "yes") == 0) {
1695*b = _gf_true;
1696return 0;
1697} else if (strcasecmp(str, "off") == 0) {
1698*b = _gf_false;
1699return 0;
1700}
1701break;
1702case 4:
1703if (strcasecmp(str, "true") == 0) {
1704*b = _gf_true;
1705return 0;
1706}
1707break;
1708case 5:
1709if (strcasecmp(str, "false") == 0) {
1710*b = _gf_false;
1711return 0;
1712}
1713break;
1714case 6:
1715if (strcasecmp(str, "enable") == 0) {
1716*b = _gf_true;
1717return 0;
1718}
1719break;
1720case 7:
1721if (strcasecmp(str, "disable") == 0) {
1722*b = _gf_false;
1723return 0;
1724}
1725break;
1726default:
1727return -1;
1728break;
1729}
1730return -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*/
1748gf_boolean_t
1749gf_is_ip_in_net(const char *network, const char *ip_str)
1750{
1751/* A buffer big enough for any socket address. */
1752uint8_t net_buff[sizeof(struct sockaddr_storage) + 1];
1753uint8_t ip_buff[sizeof(struct sockaddr_storage) + 1];
1754int32_t size;
1755uint8_t mask;
1756int ret = -EINVAL;
1757int family = AF_INET;
1758
1759GF_ASSERT(network);
1760GF_ASSERT(ip_str);
1761
1762if (strchr(network, ':'))
1763family = AF_INET6;
1764else if (strchr(network, '.'))
1765family = AF_INET;
1766else {
1767goto out;
1768}
1769
1770size = inet_net_pton(family, network, net_buff, sizeof(net_buff));
1771if (size < 0) {
1772GF_LOG_E("common-utils", LG_MSG_INET_NET_PTON_FAILED(errno));
1773goto out;
1774}
1775ret = inet_pton(family, ip_str, &ip_buff);
1776if (ret < 0) {
1777gf_smsg("common-utils", GF_LOG_ERROR, errno, LG_MSG_INET_PTON_FAILED,
1778NULL);
1779goto out;
1780}
1781
1782mask = (0xff00 >> (size & 7)) & 0xff;
1783size /= 8;
1784net_buff[size] &= mask;
1785ip_buff[size] &= mask;
1786
1787return memcmp(net_buff, ip_buff, size + 1) == 0;
1788out:
1789return _gf_false;
1790}
1791
1792char *
1793strtail(char *str, const char *pattern)
1794{
1795int i = 0;
1796
1797for (i = 0; str[i] == pattern[i] && str[i]; i++)
1798;
1799
1800if (pattern[i] == '\0')
1801return str + i;
1802
1803return NULL;
1804}
1805
1806void
1807skipwhite(char **s)
1808{
1809while (isspace(**s))
1810(*s)++;
1811}
1812
1813char *
1814nwstrtail(char *str, char *pattern)
1815{
1816for (;;) {
1817skipwhite(&str);
1818skipwhite(&pattern);
1819
1820if (*str != *pattern || !*str)
1821break;
1822
1823str++;
1824pattern++;
1825}
1826
1827return *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*/
1843char *
1844token_iter_init(char *str, char sep, token_iter_t *tit)
1845{
1846tit->end = str + strlen(str);
1847tit->sep = sep;
1848
1849return 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*/
1868gf_boolean_t
1869next_token(char **tokenp, token_iter_t *tit)
1870{
1871char *cursor = NULL;
1872gf_boolean_t is_last = _gf_false;
1873
1874for (cursor = *tokenp; *cursor; cursor++)
1875;
1876if (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
1887for (cursor = *tokenp; *cursor && *cursor != tit->sep; cursor++)
1888;
1889/* If the cursor ended up on a zero byte, then it's the last token. */
1890is_last = !*cursor;
1891/* Zero-terminate the token. */
1892*cursor = 0;
1893
1894return 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*/
1944void
1945drop_token(char *token, token_iter_t *tit)
1946{
1947char *cursor = NULL;
1948
1949for (cursor = token; *cursor; cursor++)
1950;
1951if (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*/
1957for (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*/
1967for (cursor = token; cursor < tit->end; *cursor++ = 0)
1968;
1969
1970/* Adjust the end to point to the new terminating zero. */
1971tit->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>] */
1977char
1978valid_host_name(char *address, int length)
1979{
1980int i = 0;
1981int str_len = 0;
1982char ret = 1;
1983char *dup_addr = NULL;
1984char *temp_str = NULL;
1985char *save_ptr = NULL;
1986
1987if ((length > _POSIX_HOST_NAME_MAX) || (length < 1)) {
1988ret = 0;
1989goto out;
1990}
1991
1992dup_addr = gf_strndup(address, length);
1993if (!dup_addr) {
1994ret = 0;
1995goto out;
1996}
1997
1998if (!isalnum(dup_addr[length - 1]) && (dup_addr[length - 1] != '*')) {
1999ret = 0;
2000goto out;
2001}
2002
2003/* Check for consecutive dots, which is invalid in a hostname and is
2004* ignored by strtok()
2005*/
2006if (strstr(dup_addr, "..")) {
2007ret = 0;
2008goto out;
2009}
2010
2011/* gen-name */
2012temp_str = strtok_r(dup_addr, ".", &save_ptr);
2013do {
2014str_len = strlen(temp_str);
2015
2016if (!isalnum(temp_str[0]) || !isalnum(temp_str[str_len - 1])) {
2017ret = 0;
2018goto out;
2019}
2020for (i = 1; i < str_len; i++) {
2021if (!isalnum(temp_str[i]) && (temp_str[i] != '-')) {
2022ret = 0;
2023goto out;
2024}
2025}
2026} while ((temp_str = strtok_r(NULL, ".", &save_ptr)));
2027
2028out:
2029GF_FREE(dup_addr);
2030return ret;
2031}
2032
2033/* Matches all ipv4 address, if wildcard_acc is true '*' wildcard pattern for*
2034subnets is considered as valid strings as well */
2035char
2036valid_ipv4_address(char *address, int length, gf_boolean_t wildcard_acc)
2037{
2038int octets = 0;
2039int value = 0;
2040char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL;
2041char ret = 1;
2042int is_wildcard = 0;
2043
2044tmp = 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*/
2051if (length <= 0 || (strstr(address, "..")) ||
2052(!isdigit(tmp[length - 1]) && (tmp[length - 1] != '*'))) {
2053ret = 0;
2054goto out;
2055}
2056
2057prev = strtok_r(tmp, ".", &ptr);
2058
2059while (prev != NULL) {
2060octets++;
2061if (wildcard_acc && !strcmp(prev, "*")) {
2062is_wildcard = 1;
2063} else {
2064value = strtol(prev, &endptr, 10);
2065if ((value > 255) || (value < 0) ||
2066(endptr != NULL && *endptr != '\0')) {
2067ret = 0;
2068goto out;
2069}
2070}
2071prev = strtok_r(NULL, ".", &ptr);
2072}
2073
2074if ((octets > 4) || (octets < 4 && !is_wildcard)) {
2075ret = 0;
2076}
2077
2078out:
2079GF_FREE(tmp);
2080return ret;
2081}
2082
2083static char
2084valid_cidr_address(char *cidr_address, unsigned int len,
2085gf_boolean_t wildcard_acc)
2086{
2087unsigned int net_mask = 0;
2088char *temp = NULL, *cidr_str = NULL;
2089
2090cidr_str = strdupa(cidr_address);
2091temp = strstr(cidr_str, "/");
2092if (temp == NULL)
2093return 0; /* Since Invalid cidr ip address we return 0 */
2094
2095*temp = '\0';
2096temp++;
2097net_mask = (unsigned int)atoi(temp);
2098
2099if (net_mask > 32 || net_mask < 1)
2100return 0; /* Since Invalid cidr ip address we return 0*/
2101
2102return valid_ipv4_address(cidr_str, len, wildcard_acc);
2103}
2104
2105char
2106valid_ipv6_address(char *address, int length, gf_boolean_t wildcard_acc)
2107{
2108int hex_numbers = 0;
2109int value = 0;
2110int i = 0;
2111char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL;
2112char ret = 1;
2113int is_wildcard = 0;
2114int is_compressed = 0;
2115
2116tmp = gf_strndup(address, length);
2117
2118/* Check for '%' for link local addresses */
2119endptr = strchr(tmp, '%');
2120if (endptr) {
2121*endptr = '\0';
2122length = strlen(tmp);
2123endptr = NULL;
2124}
2125
2126/* Check for compressed form */
2127if (length <= 0 || tmp[length - 1] == ':') {
2128ret = 0;
2129goto out;
2130}
2131for (i = 0; i < (length - 1); i++) {
2132if (tmp[i] == ':' && tmp[i + 1] == ':') {
2133if (is_compressed == 0)
2134is_compressed = 1;
2135else {
2136ret = 0;
2137goto out;
2138}
2139}
2140}
2141
2142prev = strtok_r(tmp, ":", &ptr);
2143
2144while (prev != NULL) {
2145hex_numbers++;
2146if (wildcard_acc && !strcmp(prev, "*")) {
2147is_wildcard = 1;
2148} else {
2149value = strtol(prev, &endptr, 16);
2150if ((value > 0xffff) || (value < 0) ||
2151(endptr != NULL && *endptr != '\0')) {
2152ret = 0;
2153goto out;
2154}
2155}
2156prev = strtok_r(NULL, ":", &ptr);
2157}
2158
2159if ((hex_numbers > 8) ||
2160(hex_numbers < 8 && !is_wildcard && !is_compressed)) {
2161ret = 0;
2162}
2163
2164out:
2165GF_FREE(tmp);
2166return ret;
2167}
2168
2169char
2170valid_internet_address(char *address, gf_boolean_t wildcard_acc,
2171gf_boolean_t cidr)
2172{
2173char ret = 0;
2174int length = 0;
2175
2176if (address == NULL) {
2177gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
2178"argument invalid");
2179goto out;
2180}
2181
2182length = strlen(address);
2183if (length == 0)
2184goto out;
2185
2186if (cidr && valid_cidr_address(address, length, wildcard_acc)) {
2187ret = 1;
2188}
2189
2190if (valid_ipv4_address(address, length, wildcard_acc) ||
2191valid_ipv6_address(address, length, wildcard_acc) ||
2192valid_host_name(address, length))
2193ret = 1;
2194
2195out:
2196return 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*/
2209gf_boolean_t
2210mask_match(const uint32_t a, const uint32_t b, const uint32_t m)
2211{
2212return (((a ^ b) & m) == 0);
2213}
2214
2215/*Thread safe conversion function*/
2216char *
2217uuid_utoa(uuid_t uuid)
2218{
2219char *uuid_buffer = glusterfs_uuid_buf_get();
2220gf_uuid_unparse(uuid, uuid_buffer);
2221return uuid_buffer;
2222}
2223
2224/*Re-entrant conversion function*/
2225char *
2226uuid_utoa_r(uuid_t uuid, char *dst)
2227{
2228if (!dst)
2229return NULL;
2230gf_uuid_unparse(uuid, dst);
2231return dst;
2232}
2233
2234/*Thread safe conversion function*/
2235char *
2236lkowner_utoa(gf_lkowner_t *lkowner)
2237{
2238char *lkowner_buffer = glusterfs_lkowner_buf_get();
2239lkowner_unparse(lkowner, lkowner_buffer, GF_LKOWNER_BUF_SIZE);
2240return lkowner_buffer;
2241}
2242
2243gf_boolean_t
2244is_valid_lease_id(const char *lease_id)
2245{
2246int i = 0;
2247gf_boolean_t valid = _gf_false;
2248
2249for (i = 0; i < LEASE_ID_SIZE; i++) {
2250if (lease_id[i] != 0) {
2251valid = _gf_true;
2252goto out;
2253}
2254}
2255out:
2256return 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*/
2272char *
2273leaseid_utoa(const char *lease_id)
2274{
2275char *buf = NULL;
2276int i = 0;
2277int j = 0;
2278
2279buf = glusterfs_leaseid_buf_get();
2280if (!buf)
2281goto out;
2282
2283for (i = 0; i < LEASE_ID_SIZE; i++) {
2284if (i && !(i % 2)) {
2285buf[j] = '-';
2286j++;
2287}
2288sprintf(&buf[j], "%02hhx", lease_id[i]);
2289j += 2;
2290if (j == GF_LEASE_ID_BUF_SIZE)
2291break;
2292}
2293buf[GF_LEASE_ID_BUF_SIZE - 1] = '\0';
2294out:
2295return buf;
2296}
2297
2298char *
2299gf_leaseid_get(void)
2300{
2301return glusterfs_leaseid_buf_get();
2302}
2303
2304char *
2305gf_existing_leaseid(void)
2306{
2307return 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
2315int32_t
2316gf_roundup_power_of_two(int32_t nr)
2317{
2318int32_t result = 1;
2319
2320if (nr < 0) {
2321gf_smsg("common-utils", GF_LOG_WARNING, 0, LG_MSG_NEGATIVE_NUM_PASSED,
2322NULL);
2323result = -1;
2324goto out;
2325}
2326
2327while (result < nr)
2328result *= 2;
2329
2330out:
2331return 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
2339int32_t
2340gf_roundup_next_power_of_two(int32_t nr)
2341{
2342int32_t result = 1;
2343
2344if (nr < 0) {
2345gf_smsg("common-utils", GF_LOG_WARNING, 0, LG_MSG_NEGATIVE_NUM_PASSED,
2346NULL);
2347result = -1;
2348goto out;
2349}
2350
2351while (result <= nr)
2352result *= 2;
2353
2354out:
2355return result;
2356}
2357
2358char *
2359get_host_name(char *word, char **host)
2360{
2361char *delimiter = NULL;
2362delimiter = strrchr(word, ':');
2363if (delimiter)
2364*delimiter = '\0';
2365else
2366return NULL;
2367*host = word;
2368return *host;
2369}
2370
2371void
2372gf_path_strip_trailing_slashes(char *path)
2373{
2374int i = 0;
2375int len = 0;
2376
2377if (!path)
2378return;
2379
2380len = strlen(path);
2381for (i = len - 1; i > 0; i--) {
2382if (path[i] != '/')
2383break;
2384}
2385
2386if (i < (len - 1))
2387path[i + 1] = '\0';
2388
2389return;
2390}
2391
2392uint64_t
2393get_mem_size(void)
2394{
2395uint64_t memsize = -1;
2396
2397#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS
2398
2399uint64_t page_size = 0;
2400uint64_t num_pages = 0;
2401
2402page_size = sysconf(_SC_PAGESIZE);
2403num_pages = sysconf(_SC_PHYS_PAGES);
2404
2405memsize = page_size * num_pages;
2406#endif
2407
2408#if defined GF_DARWIN_HOST_OS || defined __FreeBSD__
2409
2410size_t len = sizeof(memsize);
2411int name[] = {CTL_HW, HW_PHYSMEM};
2412
2413sysctl(name, 2, &memsize, &len, NULL, 0);
2414#endif
2415
2416#if defined __NetBSD__
2417
2418size_t len = sizeof(memsize);
2419int name64[] = {CTL_HW, HW_PHYSMEM64};
2420
2421sysctl(name64, 2, &memsize, &len, NULL, 0);
2422if (memsize == -1)
2423sysctl(name64, 2, &memsize, &len, NULL, 0);
2424#endif
2425return memsize;
2426}
2427
2428int
2429gf_canonicalize_path(char *path)
2430{
2431int ret = -1;
2432int path_len = 0;
2433int dir_path_len = 0;
2434char *tmppath = NULL;
2435char *dir = NULL;
2436char *tmpstr = NULL;
2437int pathlen;
2438
2439if (!path || *path != '/')
2440goto out;
2441
2442if (!strcmp(path, "/"))
2443return 0;
2444
2445pathlen = strlen(path);
2446tmppath = gf_strndup(path, pathlen);
2447if (!tmppath)
2448goto out;
2449
2450/* Strip the extra slashes and return */
2451bzero(path, pathlen);
2452path[0] = '/';
2453dir = strtok_r(tmppath, "/", &tmpstr);
2454
2455while (dir) {
2456dir_path_len = strlen(dir);
2457memcpy((path + path_len + 1), dir, dir_path_len);
2458path_len += dir_path_len + 1;
2459dir = strtok_r(NULL, "/", &tmpstr);
2460if (dir) {
2461path[path_len] = '/';
2462}
2463}
2464path[path_len] = '\0';
2465ret = 0;
2466
2467out:
2468if (ret)
2469gf_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_PATH_ERROR, NULL);
2470
2471GF_FREE(tmppath);
2472
2473return ret;
2474}
2475
2476char *
2477generate_glusterfs_ctx_id(void)
2478{
2479uuid_t ctxid;
2480char *tmp = NULL;
2481
2482gf_uuid_generate(ctxid);
2483tmp = uuid_utoa(ctxid);
2484
2485return gf_strndup(tmp, UUID_CANONICAL_FORM_LEN);
2486}
2487
2488static char *
2489gf_get_reserved_ports(void)
2490{
2491char *ports_info = NULL;
2492#if defined GF_LINUX_HOST_OS
2493int proc_fd = -1;
2494char *proc_file = "/proc/sys/net/ipv4/ip_local_reserved_ports";
2495char buffer[4096] = {
24960,
2497};
2498int32_t ret = -1;
2499
2500proc_fd = open(proc_file, O_RDONLY);
2501if (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*/
2507gf_smsg("glusterfs", GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,
2508" /proc/sys/net/ipv4/ip_local_reserved_ports", NULL);
2509goto out;
2510}
2511
2512ret = sys_read(proc_fd, buffer, sizeof(buffer) - 1);
2513if (ret < 0) {
2514gf_smsg("glusterfs", GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,
2515"file=%s", proc_file, NULL);
2516goto out;
2517}
2518
2519buffer[ret] = '\0';
2520ports_info = gf_strndup(buffer, ret);
2521
2522out:
2523if (proc_fd != -1)
2524sys_close(proc_fd);
2525#endif /* GF_LINUX_HOST_OS */
2526return ports_info;
2527}
2528
2529int
2530gf_process_reserved_ports(unsigned char *ports, uint32_t ceiling)
2531{
2532int ret = -1;
2533
2534memset(ports, 0, GF_PORT_ARRAY_SIZE);
2535
2536#if defined GF_LINUX_HOST_OS
2537char *ports_info = NULL;
2538char *tmp = NULL;
2539char *blocked_port = NULL;
2540
2541ports_info = gf_get_reserved_ports();
2542if (!ports_info) {
2543gf_smsg("glusterfs", GF_LOG_WARNING, 0, LG_MSG_RESERVED_PORTS_ERROR,
2544NULL);
2545goto out;
2546}
2547
2548blocked_port = strtok_r(ports_info, ",\n", &tmp);
2549
2550while (blocked_port) {
2551gf_ports_reserved(blocked_port, ports, ceiling);
2552blocked_port = strtok_r(NULL, ",\n", &tmp);
2553}
2554
2555ret = 0;
2556
2557out:
2558GF_FREE(ports_info);
2559
2560#else /* FIXME: Non Linux Host */
2561ret = 0;
2562#endif /* GF_LINUX_HOST_OS */
2563
2564return ret;
2565}
2566
2567gf_boolean_t
2568gf_ports_reserved(char *blocked_port, unsigned char *ports, uint32_t ceiling)
2569{
2570gf_boolean_t result = _gf_false;
2571char *range_port = NULL;
2572int32_t tmp_port1 = -1;
2573int32_t tmp_port2 = -1;
2574
2575if (strstr(blocked_port, "-") == NULL) {
2576/* get rid of the new line character*/
2577if (blocked_port[strlen(blocked_port) - 1] == '\n')
2578blocked_port[strlen(blocked_port) - 1] = '\0';
2579if (gf_string2int32(blocked_port, &tmp_port1) == 0) {
2580if (tmp_port1 > GF_PORT_MAX || tmp_port1 < 0) {
2581gf_smsg("glusterfs-socket", GF_LOG_WARNING, 0,
2582LG_MSG_INVALID_PORT, "port=%d", tmp_port1, NULL);
2583result = _gf_true;
2584goto out;
2585} else {
2586gf_msg_debug("glusterfs", 0,
2587"blocking port "
2588"%d",
2589tmp_port1);
2590BIT_SET(ports, tmp_port1);
2591}
2592} else {
2593gf_smsg("glusterfs-socket", GF_LOG_WARNING, 0, LG_MSG_INVALID_PORT,
2594"port=%s", blocked_port, NULL);
2595result = _gf_true;
2596goto out;
2597}
2598} else {
2599range_port = strtok(blocked_port, "-");
2600if (!range_port) {
2601result = _gf_true;
2602goto out;
2603}
2604if (gf_string2int32(range_port, &tmp_port1) == 0) {
2605if (tmp_port1 > ceiling)
2606tmp_port1 = ceiling;
2607if (tmp_port1 < 0)
2608tmp_port1 = 0;
2609}
2610range_port = strtok(NULL, "-");
2611if (!range_port) {
2612result = _gf_true;
2613goto out;
2614}
2615/* get rid of the new line character*/
2616if (range_port[strlen(range_port) - 1] == '\n')
2617range_port[strlen(range_port) - 1] = '\0';
2618if (gf_string2int32(range_port, &tmp_port2) == 0) {
2619if (tmp_port2 > ceiling)
2620tmp_port2 = ceiling;
2621if (tmp_port2 < 0)
2622tmp_port2 = 0;
2623}
2624gf_msg_debug("glusterfs", 0, "lower: %d, higher: %d", tmp_port1,
2625tmp_port2);
2626for (; tmp_port1 <= tmp_port2; tmp_port1++)
2627BIT_SET(ports, tmp_port1);
2628}
2629
2630out:
2631return 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*/
2638int
2639gf_get_hostname_from_ip(char *client_ip, char **hostname)
2640{
2641int ret = -1;
2642struct sockaddr *client_sockaddr = NULL;
2643struct sockaddr_in client_sock_in = {0};
2644struct sockaddr_in6 client_sock_in6 = {0};
2645char client_hostname[NI_MAXHOST] = {0};
2646char *client_ip_copy = NULL;
2647char *tmp = NULL;
2648char *ip = NULL;
2649size_t addr_sz = 0;
2650int ip_len;
2651
2652if (!client_ip)
2653goto out;
2654
2655ip_len = strlen(client_ip);
2656/* if ipv4, reverse lookup the hostname to
2657* allow FQDN based rpc authentication
2658*/
2659if (!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 */
2662client_ip_copy = gf_strndup(client_ip, ip_len);
2663if (!client_ip_copy)
2664goto out;
2665
2666ip = strtok_r(client_ip_copy, ":", &tmp);
2667} else {
2668ip = client_ip;
2669}
2670
2671ip_len = strlen(ip);
2672if (valid_ipv4_address(ip, ip_len, 0) == _gf_true) {
2673client_sockaddr = (struct sockaddr *)&client_sock_in;
2674addr_sz = sizeof(client_sock_in);
2675client_sock_in.sin_family = AF_INET;
2676ret = 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) {
2679client_sockaddr = (struct sockaddr *)&client_sock_in6;
2680addr_sz = sizeof(client_sock_in6);
2681
2682client_sock_in6.sin6_family = AF_INET6;
2683ret = inet_pton(AF_INET6, ip, (void *)&client_sock_in6.sin6_addr);
2684} else {
2685goto out;
2686}
2687
2688if (ret != 1) {
2689ret = -1;
2690goto 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*/
2699ret = getnameinfo(client_sockaddr, addr_sz, client_hostname,
2700sizeof(client_hostname), NULL, 0, 0);
2701if (ret) {
2702gf_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED,
2703"ip=%s", client_ip, "ret=%s", gai_strerror(ret), NULL);
2704ret = -1;
2705goto out;
2706}
2707
2708*hostname = gf_strdup((char *)client_hostname);
2709out:
2710if (client_ip_copy)
2711GF_FREE(client_ip_copy);
2712
2713return ret;
2714}
2715
2716gf_boolean_t
2717gf_interface_search(char *ip)
2718{
2719int32_t ret = -1;
2720gf_boolean_t found = _gf_false;
2721struct ifaddrs *ifaddr, *ifa;
2722int family;
2723char host[NI_MAXHOST];
2724xlator_t *this = NULL;
2725char *pct = NULL;
2726
2727this = THIS;
2728
2729ret = getifaddrs(&ifaddr);
2730
2731if (ret != 0) {
2732gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETIFADDRS_FAILED, "ret=%s",
2733gai_strerror(ret), NULL);
2734goto out;
2735}
2736
2737for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
2738if (!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*/
2744continue;
2745}
2746family = ifa->ifa_addr->sa_family;
2747
2748if (family != AF_INET && family != AF_INET6)
2749continue;
2750
2751ret = getnameinfo(ifa->ifa_addr,
2752(family == AF_INET) ? sizeof(struct sockaddr_in)
2753: sizeof(struct sockaddr_in6),
2754host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
2755
2756if (ret != 0) {
2757gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED,
2758"ret=%s", gai_strerror(ret), NULL);
2759goto 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*/
2768pct = index(host, '%');
2769if (pct) {
2770*pct = '\0';
2771}
2772
2773if (strncmp(ip, host, NI_MAXHOST) == 0) {
2774gf_msg_debug(this->name, 0,
2775"%s is local address at "
2776"interface %s",
2777ip, ifa->ifa_name);
2778found = _gf_true;
2779goto out;
2780}
2781}
2782out:
2783if (ifaddr)
2784freeifaddrs(ifaddr);
2785return found;
2786}
2787
2788static char *
2789get_ip_from_addrinfo(struct addrinfo *addr, char **ip)
2790{
2791char buf[64];
2792void *in_addr = NULL;
2793struct sockaddr_in *s4 = NULL;
2794struct sockaddr_in6 *s6 = NULL;
2795
2796switch (addr->ai_family) {
2797case AF_INET:
2798s4 = (struct sockaddr_in *)addr->ai_addr;
2799in_addr = &s4->sin_addr;
2800break;
2801
2802case AF_INET6:
2803s6 = (struct sockaddr_in6 *)addr->ai_addr;
2804in_addr = &s6->sin6_addr;
2805break;
2806
2807default:
2808gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_INVALID_FAMILY, NULL);
2809return NULL;
2810}
2811
2812if (!inet_ntop(addr->ai_family, in_addr, buf, sizeof(buf))) {
2813gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_CONVERSION_FAILED, NULL);
2814return NULL;
2815}
2816
2817*ip = gf_strdup(buf);
2818return *ip;
2819}
2820
2821gf_boolean_t
2822gf_is_loopback_localhost(const struct sockaddr *sa, char *hostname)
2823{
2824GF_ASSERT(sa);
2825
2826gf_boolean_t is_local = _gf_false;
2827const struct in_addr *addr4 = NULL;
2828const struct in6_addr *addr6 = NULL;
2829uint8_t *ap = NULL;
2830struct in6_addr loopbackaddr6 = IN6ADDR_LOOPBACK_INIT;
2831
2832switch (sa->sa_family) {
2833case AF_INET:
2834addr4 = &(((struct sockaddr_in *)sa)->sin_addr);
2835ap = (uint8_t *)&addr4->s_addr;
2836if (ap[0] == 127)
2837is_local = _gf_true;
2838break;
2839
2840case AF_INET6:
2841addr6 = &(((struct sockaddr_in6 *)sa)->sin6_addr);
2842if (memcmp(addr6, &loopbackaddr6, sizeof(loopbackaddr6)) == 0)
2843is_local = _gf_true;
2844break;
2845
2846default:
2847if (hostname)
2848gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_INVALID_FAMILY,
2849"family=%d", sa->sa_family, "hostname=%s", hostname,
2850NULL);
2851break;
2852}
2853
2854return is_local;
2855}
2856
2857gf_boolean_t
2858gf_is_local_addr(char *hostname)
2859{
2860int32_t ret = -1;
2861struct addrinfo *result = NULL;
2862struct addrinfo *res = NULL;
2863gf_boolean_t found = _gf_false;
2864char *ip = NULL;
2865xlator_t *this = NULL;
2866struct addrinfo hints;
2867
2868this = THIS;
2869
2870memset(&hints, 0, sizeof(hints));
2871/*
2872* Removing AI_ADDRCONFIG from default_hints
2873* for being able to use link local ipv6 addresses
2874*/
2875hints.ai_family = AF_UNSPEC;
2876
2877ret = getaddrinfo(hostname, NULL, &hints, &result);
2878
2879if (ret != 0) {
2880gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETADDRINFO_FAILED,
2881"ret=%s", gai_strerror(ret), NULL);
2882goto out;
2883}
2884
2885for (res = result; res != NULL; res = res->ai_next) {
2886get_ip_from_addrinfo(res, &ip);
2887gf_msg_debug(this->name, 0, "%s ", (ip ? ip : "<unknown>"));
2888
2889if (ip) {
2890found = (gf_is_loopback_localhost(res->ai_addr, hostname) ||
2891gf_interface_search(ip));
2892}
2893if (found) {
2894GF_FREE(ip);
2895goto out;
2896}
2897GF_FREE(ip);
2898/* the above free will not set ip to NULL, and hence, there is
2899double free possible as the loop continues. set ip to NULL. */
2900ip = NULL;
2901}
2902
2903out:
2904if (result)
2905freeaddrinfo(result);
2906
2907if (!found)
2908gf_msg_debug(this->name, 0, "%s is not local", hostname);
2909
2910return found;
2911}
2912
2913gf_boolean_t
2914gf_is_same_address(char *name1, char *name2)
2915{
2916struct addrinfo *addr1 = NULL;
2917struct addrinfo *addr2 = NULL;
2918struct addrinfo *p = NULL;
2919struct addrinfo *q = NULL;
2920gf_boolean_t ret = _gf_false;
2921int gai_err = 0;
2922struct addrinfo hints;
2923
2924memset(&hints, 0, sizeof(hints));
2925hints.ai_family = AF_UNSPEC;
2926
2927gai_err = getaddrinfo(name1, NULL, &hints, &addr1);
2928if (gai_err != 0) {
2929gf_smsg(name1, GF_LOG_WARNING, 0, LG_MSG_GETADDRINFO_FAILED, "error=%s",
2930gai_strerror(gai_err), NULL);
2931goto out;
2932}
2933
2934gai_err = getaddrinfo(name2, NULL, &hints, &addr2);
2935if (gai_err != 0) {
2936gf_smsg(name2, GF_LOG_WARNING, 0, LG_MSG_GETADDRINFO_FAILED, "error=%s",
2937gai_strerror(gai_err), NULL);
2938goto out;
2939}
2940
2941for (p = addr1; p; p = p->ai_next) {
2942for (q = addr2; q; q = q->ai_next) {
2943if (p->ai_addrlen != q->ai_addrlen) {
2944continue;
2945}
2946if (memcmp(p->ai_addr, q->ai_addr, p->ai_addrlen)) {
2947continue;
2948}
2949ret = _gf_true;
2950goto out;
2951}
2952}
2953
2954out:
2955if (addr1) {
2956freeaddrinfo(addr1);
2957}
2958if (addr2) {
2959freeaddrinfo(addr2);
2960}
2961return ret;
2962}
2963
2964/*
2965* Processes list of volfile servers.
2966* Format: <host1>:<port1> <host2>:<port2>...
2967*/
2968int
2969gf_process_getspec_servers_list(cmd_args_t *cmd_args, const char *servers_list)
2970{
2971char *tmp = NULL;
2972char *address = NULL;
2973char *host = NULL;
2974char *last_colon = NULL;
2975char *save_ptr = NULL;
2976int port = 0;
2977int ret = -1;
2978
2979tmp = gf_strdup(servers_list);
2980if (!tmp) {
2981errno = ENOMEM;
2982goto out;
2983}
2984
2985address = strtok_r(tmp, " ", &save_ptr);
2986if (!address) {
2987errno = EINVAL;
2988goto out;
2989}
2990
2991while (1) {
2992last_colon = strrchr(address, ':');
2993if (!last_colon) {
2994errno = EINVAL;
2995ret = -1;
2996break;
2997}
2998*last_colon = '\0';
2999host = address;
3000port = atoi(last_colon + 1);
3001if (port <= 0) {
3002errno = EINVAL;
3003ret = -1;
3004break;
3005}
3006ret = gf_set_volfile_server_common(cmd_args, host,
3007GF_DEFAULT_VOLFILE_TRANSPORT, port);
3008if (ret && errno != EEXIST) {
3009break;
3010}
3011address = strtok_r(NULL, " ", &save_ptr);
3012if (!address) {
3013errno = 0;
3014ret = 0;
3015break;
3016}
3017}
3018
3019out:
3020if (tmp) {
3021GF_FREE(tmp);
3022}
3023
3024return ret;
3025}
3026
3027int
3028gf_set_volfile_server_common(cmd_args_t *cmd_args, const char *host,
3029const char *transport, int port)
3030{
3031server_cmdline_t *server = NULL;
3032server_cmdline_t *tmp = NULL;
3033char *duphost = NULL;
3034int ret = -1;
3035
3036GF_VALIDATE_OR_GOTO(THIS->name, cmd_args, out);
3037GF_VALIDATE_OR_GOTO(THIS->name, host, out);
3038GF_VALIDATE_OR_GOTO(THIS->name, transport, out);
3039
3040server = GF_CALLOC(1, sizeof(server_cmdline_t),
3041gf_common_mt_server_cmdline_t);
3042if (!server) {
3043errno = ENOMEM;
3044goto out;
3045}
3046
3047INIT_LIST_HEAD(&server->list);
3048server->port = port;
3049
3050duphost = gf_strdup(host);
3051if (!duphost) {
3052errno = ENOMEM;
3053goto out;
3054}
3055
3056char *lastptr = rindex(duphost, ':');
3057if (lastptr) {
3058*lastptr = '\0';
3059long port_argument = strtol(lastptr + 1, NULL, 0);
3060if (!port_argument) {
3061port_argument = port;
3062}
3063server->port = port_argument;
3064}
3065server->volfile_server = gf_strdup(duphost);
3066if (!server->volfile_server) {
3067errno = ENOMEM;
3068goto out;
3069}
3070
3071server->transport = gf_strdup(transport);
3072if (!server->transport) {
3073errno = ENOMEM;
3074goto out;
3075}
3076
3077if (!cmd_args->volfile_server) {
3078cmd_args->volfile_server = server->volfile_server;
3079cmd_args->volfile_server_transport = server->transport;
3080cmd_args->volfile_server_port = server->port;
3081cmd_args->curr_server = server;
3082}
3083
3084list_for_each_entry(tmp, &cmd_args->volfile_servers, list)
3085{
3086if ((!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 */
3090gf_smsg("gluster", GF_LOG_INFO, EEXIST, LG_MSG_DUPLICATE_ENTRY,
3091NULL);
3092ret = 0;
3093goto out;
3094}
3095}
3096
3097list_add_tail(&server->list, &cmd_args->volfile_servers);
3098
3099ret = 0;
3100out:
3101if (-1 == ret) {
3102if (server) {
3103GF_FREE(server->volfile_server);
3104GF_FREE(server->transport);
3105GF_FREE(server);
3106}
3107}
3108if (duphost)
3109GF_FREE(duphost);
3110
3111return ret;
3112}
3113
3114/* Sets log file path from user provided arguments */
3115int
3116gf_set_log_file_path(cmd_args_t *cmd_args, glusterfs_ctx_t *ctx)
3117{
3118int i = 0;
3119int j = 0;
3120int ret = 0;
3121int tmp_len = 0;
3122char tmp_str[1024] = {
31230,
3124};
3125
3126if (!cmd_args)
3127goto done;
3128
3129if (cmd_args->mount_point) {
3130j = 0;
3131i = 0;
3132if (cmd_args->mount_point[0] == '/')
3133i = 1;
3134for (; i < strlen(cmd_args->mount_point); i++, j++) {
3135tmp_str[j] = cmd_args->mount_point[i];
3136if (cmd_args->mount_point[i] == '/')
3137tmp_str[j] = '-';
3138}
3139
3140ret = gf_asprintf(&cmd_args->log_file,
3141DEFAULT_LOG_FILE_DIRECTORY "/%s.log", tmp_str);
3142if (ret > 0)
3143ret = 0;
3144goto done;
3145}
3146
3147if (ctx && GF_GLUSTERD_PROCESS == ctx->process_mode) {
3148ret = gf_asprintf(&cmd_args->log_file,
3149DEFAULT_LOG_FILE_DIRECTORY "/%s.log", GLUSTERD_NAME);
3150if (ret > 0)
3151ret = 0;
3152
3153goto done;
3154}
3155
3156if (cmd_args->volfile) {
3157j = 0;
3158i = 0;
3159if (cmd_args->volfile[0] == '/')
3160i = 1;
3161for (; i < strlen(cmd_args->volfile); i++, j++) {
3162tmp_str[j] = cmd_args->volfile[i];
3163if (cmd_args->volfile[i] == '/')
3164tmp_str[j] = '-';
3165}
3166ret = gf_asprintf(&cmd_args->log_file,
3167DEFAULT_LOG_FILE_DIRECTORY "/%s.log", tmp_str);
3168if (ret > 0)
3169ret = 0;
3170goto done;
3171}
3172
3173if (cmd_args->volfile_server) {
3174if (strncmp(cmd_args->volfile_server_transport, "unix", 4) == 0) {
3175if (cmd_args->volfile_server[0] == '/')
3176i = 1;
3177tmp_len = strlen(cmd_args->volfile_server);
3178for (j = 0; i < tmp_len; i++, j++) {
3179tmp_str[j] = cmd_args->volfile_server[i];
3180if (cmd_args->volfile_server[i] == '/')
3181tmp_str[j] = '-';
3182}
3183ret = gf_asprintf(&cmd_args->log_file, "%s/%s-%s-%d.log",
3184DEFAULT_LOG_FILE_DIRECTORY, tmp_str,
3185cmd_args->volfile_id, getpid());
3186} else {
3187ret = gf_asprintf(&cmd_args->log_file, "%s/%s-%s-%d.log",
3188DEFAULT_LOG_FILE_DIRECTORY,
3189cmd_args->volfile_server, cmd_args->volfile_id,
3190getpid());
3191}
3192if (ret > 0)
3193ret = 0;
3194}
3195done:
3196return ret;
3197}
3198
3199int
3200gf_thread_cleanup_xint(pthread_t thread)
3201{
3202int ret = 0;
3203void *res = NULL;
3204
3205ret = pthread_cancel(thread);
3206if (ret != 0)
3207goto error_return;
3208
3209ret = pthread_join(thread, &res);
3210if (ret != 0)
3211goto error_return;
3212
3213if (res != PTHREAD_CANCELED)
3214goto error_return;
3215
3216ret = 0;
3217
3218error_return:
3219return ret;
3220}
3221
3222static void
3223gf_thread_set_vname(pthread_t thread, const char *name, va_list args)
3224{
3225char thread_name[GF_THREAD_NAME_LIMIT];
3226int ret;
3227
3228/* Initialize the thread name with the prefix (not NULL terminated). */
3229memcpy(thread_name, GF_THREAD_NAME_PREFIX,
3230sizeof(GF_THREAD_NAME_PREFIX) - 1);
3231
3232ret = vsnprintf(thread_name + sizeof(GF_THREAD_NAME_PREFIX) - 1,
3233sizeof(thread_name) - sizeof(GF_THREAD_NAME_PREFIX) + 1,
3234name, args);
3235if (ret < 0) {
3236gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_PTHREAD_NAMING_FAILED,
3237"name=%s", name, NULL);
3238return;
3239}
3240
3241if (ret >= sizeof(thread_name)) {
3242gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_THREAD_NAME_TOO_LONG,
3243"name=%s", thread_name, NULL);
3244}
3245
3246ret = __gf_thread_set_name(thread, thread_name);
3247
3248if (ret != 0) {
3249gf_smsg(THIS->name, GF_LOG_WARNING, ret, LG_MSG_SET_THREAD_FAILED,
3250"name=%s", thread_name, NULL);
3251}
3252}
3253
3254void
3255gf_thread_set_name(pthread_t thread, const char *name, ...)
3256{
3257va_list args;
3258
3259va_start(args, name);
3260gf_thread_set_vname(thread, name, args);
3261va_end(args);
3262}
3263
3264static int
3265gf_thread_vcreate(pthread_t *thread, const pthread_attr_t *attr,
3266void *(*start_routine)(void *), void *arg, const char *name,
3267va_list args)
3268{
3269sigset_t set, old;
3270int ret;
3271
3272sigemptyset(&old);
3273sigfillset(&set);
3274sigdelset(&set, SIGSEGV);
3275sigdelset(&set, SIGBUS);
3276sigdelset(&set, SIGILL);
3277sigdelset(&set, SIGSYS);
3278sigdelset(&set, SIGFPE);
3279sigdelset(&set, SIGABRT);
3280sigdelset(&set, SIGCONT);
3281
3282pthread_sigmask(SIG_BLOCK, &set, &old);
3283
3284ret = pthread_create(thread, attr, start_routine, arg);
3285if (ret != 0) {
3286gf_smsg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_THREAD_CREATE_FAILED,
3287NULL);
3288ret = -1;
3289} else if (name != NULL) {
3290gf_thread_set_vname(*thread, name, args);
3291}
3292
3293pthread_sigmask(SIG_SETMASK, &old, NULL);
3294
3295return ret;
3296}
3297
3298int
3299gf_thread_create(pthread_t *thread, const pthread_attr_t *attr,
3300void *(*start_routine)(void *), void *arg, const char *name,
3301...)
3302{
3303va_list args;
3304int ret;
3305
3306va_start(args, name);
3307ret = gf_thread_vcreate(thread, attr, start_routine, arg, name, args);
3308va_end(args);
3309
3310return ret;
3311}
3312
3313int
3314gf_thread_create_detached(pthread_t *thread, void *(*start_routine)(void *),
3315void *arg, const char *name, ...)
3316{
3317pthread_attr_t attr;
3318va_list args;
3319int ret = -1;
3320
3321ret = pthread_attr_init(&attr);
3322if (ret) {
3323gf_smsg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_PTHREAD_ATTR_INIT_FAILED,
3324NULL);
3325return -1;
3326}
3327
3328pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3329
3330va_start(args, name);
3331ret = gf_thread_vcreate(thread, &attr, start_routine, arg, name, args);
3332va_end(args);
3333
3334pthread_attr_destroy(&attr);
3335
3336return ret;
3337}
3338
3339/* Below function is use to check at runtime if pid is running */
3340
3341static gf_boolean_t
3342gf_is_pid_running(int pid)
3343{
3344#ifdef __FreeBSD__
3345int ret = -1;
3346
3347ret = sys_kill(pid, 0);
3348if (ret < 0) {
3349return _gf_false;
3350}
3351#else
3352char fname[32] = {
33530,
3354};
3355int fd = -1;
3356
3357snprintf(fname, sizeof(fname), "/proc/%d/cmdline", pid);
3358
3359fd = sys_open(fname, O_RDONLY, 0);
3360if (fd < 0) {
3361return _gf_false;
3362}
3363
3364sys_close(fd);
3365#endif
3366return _gf_true;
3367}
3368
3369gf_boolean_t
3370gf_is_service_running(char *pidfile, int *pid)
3371{
3372FILE *file = NULL;
3373gf_boolean_t running = _gf_false;
3374int ret = 0;
3375int fno = 0;
3376
3377file = fopen(pidfile, "r+");
3378if (!file) {
3379goto out;
3380}
3381
3382fno = fileno(file);
3383ret = lockf(fno, F_TEST, 0);
3384if (ret == -1) {
3385running = _gf_true;
3386}
3387
3388ret = fscanf(file, "%d", pid);
3389if (ret <= 0) {
3390gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, "pidfile=%s",
3391pidfile, NULL);
3392*pid = -1;
3393running = _gf_false;
3394goto out;
3395}
3396
3397running = gf_is_pid_running(*pid);
3398out:
3399if (file)
3400fclose(file);
3401return running;
3402}
3403
3404/*
3405* gf_set_timestamp:
3406* It sets the mtime and atime of 'dest' file as of 'src'.
3407*/
3408
3409int
3410gf_set_timestamp(const char *src, const char *dest)
3411{
3412struct stat sb = {
34130,
3414};
3415#if defined(HAVE_UTIMENSAT)
3416struct timespec new_time[2] = {{
34170,
3418},
3419{
34200,
3421}};
3422#else
3423struct timeval new_time[2] = {{
34240,
3425},
3426{
34270,
3428}};
3429#endif
3430int ret = 0;
3431xlator_t *this = NULL;
3432
3433this = THIS;
3434GF_ASSERT(this);
3435GF_ASSERT(src);
3436GF_ASSERT(dest);
3437
3438ret = sys_stat(src, &sb);
3439if (ret) {
3440gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_FILE_STAT_FAILED,
3441"stat=%s", src, NULL);
3442goto out;
3443}
3444/* The granularity is nano seconds if `utimensat()` is available,
3445* and micro seconds otherwise.
3446*/
3447#if defined(HAVE_UTIMENSAT)
3448new_time[0].tv_sec = sb.st_atime;
3449new_time[0].tv_nsec = ST_ATIM_NSEC(&sb);
3450
3451new_time[1].tv_sec = sb.st_mtime;
3452new_time[1].tv_nsec = ST_MTIM_NSEC(&sb);
3453
3454/* dirfd = 0 is ignored because `dest` is an absolute path. */
3455ret = sys_utimensat(AT_FDCWD, dest, new_time, AT_SYMLINK_NOFOLLOW);
3456if (ret) {
3457gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMENSAT_FAILED,
3458"dest=%s", dest, NULL);
3459}
3460#else
3461new_time[0].tv_sec = sb.st_atime;
3462new_time[0].tv_usec = ST_ATIM_NSEC(&sb) / 1000;
3463
3464new_time[1].tv_sec = sb.st_mtime;
3465new_time[1].tv_usec = ST_MTIM_NSEC(&sb) / 1000;
3466
3467ret = sys_utimes(dest, new_time);
3468if (ret) {
3469gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMES_FAILED,
3470"dest=%s", dest, NULL);
3471}
3472#endif
3473out:
3474return ret;
3475}
3476
3477static void
3478gf_backtrace_end(char *buf, size_t frames)
3479{
3480size_t pos = 0;
3481
3482if (!buf)
3483return;
3484
3485pos = strlen(buf);
3486
3487frames = min(frames, GF_BACKTRACE_LEN - pos - 1);
3488
3489if (0 == frames)
3490return;
3491
3492memset(buf + pos, ')', frames);
3493buf[pos + frames] = '\0';
3494}
3495
3496/*Returns bytes written*/
3497static int
3498gf_backtrace_append(char *buf, size_t pos, char *framestr)
3499{
3500if (pos >= GF_BACKTRACE_LEN)
3501return -1;
3502return snprintf(buf + pos, GF_BACKTRACE_LEN - pos, "(--> %s ", framestr);
3503}
3504
3505static int
3506gf_backtrace_fillframes(char *buf)
3507{
3508void *array[GF_BACKTRACE_FRAME_COUNT];
3509size_t frames = 0;
3510FILE *fp = NULL;
3511char callingfn[GF_BACKTRACE_FRAME_COUNT - 2][1024] = {
3512{0},
3513};
3514int ret = -1;
3515int fd = -1;
3516size_t idx = 0;
3517size_t pos = 0;
3518size_t inc = 0;
3519char tmpl[] = "/tmp/glfs-bt-XXXXXX";
3520
3521frames = backtrace(array, GF_BACKTRACE_FRAME_COUNT);
3522if (!frames)
3523return -1;
3524
3525/* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */
3526fd = mkstemp(tmpl);
3527if (fd == -1)
3528return -1;
3529
3530/* Calling unlink so that when the file is closed or program
3531* terminates the temporary file is deleted.
3532*/
3533ret = sys_unlink(tmpl);
3534if (ret < 0) {
3535gf_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
3542backtrace_symbols_fd(&array[2], frames - 2, fd);
3543
3544fp = fdopen(fd, "r");
3545if (!fp) {
3546sys_close(fd);
3547goto out;
3548}
3549
3550ret = fseek(fp, 0L, SEEK_SET);
3551if (ret)
3552goto out;
3553
3554pos = 0;
3555for (idx = 0; idx < frames - 2; idx++) {
3556ret = fscanf(fp, "%1023s", callingfn[idx]);
3557if (ret == EOF)
3558break;
3559inc = gf_backtrace_append(buf, pos, callingfn[idx]);
3560if (inc == -1)
3561break;
3562pos += inc;
3563}
3564gf_backtrace_end(buf, idx);
3565
3566out:
3567if (fp)
3568fclose(fp);
3569
3570return (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
3580char *
3581gf_backtrace_save(char *buf)
3582{
3583char *bt = NULL;
3584
3585if (!buf) {
3586bt = THIS->ctx->btbuf;
3587GF_ASSERT(bt);
3588
3589} else {
3590bt = buf;
3591}
3592
3593if ((0 == gf_backtrace_fillframes(bt)))
3594return bt;
3595
3596gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_BACKTRACE_SAVE_FAILED, NULL);
3597return NULL;
3598}
3599
3600gf_loglevel_t
3601fop_log_level(glusterfs_fop_t fop, int op_errno)
3602{
3603/* if gfid doesn't exist ESTALE comes */
3604if (op_errno == ENOENT || op_errno == ESTALE)
3605return GF_LOG_DEBUG;
3606
3607if ((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*/
3614if (op_errno == EAGAIN || op_errno == ENOSYS)
3615return GF_LOG_DEBUG;
3616}
3617
3618if ((fop == GF_FOP_GETXATTR) || (fop == GF_FOP_FGETXATTR)) {
3619if (op_errno == ENOTSUP || op_errno == ENODATA)
3620return GF_LOG_DEBUG;
3621}
3622
3623if ((fop == GF_FOP_SETXATTR) || (fop == GF_FOP_FSETXATTR) ||
3624(fop == GF_FOP_REMOVEXATTR) || (fop == GF_FOP_FREMOVEXATTR)) {
3625if (op_errno == ENOTSUP)
3626return GF_LOG_DEBUG;
3627}
3628
3629if (fop == GF_FOP_MKNOD || fop == GF_FOP_MKDIR)
3630if (op_errno == EEXIST)
3631return GF_LOG_DEBUG;
3632
3633if (fop == GF_FOP_SEEK) {
3634#ifdef HAVE_SEEK_HOLE
3635if (op_errno == ENXIO) {
3636return GF_LOG_DEBUG;
3637}
3638#else
3639return GF_LOG_DEBUG;
3640#endif
3641}
3642
3643return 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*/
3653int
3654recursive_rmdir(const char *delete_path)
3655{
3656int ret = -1;
3657char path[PATH_MAX] = {
36580,
3659};
3660struct stat st = {
36610,
3662};
3663DIR *dir = NULL;
3664struct dirent *entry = NULL;
3665struct dirent scratch[2] = {
3666{
36670,
3668},
3669};
3670xlator_t *this = NULL;
3671
3672this = THIS;
3673GF_ASSERT(this);
3674GF_VALIDATE_OR_GOTO(this->name, delete_path, out);
3675
3676dir = sys_opendir(delete_path);
3677if (!dir) {
3678gf_msg_debug(this->name, errno, "Failed to open directory %s.",
3679delete_path);
3680ret = 0;
3681goto out;
3682}
3683
3684while ((entry = sys_readdir(dir, scratch))) {
3685if (gf_irrelevant_entry(entry))
3686continue;
3687snprintf(path, PATH_MAX, "%s/%s", delete_path, entry->d_name);
3688ret = sys_lstat(path, &st);
3689if (ret == -1) {
3690gf_msg_debug(this->name, errno, "Failed to stat entry %s", path);
3691(void)sys_closedir(dir);
3692goto out;
3693}
3694
3695if (S_ISDIR(st.st_mode))
3696ret = recursive_rmdir(path);
3697else
3698ret = sys_unlink(path);
3699
3700if (ret) {
3701gf_msg_debug(this->name, errno, " Failed to remove %s.", path);
3702}
3703
3704gf_msg_debug(this->name, 0, "%s %s",
3705ret ? "Failed to remove" : "Removed", entry->d_name);
3706}
3707
3708ret = sys_closedir(dir);
3709if (ret) {
3710gf_msg_debug(this->name, errno, "Failed to close dir %s", delete_path);
3711}
3712
3713ret = sys_rmdir(delete_path);
3714if (ret) {
3715gf_msg_debug(this->name, errno, "Failed to rmdir: %s", delete_path);
3716}
3717
3718out:
3719return 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*/
3727int
3728gf_get_index_by_elem(char **array, char *elem)
3729{
3730int i = 0;
3731
3732for (i = 0; array[i]; i++) {
3733if (strcmp(elem, array[i]) == 0)
3734return i;
3735}
3736
3737return -1;
3738}
3739
3740static int
3741get_pathinfo_host(char *pathinfo, char *hostname, size_t size)
3742{
3743char *start = NULL;
3744char *end = NULL;
3745int ret = -1;
3746int i = 0;
3747
3748if (!pathinfo)
3749goto out;
3750
3751start = strchr(pathinfo, ':');
3752if (!start)
3753goto out;
3754
3755end = strrchr(pathinfo, ':');
3756if (start == end)
3757goto out;
3758
3759memset(hostname, 0, size);
3760i = 0;
3761while (++start != end)
3762hostname[i++] = *start;
3763ret = 0;
3764out:
3765return ret;
3766}
3767
3768/*Note: 'pathinfo' should be gathered only from one brick*/
3769int
3770glusterfs_is_local_pathinfo(char *pathinfo, gf_boolean_t *is_local)
3771{
3772int ret = 0;
3773char pathinfohost[1024] = {0};
3774
3775*is_local = _gf_false;
3776ret = get_pathinfo_host(pathinfo, pathinfohost, sizeof(pathinfohost));
3777if (ret == 0) {
3778if (!strcmp(gf_gethostname(), pathinfohost))
3779*is_local = _gf_true;
3780}
3781return ret;
3782}
3783
3784ssize_t
3785gf_nread(int fd, void *buf, size_t count)
3786{
3787ssize_t ret = 0;
3788ssize_t read_bytes = 0;
3789
3790for (read_bytes = 0; read_bytes < count; read_bytes += ret) {
3791ret = sys_read(fd, buf + read_bytes, count - read_bytes);
3792if (ret == 0) {
3793break;
3794} else if (ret < 0) {
3795if (errno == EINTR)
3796ret = 0;
3797else
3798goto out;
3799}
3800}
3801
3802ret = read_bytes;
3803out:
3804return ret;
3805}
3806
3807ssize_t
3808gf_nwrite(int fd, const void *buf, size_t count)
3809{
3810ssize_t ret = 0;
3811ssize_t written = 0;
3812
3813for (written = 0; written != count; written += ret) {
3814ret = sys_write(fd, buf + written, count - written);
3815if (ret < 0) {
3816if (errno == EINTR)
3817ret = 0;
3818else
3819goto out;
3820}
3821}
3822
3823ret = written;
3824out:
3825return ret;
3826}
3827
3828void
3829gf_free_mig_locks(lock_migration_info_t *locks)
3830{
3831lock_migration_info_t *current = NULL;
3832lock_migration_info_t *temp = NULL;
3833
3834if (!locks)
3835return;
3836
3837if (list_empty(&locks->list))
3838return;
3839
3840list_for_each_entry_safe(current, temp, &locks->list, list)
3841{
3842list_del_init(¤t->list);
3843GF_FREE(current->client_uid);
3844GF_FREE(current);
3845}
3846}
3847
3848void
3849_mask_cancellation(void)
3850{
3851(void)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
3852}
3853
3854void
3855_unmask_cancellation(void)
3856{
3857(void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
3858}
3859
3860const char *
3861fop_enum_to_pri_string(glusterfs_fop_t fop)
3862{
3863switch (fop) {
3864case GF_FOP_OPEN:
3865case GF_FOP_STAT:
3866case GF_FOP_FSTAT:
3867case GF_FOP_LOOKUP:
3868case GF_FOP_ACCESS:
3869case GF_FOP_READLINK:
3870case GF_FOP_OPENDIR:
3871case GF_FOP_STATFS:
3872case GF_FOP_READDIR:
3873case GF_FOP_READDIRP:
3874case GF_FOP_GETACTIVELK:
3875case GF_FOP_SETACTIVELK:
3876case GF_FOP_ICREATE:
3877case GF_FOP_NAMELINK:
3878return "HIGH";
3879
3880case GF_FOP_CREATE:
3881case GF_FOP_FLUSH:
3882case GF_FOP_LK:
3883case GF_FOP_INODELK:
3884case GF_FOP_FINODELK:
3885case GF_FOP_ENTRYLK:
3886case GF_FOP_FENTRYLK:
3887case GF_FOP_UNLINK:
3888case GF_FOP_SETATTR:
3889case GF_FOP_FSETATTR:
3890case GF_FOP_MKNOD:
3891case GF_FOP_MKDIR:
3892case GF_FOP_RMDIR:
3893case GF_FOP_SYMLINK:
3894case GF_FOP_RENAME:
3895case GF_FOP_LINK:
3896case GF_FOP_SETXATTR:
3897case GF_FOP_GETXATTR:
3898case GF_FOP_FGETXATTR:
3899case GF_FOP_FSETXATTR:
3900case GF_FOP_REMOVEXATTR:
3901case GF_FOP_FREMOVEXATTR:
3902case GF_FOP_IPC:
3903case GF_FOP_LEASE:
3904return "NORMAL";
3905
3906case GF_FOP_READ:
3907case GF_FOP_WRITE:
3908case GF_FOP_FSYNC:
3909case GF_FOP_TRUNCATE:
3910case GF_FOP_FTRUNCATE:
3911case GF_FOP_FSYNCDIR:
3912case GF_FOP_XATTROP:
3913case GF_FOP_FXATTROP:
3914case GF_FOP_RCHECKSUM:
3915case GF_FOP_ZEROFILL:
3916case GF_FOP_FALLOCATE:
3917case GF_FOP_SEEK:
3918return "LOW";
3919
3920case GF_FOP_NULL:
3921case GF_FOP_FORGET:
3922case GF_FOP_RELEASE:
3923case GF_FOP_RELEASEDIR:
3924case GF_FOP_GETSPEC:
3925case GF_FOP_MAXVALUE:
3926case GF_FOP_DISCARD:
3927return "LEAST";
3928default:
3929return "UNKNOWN";
3930}
3931}
3932
3933const char *
3934gf_inode_type_to_str(ia_type_t type)
3935{
3936static const char *const str_ia_type[] = {
3937"UNKNOWN", "REGULAR FILE", "DIRECTORY", "LINK",
3938"BLOCK DEVICE", "CHARACTER DEVICE", "PIPE", "SOCKET"};
3939return str_ia_type[type];
3940}
3941
3942gf_boolean_t
3943gf_is_zero_filled_stat(struct iatt *buf)
3944{
3945if (!buf)
3946return 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*/
3953if ((buf->ia_nlink == 0) && (buf->ia_ctime == 0))
3954return 1;
3955
3956return 0;
3957}
3958
3959gf_boolean_t
3960gf_is_valid_xattr_namespace(char *key)
3961{
3962static char *xattr_namespaces[] = {"trusted.", "system.", "user.",
3963"security.", NULL};
3964int i = 0;
3965
3966for (i = 0; xattr_namespaces[i]; i++) {
3967if (strncmp(key, xattr_namespaces[i], strlen(xattr_namespaces[i])) == 0)
3968return _gf_true;
3969}
3970
3971return _gf_false;
3972}
3973
3974ino_t
3975gfid_to_ino(uuid_t gfid)
3976{
3977ino_t ino = 0;
3978int32_t i;
3979
3980for (i = 8; i < 16; i++) {
3981ino <<= 8;
3982ino += (uint8_t)gfid[i];
3983}
3984
3985return ino;
3986}
3987
3988int
3989gf_bits_count(uint64_t n)
3990{
3991int val = 0;
3992#if defined(__GNUC__) || defined(__clang__)
3993val = __builtin_popcountll(n);
3994#else
3995n -= (n >> 1) & 0x5555555555555555ULL;
3996n = ((n >> 2) & 0x3333333333333333ULL) + (n & 0x3333333333333333ULL);
3997n = (n + (n >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
3998n += n >> 8;
3999n += n >> 16;
4000n += n >> 32;
4001val = n & 0xFF;
4002#endif
4003return val;
4004}
4005
4006int
4007gf_bits_index(uint64_t n)
4008{
4009#if defined(__GNUC__) || defined(__clang__)
4010return __builtin_ffsll(n) - 1;
4011#else
4012return ffsll(n) - 1;
4013#endif
4014}
4015
4016const char *
4017gf_fop_string(glusterfs_fop_t fop)
4018{
4019if ((fop > GF_FOP_NULL) && (fop < GF_FOP_MAXVALUE))
4020return gf_fop_list[fop];
4021return "INVALID";
4022}
4023
4024int
4025gf_fop_int(char *fop)
4026{
4027int i = 0;
4028
4029for (i = GF_FOP_NULL + 1; i < GF_FOP_MAXVALUE; i++) {
4030if (strcasecmp(fop, gf_fop_list[i]) == 0)
4031return i;
4032}
4033return -1;
4034}
4035
4036int
4037close_fds_except_custom(int *fdv, size_t count, void *prm,
4038void closer(int fd, void *prm))
4039{
4040int i = 0;
4041size_t j = 0;
4042gf_boolean_t should_close = _gf_true;
4043#ifdef GF_LINUX_HOST_OS
4044DIR *d = NULL;
4045struct dirent *de = NULL;
4046struct dirent scratch[2] = {
4047{
40480,
4049},
4050};
4051char *e = NULL;
4052
4053d = sys_opendir("/proc/self/fd");
4054if (!d)
4055return -1;
4056
4057for (;;) {
4058should_close = _gf_true;
4059
4060errno = 0;
4061de = sys_readdir(d, scratch);
4062if (!de || errno != 0)
4063break;
4064i = strtoul(de->d_name, &e, 10);
4065if (*e != '\0' || i == dirfd(d))
4066continue;
4067
4068for (j = 0; j < count; j++) {
4069if (i == fdv[j]) {
4070should_close = _gf_false;
4071break;
4072}
4073}
4074if (should_close)
4075closer(i, prm);
4076}
4077sys_closedir(d);
4078#else /* !GF_LINUX_HOST_OS */
4079struct rlimit rl;
4080int ret = -1;
4081
4082ret = getrlimit(RLIMIT_NOFILE, &rl);
4083if (ret)
4084return ret;
4085
4086for (i = 0; i < rl.rlim_cur; i++) {
4087should_close = _gf_true;
4088for (j = 0; j < count; j++) {
4089if (i == fdv[j]) {
4090should_close = _gf_false;
4091break;
4092}
4093}
4094if (should_close)
4095closer(i, prm);
4096}
4097#endif /* !GF_LINUX_HOST_OS */
4098return 0;
4099}
4100
4101static void
4102closer_close(int fd, void *prm)
4103{
4104sys_close(fd);
4105}
4106
4107int
4108close_fds_except(int *fdv, size_t count)
4109{
4110return 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*/
4129int
4130gf_getgrouplist(const char *user, gid_t group, gid_t **groups)
4131{
4132int ret = -1;
4133int ngroups = SMALL_GROUP_COUNT;
4134
4135*groups = GF_CALLOC(sizeof(gid_t), ngroups, gf_common_mt_groups_t);
4136if (!*groups)
4137return -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*/
4146for (;;) {
4147int ngroups_old = ngroups;
4148ret = getgrouplist(user, group, *groups, &ngroups);
4149if (ret != -1)
4150break;
4151
4152if (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*/
4161return 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*/
4175GF_FREE(*groups);
4176return -1;
4177}
4178
4179*groups = GF_REALLOC(*groups, ngroups * sizeof(gid_t));
4180if (!*groups)
4181return -1;
4182}
4183return ret;
4184}
4185
4186int
4187glusterfs_compute_sha256(const unsigned char *content, size_t size,
4188char *sha256_hash)
4189{
4190#if OPENSSL_VERSION_NUMBER >= 0x030000000 // 3.0.0
4191
4192EVP_Digest((const unsigned char *)(content), size,
4193(unsigned char *)sha256_hash, NULL, EVP_sha256(), NULL);
4194#else
4195SHA256_CTX sha256;
4196
4197SHA256_Init(&sha256);
4198SHA256_Update(&sha256, (const unsigned char *)(content), size);
4199SHA256_Final((unsigned char *)sha256_hash, &sha256);
4200
4201#endif
4202return 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
4211char *
4212gf_strncpy(char *dest, const char *src, const size_t dest_size)
4213{
4214strncpy(dest, src, dest_size - 1);
4215dest[dest_size - 1] = '\0';
4216return dest;
4217}
4218
4219xlator_cmdline_option_t *
4220find_xlator_option_in_cmd_args_t(const char *option_name, cmd_args_t *args)
4221{
4222xlator_cmdline_option_t *pos = NULL;
4223xlator_cmdline_option_t *tmp = NULL;
4224
4225list_for_each_entry_safe(pos, tmp, &args->xlator_options, cmd_args)
4226{
4227if (strcmp(pos->key, option_name) == 0)
4228return pos;
4229}
4230return NULL;
4231}
4232
4233int
4234gf_d_type_from_ia_type(ia_type_t type)
4235{
4236switch (type) {
4237case IA_IFDIR:
4238return DT_DIR;
4239case IA_IFCHR:
4240return DT_CHR;
4241case IA_IFBLK:
4242return DT_BLK;
4243case IA_IFIFO:
4244return DT_FIFO;
4245case IA_IFLNK:
4246return DT_LNK;
4247case IA_IFREG:
4248return DT_REG;
4249case IA_IFSOCK:
4250return DT_SOCK;
4251default:
4252return DT_UNKNOWN;
4253}
4254}
4255
4256int
4257gf_nanosleep(uint64_t nsec)
4258{
4259struct timespec req;
4260struct timespec rem;
4261int ret = -1;
4262
4263req.tv_sec = nsec / GF_SEC_IN_NS;
4264req.tv_nsec = nsec % GF_SEC_IN_NS;
4265
4266do {
4267ret = nanosleep(&req, &rem);
4268req = rem;
4269} while (ret == -1 && errno == EINTR);
4270
4271return ret;
4272}
4273
4274int
4275gf_pipe(int fd[2], int flags)
4276{
4277int ret = 0;
4278#if defined(HAVE_PIPE2)
4279ret = pipe2(fd, flags);
4280#else /* not HAVE_PIPE2 */
4281ret = pipe(fd);
4282if (ret < 0)
4283return ret;
4284if (flags) {
4285ret = fcntl(fd[0], F_SETFL, (fcntl(fd[0], F_GETFL) | flags));
4286if (ret < 0)
4287goto out;
4288ret = fcntl(fd[1], F_SETFL, (fcntl(fd[1], F_GETFL) | flags));
4289if (ret < 0)
4290goto out;
4291}
4292out:
4293if (ret < 0) {
4294close(fd[0]);
4295close(fd[1]);
4296}
4297#endif /* HAVE_PIPE2 */
4298return ret;
4299}
4300
4301char **
4302get_xattrs_to_heal(void)
4303{
4304return xattrs_to_heal;
4305}
4306
4307char *
4308gf_gethostname(void)
4309{
4310return global_ctx->hostname;
4311}
4312
4313#ifndef GF_DARWIN_HOST_OS
4314
4315void
4316gf_set_nofile(rlim_t high, rlim_t low)
4317{
4318int n, ret = -1;
4319struct rlimit lim;
4320rlim_t r[2] = {high, low};
4321
4322for (n = 0; n < 2; n++)
4323if (r[n] != 0) {
4324lim.rlim_cur = r[n];
4325lim.rlim_max = r[n];
4326ret = setrlimit(RLIMIT_NOFILE, &lim);
4327if (ret == 0)
4328break;
4329}
4330
4331if (ret)
4332GF_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
4339gf_boolean_t
4340gf_unlink(const char *path)
4341{
4342int ret = 0;
4343
4344GF_ASSERT(path);
4345ret = sys_unlink(path);
4346
4347if (ret && errno != ENOENT) {
4348GF_LOG_W(THIS->name, LG_MSG_UNLINK_FAILED(path));
4349return _gf_false;
4350}
4351return _gf_true;
4352}
4353
4354int
4355gf_rebalance_thread_count(char *str, char **errmsg)
4356{
4357int count = 0, lim = sysconf(_SC_NPROCESSORS_ONLN);
4358
4359/* An option should be one of lazy|normal|aggressive or
4360a number from 1 to the number of cores in the machine. */
4361
4362if (!strcasecmp(str, "lazy"))
4363return 1;
4364else if (!strcasecmp(str, "normal"))
4365return 2;
4366else if (!strcasecmp(str, "aggressive"))
4367return max(lim - 4, 4);
4368else if (gf_string2int(str, &count) == 0) {
4369if (count > 0 && count <= lim)
4370return count;
4371else {
4372if (gf_asprintf(errmsg,
4373"number of rebalance threads should be "
4374"in range from 1 to %d, not %d",
4375lim, count) < 0)
4376*errmsg = NULL;
4377return -1;
4378}
4379}
4380if (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",
4384lim, str) < 0)
4385*errmsg = NULL;
4386return -1;
4387}
4388