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
40/* This file contains all the door server code */
41
42#include <door.h>
43#include <alloca.h>
44#include <errno.h>
45#include <note.h>
46#include <libintl.h>
47#include <ndmpd_door.h>
48#include "ndmpd.h"
49
50/* static variables */
51static int 	ndmp_door_fildes = -1;
52static mutex_t	ndmp_doorsrv_mutex;
53
54/* static routines */
55static void ndmp_door_server(void *cookie, char *ptr, size_t size,
56    door_desc_t *dp, uint_t n_desc);
57
58/*
59 * Statistics used in ndmpstat command
60 */
61ndmp_stat_t ndstat;
62
63int
64ndmp_door_init(void)
65{
66	int fd;
67
68	(void) mutex_lock(&ndmp_doorsrv_mutex);
69
70	if (ndmp_door_fildes != -1) {
71		NDMP_LOG(LOG_DEBUG,
72		    "ndmp_door_init: ndmpd service is already running.");
73		(void) mutex_unlock(&ndmp_doorsrv_mutex);
74		return (0);
75	}
76
77	if ((ndmp_door_fildes = door_create(ndmp_door_server,
78	    NULL, DOOR_UNREF)) < 0) {
79		NDMP_LOG(LOG_DEBUG, "ndmp_door_init: Could not create door.");
80		(void) mutex_unlock(&ndmp_doorsrv_mutex);
81		return (-1);
82	}
83
84	(void) unlink(NDMP_DOOR_SVC);
85
86	if ((fd = creat(NDMP_DOOR_SVC, 0444)) < 0) {
87		NDMP_LOG(LOG_DEBUG, "ndmp_door_init: Can't create %s: %m.",
88		    NDMP_DOOR_SVC);
89		(void) door_revoke(ndmp_door_fildes);
90		ndmp_door_fildes = -1;
91		(void) mutex_unlock(&ndmp_doorsrv_mutex);
92		return (-1);
93	}
94
95	(void) close(fd);
96	(void) fdetach(NDMP_DOOR_SVC);
97
98	if (fattach(ndmp_door_fildes, NDMP_DOOR_SVC) < 0) {
99		NDMP_LOG(LOG_DEBUG, "ndmp_door_init: fattach failed %m");
100		(void) door_revoke(ndmp_door_fildes);
101		ndmp_door_fildes = -1;
102		(void) mutex_unlock(&ndmp_doorsrv_mutex);
103		return (-1);
104	}
105
106	NDMP_LOG(LOG_DEBUG, "ndmp_door_init: Door server successfully started");
107	(void) mutex_unlock(&ndmp_doorsrv_mutex);
108	return (0);
109}
110
111void
112ndmp_door_fini(void)
113{
114	(void) mutex_lock(&ndmp_doorsrv_mutex);
115
116	if (ndmp_door_fildes != -1) {
117		(void) fdetach(NDMP_DOOR_SVC);
118		(void) door_revoke(ndmp_door_fildes);
119		ndmp_door_fildes = -1;
120	}
121
122	(void) mutex_unlock(&ndmp_doorsrv_mutex);
123}
124
125boolean_t
126ndmp_door_check(void)
127{
128	door_info_t info;
129	int door;
130
131	if ((door = open(NDMP_DOOR_SVC, O_RDONLY)) < 0)
132		return (0);
133
134	if (door_info(door, &info) < 0) {
135		(void) close(door);
136		return (0);
137	}
138
139	if (info.di_target > 0) {
140		NDMP_LOG(LOG_ERR,
141		    "Service already running: pid %ld", info.di_target);
142		(void) close(door);
143		return (1);
144	}
145
146	(void) close(door);
147	return (0);
148}
149
150/* door server */
151/*ARGSUSED*/
152void
153ndmp_door_server(void *cookie, char *ptr, size_t size,
154    door_desc_t *dp, uint_t n_desc)
155{
156	NOTE(ARGUNUSED(cookie,dp,n_desc))
157	int req_type;
158	char *buf;
159	int buflen;
160	unsigned int used;
161	ndmp_door_ctx_t *dec_ctx;
162	ndmp_door_ctx_t *enc_ctx;
163	unsigned int dec_status;
164	unsigned int enc_status;
165
166	dec_ctx = ndmp_door_decode_start(ptr, size);
167	if (dec_ctx == 0)
168		return;
169
170	req_type = ndmp_door_get_uint32(dec_ctx);
171	buflen = NDMP_DOOR_SIZE;
172
173	if ((buf = alloca(buflen)) == NULL) {
174		NDMP_LOG(LOG_DEBUG, "Out of memory.");
175		(void) ndmp_door_decode_finish(dec_ctx);
176		return;
177	}
178
179	enc_ctx = ndmp_door_encode_start(buf, buflen);
180	if (enc_ctx == 0) {
181		(void) ndmp_door_decode_finish(dec_ctx);
182		return;
183	}
184
185	if (req_type != NDMP_GET_STAT)
186		NDMP_LOG(LOG_DEBUG, "ndmp_door_server: req_type=%d", req_type);
187
188	switch (req_type) {
189	case NDMP_GET_DOOR_STATUS: {
190		ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
191		break;
192		}
193	case NDMP_DEVICES_GET_INFO: {
194		ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
195		ndmpd_get_devs(enc_ctx);
196		break;
197		}
198	case NDMP_SHOW: {
199		ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
200		ndmp_connect_list_get(enc_ctx);
201		break;
202		}
203	case NDMP_TERMINATE_SESSION_ID: {
204		int status, id;
205		id = ndmp_door_get_int32(dec_ctx);
206		status = ndmpd_connect_kill_id(id);
207		if (status == -1) /* session not found */
208			ndmp_door_put_int32(enc_ctx,
209			    NDMP_DOOR_SRV_SUCCESS);
210		else
211			ndmp_door_put_int32(enc_ctx,
212			    NDMP_DOOR_SRV_SUCCESS);
213		ndmp_door_put_int32(enc_ctx, status);
214		break;
215		}
216
217	case NDMP_GET_STAT:
218		ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
219		ndmp_door_put_uint32(enc_ctx, ndstat.ns_trun);
220		ndmp_door_put_uint32(enc_ctx, ndstat.ns_twait);
221		ndmp_door_put_uint32(enc_ctx, ndstat.ns_nbk);
222		ndmp_door_put_uint32(enc_ctx, ndstat.ns_nrs);
223		ndmp_door_put_uint32(enc_ctx, ndstat.ns_rfile);
224		ndmp_door_put_uint32(enc_ctx, ndstat.ns_wfile);
225		ndmp_door_put_uint64(enc_ctx, ndstat.ns_rdisk);
226		ndmp_door_put_uint64(enc_ctx, ndstat.ns_wdisk);
227		ndmp_door_put_uint64(enc_ctx, ndstat.ns_rtape);
228		ndmp_door_put_uint64(enc_ctx, ndstat.ns_wtape);
229		break;
230
231	default:
232		NDMP_LOG(LOG_DEBUG,
233		    "ndmp_door_server: Invalid request type 0x%x", req_type);
234		goto decode_error;
235	}
236
237	if ((dec_status = ndmp_door_decode_finish(dec_ctx)) != 0)
238		goto decode_error;
239
240	if ((enc_status = ndmp_door_encode_finish(enc_ctx, &used)) != 0)
241		goto encode_error;
242
243	(void) door_return(buf, used, NULL, 0);
244
245	return;
246
247decode_error:
248	ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_ERROR);
249	ndmp_door_put_uint32(enc_ctx, dec_status);
250	(void) ndmp_door_encode_finish(enc_ctx, &used);
251	(void) door_return(buf, used, NULL, 0);
252	return;
253
254encode_error:
255	enc_ctx = ndmp_door_encode_start(buf, buflen);
256	ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_ERROR);
257	ndmp_door_put_uint32(enc_ctx, enc_status);
258	(void) ndmp_door_encode_finish(enc_ctx, &used);
259	(void) door_return(buf, used, NULL, 0);
260}
261