daemon: Send back the errno as a string.
[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 #endif /* GUESTFS_ERRNOSTRING_H_ */
230 "
231
232 let generate_errnostring_c () =
233   generate_header CStyle LGPLv2plus;
234
235   pr "\
236 #include <config.h>
237
238 #include <stdlib.h>
239 #include <errno.h>
240
241 #include \"errnostring.h\"
242
243 static const char *errno_to_string[] = {
244 ";
245
246   List.iter (
247     fun e ->
248       pr "#ifdef %s\n" e;
249       pr "  [%s] = \"%s\",\n" e e;
250       pr "#endif\n"
251   ) errnos;
252
253   pr "\
254 };
255
256 #define ERRNO_TO_STRING_SIZE \\
257   (sizeof errno_to_string / sizeof errno_to_string[0])
258
259 const char *
260 guestfs___errno_to_string (int errnum)
261 {
262   /* See function documentation. */
263   if (errnum == 0)
264     abort ();
265
266   if (errnum < 0 || (size_t) errnum >= ERRNO_TO_STRING_SIZE ||
267       errno_to_string[errnum] == NULL)
268     return \"EINVAL\";
269   else
270     return errno_to_string[errnum];
271 }
272
273 "