]> git.proxmox.com Git - mirror_zfs-debian.git/blame - zfs/lib/libdmu-ctl/dctl_client.c
Remove stray stub kernel files which should be brought in my linux-kernel-module...
[mirror_zfs-debian.git] / zfs / lib / libdmu-ctl / dctl_client.c
CommitLineData
34dc7c2f
BB
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <ftw.h>
31#include <errno.h>
32#include <unistd.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/un.h>
36#include <sys/debug.h>
37
38#include <sys/dmu_ctl.h>
39#include <sys/dmu_ctl_impl.h>
40
41/*
42 * Try to connect to the socket given in path.
43 *
44 * For nftw() convenience, returns 0 if unsuccessful, otherwise
45 * returns the socket descriptor.
46 */
47static int try_connect(const char *path)
48{
49 struct sockaddr_un name;
50 int sock;
51
52 sock = socket(PF_UNIX, SOCK_STREAM, 0);
53 if (sock == -1) {
54 perror("socket");
55 return 0;
56 }
57
58 /*
59 * The socket fd cannot be 0 otherwise nftw() will not interpret the
60 * return code correctly.
61 */
62 VERIFY(sock != 0);
63
64 name.sun_family = AF_UNIX;
65 strncpy(name.sun_path, path, sizeof(name.sun_path));
66
67 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
68
69 if (connect(sock, (struct sockaddr *) &name, sizeof(name)) == -1) {
70 close(sock);
71 return 0;
72 }
73
74 return sock;
75}
76
77/*
78 * nftw() callback.
79 */
80static int nftw_cb(const char *fpath, const struct stat *sb, int typeflag,
81 struct FTW *ftwbuf)
82{
83 if (!S_ISSOCK(sb->st_mode))
84 return 0;
85
86 if (strcmp(&fpath[ftwbuf->base], SOCKNAME) != 0)
87 return 0;
88
89 return try_connect(fpath);
90}
91
92/*
93 * For convenience, if check_subdirs is true we walk the directory tree to
94 * find a good socket.
95 */
96int dctlc_connect(const char *dir, boolean_t check_subdirs)
97{
98 char *fpath;
99 int fd;
100
101 if (check_subdirs)
102 fd = nftw(dir, nftw_cb, 10, FTW_PHYS);
103 else {
104 fpath = malloc(strlen(dir) + strlen(SOCKNAME) + 2);
105 if (fpath == NULL)
106 return -1;
107
108 strcpy(fpath, dir);
109 strcat(fpath, "/" SOCKNAME);
110
111 fd = try_connect(fpath);
112
113 free(fpath);
114 }
115
116 return fd == 0 ? -1 : fd;
117}
118
119void dctlc_disconnect(int fd)
120{
121 (void) shutdown(fd, SHUT_RDWR);
122}
123
124static int dctl_reply_copyin(int fd, dctl_cmd_t *cmd)
125{
126 return dctl_send_data(fd, (void *)(uintptr_t) cmd->u.dcmd_copy.ptr,
127 cmd->u.dcmd_copy.size);
128}
129
130static int dctl_reply_copyinstr(int fd, dctl_cmd_t *cmd)
131{
132 dctl_cmd_t reply;
133 char *from;
134 size_t len, buflen, to_copy;
135 int error;
136
137 reply.dcmd_msg = DCTL_GEN_REPLY;
138
139 from = (char *)(uintptr_t) cmd->u.dcmd_copy.ptr;
140
141 buflen = cmd->u.dcmd_copy.size;
142 to_copy = strnlen(from, buflen - 1);
143
144 reply.u.dcmd_reply.rc = from[to_copy] == '\0' ? 0 : ENAMETOOLONG;
145 reply.u.dcmd_reply.size = to_copy;
146
147 error = dctl_send_msg(fd, &reply);
148
149 if (!error && to_copy > 0)
150 error = dctl_send_data(fd, from, to_copy);
151
152 return error;
153}
154
155static int dctl_reply_copyout(int fd, dctl_cmd_t *cmd)
156{
157 return dctl_read_data(fd, (void *)(uintptr_t) cmd->u.dcmd_copy.ptr,
158 cmd->u.dcmd_copy.size);
159}
160
161static int dctl_reply_fd_read(int fd, dctl_cmd_t *cmd)
162{
163 dctl_cmd_t reply;
164 void *buf;
165 int error;
166 ssize_t rrc, size = cmd->u.dcmd_fd_io.size;
167
168 buf = malloc(size);
169 if (buf == NULL)
170 return ENOMEM;
171
172 rrc = read(cmd->u.dcmd_fd_io.fd, buf, size);
173
174 reply.dcmd_msg = DCTL_GEN_REPLY;
175 reply.u.dcmd_reply.rc = rrc == -1 ? errno : 0;
176 reply.u.dcmd_reply.size = rrc;
177
178 error = dctl_send_msg(fd, &reply);
179
180 if (!error && rrc > 0)
181 error = dctl_send_data(fd, buf, rrc);
182
183out:
184 free(buf);
185
186 return error;
187}
188
189static int dctl_reply_fd_write(int fd, dctl_cmd_t *cmd)
190{
191 dctl_cmd_t reply;
192 void *buf;
193 int error;
194 ssize_t wrc, size = cmd->u.dcmd_fd_io.size;
195
196 buf = malloc(size);
197 if (buf == NULL)
198 return ENOMEM;
199
200 error = dctl_read_data(fd, buf, size);
201 if (error)
202 goto out;
203
204 wrc = write(cmd->u.dcmd_fd_io.fd, buf, size);
205
206 reply.dcmd_msg = DCTL_GEN_REPLY;
207 reply.u.dcmd_reply.rc = wrc == -1 ? errno : 0;
208 reply.u.dcmd_reply.size = wrc;
209
210 error = dctl_send_msg(fd, &reply);
211
212out:
213 free(buf);
214
215 return error;
216}
217
218int dctlc_ioctl(int fd, int32_t request, void *arg)
219{
220 int error;
221 dctl_cmd_t cmd;
222
223 ASSERT(fd != 0);
224
225 cmd.dcmd_msg = DCTL_IOCTL;
226
227 cmd.u.dcmd_ioctl.cmd = request;
228 cmd.u.dcmd_ioctl.arg = (uintptr_t) arg;
229
230 error = dctl_send_msg(fd, &cmd);
231
232 while (!error && (error = dctl_read_msg(fd, &cmd)) == 0) {
233 switch (cmd.dcmd_msg) {
234 case DCTL_IOCTL_REPLY:
235 error = cmd.u.dcmd_reply.rc;
236 goto out;
237 case DCTL_COPYIN:
238 error = dctl_reply_copyin(fd, &cmd);
239 break;
240 case DCTL_COPYINSTR:
241 error = dctl_reply_copyinstr(fd, &cmd);
242 break;
243 case DCTL_COPYOUT:
244 error = dctl_reply_copyout(fd, &cmd);
245 break;
246 case DCTL_FD_READ:
247 error = dctl_reply_fd_read(fd, &cmd);
248 break;
249 case DCTL_FD_WRITE:
250 error = dctl_reply_fd_write(fd, &cmd);
251 break;
252 default:
253 fprintf(stderr, "%s(): invalid message "
254 "received.\n", __func__);
255 error = EINVAL;
256 goto out;
257 }
258 }
259
260out:
261 errno = error;
262 return error ? -1 : 0;
263}