1 /*        $NetBSD: vnconfig.c,v 1.48 2018/10/07 20:30:50 wiz Exp $    */
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1993 University of Utah.
34  * Copyright (c) 1990, 1993
35  *        The Regents of the University of California.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * the Systems Programming Group of the University of Utah Computer
39  * Science Department.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
66  *
67  *        @(#)vnconfig.c      8.1 (Berkeley) 12/15/93
68  */
69 
70 #include <sys/param.h>
71 #include <sys/ioctl.h>
72 #include <sys/mount.h>
73 #include <sys/buf.h>
74 #include <sys/disklabel.h>
75 #include <sys/disk.h>
76 
77 #include <dev/vndvar.h>
78 
79 #include <disktab.h>
80 #include <err.h>
81 #include <errno.h>
82 #include <fcntl.h>
83 #include <stddef.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88 #include <util.h>
89 #include <paths.h>
90 #include <limits.h>
91 
92 #define VND_CONFIG  1
93 #define VND_UNCONFIG          2
94 #define VND_GET               3
95 
96 /* with -l we always print at least this many entries */
97 #define   DUMMY_FREE          4
98 
99 static int          verbose = 0;
100 static int          readonly = 0;
101 static int          fileio = 0;
102 static int          force = 0;
103 static int          compressed = 0;
104 static int          minimum = DUMMY_FREE;
105 static char         *tabname;
106 
107 static int          show(int, int, const char * const);
108 static int          config(char *, char *, char *, int);
109 static int          getgeom(struct vndgeom *, char *);
110 __dead static void  usage(void);
111 static void         show_unused(int);
112 
113 int
main(int argc,char * argv[])114 main(int argc, char *argv[])
115 {
116           int ch, rv, action = VND_CONFIG;
117           char *end;
118           unsigned long cnt;
119 
120           while ((ch = getopt(argc, argv, "Fcf:lm:rit:uvz")) != -1) {
121                     switch (ch) {
122                     case 'F':
123                               force = 1;
124                               break;
125                     case 'c':
126                               action = VND_CONFIG;
127                               break;
128                     case 'f':
129                               if (setdisktab(optarg) == -1)
130                                         usage();
131                               break;
132                     case 'l':
133                               action = VND_GET;
134                               break;
135                     case 'm':
136                               cnt = strtoul(optarg, &end, 10);
137                               if (cnt >= INT_MAX || end == optarg || *end != '\0')
138                                         usage();
139                               minimum = (int)cnt;
140                               break;
141                     case 'r':
142                               readonly = 1;
143                               break;
144                     case 'i':
145                               fileio = 1;
146                               break;
147                     case 't':
148                               tabname = optarg;
149                               break;
150                     case 'u':
151                               action = VND_UNCONFIG;
152                               break;
153                     case 'v':
154                               verbose = 1;
155                               break;
156                     case 'z':
157                               compressed = 1;
158                               readonly = 1;
159                               break;
160                     default:
161                     case '?':
162                               usage();
163                               /* NOTREACHED */
164                     }
165           }
166           argc -= optind;
167           argv += optind;
168 
169           if (action == VND_CONFIG) {
170                     if ((argc < 2 || argc > 3) ||
171                         (argc == 3 && tabname != NULL))
172                               usage();
173                     rv = config(argv[0], argv[1], (argc == 3) ? argv[2] : NULL,
174                         action);
175           } else if (action == VND_UNCONFIG) {
176                     if (argc != 1 || tabname != NULL)
177                               usage();
178                     rv = config(argv[0], NULL, NULL, action);
179           } else { /* VND_GET */
180                     int n, vdisk;
181                     const char *vn;
182                     char path[64];
183 
184                     if (argc == 0) {
185                               vn = "vnd0";
186 
187                               vdisk = opendisk(vn, O_RDONLY, path, sizeof(path), 0);
188                               if (vdisk == -1) {
189                                         if (minimum == 0)
190                                                   return 1;
191                                         err(1, "open: %s", vn);
192                               }
193 
194                               for (n = 0; show(vdisk, n, 0); n++)
195                                         continue;
196                               while (n < minimum)
197                                         show_unused(n++);
198                               close(vdisk);
199                               return 0;
200                     }
201 
202                     rv = 0;
203                     while (--argc >= 0) {
204                               vn = *argv++;
205 
206                               vdisk = opendisk(vn, O_RDONLY, path, sizeof(path), 0);
207                               if (vdisk == -1) {
208                                         warn("open: %s", vn);
209                                         rv = 1;
210                                         continue;
211                               }
212 
213                               if (!show(vdisk, -1, vn))
214                                         rv = 1;
215                               close(vdisk);
216                     }
217           }
218           return rv;
219 }
220 
221 static void
show_unused(int n)222 show_unused(int n)
223 {
224           if (minimum == 0)
225                     return;
226 
227           printf("vnd%d: not in use\n", n);
228 }
229 
230 static int
show(int v,int n,const char * const name)231 show(int v, int n, const char * const name)
232 {
233           struct vnd_user vnu;
234           char *dev;
235           struct statvfs *mnt;
236           int i, nmount;
237 
238           vnu.vnu_unit = n;
239           if (ioctl(v, VNDIOCGET, &vnu) == -1) {
240                     if (errno != ENXIO) {
241                               if (n != -1)
242                                         err(1, "VNDIOCGET");
243                               warn("%s: VNDIOCGET", name);
244                     }
245                     return 0;
246           }
247 
248           if (vnu.vnu_ino == 0) {
249                     show_unused(vnu.vnu_unit);
250                     return -1;
251           }
252 
253           printf("vnd%d: ", vnu.vnu_unit);
254 
255           dev = devname(vnu.vnu_dev, S_IFBLK);
256           if (dev != NULL)
257                     nmount = getmntinfo(&mnt, MNT_NOWAIT);
258           else {
259                     mnt = NULL;
260                     nmount = 0;
261           }
262 
263           if (mnt != NULL) {
264                     for (i = 0; i < nmount; i++) {
265                               if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) == 0 &&
266                                   strcmp(mnt[i].f_mntfromname + 5, dev) == 0)
267                                         break;
268                     }
269                     if (i < nmount)
270                               printf("%s (%s) ", mnt[i].f_mntonname,
271                                   mnt[i].f_mntfromname);
272                     else
273                               printf("%s ", dev);
274           }
275           else if (dev != NULL)
276                     printf("%s ", dev);
277           else
278                     printf("dev %llu,%llu ",
279                         (unsigned long long)major(vnu.vnu_dev),
280                         (unsigned long long)minor(vnu.vnu_dev));
281 
282           printf("inode %llu\n", (unsigned long long)vnu.vnu_ino);
283           return 1;
284 }
285 
286 static int
config(char * dev,char * file,char * geom,int action)287 config(char *dev, char *file, char *geom, int action)
288 {
289           struct vnd_ioctl vndio;
290           struct disklabel *lp;
291           char rdev[MAXPATHLEN + 1];
292           int fd, rv;
293 
294           fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0);
295           if (fd < 0) {
296                     warn("%s: opendisk", rdev);
297                     return (1);
298           }
299 
300           memset(&vndio, 0, sizeof(vndio));
301 #ifdef __GNUC__
302           rv = 0;                       /* XXX */
303 #endif
304 
305           vndio.vnd_file = file;
306           if (geom != NULL) {
307                     rv = getgeom(&vndio.vnd_geom, geom);
308                     if (rv != 0)
309                               errx(1, "invalid geometry: %s", geom);
310                     vndio.vnd_flags = VNDIOF_HASGEOM;
311           } else if (tabname != NULL) {
312                     lp = getdiskbyname(tabname);
313                     if (lp == NULL)
314                               errx(1, "unknown disk type: %s", tabname);
315                     vndio.vnd_geom.vng_secsize = lp->d_secsize;
316                     vndio.vnd_geom.vng_nsectors = lp->d_nsectors;
317                     vndio.vnd_geom.vng_ntracks = lp->d_ntracks;
318                     vndio.vnd_geom.vng_ncylinders = lp->d_ncylinders;
319                     vndio.vnd_flags = VNDIOF_HASGEOM;
320           }
321 
322           if (readonly)
323                     vndio.vnd_flags |= VNDIOF_READONLY;
324 
325           if (compressed)
326                     vndio.vnd_flags |= VNF_COMP;
327 
328           if (fileio)
329                     vndio.vnd_flags |= VNDIOF_FILEIO;
330 
331           /*
332            * Clear (un-configure) the device
333            */
334           if (action == VND_UNCONFIG) {
335                     if (force)
336                               vndio.vnd_flags |= VNDIOF_FORCE;
337                     rv = ioctl(fd, VNDIOCCLR, &vndio);
338 #ifdef VNDIOOCCLR
339                     if (rv && errno == ENOTTY)
340                               rv = ioctl(fd, VNDIOOCCLR, &vndio);
341 #endif
342                     if (rv)
343                               warn("%s: VNDIOCCLR", rdev);
344                     else if (verbose)
345                               printf("%s: cleared\n", rdev);
346           }
347           /*
348            * Configure the device
349            */
350           if (action == VND_CONFIG) {
351                     int       ffd;
352 
353                     ffd = open(file, readonly ? O_RDONLY : O_RDWR);
354                     if (ffd < 0) {
355                               warn("%s", file);
356                               rv = -1;
357                     } else {
358                               (void) close(ffd);
359 
360                               rv = ioctl(fd, VNDIOCSET, &vndio);
361 #ifdef VNDIOOCSET
362                               if (rv && errno == ENOTTY) {
363                                         rv = ioctl(fd, VNDIOOCSET, &vndio);
364                                         vndio.vnd_size = vndio.vnd_osize;
365                               }
366 #endif
367                               if (rv)
368                                         warn("%s: VNDIOCSET", rdev);
369                               else if (verbose) {
370                                         printf("%s: %" PRIu64 " bytes on %s", rdev,
371                                             vndio.vnd_size, file);
372                                         if (vndio.vnd_flags & VNDIOF_HASGEOM)
373                                                   printf(" using geometry %d/%d/%d/%d",
374                                                       vndio.vnd_geom.vng_secsize,
375                                                       vndio.vnd_geom.vng_nsectors,
376                                                       vndio.vnd_geom.vng_ntracks,
377                                             vndio.vnd_geom.vng_ncylinders);
378                                         printf("\n");
379                               }
380                     }
381           }
382 
383           (void) close(fd);
384           fflush(stdout);
385           return (rv < 0);
386 }
387 
388 static int
getgeom(struct vndgeom * vng,char * cp)389 getgeom(struct vndgeom *vng, char *cp)
390 {
391           char *secsize, *nsectors, *ntracks, *ncylinders;
392 
393 #define   GETARG(arg) \
394           do { \
395                     if (cp == NULL || *cp == '\0') \
396                               return (1); \
397                     arg = strsep(&cp, "/"); \
398                     if (arg == NULL) \
399                               return (1); \
400           } while (0)
401 
402           GETARG(secsize);
403           GETARG(nsectors);
404           GETARG(ntracks);
405           GETARG(ncylinders);
406 
407 #undef GETARG
408 
409           /* Too many? */
410           if (cp != NULL)
411                     return (1);
412 
413 #define   CVTARG(str, num) \
414           do { \
415                     num = strtol(str, &cp, 10); \
416                     if (*cp != '\0') \
417                               return (1); \
418           } while (0)
419 
420           CVTARG(secsize, vng->vng_secsize);
421           CVTARG(nsectors, vng->vng_nsectors);
422           CVTARG(ntracks, vng->vng_ntracks);
423           CVTARG(ncylinders, vng->vng_ncylinders);
424 
425 #undef CVTARG
426 
427           return (0);
428 }
429 
430 static void
usage(void)431 usage(void)
432 {
433           const char *p = getprogname();
434           (void)fprintf(stderr,
435               "Usage: %s [-cirvz] [-f dsktab] [-t type] vnode_disk"
436                     " reg-file [geomspec]\n"
437               "       %s -u [-Fv] vnode_disk\n"
438               "       %s -l [-m num | vnode_disk...]\n", p, p, p);
439           exit(1);
440 }
441