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