summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_errno.c
blob: 9ac799363589160d935509759c48afa582c574ec (plain) (blame)
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
146
147
148
149
150
151
152

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) NGINX, Inc.
 */

#include <nxt_main.h>


/*
 * The strerror() messages are copied because:
 *
 * 1) strerror() and strerror_r() functions are not Async-Signal-Safe,
 *    therefore, they can not be used in signal handlers;
 *
 * 2) a direct sys_errlist[] array may be used instead of these functions,
 *    but Linux linker warns about this usage:
 *
 * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
 * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
 *
 *    causing false bug reports.
 */

static u_char *nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr,
    size_t size);
static u_char *nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size);


nxt_strerror_t     nxt_strerror = nxt_bootstrap_strerror;
static nxt_str_t   *nxt_sys_errlist;
static nxt_uint_t  nxt_sys_nerr;


nxt_int_t
nxt_strerror_start(void)
{
    char        *msg;
    u_char      *p;
    size_t      size, length, n;
    nxt_uint_t  err, invalid;

    /* The last entry. */
    size = sizeof("Unknown error") - 1;

    /*
     * Linux has holes for error codes 41 and 58, so the loop
     * stops only after 100 invalid codes in succession.
     */

    for (invalid = 0; invalid < 100 && nxt_sys_nerr < 65536; nxt_sys_nerr++) {

        nxt_set_errno(0);
        msg = strerror((int) nxt_sys_nerr);

        /*
         * strerror() behaviour on passing invalid error code depends
         * on OS and version:
         *   Linux returns "Unknown error NN";
         *   FreeBSD, NetBSD and OpenBSD return "Unknown error: NN"
         *     and set errno to EINVAL;
         *   Solaris 10 returns "Unknown error" and sets errno to EINVAL;
         *   Solaris 9 returns "Unknown error";
         *   Solaris 2 returns NULL;
         *   MacOSX returns "Unknown error: NN";
         *   AIX returns "Error NNN occurred.";
         *   HP-UX returns "Unknown error" for invalid codes lesser than 250
         *     or empty string for larger codes.
         */

        if (msg == NULL) {
            invalid++;
            continue;
        }

        length = nxt_strlen(msg);
        size += length;

        if (length == 0  /* HP-UX empty strings. */
            || nxt_errno == NXT_EINVAL
            || nxt_memcmp(msg, "Unknown error", 13) == 0)
        {
            invalid++;
            continue;
        }

#if (NXT_AIX)

        if (nxt_memcmp(msg, "Error ", 6) == 0
            && nxt_memcmp(msg + length - 10, " occurred.", 9) == 0)
        {
            invalid++;
            continue;
        }

#endif
    }

    nxt_sys_nerr -= invalid;

    nxt_main_log_debug("sys_nerr: %d", nxt_sys_nerr);

    n = (nxt_sys_nerr + 1) * sizeof(nxt_str_t);

    nxt_sys_errlist = nxt_malloc(n + size);
    if (nxt_sys_errlist == NULL) {
        return NXT_ERROR;
    }

    p = (u_char *) nxt_sys_errlist + n;

    for (err = 0; err < nxt_sys_nerr; err++) {
        msg = strerror((int) err);
        length = nxt_strlen(msg);

        nxt_sys_errlist[err].length = length;
        nxt_sys_errlist[err].start = p;

        p = nxt_cpymem(p, msg, length);
    }

    nxt_sys_errlist[err].length = 13;
    nxt_sys_errlist[err].start = p;
    nxt_memcpy(p, "Unknown error", 13);

    nxt_strerror = nxt_runtime_strerror;

    return NXT_OK;
}


static u_char *
nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, size_t size)
{
    return nxt_cpystrn(errstr, (u_char *) strerror(err), size);
}


static u_char *
nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size)
{
    nxt_str_t   *msg;
    nxt_uint_t  n;

    n = nxt_min((nxt_uint_t) err, nxt_sys_nerr);

    msg = &nxt_sys_errlist[n];

    size = nxt_min(size, msg->length);

    return nxt_cpymem(errstr, msg->start, size);
}