1 /*
2  * Copyright (c) 2024 SUSE Software Solutions Germany GmbH
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation;
7  * version 2.1 of the License.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #define _GNU_SOURCE
19 
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <xentoollog.h>
25 #include <xenmanage.h>
26 #include <xencall.h>
27 #include <xentoolcore_internal.h>
28 
29 #include <xen/xen.h>
30 #include <xen/domctl.h>
31 
32 struct xenmanage_handle {
33     xentoollog_logger *logger, *logger_tofree;
34     unsigned int flags;
35     xencall_handle *xcall;
36 };
37 
xenmanage_open(xentoollog_logger * logger,unsigned int open_flags)38 xenmanage_handle *xenmanage_open(xentoollog_logger *logger,
39                                  unsigned int open_flags)
40 {
41     xenmanage_handle *hdl = calloc(1, sizeof(*hdl));
42     int saved_errno;
43 
44     if ( !hdl )
45         return NULL;
46 
47     if ( open_flags )
48     {
49         errno = EINVAL;
50         goto err;
51     }
52 
53     hdl->flags = open_flags;
54     hdl->logger = logger;
55     hdl->logger_tofree = NULL;
56 
57     if ( !hdl->logger )
58     {
59         hdl->logger = hdl->logger_tofree =
60             (xentoollog_logger *)
61             xtl_createlogger_stdiostream(stderr, XTL_PROGRESS, 0);
62         if ( !hdl->logger )
63             goto err;
64     }
65 
66     hdl->xcall = xencall_open(hdl->logger, 0);
67     if ( !hdl->xcall )
68         goto err;
69 
70     return hdl;
71 
72 err:
73     saved_errno = errno;
74     xenmanage_close(hdl);
75     errno = saved_errno;
76 
77     return NULL;
78 }
79 
xenmanage_close(xenmanage_handle * hdl)80 int xenmanage_close(xenmanage_handle *hdl)
81 {
82     if ( !hdl )
83         return 0;
84 
85     xencall_close(hdl->xcall);
86     xtl_logger_destroy(hdl->logger_tofree);
87     free(hdl);
88     return 0;
89 }
90 
xenmanage_do_domctl_get_domain_state(xenmanage_handle * hdl,unsigned int domid_in,unsigned int * domid_out,unsigned int * state,unsigned int * caps,uint64_t * unique_id)91 static int xenmanage_do_domctl_get_domain_state(xenmanage_handle *hdl,
92                                                 unsigned int domid_in,
93                                                 unsigned int *domid_out,
94                                                 unsigned int *state,
95                                                 unsigned int *caps,
96                                                 uint64_t *unique_id)
97 {
98     struct xen_domctl *buf;
99     int saved_errno;
100     int ret;
101 
102     buf = xencall_alloc_buffer(hdl->xcall, sizeof(*buf));
103     if ( !buf )
104     {
105         errno = ENOMEM;
106         return -1;
107     }
108 
109     memset(buf, 0, sizeof(*buf));
110 
111     buf->cmd = XEN_DOMCTL_get_domain_state;
112     buf->domain = domid_in;
113 
114     ret = xencall1(hdl->xcall, __HYPERVISOR_domctl, (unsigned long)buf);
115     saved_errno = errno;
116     if ( !ret )
117     {
118         struct xen_domctl_get_domain_state *st = &buf->u.get_domain_state;
119 
120         if ( domid_out )
121             *domid_out = buf->domain;
122         if ( state )
123         {
124             *state = 0;
125             if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_EXIST )
126                 *state |= XENMANAGE_GETDOMSTATE_STATE_EXIST;
127             if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_SHUTDOWN )
128                 *state |= XENMANAGE_GETDOMSTATE_STATE_SHUTDOWN;
129             if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_DYING )
130                 *state |= XENMANAGE_GETDOMSTATE_STATE_DYING;
131             if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_DEAD )
132                 *state |= XENMANAGE_GETDOMSTATE_STATE_DEAD;
133         }
134         if ( caps )
135         {
136             *caps = 0;
137             if ( st->caps & XEN_DOMCTL_GETDOMSTATE_CAP_CONTROL )
138                 *caps |= XENMANAGE_GETDOMSTATE_CAP_CONTROL;
139             if ( st->caps & XEN_DOMCTL_GETDOMSTATE_CAP_HARDWARE )
140                 *caps |= XENMANAGE_GETDOMSTATE_CAP_HARDWARE;
141             if ( st->caps & XEN_DOMCTL_GETDOMSTATE_CAP_XENSTORE )
142                 *caps |= XENMANAGE_GETDOMSTATE_CAP_XENSTORE;
143         }
144         if ( unique_id )
145             *unique_id = st->unique_id;
146     }
147 
148     xencall_free_buffer(hdl->xcall, buf);
149 
150     errno = saved_errno;
151 
152     return ret;
153 }
154 
xenmanage_get_domain_info(xenmanage_handle * hdl,unsigned int domid,unsigned int * state,unsigned int * caps,uint64_t * unique_id)155 int xenmanage_get_domain_info(xenmanage_handle *hdl, unsigned int domid,
156                               unsigned int *state, unsigned int *caps,
157                               uint64_t *unique_id)
158 {
159     if ( !hdl || domid >= DOMID_FIRST_RESERVED )
160     {
161         errno = EINVAL;
162         return -1;
163     }
164 
165     return xenmanage_do_domctl_get_domain_state(hdl, domid, NULL, state, caps,
166                                                 unique_id);
167 }
168 
xenmanage_poll_changed_domain(xenmanage_handle * hdl,unsigned int * domid,unsigned int * state,unsigned int * caps,uint64_t * unique_id)169 int xenmanage_poll_changed_domain(xenmanage_handle *hdl, unsigned int *domid,
170                                   unsigned int *state, unsigned int *caps,
171                                   uint64_t *unique_id)
172 {
173     if ( !hdl || !domid )
174     {
175         errno = EINVAL;
176         return -1;
177     }
178 
179     return xenmanage_do_domctl_get_domain_state(hdl, DOMID_INVALID, domid,
180                                                 state, caps, unique_id);
181 }
182