Whamcloud - gitweb
LU-6245 libcfs: remove libcfsutil.h
[fs/lustre-release.git] / libcfs / libcfs / util / l_ioctl.c
1 /*
2  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
3  *
4  * Copyright (c) 2014, Intel Corporation.
5  *
6  *   This file is part of Portals, http://www.sf.net/projects/lustre/
7  *
8  *   Portals is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Portals is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Portals; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define __USE_FILE_OFFSET64
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <linux/types.h>
36
37 #include <libcfs/util/ioctl.h>
38 #include <lnet/lnetctl.h>
39
40 struct ioc_dev {
41         const char * dev_name;
42         int dev_fd;
43         int dev_major;
44         int dev_minor;
45 };
46
47 static struct ioc_dev ioc_dev_list[10];
48
49 struct dump_hdr {
50         int magic;
51         int dev_id;
52         unsigned int opc;
53 };
54
55 /* Catamount has no <linux/kdev_t.h>, so just define it here */
56 #ifndef MKDEV
57 # define MKDEV(a,b) (((a) << 8) | (b))
58 #endif
59
60 static int
61 open_ioc_dev(int dev_id)
62 {
63         const char * dev_name;
64
65         if (dev_id < 0 ||
66             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
67                 return -EINVAL;
68
69         dev_name = ioc_dev_list[dev_id].dev_name;
70         if (dev_name == NULL) {
71                 fprintf(stderr, "unknown device id: %d\n", dev_id);
72                 return -EINVAL;
73         }
74
75         if (ioc_dev_list[dev_id].dev_fd < 0) {
76                 int fd = open(dev_name, O_RDWR);
77
78                 /* Make the /dev/ node if we need to */
79                 if (fd < 0 && errno == ENOENT) {
80                         if (mknod(dev_name, S_IFCHR|S_IWUSR|S_IRUSR,
81                                   MKDEV(ioc_dev_list[dev_id].dev_major,
82                                         ioc_dev_list[dev_id].dev_minor)) == 0)
83                                 fd = open(dev_name, O_RDWR);
84                         else
85                                 fprintf(stderr, "mknod %s failed: %s\n",
86                                         dev_name, strerror(errno));
87                 }
88
89                 if (fd < 0) {
90                         fprintf(stderr, "opening %s failed: %s\n"
91                                 "hint: the kernel modules may not be loaded\n",
92                                 dev_name, strerror(errno));
93                         return fd;
94                 }
95                 ioc_dev_list[dev_id].dev_fd = fd;
96         }
97
98         return ioc_dev_list[dev_id].dev_fd;
99 }
100
101
102 int l_ioctl(int dev_id, unsigned int opc, void *buf)
103 {
104         int fd, rc;
105
106         fd = open_ioc_dev(dev_id);
107         if (fd < 0)
108                 return fd;
109
110         rc = ioctl(fd, opc, buf);
111
112         return rc;
113 }
114
115 /* register a device to send ioctls to.  */
116 int
117 register_ioc_dev(int dev_id, const char *dev_name, int major, int minor)
118 {
119
120         if (dev_id < 0 ||
121             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
122                 return -EINVAL;
123
124         unregister_ioc_dev(dev_id);
125
126         ioc_dev_list[dev_id].dev_name = dev_name;
127         ioc_dev_list[dev_id].dev_fd = -1;
128         ioc_dev_list[dev_id].dev_major = major;
129         ioc_dev_list[dev_id].dev_minor = minor;
130
131         return dev_id;
132 }
133
134 void
135 unregister_ioc_dev(int dev_id)
136 {
137         if (dev_id < 0 ||
138             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
139                 return;
140
141         if (ioc_dev_list[dev_id].dev_name != NULL &&
142             ioc_dev_list[dev_id].dev_fd >= 0)
143                 close(ioc_dev_list[dev_id].dev_fd);
144
145         ioc_dev_list[dev_id].dev_name = NULL;
146         ioc_dev_list[dev_id].dev_fd = -1;
147 }
148
149 int libcfs_ioctl_pack(struct libcfs_ioctl_data *data, char **pbuf,
150                                     int max)
151 {
152         char *ptr;
153         struct libcfs_ioctl_data *overlay;
154         data->ioc_hdr.ioc_len = libcfs_ioctl_packlen(data);
155         data->ioc_hdr.ioc_version = LIBCFS_IOCTL_VERSION;
156
157         if (*pbuf != NULL && libcfs_ioctl_packlen(data) > max)
158                 return 1;
159         if (*pbuf == NULL)
160                 *pbuf = malloc(data->ioc_hdr.ioc_len);
161         if (*pbuf == NULL)
162                 return 1;
163         overlay = (struct libcfs_ioctl_data *)*pbuf;
164         memcpy(*pbuf, data, sizeof(*data));
165
166         ptr = overlay->ioc_bulk;
167         if (data->ioc_inlbuf1 != NULL) {
168                 memcpy((char *)ptr, (const char *)data->ioc_inlbuf1,
169                        data->ioc_inllen1);
170                 ptr += ((data->ioc_inllen1 + 7) & ~7);
171         }
172         if (data->ioc_inlbuf2 != NULL) {
173                 memcpy((char *)ptr, (const char *)data->ioc_inlbuf2,
174                        data->ioc_inllen2);
175                 ptr += ((data->ioc_inllen2 + 7) & ~7);
176         }
177
178         if (libcfs_ioctl_is_invalid(overlay))
179                 return 1;
180
181         return 0;
182 }
183
184 void
185 libcfs_ioctl_unpack(struct libcfs_ioctl_data *data, char *pbuf)
186 {
187         struct libcfs_ioctl_data *overlay = (struct libcfs_ioctl_data *)pbuf;
188         char *ptr;
189
190         /* Preserve the caller's buffer pointers */
191         overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
192         overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
193
194         memcpy(data, pbuf, sizeof(*data));
195         ptr = &overlay->ioc_bulk[0];
196
197         if (data->ioc_inlbuf1 != NULL) {
198                 memcpy((char *)data->ioc_inlbuf1, (const char *)ptr,
199                        data->ioc_inllen1);
200                 ptr += ((data->ioc_inllen1 + 7) & ~7);
201         }
202         if (data->ioc_inlbuf2 != NULL) {
203                 memcpy((char *)data->ioc_inlbuf2, (const char *)ptr,
204                        data->ioc_inllen2);
205                 ptr += ((data->ioc_inllen2 + 7) & ~7);
206         }
207 }