netdev-linux: Fix off-by-one error dumping queue stats.
[openvswitch] / lib / util.c
1 /*
2  * Copyright (c) 2008, 2009, 2010 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "util.h"
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include "coverage.h"
26 #include "vlog.h"
27
28 VLOG_DEFINE_THIS_MODULE(util)
29
30 const char *program_name;
31
32 void
33 out_of_memory(void)
34 {
35     ovs_fatal(0, "virtual memory exhausted");
36 }
37
38 void *
39 xcalloc(size_t count, size_t size)
40 {
41     void *p = count && size ? calloc(count, size) : malloc(1);
42     COVERAGE_INC(util_xalloc);
43     if (p == NULL) {
44         out_of_memory();
45     }
46     return p;
47 }
48
49 void *
50 xzalloc(size_t size)
51 {
52     return xcalloc(1, size);
53 }
54
55 void *
56 xmalloc(size_t size)
57 {
58     void *p = malloc(size ? size : 1);
59     COVERAGE_INC(util_xalloc);
60     if (p == NULL) {
61         out_of_memory();
62     }
63     return p;
64 }
65
66 void *
67 xrealloc(void *p, size_t size)
68 {
69     p = realloc(p, size ? size : 1);
70     COVERAGE_INC(util_xalloc);
71     if (p == NULL) {
72         out_of_memory();
73     }
74     return p;
75 }
76
77 void *
78 xmemdup(const void *p_, size_t size)
79 {
80     void *p = xmalloc(size);
81     memcpy(p, p_, size);
82     return p;
83 }
84
85 char *
86 xmemdup0(const char *p_, size_t length)
87 {
88     char *p = xmalloc(length + 1);
89     memcpy(p, p_, length);
90     p[length] = '\0';
91     return p;
92 }
93
94 char *
95 xstrdup(const char *s)
96 {
97     return xmemdup0(s, strlen(s));
98 }
99
100 char *
101 xvasprintf(const char *format, va_list args)
102 {
103     va_list args2;
104     size_t needed;
105     char *s;
106
107     va_copy(args2, args);
108     needed = vsnprintf(NULL, 0, format, args);
109
110     s = xmalloc(needed + 1);
111
112     vsnprintf(s, needed + 1, format, args2);
113     va_end(args2);
114
115     return s;
116 }
117
118 void *
119 x2nrealloc(void *p, size_t *n, size_t s)
120 {
121     *n = *n == 0 ? 1 : 2 * *n;
122     return xrealloc(p, *n * s);
123 }
124
125 char *
126 xasprintf(const char *format, ...)
127 {
128     va_list args;
129     char *s;
130
131     va_start(args, format);
132     s = xvasprintf(format, args);
133     va_end(args);
134
135     return s;
136 }
137
138 void
139 ovs_strlcpy(char *dst, const char *src, size_t size)
140 {
141     if (size > 0) {
142         size_t n = strlen(src);
143         size_t n_copy = MIN(n, size - 1);
144         memcpy(dst, src, n_copy);
145         dst[n_copy] = '\0';
146     }
147 }
148
149 void
150 ovs_fatal(int err_no, const char *format, ...)
151 {
152     va_list args;
153
154     fprintf(stderr, "%s: ", program_name);
155     va_start(args, format);
156     vfprintf(stderr, format, args);
157     va_end(args);
158     if (err_no != 0)
159         fprintf(stderr, " (%s)",
160                 err_no == EOF ? "end of file" : strerror(err_no));
161     putc('\n', stderr);
162
163     exit(EXIT_FAILURE);
164 }
165
166 void
167 ovs_error(int err_no, const char *format, ...)
168 {
169     int save_errno = errno;
170     va_list args;
171
172     fprintf(stderr, "%s: ", program_name);
173     va_start(args, format);
174     vfprintf(stderr, format, args);
175     va_end(args);
176     if (err_no != 0) {
177         fprintf(stderr, " (%s)",
178                 err_no == EOF ? "end of file" : strerror(err_no));
179     }
180     putc('\n', stderr);
181
182     errno = save_errno;
183 }
184
185 /* Sets program_name based on 'argv0'.  Should be called at the beginning of
186  * main(), as "set_program_name(argv[0]);".  */
187 void set_program_name(const char *argv0)
188 {
189     const char *slash = strrchr(argv0, '/');
190     program_name = slash ? slash + 1 : argv0;
191 }
192
193 /* Print the version information for the program.  */
194 void
195 ovs_print_version(char *date, char *time,
196                   uint8_t min_ofp, uint8_t max_ofp)
197 {
198     printf("%s (Open vSwitch) "VERSION BUILDNR"\n", program_name);
199     printf("Compiled %s %s\n", date, time);
200     if (min_ofp || max_ofp) {
201         printf("OpenFlow versions %#x:%#x\n", min_ofp, max_ofp);
202     }
203 }
204
205 /* Writes the 'size' bytes in 'buf' to 'stream' as hex bytes arranged 16 per
206  * line.  Numeric offsets are also included, starting at 'ofs' for the first
207  * byte in 'buf'.  If 'ascii' is true then the corresponding ASCII characters
208  * are also rendered alongside. */
209 void
210 ovs_hex_dump(FILE *stream, const void *buf_, size_t size,
211              uintptr_t ofs, bool ascii)
212 {
213   const uint8_t *buf = buf_;
214   const size_t per_line = 16; /* Maximum bytes per line. */
215
216   while (size > 0)
217     {
218       size_t start, end, n;
219       size_t i;
220
221       /* Number of bytes on this line. */
222       start = ofs % per_line;
223       end = per_line;
224       if (end - start > size)
225         end = start + size;
226       n = end - start;
227
228       /* Print line. */
229       fprintf(stream, "%08jx  ", (uintmax_t) ROUND_DOWN(ofs, per_line));
230       for (i = 0; i < start; i++)
231         fprintf(stream, "   ");
232       for (; i < end; i++)
233         fprintf(stream, "%02hhx%c",
234                 buf[i - start], i == per_line / 2 - 1? '-' : ' ');
235       if (ascii)
236         {
237           for (; i < per_line; i++)
238             fprintf(stream, "   ");
239           fprintf(stream, "|");
240           for (i = 0; i < start; i++)
241             fprintf(stream, " ");
242           for (; i < end; i++) {
243               int c = buf[i - start];
244               putc(c >= 32 && c < 127 ? c : '.', stream);
245           }
246           for (; i < per_line; i++)
247             fprintf(stream, " ");
248           fprintf(stream, "|");
249         }
250       fprintf(stream, "\n");
251
252       ofs += n;
253       buf += n;
254       size -= n;
255     }
256 }
257
258 bool
259 str_to_int(const char *s, int base, int *i)
260 {
261     long long ll;
262     bool ok = str_to_llong(s, base, &ll);
263     *i = ll;
264     return ok;
265 }
266
267 bool
268 str_to_long(const char *s, int base, long *li)
269 {
270     long long ll;
271     bool ok = str_to_llong(s, base, &ll);
272     *li = ll;
273     return ok;
274 }
275
276 bool
277 str_to_llong(const char *s, int base, long long *x)
278 {
279     int save_errno = errno;
280     char *tail;
281     errno = 0;
282     *x = strtoll(s, &tail, base);
283     if (errno == EINVAL || errno == ERANGE || tail == s || *tail != '\0') {
284         errno = save_errno;
285         *x = 0;
286         return false;
287     } else {
288         errno = save_errno;
289         return true;
290     }
291 }
292
293 bool
294 str_to_uint(const char *s, int base, unsigned int *u)
295 {
296     return str_to_int(s, base, (int *) u);
297 }
298
299 bool
300 str_to_ulong(const char *s, int base, unsigned long *ul)
301 {
302     return str_to_long(s, base, (long *) ul);
303 }
304
305 bool
306 str_to_ullong(const char *s, int base, unsigned long long *ull)
307 {
308     return str_to_llong(s, base, (long long *) ull);
309 }
310
311 /* Converts floating-point string 's' into a double.  If successful, stores
312  * the double in '*d' and returns true; on failure, stores 0 in '*d' and
313  * returns false.
314  *
315  * Underflow (e.g. "1e-9999") is not considered an error, but overflow
316  * (e.g. "1e9999)" is. */
317 bool
318 str_to_double(const char *s, double *d)
319 {
320     int save_errno = errno;
321     char *tail;
322     errno = 0;
323     *d = strtod(s, &tail);
324     if (errno == EINVAL || (errno == ERANGE && *d != 0)
325         || tail == s || *tail != '\0') {
326         errno = save_errno;
327         *d = 0;
328         return false;
329     } else {
330         errno = save_errno;
331         return true;
332     }
333 }
334
335 /* Returns the value of 'c' as a hexadecimal digit. */
336 int
337 hexit_value(int c)
338 {
339     switch (c) {
340     case '0': case '1': case '2': case '3': case '4':
341     case '5': case '6': case '7': case '8': case '9':
342         return c - '0';
343
344     case 'a': case 'A':
345         return 0xa;
346
347     case 'b': case 'B':
348         return 0xb;
349
350     case 'c': case 'C':
351         return 0xc;
352
353     case 'd': case 'D':
354         return 0xd;
355
356     case 'e': case 'E':
357         return 0xe;
358
359     case 'f': case 'F':
360         return 0xf;
361     }
362
363     NOT_REACHED();
364 }
365
366 /* Returns the current working directory as a malloc()'d string, or a null
367  * pointer if the current working directory cannot be determined. */
368 char *
369 get_cwd(void)
370 {
371     long int path_max;
372     size_t size;
373
374     /* Get maximum path length or at least a reasonable estimate. */
375     path_max = pathconf(".", _PC_PATH_MAX);
376     size = (path_max < 0 ? 1024
377             : path_max > 10240 ? 10240
378             : path_max);
379
380     /* Get current working directory. */
381     for (;;) {
382         char *buf = xmalloc(size);
383         if (getcwd(buf, size)) {
384             return xrealloc(buf, strlen(buf) + 1);
385         } else {
386             int error = errno;
387             free(buf);
388             if (error != ERANGE) {
389                 VLOG_WARN("getcwd failed (%s)", strerror(error));
390                 return NULL;
391             }
392             size *= 2;
393         }
394     }
395 }
396
397 /* Returns the directory name portion of 'file_name' as a malloc()'d string,
398  * similar to the POSIX dirname() function but thread-safe. */
399 char *
400 dir_name(const char *file_name)
401 {
402     size_t len = strlen(file_name);
403     while (len > 0 && file_name[len - 1] == '/') {
404         len--;
405     }
406     while (len > 0 && file_name[len - 1] != '/') {
407         len--;
408     }
409     while (len > 0 && file_name[len - 1] == '/') {
410         len--;
411     }
412     if (!len) {
413         return xstrdup((file_name[0] == '/'
414                         && file_name[1] == '/'
415                         && file_name[2] != '/') ? "//"
416                        : file_name[0] == '/' ? "/"
417                        : ".");
418     } else {
419         return xmemdup0(file_name, len);
420     }
421 }
422
423 /* If 'file_name' starts with '/', returns a copy of 'file_name'.  Otherwise,
424  * returns an absolute path to 'file_name' considering it relative to 'dir',
425  * which itself must be absolute.  'dir' may be null or the empty string, in
426  * which case the current working directory is used.
427  *
428  * Returns a null pointer if 'dir' is null and getcwd() fails. */
429 char *
430 abs_file_name(const char *dir, const char *file_name)
431 {
432     if (file_name[0] == '/') {
433         return xstrdup(file_name);
434     } else if (dir && dir[0]) {
435         char *separator = dir[strlen(dir) - 1] == '/' ? "" : "/";
436         return xasprintf("%s%s%s", dir, separator, file_name);
437     } else {
438         char *cwd = get_cwd();
439         if (cwd) {
440             char *abs_name = xasprintf("%s/%s", cwd, file_name);
441             free(cwd);
442             return abs_name;
443         } else {
444             return NULL;
445         }
446     }
447 }
448
449
450 /* Pass a value to this function if it is marked with
451  * __attribute__((warn_unused_result)) and you genuinely want to ignore
452  * its return value.  (Note that every scalar type can be implicitly
453  * converted to bool.) */
454 void ignore(bool x OVS_UNUSED) { }