1 /*
2 * netlink-private/utils.h Local Utility Functions
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
10 */
11
12 #ifndef NETLINK_UTILS_PRIV_H_
13 #define NETLINK_UTILS_PRIV_H_
14
15 #include <byteswap.h>
16
17 #if __BYTE_ORDER == __BIG_ENDIAN
18 #define ntohll(x) (x)
19 #elif __BYTE_ORDER == __LITTLE_ENDIAN
20 #define ntohll(x) bswap_64((x))
21 #endif
22 #define htonll(x) ntohll(x)
23
24 /*****************************************************************************/
25
26 #define _NL_STRINGIFY_ARG(contents) #contents
27 #define _NL_STRINGIFY(macro_or_string) _NL_STRINGIFY_ARG (macro_or_string)
28
29 /*****************************************************************************/
30
31 #if defined (__GNUC__)
32 #define _NL_PRAGMA_WARNING_DO(warning) _NL_STRINGIFY(GCC diagnostic ignored warning)
33 #elif defined (__clang__)
34 #define _NL_PRAGMA_WARNING_DO(warning) _NL_STRINGIFY(clang diagnostic ignored warning)
35 #endif
36
37 /* you can only suppress a specific warning that the compiler
38 * understands. Otherwise you will get another compiler warning
39 * about invalid pragma option.
40 * It's not that bad however, because gcc and clang often have the
41 * same name for the same warning. */
42
43 #if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
44 #define _NL_PRAGMA_WARNING_DISABLE(warning) \
45 _Pragma("GCC diagnostic push") \
46 _Pragma(_NL_PRAGMA_WARNING_DO("-Wpragmas")) \
47 _Pragma(_NL_PRAGMA_WARNING_DO(warning))
48 #elif defined (__clang__)
49 #define _NL_PRAGMA_WARNING_DISABLE(warning) \
50 _Pragma("clang diagnostic push") \
51 _Pragma(_NL_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \
52 _Pragma(_NL_PRAGMA_WARNING_DO(warning))
53 #else
54 #define _NL_PRAGMA_WARNING_DISABLE(warning)
55 #endif
56
57 #if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
58 #define _NL_PRAGMA_WARNING_REENABLE \
59 _Pragma("GCC diagnostic pop")
60 #elif defined (__clang__)
61 #define _NL_PRAGMA_WARNING_REENABLE \
62 _Pragma("clang diagnostic pop")
63 #else
64 #define _NL_PRAGMA_WARNING_REENABLE
65 #endif
66
67 /*****************************************************************************/
68
69 #define _nl_unused __attribute__ ((__unused__))
70 #define _nl_auto(fcn) __attribute__ ((__cleanup__(fcn)))
71
72 /*****************************************************************************/
73
74 #define _NL_STATIC_ASSERT(cond) ((void) sizeof (char[(cond) ? 1 : -1]))
75
76 /*****************************************************************************/
77
78 #if defined(NL_MORE_ASSERTS) && NL_MORE_ASSERTS > 0
79 #define _nl_assert(cond) assert(cond)
80 #else
81 #define _nl_assert(cond) do { if (0) { assert(cond); } } while (0)
82 #endif
83
84 /*****************************************************************************/
85
86 #define _NL_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \
87 static inline void name (void *v) \
88 { \
89 if (*((CastType *) v)) \
90 func (*((CastType *) v)); \
91 }
92
93 #define _nl_auto_free _nl_auto(_nl_auto_free_fcn)
94 _NL_AUTO_DEFINE_FCN_VOID0 (void *, _nl_auto_free_fcn, free)
95
96 /*****************************************************************************/
97
98 extern const char *nl_strerror_l(int err);
99
100 /*****************************************************************************/
101
102 /* internal macro to calculate the size of a struct @type up to (and including) @field.
103 * this will be used for .minlen policy fields, so that we require only a field of up
104 * to the given size. */
105 #define _nl_offsetofend(type, field) (offsetof (type, field) + sizeof (((type *) NULL)->field))
106
107 /*****************************************************************************/
108
109 #define _nl_clear_pointer(pp, destroy) \
110 ({ \
111 __typeof__ (*(pp)) *_pp = (pp); \
112 __typeof__ (*_pp) _p; \
113 int _changed = 0; \
114 \
115 if ( _pp \
116 && (_p = *_pp)) { \
117 _nl_unused const void *const _p_check_is_pointer = _p; \
118 \
119 *_pp = NULL; \
120 \
121 (destroy) (_p); \
122 \
123 _changed = 1; \
124 } \
125 _changed; \
126 })
127
128 #define _nl_clear_free(pp) _nl_clear_pointer (pp, free)
129
130 #define _nl_steal_pointer(pp) \
131 ({ \
132 __typeof__ (*(pp)) *const _pp = (pp); \
133 __typeof__ (*_pp) _p = NULL; \
134 \
135 if ( _pp \
136 && (_p = *_pp)) { \
137 *_pp = NULL; \
138 } \
139 \
140 _p; \
141 })
142
143 /*****************************************************************************/
144
145 #define _nl_malloc_maybe_a(alloca_maxlen, bytes, to_free) \
146 ({ \
147 const size_t _bytes = (bytes); \
148 __typeof__ (to_free) _to_free = (to_free); \
149 __typeof__ (*_to_free) _ptr; \
150 \
151 _NL_STATIC_ASSERT ((alloca_maxlen) <= 500); \
152 _nl_assert (_to_free && !*_to_free); \
153 \
154 if (_bytes <= (alloca_maxlen)) { \
155 _ptr = alloca (_bytes); \
156 } else { \
157 _ptr = malloc (_bytes); \
158 *_to_free = _ptr; \
159 }; \
160 \
161 _ptr; \
162 })
163
164 /*****************************************************************************/
165
166 static inline char *
_nl_strncpy_trunc(char * dst,const char * src,size_t len)167 _nl_strncpy_trunc(char *dst, const char *src, size_t len)
168 {
169 /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL
170 * behavior of strncpy(). This is just strncpy() with gracefully handling trunction
171 * (and disabling the "-Wstringop-truncation" warning).
172 *
173 * Note that truncation is silently accepted.
174 */
175
176 _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
177 _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow");
178
179 if (len > 0) {
180 _nl_assert(dst);
181 _nl_assert(src);
182
183 strncpy(dst, src, len);
184
185 dst[len - 1] = '\0';
186 }
187
188 _NL_PRAGMA_WARNING_REENABLE;
189 _NL_PRAGMA_WARNING_REENABLE;
190
191 return dst;
192 }
193
194 static inline char *
_nl_strncpy(char * dst,const char * src,size_t len)195 _nl_strncpy(char *dst, const char *src, size_t len)
196 {
197 /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL
198 * behavior of strncpy(). This is just strncpy() with gracefully handling trunction
199 * (and disabling the "-Wstringop-truncation" warning).
200 *
201 * Note that truncation is still a bug and there is an _nl_assert()
202 * against that.
203 */
204
205 if (len > 0) {
206 _nl_assert(dst);
207 _nl_assert(src);
208
209 strncpy(dst, src, len);
210
211 /* Truncation is a bug and we assert against it. But note that this
212 * assertion is disabled by default because we cannot be sure that
213 * there are not wrong uses of _nl_strncpy() where truncation might
214 * happen (wrongly!!). */
215 _nl_assert (memchr(dst, '\0', len));
216
217 dst[len - 1] = '\0';
218 }
219
220 return dst;
221 }
222
223 #endif
224