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