1 /* libguestfs Erlang bindings.
2 * Copyright (C) 2011 Red Hat Inc.
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.
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.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <erl_interface.h>
28 #include "full-read.h"
29 #include "full-write.h"
35 extern ETERM *dispatch (ETERM *message);
36 extern int atom_equals (ETERM *atom, const char *name);
37 extern ETERM *make_error (const char *funname);
38 extern ETERM *unknown_optarg (const char *funname, ETERM *optargname);
39 extern ETERM *unknown_function (ETERM *fun);
40 extern ETERM *make_string_list (char **r);
41 extern ETERM *make_table (char **r);
42 extern ETERM *make_bool (int r);
43 extern char **get_string_list (ETERM *term);
44 extern int get_bool (ETERM *term);
45 extern void free_strings (char **r);
47 /* This stops things getting out of hand, but also lets us detect
48 * protocol problems quickly.
50 #define MAX_MESSAGE_SIZE (32*1024*1024)
52 static unsigned char *read_message (void);
53 static void write_reply (ETERM *);
63 /* This process has a single libguestfs handle. If the Erlang
64 * system creates more than one handle, then more than one of these
65 * processes will be running.
67 g = guestfs_create ();
69 error (EXIT_FAILURE, 0, "could not create guestfs handle");
71 guestfs_set_error_handler (g, NULL, NULL);
73 while ((buf = read_message ()) != NULL) {
74 message = erl_decode (buf);
77 ret = dispatch (message);
78 erl_free_term (message);
89 /* The Erlang port always sends the length of the buffer as 4
90 * bytes in network byte order, followed by the message buffer.
92 static unsigned char *
100 if (full_read (0, buf, 4) != 4) {
101 if (errno == 0) /* ok - closed connection normally */
104 error (EXIT_FAILURE, errno, "read message size");
107 size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
109 if (size > MAX_MESSAGE_SIZE)
110 error (EXIT_FAILURE, 0, "message larger than MAX_MESSAGE_SIZE");
114 error (EXIT_FAILURE, errno, "malloc");
116 if (full_read (0, r, size) != size)
117 error (EXIT_FAILURE, errno, "read message content");
123 write_reply (ETERM *term)
126 unsigned char sbuf[4];
129 size = erl_term_len (term);
133 error (EXIT_FAILURE, errno, "malloc");
135 erl_encode (term, buf);
137 sbuf[0] = (size >> 24) & 0xff;
138 sbuf[1] = (size >> 16) & 0xff;
139 sbuf[2] = (size >> 8) & 0xff;
140 sbuf[3] = size & 0xff;
142 if (full_write (1, sbuf, 4) != 4)
143 error (EXIT_FAILURE, errno, "write message size");
145 if (full_write (1, buf, size) != size)
146 error (EXIT_FAILURE, errno, "write message content");
151 /* Note that all published Erlang code/examples etc uses strncmp in
152 * a buggy way. This is the right way to do it.
155 atom_equals (ETERM *atom, const char *name)
157 size_t namelen = strlen (name);
158 size_t atomlen = ERL_ATOM_SIZE (atom);
159 if (namelen != atomlen) return 0;
160 return strncmp (ERL_ATOM_PTR (atom), name, atomlen) == 0;
164 make_error (const char *funname)
166 ETERM *error = erl_mk_atom ("error");
167 ETERM *msg = erl_mk_string (guestfs_last_error (g));
168 ETERM *num = erl_mk_int (guestfs_last_errno (g));
169 ETERM *t[3] = { error, msg, num };
170 return erl_mk_tuple (t, 3);
174 unknown_function (ETERM *fun)
176 ETERM *unknown = erl_mk_atom ("unknown");
177 ETERM *funcopy = erl_copy_term (fun);
178 ETERM *t[2] = { unknown, funcopy };
179 return erl_mk_tuple (t, 2);
183 unknown_optarg (const char *funname, ETERM *optargname)
185 ETERM *unknownarg = erl_mk_atom ("unknownarg");
186 ETERM *copy = erl_copy_term (optargname);
187 ETERM *t[2] = { unknownarg, copy };
188 return erl_mk_tuple (t, 2);
192 make_string_list (char **r)
196 for (size = 0; r[size] != NULL; ++size)
201 for (i = 0; r[i] != NULL; ++i)
202 t[i] = erl_mk_string (r[i]);
204 return erl_mk_list (t, size);
207 /* Make a hash table. The number of elements returned by the C
208 * function is always even.
211 make_table (char **r)
215 for (size = 0; r[size] != NULL; ++size)
221 for (i = 0; r[i] != NULL; i += 2) {
222 a[0] = erl_mk_string (r[i]);
223 a[1] = erl_mk_string (r[i+1]);
224 t[i/2] = erl_mk_tuple (a, 2);
227 return erl_mk_list (t, size/2);
234 return erl_mk_atom ("true");
236 return erl_mk_atom ("false");
240 get_string_list (ETERM *term)
246 for (size = 0, t = term; !ERL_IS_EMPTY_LIST (t);
247 size++, t = ERL_CONS_TAIL (t))
250 r = malloc ((size+1) * sizeof (char *));
252 error (EXIT_FAILURE, errno, "malloc");
254 for (i = 0, t = term; !ERL_IS_EMPTY_LIST (t); i++, t = ERL_CONS_TAIL (t))
255 r[i] = erl_iolist_to_string (ERL_CONS_HEAD (t));
262 get_bool (ETERM *term)
264 if (atom_equals (term, "true"))
271 free_strings (char **r)
275 for (i = 0; r[i] != NULL; ++i)