2 #if defined(HAVE_CONFIG_H)
14 #include <sys/socket.h>
16 #include <asm/byteorder.h>
18 #include <talloc/talloc.h>
21 #include "discover-client.h"
22 #include "pb-protocol/pb-protocol.h"
24 struct discover_client {
26 struct discover_client_ops ops;
28 struct device **devices;
32 static int discover_client_destructor(void *arg)
34 struct discover_client *client = arg;
42 void discover_client_destroy(struct discover_client *client)
47 static struct device *find_device(struct discover_client *client,
52 for (i = 0; i < client->n_devices; i++) {
53 struct device *dev = client->devices[i];
54 if (!strcmp(dev->id, id))
61 static void device_add(struct discover_client *client, struct device *device)
64 client->devices = talloc_realloc(client, client->devices,
65 struct device *, client->n_devices);
67 client->devices[client->n_devices - 1] = device;
68 talloc_steal(client, device);
69 list_init(&device->boot_options);
71 if (client->ops.device_add)
72 client->ops.device_add(device, client->ops.cb_arg);
75 static void boot_option_add(struct discover_client *client,
76 struct boot_option *opt)
80 dev = find_device(client, opt->device_id);
82 /* we require that devices are already present before any boot options
86 talloc_steal(dev, opt);
87 list_add(&dev->boot_options, &opt->list);
89 if (client->ops.boot_option_add)
90 client->ops.boot_option_add(dev, opt, client->ops.cb_arg);
93 static void device_remove(struct discover_client *client, const char *id)
95 struct device *device = NULL;
98 for (i = 0; i < client->n_devices; i++) {
99 if (!strcmp(client->devices[i]->id, id)) {
100 device = client->devices[i];
108 /* remove the device from the client's device array */
110 memmove(&client->devices[i], &client->devices[i+1],
111 (client->n_devices - i) * sizeof(client->devices[0]));
112 client->devices = talloc_realloc(client, client->devices,
113 struct device *, client->n_devices);
116 client->ops.device_remove(device, client->ops.cb_arg);
121 static void plugin_option_add(struct discover_client *client,
122 struct plugin_option *opt)
124 talloc_steal(client, opt);
126 if (client->ops.plugin_option_add)
127 client->ops.plugin_option_add(opt, client->ops.cb_arg);
130 static void plugins_remove(struct discover_client *client)
132 if (client->ops.plugins_remove)
133 client->ops.plugins_remove(client->ops.cb_arg);
136 void discover_client_enumerate(struct discover_client *client)
138 struct boot_option *opt;
139 struct device *device;
142 for (i = 0; i < client->n_devices; i++) {
143 device = client->devices[i];
144 if (client->ops.device_add)
145 client->ops.device_add(device, client->ops.cb_arg);
147 list_for_each_entry(&device->boot_options, opt, list)
148 if (client->ops.boot_option_add)
149 client->ops.boot_option_add(device, opt,
154 static void update_status(struct discover_client *client,
155 struct status *status)
157 if (client->ops.update_status)
158 client->ops.update_status(status, client->ops.cb_arg);
161 static void update_sysinfo(struct discover_client *client,
162 struct system_info *sysinfo)
164 if (client->ops.update_sysinfo)
165 client->ops.update_sysinfo(sysinfo, client->ops.cb_arg);
168 static void update_config(struct discover_client *client,
169 struct config *config)
171 if (client->ops.update_config)
172 client->ops.update_config(config, client->ops.cb_arg);
175 static int discover_client_process(void *arg)
177 struct discover_client *client = arg;
178 struct pb_protocol_message *message;
179 struct auth_message *auth_msg;
180 struct plugin_option *p_opt;
181 struct system_info *sysinfo;
182 struct boot_option *opt;
183 struct status *status;
184 struct config *config;
190 /* We use a temporary context for processing one message; persistent
191 * data is re-parented to the client in the callbacks. */
192 ctx = talloc_new(client);
194 message = pb_protocol_read_message(ctx, client->fd);
199 switch (message->action) {
200 case PB_PROTOCOL_ACTION_DEVICE_ADD:
201 dev = talloc_zero(ctx, struct device);
202 list_init(&dev->boot_options);
204 rc = pb_protocol_deserialise_device(dev, message);
206 pb_log_fn("no device?\n");
210 device_add(client, dev);
212 case PB_PROTOCOL_ACTION_BOOT_OPTION_ADD:
213 opt = talloc_zero(ctx, struct boot_option);
215 rc = pb_protocol_deserialise_boot_option(opt, message);
217 pb_log_fn("no boot_option?\n");
221 boot_option_add(client, opt);
223 case PB_PROTOCOL_ACTION_DEVICE_REMOVE:
224 dev_id = pb_protocol_deserialise_string(ctx, message);
226 pb_log_fn("no device id?\n");
229 device_remove(client, dev_id);
231 case PB_PROTOCOL_ACTION_STATUS:
232 status = talloc_zero(ctx, struct status);
234 rc = pb_protocol_deserialise_boot_status(status, message);
236 pb_log_fn("invalid status message?\n");
239 update_status(client, status);
241 case PB_PROTOCOL_ACTION_SYSTEM_INFO:
242 sysinfo = talloc_zero(ctx, struct system_info);
244 rc = pb_protocol_deserialise_system_info(sysinfo, message);
246 pb_log_fn("invalid sysinfo message?\n");
249 update_sysinfo(client, sysinfo);
251 case PB_PROTOCOL_ACTION_CONFIG:
252 config = talloc_zero(ctx, struct config);
254 rc = pb_protocol_deserialise_config(config, message);
256 pb_log_fn("invalid config message?\n");
259 update_config(client, config);
261 case PB_PROTOCOL_ACTION_PLUGIN_OPTION_ADD:
262 p_opt = talloc_zero(ctx, struct plugin_option);
264 rc = pb_protocol_deserialise_plugin_option(p_opt, message);
266 pb_log_fn("no plugin_option?\n");
270 plugin_option_add(client, p_opt);
272 case PB_PROTOCOL_ACTION_PLUGINS_REMOVE:
273 plugins_remove(client);
275 case PB_PROTOCOL_ACTION_AUTHENTICATE:
276 auth_msg = talloc_zero(ctx, struct auth_message);
278 rc = pb_protocol_deserialise_authenticate(auth_msg, message);
279 if (rc || auth_msg->op != AUTH_MSG_RESPONSE) {
280 pb_log("%s: invalid auth message? (%d)\n",
285 pb_log("Client %sauthenticated by server\n",
286 client->authenticated ? "" : "un");
287 client->authenticated = auth_msg->authenticated;
290 pb_log_fn("unknown action %d\n", message->action);
299 struct discover_client* discover_client_init(struct waitset *waitset,
300 const struct discover_client_ops *ops, void *cb_arg)
302 struct discover_client *client;
303 struct sockaddr_un addr;
305 client = talloc(NULL, struct discover_client);
309 memcpy(&client->ops, ops, sizeof(client->ops));
310 client->ops.cb_arg = cb_arg;
312 client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
313 if (client->fd < 0) {
314 pb_log_fn("socket: %s\n", strerror(errno));
318 talloc_set_destructor(client, discover_client_destructor);
320 client->n_devices = 0;
321 client->devices = NULL;
323 addr.sun_family = AF_UNIX;
324 strcpy(addr.sun_path, PB_SOCKET_PATH);
326 if (connect(client->fd, (struct sockaddr *)&addr, sizeof(addr))) {
327 pb_log_fn("connect: %s\n", strerror(errno));
331 waiter_register_io(waitset, client->fd, WAIT_IN,
332 discover_client_process, client);
334 /* Assume this client can't make changes if crypt support is enabled */
336 client->authenticated = false;
338 client->authenticated = true;
348 /* accessors for discovered devices */
349 int discover_client_device_count(struct discover_client *client)
351 return client->n_devices;
354 struct device *discover_client_get_device(struct discover_client *client,
357 if (index < 0 || index >= client->n_devices)
360 return client->devices[index];
363 bool discover_client_authenticated(struct discover_client *client)
365 return client->authenticated;
368 static void create_boot_command(struct boot_command *command,
369 const struct device *device __attribute__((unused)),
370 const struct boot_option *boot_option,
371 const struct pb_boot_data *data)
373 command->option_id = boot_option ? boot_option->id : NULL;
374 command->boot_image_file = data->image;
375 command->initrd_file = data->initrd;
376 command->dtb_file = data->dtb;
377 command->boot_args = data->args;
378 command->args_sig_file = data->args_sig_file;
379 command->console = ttyname(STDIN_FILENO);
382 int discover_client_boot(struct discover_client *client,
383 const struct device *device,
384 const struct boot_option *boot_option,
385 const struct pb_boot_data *data)
387 struct pb_protocol_message *message;
388 struct boot_command boot_command;
391 create_boot_command(&boot_command, device, boot_option, data);
393 len = pb_protocol_boot_len(&boot_command);
395 message = pb_protocol_create_message(client,
396 PB_PROTOCOL_ACTION_BOOT, len);
401 pb_protocol_serialise_boot_command(&boot_command,
402 message->payload, len);
404 rc = pb_protocol_write_message(client->fd, message);
409 int discover_client_cancel_default(struct discover_client *client)
411 struct pb_protocol_message *message;
413 message = pb_protocol_create_message(client,
414 PB_PROTOCOL_ACTION_CANCEL_DEFAULT, 0);
419 return pb_protocol_write_message(client->fd, message);
422 int discover_client_send_reinit(struct discover_client *client)
424 struct pb_protocol_message *message;
426 message = pb_protocol_create_message(client,
427 PB_PROTOCOL_ACTION_REINIT, 0);
432 return pb_protocol_write_message(client->fd, message);
435 int discover_client_send_config(struct discover_client *client,
436 struct config *config)
438 struct pb_protocol_message *message;
441 len = pb_protocol_config_len(config);
443 message = pb_protocol_create_message(client,
444 PB_PROTOCOL_ACTION_CONFIG, len);
448 pb_protocol_serialise_config(config, message->payload, len);
450 return pb_protocol_write_message(client->fd, message);
453 int discover_client_send_url(struct discover_client *client,
456 struct pb_protocol_message *message;
459 len = pb_protocol_url_len(url);
461 message = pb_protocol_create_message(client,
462 PB_PROTOCOL_ACTION_ADD_URL, len);
466 pb_protocol_serialise_url(url, message->payload, len);
468 return pb_protocol_write_message(client->fd, message);
471 int discover_client_send_plugin_install(struct discover_client *client,
474 struct pb_protocol_message *message;
477 len = pb_protocol_url_len(file);
479 message = pb_protocol_create_message(client,
480 PB_PROTOCOL_ACTION_PLUGIN_INSTALL, len);
484 pb_protocol_serialise_url(file, message->payload, len);
486 return pb_protocol_write_message(client->fd, message);
489 int discover_client_send_temp_autoboot(struct discover_client *client,
490 const struct autoboot_option *opt)
492 struct pb_protocol_message *message;
495 len = pb_protocol_temp_autoboot_len(opt);
497 message = pb_protocol_create_message(client,
498 PB_PROTOCOL_ACTION_TEMP_AUTOBOOT, len);
502 pb_protocol_serialise_temp_autoboot(opt, message->payload, len);
504 return pb_protocol_write_message(client->fd, message);
507 int discover_client_send_authenticate(struct discover_client *client,
510 struct pb_protocol_message *message;
511 struct auth_message auth_msg;
514 auth_msg.op = AUTH_MSG_REQUEST;
515 auth_msg.password = password;
517 len = pb_protocol_authenticate_len(&auth_msg);
519 message = pb_protocol_create_message(client,
520 PB_PROTOCOL_ACTION_AUTHENTICATE, len);
524 pb_log("serialising auth message..\n");
525 pb_protocol_serialise_authenticate(&auth_msg, message->payload, len);
527 pb_log("sending auth message..\n");
528 return pb_protocol_write_message(client->fd, message);
531 int discover_client_send_set_password(struct discover_client *client,
532 char *password, char *new_password)
534 struct pb_protocol_message *message;
535 struct auth_message auth_msg;
538 auth_msg.op = AUTH_MSG_SET;
539 auth_msg.set_password.password = password;
540 auth_msg.set_password.new_password = new_password;
542 len = pb_protocol_authenticate_len(&auth_msg);
544 message = pb_protocol_create_message(client,
545 PB_PROTOCOL_ACTION_AUTHENTICATE, len);
549 pb_log("serialising auth message..\n");
550 pb_protocol_serialise_authenticate(&auth_msg, message->payload, len);
552 pb_log("sending auth message..\n");
553 return pb_protocol_write_message(client->fd, message);