1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
25 * permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
40
41 /* This file contains all the door server code */
42
43 #include <syslog.h>
44 #include <door.h>
45 #include <alloca.h>
46 #include <errno.h>
47 #include <note.h>
48 #include <libintl.h>
49 #include <ndmpd_door.h>
50 #include "ndmpd.h"
51
52 /* static variables */
53 static int ndmp_door_fildes = -1;
54 static mutex_t ndmp_doorsrv_mutex;
55
56 /* static routines */
57 static void ndmp_door_server(void *cookie, char *ptr, size_t size,
58 door_desc_t *dp, uint_t n_desc);
59
60 /*
61 * Statistics used in ndmpstat command
62 */
63 ndmp_stat_t ndstat;
64
65 int
66 ndmp_door_init(void)
67 {
68 int fd;
69
70 (void) mutex_lock(&ndmp_doorsrv_mutex);
71
72 if (ndmp_door_fildes != -1) {
73 syslog(LOG_ERR,
74 "ndmp_door_init: ndmpd service is already running.");
75 (void) mutex_unlock(&ndmp_doorsrv_mutex);
76 return (0);
77 }
78
79 if ((ndmp_door_fildes = door_create(ndmp_door_server,
80 NULL, DOOR_UNREF)) < 0) {
81 syslog(LOG_ERR, "ndmp_door_init: Could not create door.");
82 (void) mutex_unlock(&ndmp_doorsrv_mutex);
83 return (-1);
84 }
85
86 (void) unlink(NDMP_DOOR_SVC);
87
88 if ((fd = creat(NDMP_DOOR_SVC, 0444)) < 0) {
89 syslog(LOG_ERR, "ndmp_door_init: Can't create %s: %m.",
90 NDMP_DOOR_SVC);
91 (void) door_revoke(ndmp_door_fildes);
92 ndmp_door_fildes = -1;
93 (void) mutex_unlock(&ndmp_doorsrv_mutex);
94 return (-1);
95 }
96
97 (void) close(fd);
98 (void) fdetach(NDMP_DOOR_SVC);
99
100 if (fattach(ndmp_door_fildes, NDMP_DOOR_SVC) < 0) {
101 syslog(LOG_ERR, "ndmp_door_init: fattach failed %m");
102 (void) door_revoke(ndmp_door_fildes);
103 ndmp_door_fildes = -1;
104 (void) mutex_unlock(&ndmp_doorsrv_mutex);
105 return (-1);
106 }
107
108 syslog(LOG_DEBUG, "ndmp_door_init: Door server successfully started");
109 (void) mutex_unlock(&ndmp_doorsrv_mutex);
110 return (0);
111 }
112
113 void
114 ndmp_door_fini(void)
115 {
116 (void) mutex_lock(&ndmp_doorsrv_mutex);
117
118 if (ndmp_door_fildes != -1) {
119 (void) fdetach(NDMP_DOOR_SVC);
120 (void) door_revoke(ndmp_door_fildes);
121 ndmp_door_fildes = -1;
122 }
123
124 (void) mutex_unlock(&ndmp_doorsrv_mutex);
125 }
126
127 boolean_t
128 ndmp_door_check(void)
129 {
130 door_info_t info;
131 int door;
132
133 if ((door = open(NDMP_DOOR_SVC, O_RDONLY)) < 0)
134 return (0);
135
136 if (door_info(door, &info) < 0) {
137 (void) close(door);
138 return (0);
139 }
140
141 if (info.di_target > 0) {
142 syslog(LOG_ERR,
143 "Service already running: pid %ld", info.di_target);
144 (void) close(door);
145 return (1);
146 }
147
148 (void) close(door);
149 return (0);
150 }
151
152 /* door server */
153 /*ARGSUSED*/
154 void
155 ndmp_door_server(void *cookie, char *ptr, size_t size,
156 door_desc_t *dp, uint_t n_desc)
157 {
158 NOTE(ARGUNUSED(cookie,dp,n_desc))
159 int req_type;
160 char *buf;
161 int buflen;
162 unsigned int used;
163 ndmp_door_ctx_t *dec_ctx;
164 ndmp_door_ctx_t *enc_ctx;
165 unsigned int dec_status = EINVAL;
166 unsigned int enc_status = EINVAL;
167
168 dec_ctx = ndmp_door_decode_start(ptr, size);
169 if (dec_ctx == 0)
170 return;
171
172 req_type = ndmp_door_get_uint32(dec_ctx);
173 buflen = NDMP_DOOR_SIZE;
174
175 if ((buf = alloca(buflen)) == NULL) {
176 syslog(LOG_ERR, "Out of memory.");
177 (void) ndmp_door_decode_finish(dec_ctx);
178 return;
179 }
180
181 enc_ctx = ndmp_door_encode_start(buf, buflen);
182 if (enc_ctx == 0) {
183 (void) ndmp_door_decode_finish(dec_ctx);
184 return;
185 }
186
187 if (req_type != NDMP_GET_STAT)
188 syslog(LOG_DEBUG, "ndmp_door_server: req_type=%d", req_type);
189
190 switch (req_type) {
191 case NDMP_GET_DOOR_STATUS: {
192 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
193 break;
194 }
195 case NDMP_DEVICES_GET_INFO: {
196 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
197 ndmpd_get_devs(enc_ctx);
198 break;
199 }
200 case NDMP_SHOW: {
201 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
202 ndmp_connect_list_get(enc_ctx);
203 break;
204 }
205 case NDMP_TERMINATE_SESSION_ID: {
206 int status, id;
207 id = ndmp_door_get_int32(dec_ctx);
208 status = ndmpd_connect_kill_id(id);
209 if (status == -1) /* session not found */
210 ndmp_door_put_int32(enc_ctx,
211 NDMP_DOOR_SRV_SUCCESS);
212 else
213 ndmp_door_put_int32(enc_ctx,
214 NDMP_DOOR_SRV_SUCCESS);
215 ndmp_door_put_int32(enc_ctx, status);
216 break;
217 }
218
219 case NDMP_GET_STAT:
220 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
221 ndmp_door_put_uint32(enc_ctx, ndstat.ns_trun);
222 ndmp_door_put_uint32(enc_ctx, ndstat.ns_twait);
223 ndmp_door_put_uint32(enc_ctx, ndstat.ns_nbk);
224 ndmp_door_put_uint32(enc_ctx, ndstat.ns_nrs);
225 ndmp_door_put_uint32(enc_ctx, ndstat.ns_rfile);
226 ndmp_door_put_uint32(enc_ctx, ndstat.ns_wfile);
227 ndmp_door_put_uint64(enc_ctx, ndstat.ns_rdisk);
228 ndmp_door_put_uint64(enc_ctx, ndstat.ns_wdisk);
229 ndmp_door_put_uint64(enc_ctx, ndstat.ns_rtape);
230 ndmp_door_put_uint64(enc_ctx, ndstat.ns_wtape);
231 break;
232
233 default:
234 syslog(LOG_ERR,
235 "ndmp_door_server: Invalid request type 0x%x", req_type);
236 goto decode_error;
237 }
238
239 if ((dec_status = ndmp_door_decode_finish(dec_ctx)) != 0)
240 goto decode_error;
241
242 if ((enc_status = ndmp_door_encode_finish(enc_ctx, &used)) != 0)
243 goto encode_error;
244
245 (void) door_return(buf, used, NULL, 0);
246
247 return;
248
249 decode_error:
250 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_ERROR);
251 ndmp_door_put_uint32(enc_ctx, dec_status);
252 (void) ndmp_door_encode_finish(enc_ctx, &used);
253 (void) door_return(buf, used, NULL, 0);
254 return;
255
256 encode_error:
257 enc_ctx = ndmp_door_encode_start(buf, buflen);
258 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_ERROR);
259 ndmp_door_put_uint32(enc_ctx, enc_status);
260 (void) ndmp_door_encode_finish(enc_ctx, &used);
261 (void) door_return(buf, used, NULL, 0);
262 }