summaryrefslogtreecommitdiffstats
path: root/proxy/src/gp_util.c
blob: ff1cfedcbe05d2ff637eb1a50e1dd13554c3c1f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* Copyright (C) 2013 the GSS-PROXY contributors, see COPYING for license */

#include "config.h"
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#include "gp_common.h"

bool gp_same(const char *a, const char *b)
{
    if ((a == b) || strcmp(a, b) == 0) {
        return true;
    }

    return false;
}

bool gp_boolean_is_true(const char *s)
{
    if (strcasecmp(s, "1") == 0 ||
        strcasecmp(s, "on") == 0 ||
        strcasecmp(s, "true") == 0 ||
        strcasecmp(s, "yes") == 0) {
        return true;
    }

    return false;
}

char *gp_getenv(const char *name)
{
#if HAVE_SECURE_GETENV
    return secure_getenv(name);
#elif HAVE___SECURE_GETENV
    return __secure_getenv(name);
#else
#include <unistd.h>
#include <sys/types.h>
#warning secure_getenv not available, falling back to poorman emulation
    if ((getuid() == geteuid()) &&
        (getgid() == getegid())) {
        return getenv(name);
    }
    return NULL;
#endif
}

/* NOTE: because strerror_r() is such a mess with glibc, we need to do some
 * magic checking to find out what function prototype is being used of the
 * two incompatible ones, and pray it doesn't change in the future.
 * On top of that to avoid impacting the current code too much we've got to use
 * thread-local storage to hold a buffer.
 * gp_strerror() is basically a thread-safe version of strerror() that can
 * never fail.
 */
const char gp_internal_err[] = "Internal strerror_r() error.";
#define MAX_GP_STRERROR 1024
char *gp_strerror(int errnum)
{
    static __thread char buf[MAX_GP_STRERROR];
    int saved_errno = errno;

#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
    /* XSI version */
    int ret;

    ret = strerror_r(errnum, buf, MAX_GP_STRERROR);
    if (ret == -1) ret = errno;
    switch (ret) {
    case 0:
        break;
    case EINVAL:
        ret = snprintf(buf, MAX_GP_STRERROR,
                       "Unknown error code: %d", errnum);
        if (ret > 0) break;
        /* fallthrough */
    default:
        ret = snprintf(buf, MAX_GP_STRERROR,
                       "Internal error describing error code: %d", errnum);
        if (ret > 0) break;
        memset(buf, 0, MAX_GP_STRERROR);
        strncpy(buf, gp_internal_err, MAX_GP_STRERROR);
        buf[MAX_GP_STRERROR -1] = '\0';
    }
#else
    /* GNU-specific version */
    char *ret;

    ret = strerror_r(errnum, buf, MAX_GP_STRERROR);
    if (ret == NULL) {
        memset(buf, 0, MAX_GP_STRERROR);
        strncpy(buf, gp_internal_err, MAX_GP_STRERROR);
        buf[MAX_GP_STRERROR -1] = '\0';
    } else if (ret != buf) {
        memset(buf, 0, MAX_GP_STRERROR);
        strncpy(buf, ret, MAX_GP_STRERROR);
        buf[MAX_GP_STRERROR -1] = '\0';
    }
#endif

    errno = saved_errno;
    return buf;
}

ssize_t gp_safe_read(int fd, void *buf, size_t count)
{
    char *b = (char *)buf;
    ssize_t len = 0;
    ssize_t ret;

    do {
        ret = read(fd, &b[len], count - len);
        if (ret == -1) {
            if (errno == EINTR) continue;
            return ret;
        }
        if (ret == 0) break; /* EOF */
        len += ret;
    } while (count > len);

    return len;
}

ssize_t gp_safe_write(int fd, const void *buf, size_t count)
{
    const char *b = (const char *)buf;
    ssize_t len = 0;
    ssize_t ret;

    do {
        ret = write(fd, &b[len], count - len);
        if (ret == -1) {
            if (errno == EINTR) continue;
            return ret;
        }
        if (ret == 0) break; /* EOF */
        len += ret;
    } while (count > len);

    return len;
}