1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /*
4  * Live Update for Xen Store Daemon.
5  * Copyright (C) 2022 Juergen Gross, SUSE LLC
6  */
7 
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <syslog.h>
12 #include <sys/mman.h>
13 #include <xenctrl.h>
14 #include <xen-tools/common-macros.h>
15 
16 #include "talloc.h"
17 #include "lu.h"
18 
19 /* Mini-OS only knows about MAP_ANON. */
20 #ifndef MAP_ANONYMOUS
21 #define MAP_ANONYMOUS MAP_ANON
22 #endif
23 
24 #ifndef NO_LIVE_UPDATE
lu_get_dump_state(struct lu_dump_state * state)25 void lu_get_dump_state(struct lu_dump_state *state)
26 {
27 }
28 
lu_close_dump_state(struct lu_dump_state * state)29 void lu_close_dump_state(struct lu_dump_state *state)
30 {
31 }
32 
lu_dump_open(const void * ctx)33 FILE *lu_dump_open(const void *ctx)
34 {
35 	lu_status->dump_size = ROUNDUP(talloc_total_size(NULL) * 2,
36 				       XC_PAGE_SHIFT);
37 	lu_status->dump_state = mmap(NULL, lu_status->dump_size,
38 				     PROT_READ | PROT_WRITE,
39 				     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
40 	if (lu_status->dump_state == MAP_FAILED)
41 		return NULL;
42 
43 	return fmemopen(lu_status->dump_state, lu_status->dump_size, "w");
44 }
45 
lu_dump_close(FILE * fp)46 void lu_dump_close(FILE *fp)
47 {
48 	size_t size;
49 
50 	size = ftell(fp);
51 	size = ROUNDUP(size, XC_PAGE_SHIFT);
52 	munmap(lu_status->dump_state + size, lu_status->dump_size - size);
53 	lu_status->dump_size = size;
54 
55 	fclose(fp);
56 }
57 
lu_exec(const void * ctx,int argc,char ** argv)58 char *lu_exec(const void *ctx, int argc, char **argv)
59 {
60 	return "NYI";
61 }
62 
lu_destroy_arch(void * data)63 void lu_destroy_arch(void *data)
64 {
65 	if (lu_status->dump_state)
66 		munmap(lu_status->dump_state, lu_status->dump_size);
67 }
68 
lu_binary_alloc(const void * ctx,struct connection * conn,unsigned long size)69 static const char *lu_binary_alloc(const void *ctx, struct connection *conn,
70 				   unsigned long size)
71 {
72 	const char *ret;
73 
74 	syslog(LOG_INFO, "live-update: binary size %lu\n", size);
75 
76 	ret = lu_begin(conn);
77 	if (ret)
78 		return ret;
79 
80 	lu_status->kernel = talloc_size(lu_status, size);
81 	if (!lu_status->kernel)
82 		return "Allocation failure.";
83 
84 	lu_status->kernel_size = size;
85 	lu_status->kernel_off = 0;
86 
87 	errno = 0;
88 	return NULL;
89 }
90 
lu_binary_save(const void * ctx,struct connection * conn,unsigned int size,const char * data)91 static const char *lu_binary_save(const void *ctx, struct connection *conn,
92 				  unsigned int size, const char *data)
93 {
94 	if (!lu_status || lu_status->conn != conn)
95 		return "Not in live-update session.";
96 
97 	if (lu_status->kernel_off + size > lu_status->kernel_size)
98 		return "Too much kernel data.";
99 
100 	memcpy(lu_status->kernel + lu_status->kernel_off, data, size);
101 	lu_status->kernel_off += size;
102 
103 	errno = 0;
104 	return NULL;
105 }
106 
lu_arch(const void * ctx,struct connection * conn,const char ** vec,int num)107 const char *lu_arch(const void *ctx, struct connection *conn, const char **vec,
108 		    int num)
109 {
110 	if (num == 2 && !strcmp(vec[0], "-b"))
111 		return lu_binary_alloc(ctx, conn, atol(vec[1]));
112 	if (num > 2 && !strcmp(vec[0], "-d"))
113 		return lu_binary_save(ctx, conn, atoi(vec[1]), vec[2]);
114 
115 	errno = EINVAL;
116 	return NULL;
117 }
118 #endif
119