1 /*
2 * Copyright 2008 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 #include <locale.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <door.h>
45 #include <thread.h>
46 #include <ndmpd_door.h>
47 #include <libndmp.h>
48
49 static int ndmp_door_fildes = -1;
50 static char *buf;
51 static ndmp_door_ctx_t *dec_ctx;
52 static ndmp_door_ctx_t *enc_ctx;
53 static door_arg_t arg;
54 static mutex_t ndmp_lock = DEFAULTMUTEX;
55
56 static int ndmp_door_setup(int opcode);
57 static int ndmp_door_call(void);
58 static int ndmp_door_fini(void);
59
60 /* ndmp library APIs */
61 int
ndmp_get_devinfo(ndmp_devinfo_t ** dip,size_t * size)62 ndmp_get_devinfo(ndmp_devinfo_t **dip, size_t *size)
63 {
64 ndmp_devinfo_t *dipptr;
65 int i;
66 int opcode = NDMP_DEVICES_GET_INFO;
67
68 (void) mutex_lock(&ndmp_lock);
69 if (ndmp_door_setup(opcode))
70 goto err;
71
72 if (ndmp_door_call())
73 goto err;
74
75 /* get the number of devices available */
76 *size = ndmp_door_get_uint32(dec_ctx);
77
78 *dip = malloc(sizeof (ndmp_devinfo_t) * *size);
79 if (!*dip) {
80 free(buf);
81 ndmp_errno = ENDMP_MEM_ALLOC;
82 goto err;
83 }
84 dipptr = *dip;
85 for (i = 0; i < *size; i++, dipptr++) {
86 dipptr->nd_dev_type = ndmp_door_get_int32(dec_ctx);
87 dipptr->nd_name = ndmp_door_get_string(dec_ctx);
88 dipptr->nd_lun = ndmp_door_get_int32(dec_ctx);
89 dipptr->nd_sid = ndmp_door_get_int32(dec_ctx);
90 dipptr->nd_vendor = ndmp_door_get_string(dec_ctx);
91 dipptr->nd_product = ndmp_door_get_string(dec_ctx);
92 dipptr->nd_revision = ndmp_door_get_string(dec_ctx);
93 dipptr->nd_serial = ndmp_door_get_string(dec_ctx);
94 dipptr->nd_wwn = ndmp_door_get_string(dec_ctx);
95 }
96 if (ndmp_door_fini()) {
97 free(*dip);
98 goto err;
99 }
100 (void) mutex_unlock(&ndmp_lock);
101 return (0);
102 err:
103 (void) mutex_unlock(&ndmp_lock);
104 return (-1);
105 }
106
107 void
ndmp_get_devinfo_free(ndmp_devinfo_t * dip,size_t size)108 ndmp_get_devinfo_free(ndmp_devinfo_t *dip, size_t size)
109 {
110 ndmp_devinfo_t *dipptr;
111 int i;
112
113 dipptr = dip;
114 for (i = 0; i < size; i++, dipptr++) {
115 free(dipptr->nd_name);
116 free(dipptr->nd_vendor);
117 free(dipptr->nd_product);
118 free(dipptr->nd_revision);
119 }
120 free(dip);
121 }
122
123 int
ndmp_terminate_session(int session)124 ndmp_terminate_session(int session)
125 {
126 int ret;
127 int opcode = NDMP_TERMINATE_SESSION_ID;
128
129 (void) mutex_lock(&ndmp_lock);
130 if (ndmp_door_setup(opcode))
131 goto err;
132
133 ndmp_door_put_uint32(enc_ctx, session);
134 if (ndmp_door_call())
135 goto err;
136
137 ret = ndmp_door_get_uint32(dec_ctx);
138 if (ndmp_door_fini())
139 goto err;
140
141 (void) mutex_unlock(&ndmp_lock);
142 return (ret);
143 err:
144 (void) mutex_unlock(&ndmp_lock);
145 return (-1);
146 }
147
148 int
ndmp_get_session_info(ndmp_session_info_t ** sinfo,size_t * size)149 ndmp_get_session_info(ndmp_session_info_t **sinfo, size_t *size)
150 {
151 int status;
152 int i, j;
153 ndmp_session_info_t *sp;
154 ndmp_dt_pval_t *ep;
155 ndmp_dt_name_t *np;
156 ndmp_dt_name_v3_t *npv3;
157 int opcode = NDMP_SHOW;
158
159 (void) mutex_lock(&ndmp_lock);
160 if (ndmp_door_setup(opcode))
161 goto err;
162
163 if (ndmp_door_call())
164 goto err;
165
166 /* number of sessions */
167 *size = ndmp_door_get_int32(dec_ctx);
168
169 *sinfo = malloc((sizeof (ndmp_session_info_t)) * *size);
170 if (!*sinfo) {
171 free(buf);
172 ndmp_errno = ENDMP_MEM_ALLOC;
173 goto err;
174 }
175 sp = *sinfo;
176 for (i = 0; i < *size; i++, sp++) {
177 status = ndmp_door_get_int32(dec_ctx);
178 if (status == NDMP_SESSION_NODATA)
179 continue;
180
181 /* connection common info */
182 sp->nsi_sid = ndmp_door_get_int32(dec_ctx);
183 sp->nsi_pver = ndmp_door_get_int32(dec_ctx);
184 sp->nsi_auth = ndmp_door_get_int32(dec_ctx);
185 sp->nsi_eof = ndmp_door_get_int32(dec_ctx);
186 sp->nsi_cl_addr = ndmp_door_get_string(dec_ctx);
187 /*
188 * scsi and tape data are same for all version,
189 * so keep reading
190 */
191 /* connection common scsi info. */
192 sp->nsi_scsi.ns_scsi_open = ndmp_door_get_int32(dec_ctx);
193 sp->nsi_scsi.ns_adapter_name = ndmp_door_get_string(dec_ctx);
194 sp->nsi_scsi.ns_valid_target_set = ndmp_door_get_int32(dec_ctx);
195 if (sp->nsi_scsi.ns_valid_target_set) {
196 sp->nsi_scsi.ns_scsi_id = ndmp_door_get_int32(dec_ctx);
197 sp->nsi_scsi.ns_lun = ndmp_door_get_int32(dec_ctx);
198 }
199
200 /* connection common tape info. */
201 sp->nsi_tape.nt_fd = ndmp_door_get_int32(dec_ctx);
202 if (sp->nsi_tape.nt_fd != -1) {
203 sp->nsi_tape.nt_rec_count =
204 ndmp_door_get_uint64(dec_ctx);
205 sp->nsi_tape.nt_mode = ndmp_door_get_int32(dec_ctx);
206 sp->nsi_tape.nt_dev_name =
207 ndmp_door_get_string(dec_ctx);
208 sp->nsi_tape.nt_adapter_name =
209 ndmp_door_get_string(dec_ctx);
210 sp->nsi_tape.nt_sid = ndmp_door_get_int32(dec_ctx);
211 sp->nsi_tape.nt_lun = ndmp_door_get_int32(dec_ctx);
212 }
213 /* all the V2 mover data are same as V3/V4 */
214 sp->nsi_mover.nm_state = ndmp_door_get_int32(dec_ctx);
215 sp->nsi_mover.nm_mode = ndmp_door_get_int32(dec_ctx);
216 sp->nsi_mover.nm_pause_reason = ndmp_door_get_int32(dec_ctx);
217 sp->nsi_mover.nm_halt_reason = ndmp_door_get_int32(dec_ctx);
218 sp->nsi_mover.nm_rec_size = ndmp_door_get_uint64(dec_ctx);
219 sp->nsi_mover.nm_rec_num = ndmp_door_get_uint64(dec_ctx);
220 sp->nsi_mover.nm_mov_pos = ndmp_door_get_uint64(dec_ctx);
221 sp->nsi_mover.nm_window_offset = ndmp_door_get_uint64(dec_ctx);
222 sp->nsi_mover.nm_window_length = ndmp_door_get_uint64(dec_ctx);
223 sp->nsi_mover.nm_sock = ndmp_door_get_int32(dec_ctx);
224
225 /* Read V3/V4 mover info */
226 if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4)) {
227 sp->nsi_mover.nm_listen_sock =
228 ndmp_door_get_int32(dec_ctx);
229 sp->nsi_mover.nm_addr_type =
230 ndmp_door_get_int32(dec_ctx);
231 sp->nsi_mover.nm_tcp_addr =
232 ndmp_door_get_string(dec_ctx);
233 }
234
235 /* connection common data info */
236 sp->nsi_data.nd_oper = ndmp_door_get_int32(dec_ctx);
237 sp->nsi_data.nd_state = ndmp_door_get_int32(dec_ctx);
238 sp->nsi_data.nd_halt_reason = ndmp_door_get_int32(dec_ctx);
239 sp->nsi_data.nd_sock = ndmp_door_get_int32(dec_ctx);
240 sp->nsi_data.nd_addr_type = ndmp_door_get_int32(dec_ctx);
241 sp->nsi_data.nd_abort = ndmp_door_get_int32(dec_ctx);
242 sp->nsi_data.nd_read_offset = ndmp_door_get_uint64(dec_ctx);
243 sp->nsi_data.nd_read_length = ndmp_door_get_uint64(dec_ctx);
244 sp->nsi_data.nd_total_size = ndmp_door_get_uint64(dec_ctx);
245 sp->nsi_data.nd_env_len = ndmp_door_get_uint64(dec_ctx);
246 sp->nsi_data.nd_env =
247 malloc(sizeof (ndmp_dt_pval_t) * sp->nsi_data.nd_env_len);
248 if (!sp->nsi_data.nd_env) {
249 free(buf);
250 ndmp_errno = ENDMP_MEM_ALLOC;
251 goto err;
252 }
253 ep = sp->nsi_data.nd_env;
254 for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) {
255 ep->np_name = ndmp_door_get_string(dec_ctx);
256 ep->np_value = ndmp_door_get_string(dec_ctx);
257 }
258 sp->nsi_data.nd_tcp_addr = ndmp_door_get_string(dec_ctx);
259
260 /* Read V2 data info */
261 if (sp->nsi_pver == NDMP_V2) {
262 sp->nsi_data.nld_nlist_len =
263 ndmp_door_get_int64(dec_ctx);
264 sp->nsi_data.nd_nlist.nld_nlist =
265 malloc(sizeof (ndmp_dt_name_t) *
266 sp->nsi_data.nld_nlist_len);
267 if (!sp->nsi_data.nd_nlist.nld_nlist) {
268 free(buf);
269 ndmp_errno = ENDMP_MEM_ALLOC;
270 goto err;
271 }
272 np = sp->nsi_data.nd_nlist.nld_nlist;
273
274 for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) {
275 np->nn_name = ndmp_door_get_string(dec_ctx);
276 np->nn_dest = ndmp_door_get_string(dec_ctx);
277 }
278 } else if ((sp->nsi_pver == NDMP_V3) ||
279 (sp->nsi_pver == NDMP_V4)) {
280 /* Read V3/V4 data info */
281 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_listen_sock =
282 ndmp_door_get_int32(dec_ctx);
283 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_bytes_processed =
284 ndmp_door_get_uint64(dec_ctx);
285 sp->nsi_data.nld_nlist_len =
286 ndmp_door_get_uint64(dec_ctx);
287 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist =
288 malloc(sizeof (ndmp_dt_name_v3_t) *
289 sp->nsi_data.nld_nlist_len);
290 if (!sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist) {
291 free(buf);
292 ndmp_errno = ENDMP_MEM_ALLOC;
293 goto err;
294 }
295 npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist;
296 for (j = 0; j < sp->nsi_data.nld_nlist_len;
297 j++, npv3++) {
298 npv3->nn3_opath = ndmp_door_get_string(dec_ctx);
299 npv3->nn3_dpath = ndmp_door_get_string(dec_ctx);
300 npv3->nn3_node = ndmp_door_get_uint64(dec_ctx);
301 npv3->nn3_fh_info =
302 ndmp_door_get_uint64(dec_ctx);
303 }
304 }
305 }
306
307 if (ndmp_door_fini())
308 goto err;
309
310 (void) mutex_unlock(&ndmp_lock);
311 return (0);
312 err:
313 (void) mutex_unlock(&ndmp_lock);
314 return (-1);
315 }
316
317 void
ndmp_get_session_info_free(ndmp_session_info_t * sinfo,size_t size)318 ndmp_get_session_info_free(ndmp_session_info_t *sinfo, size_t size)
319 {
320 ndmp_session_info_t *sp;
321 ndmp_dt_pval_t *ep;
322 ndmp_dt_name_t *np;
323 ndmp_dt_name_v3_t *npv3;
324 int i, j;
325
326 sp = sinfo;
327 for (i = 0; i < size; i++, sp++) {
328 free(sp->nsi_cl_addr);
329 free(sp->nsi_scsi.ns_adapter_name);
330 if (sp->nsi_tape.nt_fd != -1) {
331 free(sp->nsi_tape.nt_dev_name);
332 free(sp->nsi_tape.nt_adapter_name);
333 }
334 if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4))
335 free(sp->nsi_mover.nm_tcp_addr);
336
337 ep = sp->nsi_data.nd_env;
338 for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) {
339 free(ep->np_name);
340 free(ep->np_value);
341 }
342 free(sp->nsi_data.nd_env);
343 free(sp->nsi_data.nd_tcp_addr);
344
345 if (sp->nsi_pver == NDMP_V2) {
346 np = sp->nsi_data.nd_nlist.nld_nlist;
347 for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) {
348 free(np->nn_name);
349 free(np->nn_dest);
350 }
351 free(sp->nsi_data.nd_nlist.nld_nlist);
352 } else if ((sp->nsi_pver == NDMP_V3) ||
353 (sp->nsi_pver == NDMP_V4)) {
354 npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist;
355 for (j = 0; j < sp->nsi_data.nld_nlist_len;
356 j++, npv3++) {
357 free(npv3->nn3_opath);
358 free(npv3->nn3_dpath);
359 }
360 free(sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist);
361 }
362 }
363 free(sinfo);
364 }
365
366 /* ARGSUSED */
367 int
ndmp_get_stats(ndmp_stat_t * statp)368 ndmp_get_stats(ndmp_stat_t *statp)
369 {
370 int opcode = NDMP_GET_STAT;
371
372 (void) mutex_lock(&ndmp_lock);
373 if (!statp) {
374 ndmp_errno = ENDMP_INVALID_ARG;
375 goto err;
376 }
377
378 if (ndmp_door_setup(opcode))
379 goto err;
380
381 if (ndmp_door_call())
382 goto err;
383
384 statp->ns_trun = ndmp_door_get_uint32(dec_ctx);
385 statp->ns_twait = ndmp_door_get_uint32(dec_ctx);
386 statp->ns_nbk = ndmp_door_get_uint32(dec_ctx);
387 statp->ns_nrs = ndmp_door_get_uint32(dec_ctx);
388 statp->ns_rfile = ndmp_door_get_uint32(dec_ctx);
389 statp->ns_wfile = ndmp_door_get_uint32(dec_ctx);
390 statp->ns_rdisk = ndmp_door_get_uint64(dec_ctx);
391 statp->ns_wdisk = ndmp_door_get_uint64(dec_ctx);
392 statp->ns_rtape = ndmp_door_get_uint64(dec_ctx);
393 statp->ns_wtape = ndmp_door_get_uint64(dec_ctx);
394
395 if (ndmp_door_fini())
396 goto err;
397
398 (void) mutex_unlock(&ndmp_lock);
399 return (0);
400 err:
401 (void) mutex_unlock(&ndmp_lock);
402 return (-1);
403 }
404
405 int
ndmp_door_status(void)406 ndmp_door_status(void)
407 {
408 int opcode = NDMP_GET_DOOR_STATUS;
409
410 (void) mutex_lock(&ndmp_lock);
411 if (ndmp_door_setup(opcode))
412 goto err;
413
414 if (ndmp_door_call())
415 goto err;
416
417 if (ndmp_door_fini())
418 goto err;
419
420 (void) mutex_unlock(&ndmp_lock);
421 return (0);
422 err:
423 (void) mutex_unlock(&ndmp_lock);
424 return (-1);
425 }
426
427 static int
ndmp_door_setup(int opcode)428 ndmp_door_setup(int opcode)
429 {
430 /* Open channel to NDMP service */
431 if ((ndmp_door_fildes == -1) &&
432 (ndmp_door_fildes = open(NDMP_DOOR_SVC, O_RDONLY)) < 0) {
433 ndmp_errno = ENDMP_DOOR_OPEN;
434 return (-1);
435 }
436
437 buf = malloc(NDMP_DOOR_SIZE);
438 if (!buf) {
439 ndmp_errno = ENDMP_MEM_ALLOC;
440 return (-1);
441 }
442
443 enc_ctx = ndmp_door_encode_start(buf, NDMP_DOOR_SIZE);
444 if (enc_ctx == 0) {
445 free(buf);
446 ndmp_errno = ENDMP_DOOR_ENCODE_START;
447 return (-1);
448 }
449 ndmp_door_put_uint32(enc_ctx, opcode);
450 return (0);
451 }
452
453 static int
ndmp_door_call(void)454 ndmp_door_call(void)
455 {
456 uint32_t used;
457 int rc;
458
459 if ((ndmp_door_encode_finish(enc_ctx, &used)) != 0) {
460 free(buf);
461 ndmp_errno = ENDMP_DOOR_ENCODE_FINISH;
462 return (-1);
463 }
464
465 arg.data_ptr = buf;
466 arg.data_size = used;
467 arg.desc_ptr = NULL;
468 arg.desc_num = 0;
469 arg.rbuf = buf;
470 arg.rsize = NDMP_DOOR_SIZE;
471
472 if (door_call(ndmp_door_fildes, &arg) < 0) {
473 free(buf);
474 ndmp_errno = ENDMP_DOOR_SRV_TIMEOUT;
475 (void) close(ndmp_door_fildes);
476 ndmp_door_fildes = -1;
477 return (-1);
478 }
479
480 dec_ctx = ndmp_door_decode_start(arg.data_ptr, arg.data_size);
481 rc = ndmp_door_get_uint32(dec_ctx);
482 if (rc != NDMP_DOOR_SRV_SUCCESS) {
483 free(buf);
484 ndmp_errno = ENDMP_DOOR_SRV_OPERATION;
485 return (-1);
486 }
487 return (0);
488 }
489
490 static int
ndmp_door_fini(void)491 ndmp_door_fini(void)
492 {
493 if ((ndmp_door_decode_finish(dec_ctx)) != 0) {
494 free(buf);
495 ndmp_errno = ENDMP_DOOR_DECODE_FINISH;
496 return (-1);
497 }
498 free(buf);
499 return (0);
500 }
501