17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51d8ed0f0Svikram * Common Development and Distribution License (the "License"). 61d8ed0f0Svikram * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 223d7072f8Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 231d8ed0f0Svikram * Use is subject to license terms. 243d7072f8Seschrock */ 253d7072f8Seschrock 263d7072f8Seschrock /* 277c478bd9Sstevel@tonic-gate * lofiadm - administer lofi(7d). Very simple, add and remove file<->device 287c478bd9Sstevel@tonic-gate * associations, and display status. All the ioctls are private between 297c478bd9Sstevel@tonic-gate * lofi and lofiadm, and so are very simple - device information is 307c478bd9Sstevel@tonic-gate * communicated via a minor number. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/param.h> 377c478bd9Sstevel@tonic-gate #include <sys/lofi.h> 387c478bd9Sstevel@tonic-gate #include <sys/stat.h> 39*87117650Saalok #include <netinet/in.h> 407c478bd9Sstevel@tonic-gate #include <stdio.h> 417c478bd9Sstevel@tonic-gate #include <fcntl.h> 427c478bd9Sstevel@tonic-gate #include <locale.h> 437c478bd9Sstevel@tonic-gate #include <string.h> 44*87117650Saalok #include <strings.h> 457c478bd9Sstevel@tonic-gate #include <errno.h> 467c478bd9Sstevel@tonic-gate #include <stdlib.h> 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate #include <stropts.h> 491d8ed0f0Svikram #include <libdevinfo.h> 50*87117650Saalok #include <libgen.h> 51*87117650Saalok #include <ctype.h> 52*87117650Saalok #include <zlib.h> 537c478bd9Sstevel@tonic-gate #include "utils.h" 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate static const char USAGE[] = 567c478bd9Sstevel@tonic-gate "Usage: %s -a file [ device ]\n" 577c478bd9Sstevel@tonic-gate " %s -d file | device \n" 58*87117650Saalok " %s -C [algorithm] [-s segment_size] file \n" 59*87117650Saalok " %s -U file \n" 607c478bd9Sstevel@tonic-gate " %s [ device | file ]\n"; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static const char *pname; 637c478bd9Sstevel@tonic-gate static int addflag = 0; 647c478bd9Sstevel@tonic-gate static int deleteflag = 0; 657c478bd9Sstevel@tonic-gate static int errflag = 0; 66*87117650Saalok static int compressflag = 0; 67*87117650Saalok static int uncompressflag = 0; 687c478bd9Sstevel@tonic-gate 69*87117650Saalok static int gzip_compress(void *src, size_t srclen, void *dst, 70*87117650Saalok size_t *destlen, int level); 71*87117650Saalok 72*87117650Saalok lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = { 73*87117650Saalok {NULL, gzip_compress, 6, "gzip"}, /* default */ 74*87117650Saalok {NULL, gzip_compress, 6, "gzip-6"}, 75*87117650Saalok {NULL, gzip_compress, 9, "gzip-9"} 76*87117650Saalok }; 77*87117650Saalok 78*87117650Saalok #define FORMAT "%-20s %-30s %s\n" 79*87117650Saalok #define NONE "-" 80*87117650Saalok #define COMPRESS "Compressed" 81*87117650Saalok #define COMPRESS_ALGORITHM "gzip" 82*87117650Saalok #define COMPRESS_THRESHOLD 2048 83*87117650Saalok #define SEGSIZE 131072 84*87117650Saalok #define BLOCK_SIZE 512 85*87117650Saalok #define KILOBYTE 1024 86*87117650Saalok #define MEGABYTE (KILOBYTE * KILOBYTE) 87*87117650Saalok #define GIGABYTE (KILOBYTE * MEGABYTE) 88*87117650Saalok 89*87117650Saalok static int gzip_compress(void *src, size_t srclen, void *dst, 90*87117650Saalok size_t *dstlen, int level) 91*87117650Saalok { 92*87117650Saalok if (compress2(dst, (ulong_t *)dstlen, src, srclen, level) != Z_OK) 93*87117650Saalok return (-1); 94*87117650Saalok 95*87117650Saalok return (0); 96*87117650Saalok } 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Print the list of all the mappings. Including a header. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate static void 1027c478bd9Sstevel@tonic-gate print_mappings(int fd) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 1057c478bd9Sstevel@tonic-gate int minor; 1067c478bd9Sstevel@tonic-gate int maxminor; 107*87117650Saalok char path[MAXPATHLEN]; 108*87117650Saalok char options[MAXPATHLEN]; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate li.li_minor = 0; 1117c478bd9Sstevel@tonic-gate if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) { 1127c478bd9Sstevel@tonic-gate perror("ioctl"); 1137c478bd9Sstevel@tonic-gate exit(E_ERROR); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate maxminor = li.li_minor; 1177c478bd9Sstevel@tonic-gate 118*87117650Saalok (void) printf(FORMAT, "Block Device", "File", "Options"); 1197c478bd9Sstevel@tonic-gate for (minor = 1; minor <= maxminor; minor++) { 1207c478bd9Sstevel@tonic-gate li.li_minor = minor; 1217c478bd9Sstevel@tonic-gate if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) { 1227c478bd9Sstevel@tonic-gate if (errno == ENXIO) 1237c478bd9Sstevel@tonic-gate continue; 1247c478bd9Sstevel@tonic-gate perror("ioctl"); 1257c478bd9Sstevel@tonic-gate break; 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "/dev/%s/%d", 1287c478bd9Sstevel@tonic-gate LOFI_BLOCK_NAME, minor); 129*87117650Saalok if (li.li_algorithm[0] == '\0') 130*87117650Saalok (void) snprintf(options, sizeof (options), "%s", NONE); 131*87117650Saalok else 132*87117650Saalok (void) snprintf(options, sizeof (options), 133*87117650Saalok COMPRESS "(%s)", li.li_algorithm); 134*87117650Saalok 135*87117650Saalok (void) printf(FORMAT, path, li.li_filename, options); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static void 1407c478bd9Sstevel@tonic-gate usage(void) 1417c478bd9Sstevel@tonic-gate { 142*87117650Saalok (void) fprintf(stderr, gettext(USAGE), pname, pname, 143*87117650Saalok pname, pname, pname); 1447c478bd9Sstevel@tonic-gate exit(E_USAGE); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* 1487c478bd9Sstevel@tonic-gate * Translate a lofi device name to a minor number. We might be asked 1497c478bd9Sstevel@tonic-gate * to do this when there is no association (such as when the user specifies 1507c478bd9Sstevel@tonic-gate * a particular device), so we can only look at the string. 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate static int 1537c478bd9Sstevel@tonic-gate name_to_minor(const char *devicename) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate int minor; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor) == 1) { 1587c478bd9Sstevel@tonic-gate return (minor); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate if (sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor) == 1) { 1617c478bd9Sstevel@tonic-gate return (minor); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate return (0); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* 1677c478bd9Sstevel@tonic-gate * This might be the first time we've used this minor number. If so, 1687c478bd9Sstevel@tonic-gate * it might also be that the /dev links are in the process of being created 1697c478bd9Sstevel@tonic-gate * by devfsadmd (or that they'll be created "soon"). We cannot return 1707c478bd9Sstevel@tonic-gate * until they're there or the invoker of lofiadm might try to use them 1717c478bd9Sstevel@tonic-gate * and not find them. This can happen if a shell script is running on 1727c478bd9Sstevel@tonic-gate * an MP. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static int sleeptime = 2; /* number of seconds to sleep between stat's */ 1757c478bd9Sstevel@tonic-gate static int maxsleep = 120; /* maximum number of seconds to sleep */ 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static void 1787c478bd9Sstevel@tonic-gate wait_until_dev_complete(int minor) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate struct stat64 buf; 1817c478bd9Sstevel@tonic-gate int cursleep; 182*87117650Saalok char blkpath[MAXPATHLEN]; 183*87117650Saalok char charpath[MAXPATHLEN]; 1841d8ed0f0Svikram di_devlink_handle_t hdl; 1851d8ed0f0Svikram 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate (void) snprintf(blkpath, sizeof (blkpath), "/dev/%s/%d", 1887c478bd9Sstevel@tonic-gate LOFI_BLOCK_NAME, minor); 1897c478bd9Sstevel@tonic-gate (void) snprintf(charpath, sizeof (charpath), "/dev/%s/%d", 1907c478bd9Sstevel@tonic-gate LOFI_CHAR_NAME, minor); 1911d8ed0f0Svikram 1921d8ed0f0Svikram /* Check if links already present */ 1931d8ed0f0Svikram if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0) 1941d8ed0f0Svikram return; 1951d8ed0f0Svikram 1961d8ed0f0Svikram /* First use di_devlink_init() */ 1971d8ed0f0Svikram if (hdl = di_devlink_init("lofi", DI_MAKE_LINK)) { 1981d8ed0f0Svikram (void) di_devlink_fini(&hdl); 1991d8ed0f0Svikram goto out; 2001d8ed0f0Svikram } 2011d8ed0f0Svikram 2021d8ed0f0Svikram /* 2031d8ed0f0Svikram * Under normal conditions, di_devlink_init(DI_MAKE_LINK) above will 2041d8ed0f0Svikram * only fail if the caller is non-root. In that case, wait for 2051d8ed0f0Svikram * link creation via sysevents. 2061d8ed0f0Svikram */ 2077c478bd9Sstevel@tonic-gate cursleep = 0; 2087c478bd9Sstevel@tonic-gate while (cursleep < maxsleep) { 2097c478bd9Sstevel@tonic-gate if ((stat64(blkpath, &buf) == -1) || 2107c478bd9Sstevel@tonic-gate (stat64(charpath, &buf) == -1)) { 2117c478bd9Sstevel@tonic-gate (void) sleep(sleeptime); 2127c478bd9Sstevel@tonic-gate cursleep += sleeptime; 2137c478bd9Sstevel@tonic-gate continue; 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate return; 2167c478bd9Sstevel@tonic-gate } 2171d8ed0f0Svikram 2187c478bd9Sstevel@tonic-gate /* one last try */ 2191d8ed0f0Svikram 2201d8ed0f0Svikram out: 2217c478bd9Sstevel@tonic-gate if (stat64(blkpath, &buf) == -1) { 2227c478bd9Sstevel@tonic-gate die(gettext("%s was not created"), blkpath); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate if (stat64(charpath, &buf) == -1) { 2257c478bd9Sstevel@tonic-gate die(gettext("%s was not created"), charpath); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Add a device association. If devicename is NULL, let the driver 2317c478bd9Sstevel@tonic-gate * pick a device. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate static void 234*87117650Saalok add_mapping(int lfd, const char *devicename, const char *filename, 235*87117650Saalok int *minor_created, int suppress) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 2387c478bd9Sstevel@tonic-gate int minor; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (devicename == NULL) { 2417c478bd9Sstevel@tonic-gate /* pick one */ 2427c478bd9Sstevel@tonic-gate li.li_minor = 0; 243*87117650Saalok (void) strlcpy(li.li_filename, filename, 244*87117650Saalok sizeof (li.li_filename)); 2457c478bd9Sstevel@tonic-gate minor = ioctl(lfd, LOFI_MAP_FILE, &li); 2467c478bd9Sstevel@tonic-gate if (minor == -1) { 2477c478bd9Sstevel@tonic-gate die(gettext("could not map file %s"), filename); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate wait_until_dev_complete(minor); 2507c478bd9Sstevel@tonic-gate /* print one picked */ 251*87117650Saalok if (!suppress) 2527c478bd9Sstevel@tonic-gate (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor); 253*87117650Saalok 254*87117650Saalok /* fill in the minor if needed */ 255*87117650Saalok if (minor_created != NULL) { 256*87117650Saalok *minor_created = minor; 257*87117650Saalok } 2587c478bd9Sstevel@tonic-gate return; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate /* use device we were given */ 2617c478bd9Sstevel@tonic-gate minor = name_to_minor(devicename); 2627c478bd9Sstevel@tonic-gate if (minor == 0) { 2637c478bd9Sstevel@tonic-gate die(gettext("malformed device name %s\n"), devicename); 2647c478bd9Sstevel@tonic-gate } 265*87117650Saalok (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); 2667c478bd9Sstevel@tonic-gate li.li_minor = minor; 2677c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_MAP_FILE_MINOR, &li) == -1) { 2687c478bd9Sstevel@tonic-gate die(gettext("could not map file %s to %s"), filename, 2697c478bd9Sstevel@tonic-gate devicename); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate wait_until_dev_complete(minor); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Remove an association. Delete by device name if non-NULL, or by 2767c478bd9Sstevel@tonic-gate * filename otherwise. 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate static void 2793d7072f8Seschrock delete_mapping(int lfd, const char *devicename, const char *filename, 2803d7072f8Seschrock boolean_t force) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 2837c478bd9Sstevel@tonic-gate 2843d7072f8Seschrock li.li_force = force; 2857c478bd9Sstevel@tonic-gate if (devicename == NULL) { 2867c478bd9Sstevel@tonic-gate /* delete by filename */ 287*87117650Saalok (void) strlcpy(li.li_filename, filename, 288*87117650Saalok sizeof (li.li_filename)); 2897c478bd9Sstevel@tonic-gate li.li_minor = 0; 2907c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_UNMAP_FILE, &li) == -1) { 2917c478bd9Sstevel@tonic-gate die(gettext("could not unmap file %s"), filename); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate return; 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate /* delete by device */ 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate li.li_minor = name_to_minor(devicename); 2987c478bd9Sstevel@tonic-gate if (li.li_minor == 0) { 2997c478bd9Sstevel@tonic-gate die(gettext("malformed device name %s\n"), devicename); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_UNMAP_FILE_MINOR, &li) == -1) { 3027c478bd9Sstevel@tonic-gate die(gettext("could not unmap device %s"), devicename); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate static void 3077c478bd9Sstevel@tonic-gate print_one_mapping(int lfd, const char *devicename, const char *filename) 3087c478bd9Sstevel@tonic-gate { 3097c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate if (devicename == NULL) { 3127c478bd9Sstevel@tonic-gate /* given filename, print devicename */ 3137c478bd9Sstevel@tonic-gate li.li_minor = 0; 314*87117650Saalok (void) strlcpy(li.li_filename, filename, 315*87117650Saalok sizeof (li.li_filename)); 3167c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_GET_MINOR, &li) == -1) { 3177c478bd9Sstevel@tonic-gate die(gettext("could not find device for %s"), filename); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, li.li_minor); 3207c478bd9Sstevel@tonic-gate return; 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* given devicename, print filename */ 3247c478bd9Sstevel@tonic-gate li.li_minor = name_to_minor(devicename); 3257c478bd9Sstevel@tonic-gate if (li.li_minor == 0) { 3267c478bd9Sstevel@tonic-gate die(gettext("malformed device name %s\n"), devicename); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) { 3297c478bd9Sstevel@tonic-gate die(gettext("could not find filename for %s"), devicename); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate (void) printf("%s\n", li.li_filename); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 334*87117650Saalok /* 335*87117650Saalok * Uncompress a file. 336*87117650Saalok * 337*87117650Saalok * First map the file in to establish a device 338*87117650Saalok * association, then read from it. On-the-fly 339*87117650Saalok * decompression will automatically uncompress 340*87117650Saalok * the file if it's compressed 341*87117650Saalok * 342*87117650Saalok * If the file is mapped and a device association 343*87117650Saalok * has been established, disallow uncompressing 344*87117650Saalok * the file until it is unmapped. 345*87117650Saalok */ 346*87117650Saalok static void 347*87117650Saalok lofi_uncompress(int lfd, const char *filename) 3487c478bd9Sstevel@tonic-gate { 349*87117650Saalok struct lofi_ioctl li; 350*87117650Saalok char buf[MAXBSIZE]; 351*87117650Saalok char devicename[32]; 352*87117650Saalok char tmpfilename[MAXPATHLEN]; 353*87117650Saalok char *dir = NULL; 354*87117650Saalok char *file = NULL; 355*87117650Saalok int minor = 0; 356*87117650Saalok struct stat64 statbuf; 357*87117650Saalok int compfd = -1; 358*87117650Saalok int uncompfd = -1; 359*87117650Saalok ssize_t rbytes; 360*87117650Saalok 361*87117650Saalok /* 362*87117650Saalok * Disallow uncompressing the file if it is 363*87117650Saalok * already mapped. 364*87117650Saalok */ 365*87117650Saalok li.li_minor = 0; 366*87117650Saalok (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); 367*87117650Saalok if (ioctl(lfd, LOFI_GET_MINOR, &li) != -1) 368*87117650Saalok die(gettext("%s must be unmapped before uncompressing"), 369*87117650Saalok filename); 370*87117650Saalok 371*87117650Saalok /* Zero length files don't need to be uncompressed */ 372*87117650Saalok if (stat64(filename, &statbuf) == -1) 373*87117650Saalok die(gettext("stat: %s"), filename); 374*87117650Saalok if (statbuf.st_size == 0) 375*87117650Saalok return; 376*87117650Saalok 377*87117650Saalok add_mapping(lfd, NULL, filename, &minor, 1); 378*87117650Saalok (void) snprintf(devicename, sizeof (devicename), "/dev/%s/%d", 379*87117650Saalok LOFI_BLOCK_NAME, minor); 380*87117650Saalok 381*87117650Saalok /* If the file isn't compressed, we just return */ 382*87117650Saalok if ((ioctl(lfd, LOFI_CHECK_COMPRESSED, &li) == -1) || 383*87117650Saalok (li.li_algorithm == '\0')) { 384*87117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 385*87117650Saalok return; 386*87117650Saalok } 387*87117650Saalok 388*87117650Saalok if ((compfd = open64(devicename, O_RDONLY | O_NONBLOCK)) == -1) { 389*87117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 390*87117650Saalok die(gettext("open: %s"), filename); 391*87117650Saalok } 392*87117650Saalok /* Create a temp file in the same directory */ 393*87117650Saalok dir = strdup(filename); 394*87117650Saalok dir = dirname(dir); 395*87117650Saalok file = strdup(filename); 396*87117650Saalok file = basename(file); 397*87117650Saalok (void) snprintf(tmpfilename, sizeof (tmpfilename), 398*87117650Saalok "%s/.%sXXXXXX", dir, file); 399*87117650Saalok 400*87117650Saalok if ((uncompfd = mkstemp64(tmpfilename)) == -1) { 401*87117650Saalok (void) close(compfd); 402*87117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 403*87117650Saalok free(dir); 404*87117650Saalok free(file); 405*87117650Saalok return; 406*87117650Saalok } 407*87117650Saalok 408*87117650Saalok /* 409*87117650Saalok * Set the mode bits and the owner of this temporary 410*87117650Saalok * file to be that of the original uncompressed file 411*87117650Saalok */ 412*87117650Saalok (void) fchmod(uncompfd, statbuf.st_mode); 413*87117650Saalok 414*87117650Saalok if (fchown(uncompfd, statbuf.st_uid, statbuf.st_gid) == -1) { 415*87117650Saalok (void) close(compfd); 416*87117650Saalok (void) close(uncompfd); 417*87117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 418*87117650Saalok free(dir); 419*87117650Saalok free(file); 420*87117650Saalok return; 421*87117650Saalok } 422*87117650Saalok 423*87117650Saalok /* Now read from the device in MAXBSIZE-sized chunks */ 424*87117650Saalok for (;;) { 425*87117650Saalok rbytes = read(compfd, buf, sizeof (buf)); 426*87117650Saalok 427*87117650Saalok if (rbytes <= 0) 428*87117650Saalok break; 429*87117650Saalok 430*87117650Saalok if (write(uncompfd, buf, rbytes) != rbytes) { 431*87117650Saalok rbytes = -1; 432*87117650Saalok break; 433*87117650Saalok } 434*87117650Saalok } 435*87117650Saalok 436*87117650Saalok (void) close(compfd); 437*87117650Saalok (void) close(uncompfd); 438*87117650Saalok free(dir); 439*87117650Saalok free(file); 440*87117650Saalok 441*87117650Saalok /* Delete the mapping */ 442*87117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 443*87117650Saalok 444*87117650Saalok /* 445*87117650Saalok * If an error occured while reading or writing, rbytes will 446*87117650Saalok * be negative 447*87117650Saalok */ 448*87117650Saalok if (rbytes < 0) { 449*87117650Saalok (void) unlink(tmpfilename); 450*87117650Saalok die(gettext("could not read from %s"), filename); 451*87117650Saalok } 452*87117650Saalok 453*87117650Saalok /* Rename the temp file to the actual file */ 454*87117650Saalok if (rename(tmpfilename, filename) == -1) 455*87117650Saalok (void) unlink(tmpfilename); 456*87117650Saalok } 457*87117650Saalok 458*87117650Saalok /* 459*87117650Saalok * Compress a file 460*87117650Saalok */ 461*87117650Saalok static void 462*87117650Saalok lofi_compress(int lfd, const char *filename, int compress_index, 463*87117650Saalok uint32_t segsize) 464*87117650Saalok { 465*87117650Saalok struct lofi_ioctl lic; 466*87117650Saalok lofi_compress_info_t *li; 467*87117650Saalok char tmpfilename[MAXPATHLEN]; 468*87117650Saalok char comp_filename[MAXPATHLEN]; 469*87117650Saalok char algorithm[MAXALGLEN]; 470*87117650Saalok char *dir = NULL, *file = NULL; 471*87117650Saalok uchar_t *uncompressed_seg = NULL; 472*87117650Saalok uchar_t *compressed_seg = NULL; 473*87117650Saalok uint32_t compressed_segsize; 474*87117650Saalok uint32_t len_compressed, count; 475*87117650Saalok uint32_t index_entries, index_sz; 476*87117650Saalok uint64_t *index = NULL; 477*87117650Saalok uint64_t offset; 478*87117650Saalok size_t real_segsize; 479*87117650Saalok struct stat64 statbuf; 480*87117650Saalok int compfd = -1, uncompfd = -1; 481*87117650Saalok int tfd = -1; 482*87117650Saalok ssize_t rbytes, wbytes, lastread; 483*87117650Saalok int i, type; 484*87117650Saalok 485*87117650Saalok /* 486*87117650Saalok * Disallow compressing the file if it is 487*87117650Saalok * already mapped 488*87117650Saalok */ 489*87117650Saalok lic.li_minor = 0; 490*87117650Saalok (void) strlcpy(lic.li_filename, filename, sizeof (lic.li_filename)); 491*87117650Saalok if (ioctl(lfd, LOFI_GET_MINOR, &lic) != -1) 492*87117650Saalok die(gettext("%s must be unmapped before compressing"), 493*87117650Saalok filename); 494*87117650Saalok 495*87117650Saalok li = &lofi_compress_table[compress_index]; 496*87117650Saalok 497*87117650Saalok /* 498*87117650Saalok * The size of the buffer to hold compressed data must 499*87117650Saalok * be slightly larger than the compressed segment size. 500*87117650Saalok * 501*87117650Saalok * The compress functions use part of the buffer as 502*87117650Saalok * scratch space to do calculations. 503*87117650Saalok * Ref: http://www.zlib.net/manual.html#compress2 504*87117650Saalok */ 505*87117650Saalok compressed_segsize = segsize + (segsize >> 6); 506*87117650Saalok compressed_seg = (uchar_t *)malloc(compressed_segsize + SEGHDR); 507*87117650Saalok uncompressed_seg = (uchar_t *)malloc(segsize); 508*87117650Saalok 509*87117650Saalok if (compressed_seg == NULL || uncompressed_seg == NULL) 510*87117650Saalok die(gettext("No memory")); 511*87117650Saalok 512*87117650Saalok if ((uncompfd = open64(filename, O_RDONLY|O_LARGEFILE, 0)) == -1) 513*87117650Saalok die(gettext("open: %s"), filename); 514*87117650Saalok 515*87117650Saalok if (fstat64(uncompfd, &statbuf) == -1) { 516*87117650Saalok (void) close(uncompfd); 517*87117650Saalok die(gettext("fstat: %s"), filename); 518*87117650Saalok } 519*87117650Saalok 520*87117650Saalok /* Zero length files don't need to be compressed */ 521*87117650Saalok if (statbuf.st_size == 0) { 522*87117650Saalok (void) close(uncompfd); 523*87117650Saalok return; 524*87117650Saalok } 525*87117650Saalok 526*87117650Saalok /* 527*87117650Saalok * Create temporary files in the same directory that 528*87117650Saalok * will hold the intermediate data 529*87117650Saalok */ 530*87117650Saalok dir = strdup(filename); 531*87117650Saalok dir = dirname(dir); 532*87117650Saalok file = strdup(filename); 533*87117650Saalok file = basename(file); 534*87117650Saalok (void) snprintf(tmpfilename, sizeof (tmpfilename), 535*87117650Saalok "%s/.%sXXXXXX", dir, file); 536*87117650Saalok (void) snprintf(comp_filename, sizeof (comp_filename), 537*87117650Saalok "%s/.%sXXXXXX", dir, file); 538*87117650Saalok 539*87117650Saalok if ((tfd = mkstemp64(tmpfilename)) == -1) 540*87117650Saalok goto cleanup; 541*87117650Saalok 542*87117650Saalok if ((compfd = mkstemp64(comp_filename)) == -1) 543*87117650Saalok goto cleanup; 544*87117650Saalok 545*87117650Saalok /* 546*87117650Saalok * Set the mode bits and owner of the compressed 547*87117650Saalok * file to be that of the original uncompressed file 548*87117650Saalok */ 549*87117650Saalok (void) fchmod(compfd, statbuf.st_mode); 550*87117650Saalok 551*87117650Saalok if (fchown(compfd, statbuf.st_uid, statbuf.st_gid) == -1) 552*87117650Saalok goto cleanup; 553*87117650Saalok 554*87117650Saalok /* 555*87117650Saalok * Calculate the number of index entries required. 556*87117650Saalok * index entries are stored as an array. adding 557*87117650Saalok * a '2' here accounts for the fact that the last 558*87117650Saalok * segment may not be a multiple of the segment size 559*87117650Saalok */ 560*87117650Saalok index_sz = (statbuf.st_size / segsize) + 2; 561*87117650Saalok index = malloc(sizeof (*index) * index_sz); 562*87117650Saalok 563*87117650Saalok if (index == NULL) 564*87117650Saalok goto cleanup; 565*87117650Saalok 566*87117650Saalok offset = 0; 567*87117650Saalok lastread = segsize; 568*87117650Saalok count = 0; 569*87117650Saalok 570*87117650Saalok /* 571*87117650Saalok * Now read from the uncompressed file in 'segsize' 572*87117650Saalok * sized chunks, compress what was read in and 573*87117650Saalok * write it out to a temporary file 574*87117650Saalok */ 575*87117650Saalok for (;;) { 576*87117650Saalok rbytes = read(uncompfd, uncompressed_seg, segsize); 577*87117650Saalok 578*87117650Saalok if (rbytes <= 0) 579*87117650Saalok break; 580*87117650Saalok 581*87117650Saalok if (lastread < segsize) 582*87117650Saalok goto cleanup; 583*87117650Saalok 584*87117650Saalok /* 585*87117650Saalok * Account for the first byte that 586*87117650Saalok * indicates whether a segment is 587*87117650Saalok * compressed or not 588*87117650Saalok */ 589*87117650Saalok real_segsize = segsize - 1; 590*87117650Saalok (void) li->l_compress(uncompressed_seg, rbytes, 591*87117650Saalok compressed_seg + SEGHDR, &real_segsize, li->l_level); 592*87117650Saalok 593*87117650Saalok /* 594*87117650Saalok * If the length of the compressed data is more 595*87117650Saalok * than a threshold then there isn't any benefit 596*87117650Saalok * to be had from compressing this segment - leave 597*87117650Saalok * it uncompressed. 598*87117650Saalok * 599*87117650Saalok * NB. In case an error occurs during compression (above) 600*87117650Saalok * the 'real_segsize' isn't changed. The logic below 601*87117650Saalok * ensures that that segment is left uncompressed. 602*87117650Saalok */ 603*87117650Saalok len_compressed = real_segsize; 604*87117650Saalok if (real_segsize > segsize - COMPRESS_THRESHOLD) { 605*87117650Saalok (void) memcpy(compressed_seg + SEGHDR, uncompressed_seg, 606*87117650Saalok rbytes); 607*87117650Saalok type = UNCOMPRESSED; 608*87117650Saalok len_compressed = rbytes; 609*87117650Saalok } else { 610*87117650Saalok type = COMPRESSED; 611*87117650Saalok } 612*87117650Saalok 613*87117650Saalok /* 614*87117650Saalok * Set the first byte or the SEGHDR to 615*87117650Saalok * indicate if it's compressed or not 616*87117650Saalok */ 617*87117650Saalok *compressed_seg = type; 618*87117650Saalok wbytes = write(tfd, compressed_seg, len_compressed + SEGHDR); 619*87117650Saalok if (wbytes != (len_compressed + SEGHDR)) { 620*87117650Saalok rbytes = -1; 621*87117650Saalok break; 622*87117650Saalok } 623*87117650Saalok 624*87117650Saalok index[count] = BE_64(offset); 625*87117650Saalok offset += wbytes; 626*87117650Saalok lastread = rbytes; 627*87117650Saalok count++; 628*87117650Saalok } 629*87117650Saalok 630*87117650Saalok (void) close(uncompfd); 631*87117650Saalok 632*87117650Saalok if (rbytes < 0) 633*87117650Saalok goto cleanup; 634*87117650Saalok /* 635*87117650Saalok * The last index entry is a sentinel entry. It does not point to 636*87117650Saalok * an actual compressed segment but helps in computing the size of 637*87117650Saalok * the compressed segment. The size of each compressed segment is 638*87117650Saalok * computed by subtracting the current index value from the next 639*87117650Saalok * one (the compressed blocks are stored sequentially) 640*87117650Saalok */ 641*87117650Saalok index[count++] = BE_64(offset); 642*87117650Saalok 643*87117650Saalok /* 644*87117650Saalok * Now write the compressed data along with the 645*87117650Saalok * header information to this file which will 646*87117650Saalok * later be renamed to the original uncompressed 647*87117650Saalok * file name 648*87117650Saalok * 649*87117650Saalok * The header is as follows - 650*87117650Saalok * 651*87117650Saalok * Signature (name of the compression algorithm) 652*87117650Saalok * Compression segment size (a multiple of 512) 653*87117650Saalok * Number of index entries 654*87117650Saalok * Size of the last block 655*87117650Saalok * The array containing the index entries 656*87117650Saalok * 657*87117650Saalok * the header is always stored in network byte 658*87117650Saalok * order 659*87117650Saalok */ 660*87117650Saalok (void) bzero(algorithm, sizeof (algorithm)); 661*87117650Saalok (void) strlcpy(algorithm, li->l_name, sizeof (algorithm)); 662*87117650Saalok if (write(compfd, algorithm, sizeof (algorithm)) 663*87117650Saalok != sizeof (algorithm)) 664*87117650Saalok goto cleanup; 665*87117650Saalok 666*87117650Saalok segsize = htonl(segsize); 667*87117650Saalok if (write(compfd, &segsize, sizeof (segsize)) != sizeof (segsize)) 668*87117650Saalok goto cleanup; 669*87117650Saalok 670*87117650Saalok index_entries = htonl(count); 671*87117650Saalok if (write(compfd, &index_entries, sizeof (index_entries)) != 672*87117650Saalok sizeof (index_entries)) 673*87117650Saalok goto cleanup; 674*87117650Saalok 675*87117650Saalok lastread = htonl(lastread); 676*87117650Saalok if (write(compfd, &lastread, sizeof (lastread)) != sizeof (lastread)) 677*87117650Saalok goto cleanup; 678*87117650Saalok 679*87117650Saalok for (i = 0; i < count; i++) { 680*87117650Saalok if (write(compfd, index + i, sizeof (*index)) != 681*87117650Saalok sizeof (*index)) 682*87117650Saalok goto cleanup; 683*87117650Saalok } 684*87117650Saalok 685*87117650Saalok /* Header is written, now write the compressed data */ 686*87117650Saalok if (lseek(tfd, 0, SEEK_SET) != 0) 687*87117650Saalok goto cleanup; 688*87117650Saalok 689*87117650Saalok rbytes = wbytes = 0; 690*87117650Saalok 691*87117650Saalok for (;;) { 692*87117650Saalok rbytes = read(tfd, compressed_seg, compressed_segsize + SEGHDR); 693*87117650Saalok 694*87117650Saalok if (rbytes <= 0) 695*87117650Saalok break; 696*87117650Saalok 697*87117650Saalok if (write(compfd, compressed_seg, rbytes) != rbytes) 698*87117650Saalok goto cleanup; 699*87117650Saalok } 700*87117650Saalok 701*87117650Saalok if (fstat64(compfd, &statbuf) == -1) 702*87117650Saalok goto cleanup; 703*87117650Saalok 704*87117650Saalok /* 705*87117650Saalok * Round up the compressed file size to be a multiple of 706*87117650Saalok * DEV_BSIZE. lofi(7D) likes it that way. 707*87117650Saalok */ 708*87117650Saalok if ((offset = statbuf.st_size % DEV_BSIZE) > 0) { 709*87117650Saalok 710*87117650Saalok offset = DEV_BSIZE - offset; 711*87117650Saalok 712*87117650Saalok for (i = 0; i < offset; i++) 713*87117650Saalok uncompressed_seg[i] = '\0'; 714*87117650Saalok if (write(compfd, uncompressed_seg, offset) != offset) 715*87117650Saalok goto cleanup; 716*87117650Saalok } 717*87117650Saalok (void) close(compfd); 718*87117650Saalok (void) close(tfd); 719*87117650Saalok (void) unlink(tmpfilename); 720*87117650Saalok cleanup: 721*87117650Saalok if (rbytes < 0) { 722*87117650Saalok if (tfd != -1) 723*87117650Saalok (void) unlink(tmpfilename); 724*87117650Saalok if (compfd != -1) 725*87117650Saalok (void) unlink(comp_filename); 726*87117650Saalok die(gettext("error compressing file %s"), filename); 727*87117650Saalok } else { 728*87117650Saalok /* Rename the compressed file to the actual file */ 729*87117650Saalok if (rename(comp_filename, filename) == -1) { 730*87117650Saalok (void) unlink(comp_filename); 731*87117650Saalok die(gettext("error compressing file %s"), filename); 732*87117650Saalok } 733*87117650Saalok } 734*87117650Saalok if (compressed_seg != NULL) 735*87117650Saalok free(compressed_seg); 736*87117650Saalok if (uncompressed_seg != NULL) 737*87117650Saalok free(uncompressed_seg); 738*87117650Saalok if (dir != NULL) 739*87117650Saalok free(dir); 740*87117650Saalok if (file != NULL) 741*87117650Saalok free(file); 742*87117650Saalok if (index != NULL) 743*87117650Saalok free(index); 744*87117650Saalok if (compfd != -1) 745*87117650Saalok (void) close(compfd); 746*87117650Saalok if (uncompfd != -1) 747*87117650Saalok (void) close(uncompfd); 748*87117650Saalok if (tfd != -1) 749*87117650Saalok (void) close(tfd); 750*87117650Saalok } 751*87117650Saalok 752*87117650Saalok static int 753*87117650Saalok lofi_compress_select(const char *algname) 754*87117650Saalok { 755*87117650Saalok int i; 756*87117650Saalok 757*87117650Saalok for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) { 758*87117650Saalok if (strcmp(lofi_compress_table[i].l_name, algname) == 0) 759*87117650Saalok return (i); 760*87117650Saalok } 761*87117650Saalok return (-1); 762*87117650Saalok } 763*87117650Saalok 764*87117650Saalok static void 765*87117650Saalok check_algorithm_validity(const char *algname, int *compress_index) 766*87117650Saalok { 767*87117650Saalok *compress_index = lofi_compress_select(algname); 768*87117650Saalok if (*compress_index < 0) 769*87117650Saalok die(gettext("invalid algorithm name: %s\n"), algname); 770*87117650Saalok } 771*87117650Saalok 772*87117650Saalok static void 773*87117650Saalok check_file_validity(const char *filename) 774*87117650Saalok { 7757c478bd9Sstevel@tonic-gate struct stat64 buf; 776*87117650Saalok int error; 7777c478bd9Sstevel@tonic-gate int fd = -1; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate fd = open64(filename, O_RDONLY); 7807c478bd9Sstevel@tonic-gate if (fd == -1) { 7817c478bd9Sstevel@tonic-gate die(gettext("open: %s"), filename); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate error = fstat64(fd, &buf); 7847c478bd9Sstevel@tonic-gate if (error == -1) { 7857c478bd9Sstevel@tonic-gate die(gettext("fstat: %s"), filename); 7867c478bd9Sstevel@tonic-gate } else if (!S_ISLOFIABLE(buf.st_mode)) { 7877c478bd9Sstevel@tonic-gate die(gettext("%s is not a regular file, " 7887c478bd9Sstevel@tonic-gate "block, or character device\n"), 7897c478bd9Sstevel@tonic-gate filename); 7907c478bd9Sstevel@tonic-gate } else if ((buf.st_size % DEV_BSIZE) != 0) { 7917c478bd9Sstevel@tonic-gate die(gettext("size of %s is not a multiple " 7927c478bd9Sstevel@tonic-gate "of %d\n"), 7937c478bd9Sstevel@tonic-gate filename, DEV_BSIZE); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate (void) close(fd); 796*87117650Saalok 797*87117650Saalok if (name_to_minor(filename) != 0) { 7987c478bd9Sstevel@tonic-gate die(gettext("cannot use " LOFI_DRIVER_NAME 799*87117650Saalok " on itself\n"), NULL); 8007c478bd9Sstevel@tonic-gate } 801*87117650Saalok } 802*87117650Saalok 803*87117650Saalok static uint32_t 804*87117650Saalok convert_to_num(const char *str) 805*87117650Saalok { 806*87117650Saalok int len; 807*87117650Saalok uint32_t segsize, mult = 1; 808*87117650Saalok 809*87117650Saalok len = strlen(str); 810*87117650Saalok if (len && isalpha(str[len - 1])) { 811*87117650Saalok switch (str[len - 1]) { 812*87117650Saalok case 'k': 813*87117650Saalok case 'K': 814*87117650Saalok mult = KILOBYTE; 815*87117650Saalok break; 816*87117650Saalok case 'b': 817*87117650Saalok case 'B': 818*87117650Saalok mult = BLOCK_SIZE; 819*87117650Saalok break; 820*87117650Saalok case 'm': 821*87117650Saalok case 'M': 822*87117650Saalok mult = MEGABYTE; 823*87117650Saalok break; 824*87117650Saalok case 'g': 825*87117650Saalok case 'G': 826*87117650Saalok mult = GIGABYTE; 827*87117650Saalok break; 828*87117650Saalok default: 829*87117650Saalok die(gettext("invalid segment size %s\n"), str); 830*87117650Saalok } 831*87117650Saalok } 832*87117650Saalok 833*87117650Saalok segsize = atol(str); 834*87117650Saalok segsize *= mult; 835*87117650Saalok 836*87117650Saalok return (segsize); 837*87117650Saalok } 838*87117650Saalok 839*87117650Saalok int 840*87117650Saalok main(int argc, char *argv[]) 841*87117650Saalok { 842*87117650Saalok int lfd; 843*87117650Saalok int c; 844*87117650Saalok const char *devicename = NULL; 845*87117650Saalok const char *filename = NULL; 846*87117650Saalok const char *algname = COMPRESS_ALGORITHM; 847*87117650Saalok int openflag; 848*87117650Saalok int minor; 849*87117650Saalok int compress_index; 850*87117650Saalok uint32_t segsize = SEGSIZE; 851*87117650Saalok static char *lofictl = "/dev/" LOFI_CTL_NAME; 852*87117650Saalok boolean_t force = B_FALSE; 853*87117650Saalok 854*87117650Saalok pname = getpname(argv[0]); 855*87117650Saalok 856*87117650Saalok (void) setlocale(LC_ALL, ""); 857*87117650Saalok (void) textdomain(TEXT_DOMAIN); 858*87117650Saalok 859*87117650Saalok while ((c = getopt(argc, argv, "a:C:d:s:U:f")) != EOF) { 860*87117650Saalok switch (c) { 861*87117650Saalok case 'a': 862*87117650Saalok addflag = 1; 863*87117650Saalok filename = optarg; 864*87117650Saalok check_file_validity(filename); 865*87117650Saalok 8667c478bd9Sstevel@tonic-gate if (((argc - optind) > 0) && (*argv[optind] != '-')) { 8677c478bd9Sstevel@tonic-gate /* optional device */ 8687c478bd9Sstevel@tonic-gate devicename = argv[optind]; 8697c478bd9Sstevel@tonic-gate optind++; 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate break; 872*87117650Saalok case 'C': 873*87117650Saalok compressflag = 1; 874*87117650Saalok 875*87117650Saalok if (((argc - optind) > 0) && 876*87117650Saalok (*optarg == '-')) { 877*87117650Saalok check_algorithm_validity(algname, 878*87117650Saalok &compress_index); 879*87117650Saalok optind--; 880*87117650Saalok break; 881*87117650Saalok } else if (((argc - optind) == 1) && 882*87117650Saalok (*argv[optind] != '-')) { 883*87117650Saalok algname = optarg; 884*87117650Saalok filename = argv[optind]; 885*87117650Saalok optind++; 886*87117650Saalok } else if (((argc - optind) > 1) && 887*87117650Saalok (*argv[optind] == '-')) { 888*87117650Saalok algname = optarg; 889*87117650Saalok check_algorithm_validity(algname, 890*87117650Saalok &compress_index); 891*87117650Saalok break; 892*87117650Saalok } else { 893*87117650Saalok filename = optarg; 894*87117650Saalok } 895*87117650Saalok 896*87117650Saalok check_file_validity(filename); 897*87117650Saalok check_algorithm_validity(algname, &compress_index); 898*87117650Saalok break; 8997c478bd9Sstevel@tonic-gate case 'd': 9007c478bd9Sstevel@tonic-gate deleteflag = 1; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate minor = name_to_minor(optarg); 9037c478bd9Sstevel@tonic-gate if (minor != 0) 9047c478bd9Sstevel@tonic-gate devicename = optarg; 9057c478bd9Sstevel@tonic-gate else 9067c478bd9Sstevel@tonic-gate filename = optarg; 9077c478bd9Sstevel@tonic-gate break; 9083d7072f8Seschrock case 'f': 9093d7072f8Seschrock force = B_TRUE; 9103d7072f8Seschrock break; 911*87117650Saalok case 's': 912*87117650Saalok segsize = convert_to_num(optarg); 913*87117650Saalok 914*87117650Saalok if (segsize == 0 || segsize % DEV_BSIZE) 915*87117650Saalok die(gettext("segment size %s is invalid " 916*87117650Saalok "or not a multiple of minimum block " 917*87117650Saalok "size %ld\n"), optarg, DEV_BSIZE); 918*87117650Saalok 919*87117650Saalok filename = argv[optind]; 920*87117650Saalok check_file_validity(filename); 921*87117650Saalok optind++; 922*87117650Saalok break; 923*87117650Saalok case 'U': 924*87117650Saalok uncompressflag = 1; 925*87117650Saalok filename = optarg; 926*87117650Saalok check_file_validity(filename); 927*87117650Saalok break; 9287c478bd9Sstevel@tonic-gate case '?': 9297c478bd9Sstevel@tonic-gate default: 9307c478bd9Sstevel@tonic-gate errflag = 1; 9317c478bd9Sstevel@tonic-gate break; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate } 934*87117650Saalok if (errflag || 935*87117650Saalok (addflag && deleteflag) || 936*87117650Saalok ((compressflag || uncompressflag) && (addflag || deleteflag))) 9377c478bd9Sstevel@tonic-gate usage(); 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate switch (argc - optind) { 9407c478bd9Sstevel@tonic-gate case 0: /* no more args */ 9417c478bd9Sstevel@tonic-gate break; 9427c478bd9Sstevel@tonic-gate case 1: /* one arg without options means print the association */ 9437c478bd9Sstevel@tonic-gate if (addflag || deleteflag) 9447c478bd9Sstevel@tonic-gate usage(); 945*87117650Saalok if (compressflag || uncompressflag) 946*87117650Saalok usage(); 9477c478bd9Sstevel@tonic-gate minor = name_to_minor(argv[optind]); 9487c478bd9Sstevel@tonic-gate if (minor != 0) 9497c478bd9Sstevel@tonic-gate devicename = argv[optind]; 9507c478bd9Sstevel@tonic-gate else 9517c478bd9Sstevel@tonic-gate filename = argv[optind]; 9527c478bd9Sstevel@tonic-gate break; 9537c478bd9Sstevel@tonic-gate default: 9547c478bd9Sstevel@tonic-gate usage(); 9557c478bd9Sstevel@tonic-gate break; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (filename && !valid_abspath(filename)) 9597c478bd9Sstevel@tonic-gate exit(E_ERROR); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * Here, we know the arguments are correct, the filename is an 9637c478bd9Sstevel@tonic-gate * absolute path, it exists and is a regular file. We don't yet 9647c478bd9Sstevel@tonic-gate * know that the device name is ok or not. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * Now to the real work. 9687c478bd9Sstevel@tonic-gate */ 9697c478bd9Sstevel@tonic-gate openflag = O_EXCL; 970*87117650Saalok if (addflag || deleteflag || compressflag || uncompressflag) 9717c478bd9Sstevel@tonic-gate openflag |= O_RDWR; 9727c478bd9Sstevel@tonic-gate else 9737c478bd9Sstevel@tonic-gate openflag |= O_RDONLY; 9747c478bd9Sstevel@tonic-gate lfd = open(lofictl, openflag); 9757c478bd9Sstevel@tonic-gate if (lfd == -1) { 9767c478bd9Sstevel@tonic-gate if ((errno == EPERM) || (errno == EACCES)) { 9777c478bd9Sstevel@tonic-gate die("you do not have permission to perform " 9787c478bd9Sstevel@tonic-gate "that operation.\n"); 9797c478bd9Sstevel@tonic-gate } else { 9807c478bd9Sstevel@tonic-gate die("%s", lofictl); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate if (addflag) 985*87117650Saalok add_mapping(lfd, devicename, filename, NULL, 0); 986*87117650Saalok else if (compressflag) 987*87117650Saalok lofi_compress(lfd, filename, compress_index, segsize); 988*87117650Saalok else if (uncompressflag) 989*87117650Saalok lofi_uncompress(lfd, filename); 9907c478bd9Sstevel@tonic-gate else if (deleteflag) 9913d7072f8Seschrock delete_mapping(lfd, devicename, filename, force); 9927c478bd9Sstevel@tonic-gate else if (filename || devicename) 9937c478bd9Sstevel@tonic-gate print_one_mapping(lfd, devicename, filename); 9947c478bd9Sstevel@tonic-gate else 9957c478bd9Sstevel@tonic-gate print_mappings(lfd); 9967c478bd9Sstevel@tonic-gate (void) close(lfd); 9977c478bd9Sstevel@tonic-gate return (E_SUCCESS); 9987c478bd9Sstevel@tonic-gate } 999