New API: debug-cmdline for printing QEMU command line (internal only).
[libguestfs.git] / generator / generator_errnostring.ml
1 (* libguestfs
2  * Copyright (C) 2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* Please read generator/README first. *)
20
21 open Printf
22
23 open Generator_types
24 open Generator_utils
25 open Generator_pr
26 open Generator_docstrings
27
28 (* Generate the functions errno_to_string and string_to_errno which
29  * convert errno (eg. EINVAL) into string ("EINVAL") and back again,
30  * allowing us to portably pass error values over the protocol between
31  * different versions of Un*x.
32  *)
33
34 (* Errors found in POSIX plus additional errors found in the Linux
35  * header files.  NOTE keep this sorted and avoid duplicates.
36  *)
37 let errnos = [
38   "E2BIG";
39   "EACCES";
40   "EADDRINUSE";
41   "EADDRNOTAVAIL";
42   "EADV";
43   "EAFNOSUPPORT";
44   "EAGAIN";
45   "EALREADY";
46   "EBADE";
47   "EBADF";
48   "EBADFD";
49   "EBADMSG";
50   "EBADR";
51   "EBADRQC";
52   "EBADSLT";
53   "EBFONT";
54   "EBUSY";
55   "ECANCELED";
56   "ECHILD";
57   "ECHRNG";
58   "ECOMM";
59   "ECONNABORTED";
60   "ECONNREFUSED";
61   "ECONNRESET";
62   (*"EDEADLK"; - same as EDEADLOCK*)
63   "EDEADLOCK";
64   "EDESTADDRREQ";
65   "EDOM";
66   "EDOTDOT";
67   "EDQUOT";
68   "EEXIST";
69   "EFAULT";
70   "EFBIG";
71   "EHOSTDOWN";
72   "EHOSTUNREACH";
73   "EIDRM";
74   "EILSEQ";
75   "EINPROGRESS";
76   "EINTR";
77   "EINVAL";
78   "EIO";
79   "EISCONN";
80   "EISDIR";
81   "EISNAM";
82   "EKEYEXPIRED";
83   "EKEYREJECTED";
84   "EKEYREVOKED";
85   "EL2HLT";
86   "EL2NSYNC";
87   "EL3HLT";
88   "EL3RST";
89   "ELIBACC";
90   "ELIBBAD";
91   "ELIBEXEC";
92   "ELIBMAX";
93   "ELIBSCN";
94   "ELNRNG";
95   "ELOOP";
96   "EMEDIUMTYPE";
97   "EMFILE";
98   "EMLINK";
99   "EMSGSIZE";
100   "EMULTIHOP";
101   "ENAMETOOLONG";
102   "ENAVAIL";
103   "ENETDOWN";
104   "ENETRESET";
105   "ENETUNREACH";
106   "ENFILE";
107   "ENOANO";
108   "ENOBUFS";
109   "ENOCSI";
110   "ENODATA";
111   "ENODEV";
112   "ENOENT";
113   "ENOEXEC";
114   "ENOKEY";
115   "ENOLCK";
116   "ENOLINK";
117   "ENOMEDIUM";
118   "ENOMEM";
119   "ENOMSG";
120   "ENONET";
121   "ENOPKG";
122   "ENOPROTOOPT";
123   "ENOSPC";
124   "ENOSR";
125   "ENOSTR";
126   "ENOSYS";
127   "ENOTBLK";
128   "ENOTCONN";
129   "ENOTDIR";
130   "ENOTEMPTY";
131   "ENOTNAM";
132   "ENOTRECOVERABLE";
133   "ENOTSOCK";
134   "ENOTSUP";
135   "ENOTTY";
136   "ENOTUNIQ";
137   "ENXIO";
138   (*"EOPNOTSUPP"; - duplicates another error, and we don't care because
139     it's a network error *)
140   "EOVERFLOW";
141   "EOWNERDEAD";
142   "EPERM";
143   "EPFNOSUPPORT";
144   "EPIPE";
145   "EPROTO";
146   "EPROTONOSUPPORT";
147   "EPROTOTYPE";
148   "ERANGE";
149   "EREMCHG";
150   "EREMOTE";
151   "EREMOTEIO";
152   "ERESTART";
153   "ERFKILL";
154   "EROFS";
155   "ESHUTDOWN";
156   "ESOCKTNOSUPPORT";
157   "ESPIPE";
158   "ESRCH";
159   "ESRMNT";
160   "ESTALE";
161   "ESTRPIPE";
162   "ETIME";
163   "ETIMEDOUT";
164   "ETOOMANYREFS";
165   "ETXTBSY";
166   "EUCLEAN";
167   "EUNATCH";
168   "EUSERS";
169   (*"EWOULDBLOCK"; - same as EAGAIN*)
170   "EXDEV";
171   "EXFULL";
172
173   (* This is a non-existent errno which is simply used to test that
174    * the generated code can handle such cases on future platforms
175    * where one of the above error codes might not exist.
176    *)
177   "EZZZ";
178 ]
179
180 let () =
181   (* Check list is sorted and no duplicates. *)
182   let file = "generator/generator_errnostring.ml" in
183   let check str =
184     let len = String.length str in
185     if len == 0 || len > 32 then
186       failwithf "%s: errno empty or length > 32 (%s)" file str;
187     if str.[0] <> 'E' then
188       failwithf "%s: errno string does not begin with letter 'E' (%s)" file str;
189     for i = 0 to len-1 do
190       let c = str.[i] in
191       if Char.uppercase c <> c then
192         failwithf "%s: errno string is not all uppercase (%s)" file str
193     done
194   in
195   let rec loop = function
196     | [] -> ()
197     | x :: y :: xs when x = y ->
198         failwithf "%s: errnos list contains duplicates (%s)" file x
199     | x :: y :: xs when x > y ->
200         failwithf "%s: errnos list is not sorted (%s > %s)" file x y
201     | x :: xs -> check x; loop xs
202   in
203   loop errnos
204
205 let generate_errnostring_h () =
206   generate_header CStyle LGPLv2plus;
207
208   pr "
209 #ifndef GUESTFS_ERRNOSTRING_H_
210 #define GUESTFS_ERRNOSTRING_H_
211
212 /* Convert errno (eg. EIO) to its string representation (\"EIO\").
213  * This only works for a set of errors that are listed in the generator
214  * AND are supported on the local operating system.  For other errors
215  * the string (\"EINVAL\") is returned.
216  *
217  * NOTE: It is an error to call this function with errnum == 0.
218  */
219 extern const char *guestfs___errno_to_string (int errnum);
220
221 /* Convert string representation of an error (eg. \"EIO\") to the errno
222  * value (EIO).  As for the function above, this only works for a
223  * subset of errors.  For errors not supported by the local operating
224  * system, EINVAL is returned (all POSIX-conforming systems must
225  * support EINVAL).
226  */
227 extern int guestfs___string_to_errno (const char *errnostr);
228
229 /* Private structure and function used by the perfect hash implementation. */
230 struct errnostring_entry { char *name; int errnum; };
231 extern const struct errnostring_entry *guestfs___string_to_errno_lookup (register const char *str, register unsigned int len);
232
233 #endif /* GUESTFS_ERRNOSTRING_H_ */
234 "
235
236 let generate_errnostring_c () =
237   generate_header CStyle LGPLv2plus;
238
239   pr "\
240 #include <config.h>
241
242 #include <stdlib.h>
243 #include <string.h>
244 #include <errno.h>
245
246 #include \"errnostring.h\"
247
248 static const char *errno_to_string[] = {
249 ";
250
251   List.iter (
252     fun e ->
253       pr "#ifdef %s\n" e;
254       pr "  [%s] = \"%s\",\n" e e;
255       pr "#endif\n"
256   ) errnos;
257
258   pr "\
259 };
260
261 #define ERRNO_TO_STRING_SIZE \\
262   (sizeof errno_to_string / sizeof errno_to_string[0])
263
264 const char *
265 guestfs___errno_to_string (int errnum)
266 {
267   /* See function documentation. */
268   if (errnum == 0)
269     abort ();
270
271   if (errnum < 0 || (size_t) errnum >= ERRNO_TO_STRING_SIZE ||
272       errno_to_string[errnum] == NULL)
273     return \"EINVAL\";
274   else
275     return errno_to_string[errnum];
276 }
277
278 int
279 guestfs___string_to_errno (const char *errnostr)
280 {
281   const struct errnostring_entry *v =
282     guestfs___string_to_errno_lookup (errnostr, strlen (errnostr));
283   if (v /* not necessary to check v->name != NULL here */)
284     return v->errnum;
285   else
286     return EINVAL;
287 }
288 "
289
290 let generate_errnostring_gperf () =
291   generate_header CStyle LGPLv2plus;
292
293   pr "\
294 %%language=ANSI-C
295 %%define lookup-function-name guestfs___string_to_errno_lookup
296 %%readonly-tables
297 %%null-strings
298
299 %%{
300
301 #include <config.h>
302
303 #include <stdlib.h>
304 #include <string.h>
305 #include <errno.h>
306
307 #include \"errnostring.h\"
308
309 ";
310
311   (* Some of these errnos might not exist on the target platform, but
312    * we are going to include E_ macros directly in the C output of
313    * gperf.  To avoid this causing errors, we include macros to define
314    * unknown errors as EINVAL (see specification of
315    * guestfs___string_to_errno above).  Note this only affects the
316    * single output file containing gperf-generated code.
317    *)
318   List.iter (
319     fun e ->
320       pr "#ifndef %s\n" e;
321       pr "#define %s EINVAL\n" e;
322       pr "#endif\n";
323   ) errnos;
324
325   pr "\
326
327 %%}
328
329 struct errnostring_entry;
330
331 %%%%
332 ";
333
334   List.iter (
335     fun e ->
336       pr "%s, %s\n" e e
337   ) errnos