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 /* 2293239addSjohnlev * Copyright 2008 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> 3987117650Saalok #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> 4487117650Saalok #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> 5087117650Saalok #include <libgen.h> 5187117650Saalok #include <ctype.h> 52579df0adSaalok #include <dlfcn.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" 5887117650Saalok " %s -C [algorithm] [-s segment_size] file \n" 5987117650Saalok " %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; 6687117650Saalok static int compressflag = 0; 6787117650Saalok static int uncompressflag = 0; 687c478bd9Sstevel@tonic-gate 6987117650Saalok static int gzip_compress(void *src, size_t srclen, void *dst, 7087117650Saalok size_t *destlen, int level); 7187117650Saalok 7287117650Saalok lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = { 7387117650Saalok {NULL, gzip_compress, 6, "gzip"}, /* default */ 7487117650Saalok {NULL, gzip_compress, 6, "gzip-6"}, 7587117650Saalok {NULL, gzip_compress, 9, "gzip-9"} 7687117650Saalok }; 7787117650Saalok 7887117650Saalok #define FORMAT "%-20s %-30s %s\n" 7987117650Saalok #define NONE "-" 8087117650Saalok #define COMPRESS "Compressed" 8187117650Saalok #define COMPRESS_ALGORITHM "gzip" 8287117650Saalok #define COMPRESS_THRESHOLD 2048 8387117650Saalok #define SEGSIZE 131072 8487117650Saalok #define BLOCK_SIZE 512 8587117650Saalok #define KILOBYTE 1024 8687117650Saalok #define MEGABYTE (KILOBYTE * KILOBYTE) 8787117650Saalok #define GIGABYTE (KILOBYTE * MEGABYTE) 88579df0adSaalok #define LIBZ "libz.so" 89579df0adSaalok 90579df0adSaalok static int (*compress2p)(void *, ulong_t *, void *, size_t, int) = NULL; 9187117650Saalok 9287117650Saalok static int gzip_compress(void *src, size_t srclen, void *dst, 9387117650Saalok size_t *dstlen, int level) 9487117650Saalok { 95579df0adSaalok void *libz_hdl = NULL; 9687117650Saalok 97579df0adSaalok /* 98579df0adSaalok * The first time we are called, attempt to dlopen() 99579df0adSaalok * libz.so and get a pointer to the compress2() function 100579df0adSaalok */ 101579df0adSaalok if (compress2p == NULL) { 102579df0adSaalok if ((libz_hdl = openlib(LIBZ)) == NULL) 103579df0adSaalok die(gettext("could not find %s. " 104579df0adSaalok "gzip compression unavailable\n"), LIBZ); 105579df0adSaalok 106579df0adSaalok if ((compress2p = 107579df0adSaalok (int (*)(void *, ulong_t *, void *, size_t, int)) 108579df0adSaalok dlsym(libz_hdl, "compress2")) == NULL) { 109579df0adSaalok closelib(); 110579df0adSaalok die(gettext("could not find the correct %s. " 111579df0adSaalok "gzip compression unavailable\n"), LIBZ); 112579df0adSaalok } 113579df0adSaalok } 114579df0adSaalok 115579df0adSaalok if ((*compress2p)(dst, (ulong_t *)dstlen, src, srclen, level) != 0) 116579df0adSaalok return (-1); 11787117650Saalok return (0); 11887117650Saalok } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * Print the list of all the mappings. Including a header. 1227c478bd9Sstevel@tonic-gate */ 1237c478bd9Sstevel@tonic-gate static void 1247c478bd9Sstevel@tonic-gate print_mappings(int fd) 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 1277c478bd9Sstevel@tonic-gate int minor; 1287c478bd9Sstevel@tonic-gate int maxminor; 12987117650Saalok char path[MAXPATHLEN]; 13087117650Saalok char options[MAXPATHLEN]; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate li.li_minor = 0; 1337c478bd9Sstevel@tonic-gate if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) { 1347c478bd9Sstevel@tonic-gate perror("ioctl"); 1357c478bd9Sstevel@tonic-gate exit(E_ERROR); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate maxminor = li.li_minor; 1397c478bd9Sstevel@tonic-gate 14087117650Saalok (void) printf(FORMAT, "Block Device", "File", "Options"); 1417c478bd9Sstevel@tonic-gate for (minor = 1; minor <= maxminor; minor++) { 1427c478bd9Sstevel@tonic-gate li.li_minor = minor; 1437c478bd9Sstevel@tonic-gate if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) { 1447c478bd9Sstevel@tonic-gate if (errno == ENXIO) 1457c478bd9Sstevel@tonic-gate continue; 1467c478bd9Sstevel@tonic-gate perror("ioctl"); 1477c478bd9Sstevel@tonic-gate break; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "/dev/%s/%d", 1507c478bd9Sstevel@tonic-gate LOFI_BLOCK_NAME, minor); 15187117650Saalok if (li.li_algorithm[0] == '\0') 15287117650Saalok (void) snprintf(options, sizeof (options), "%s", NONE); 15387117650Saalok else 15487117650Saalok (void) snprintf(options, sizeof (options), 15587117650Saalok COMPRESS "(%s)", li.li_algorithm); 15687117650Saalok 15787117650Saalok (void) printf(FORMAT, path, li.li_filename, options); 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate static void 1627c478bd9Sstevel@tonic-gate usage(void) 1637c478bd9Sstevel@tonic-gate { 16487117650Saalok (void) fprintf(stderr, gettext(USAGE), pname, pname, 16587117650Saalok pname, pname, pname); 1667c478bd9Sstevel@tonic-gate exit(E_USAGE); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Translate a lofi device name to a minor number. We might be asked 1717c478bd9Sstevel@tonic-gate * to do this when there is no association (such as when the user specifies 1727c478bd9Sstevel@tonic-gate * a particular device), so we can only look at the string. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static int 1757c478bd9Sstevel@tonic-gate name_to_minor(const char *devicename) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate int minor; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if (sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor) == 1) { 1807c478bd9Sstevel@tonic-gate return (minor); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate if (sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor) == 1) { 1837c478bd9Sstevel@tonic-gate return (minor); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate return (0); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * This might be the first time we've used this minor number. If so, 1907c478bd9Sstevel@tonic-gate * it might also be that the /dev links are in the process of being created 1917c478bd9Sstevel@tonic-gate * by devfsadmd (or that they'll be created "soon"). We cannot return 1927c478bd9Sstevel@tonic-gate * until they're there or the invoker of lofiadm might try to use them 1937c478bd9Sstevel@tonic-gate * and not find them. This can happen if a shell script is running on 1947c478bd9Sstevel@tonic-gate * an MP. 1957c478bd9Sstevel@tonic-gate */ 1967c478bd9Sstevel@tonic-gate static int sleeptime = 2; /* number of seconds to sleep between stat's */ 1977c478bd9Sstevel@tonic-gate static int maxsleep = 120; /* maximum number of seconds to sleep */ 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate static void 2007c478bd9Sstevel@tonic-gate wait_until_dev_complete(int minor) 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate struct stat64 buf; 2037c478bd9Sstevel@tonic-gate int cursleep; 20487117650Saalok char blkpath[MAXPATHLEN]; 20587117650Saalok char charpath[MAXPATHLEN]; 2061d8ed0f0Svikram di_devlink_handle_t hdl; 2071d8ed0f0Svikram 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate (void) snprintf(blkpath, sizeof (blkpath), "/dev/%s/%d", 2107c478bd9Sstevel@tonic-gate LOFI_BLOCK_NAME, minor); 2117c478bd9Sstevel@tonic-gate (void) snprintf(charpath, sizeof (charpath), "/dev/%s/%d", 2127c478bd9Sstevel@tonic-gate LOFI_CHAR_NAME, minor); 2131d8ed0f0Svikram 2141d8ed0f0Svikram /* Check if links already present */ 2151d8ed0f0Svikram if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0) 2161d8ed0f0Svikram return; 2171d8ed0f0Svikram 2181d8ed0f0Svikram /* First use di_devlink_init() */ 2191d8ed0f0Svikram if (hdl = di_devlink_init("lofi", DI_MAKE_LINK)) { 2201d8ed0f0Svikram (void) di_devlink_fini(&hdl); 2211d8ed0f0Svikram goto out; 2221d8ed0f0Svikram } 2231d8ed0f0Svikram 2241d8ed0f0Svikram /* 2251d8ed0f0Svikram * Under normal conditions, di_devlink_init(DI_MAKE_LINK) above will 2261d8ed0f0Svikram * only fail if the caller is non-root. In that case, wait for 2271d8ed0f0Svikram * link creation via sysevents. 2281d8ed0f0Svikram */ 2297c478bd9Sstevel@tonic-gate cursleep = 0; 2307c478bd9Sstevel@tonic-gate while (cursleep < maxsleep) { 2317c478bd9Sstevel@tonic-gate if ((stat64(blkpath, &buf) == -1) || 2327c478bd9Sstevel@tonic-gate (stat64(charpath, &buf) == -1)) { 2337c478bd9Sstevel@tonic-gate (void) sleep(sleeptime); 2347c478bd9Sstevel@tonic-gate cursleep += sleeptime; 2357c478bd9Sstevel@tonic-gate continue; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate return; 2387c478bd9Sstevel@tonic-gate } 2391d8ed0f0Svikram 2407c478bd9Sstevel@tonic-gate /* one last try */ 2411d8ed0f0Svikram 2421d8ed0f0Svikram out: 2437c478bd9Sstevel@tonic-gate if (stat64(blkpath, &buf) == -1) { 2447c478bd9Sstevel@tonic-gate die(gettext("%s was not created"), blkpath); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate if (stat64(charpath, &buf) == -1) { 2477c478bd9Sstevel@tonic-gate die(gettext("%s was not created"), charpath); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * Add a device association. If devicename is NULL, let the driver 2537c478bd9Sstevel@tonic-gate * pick a device. 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate static void 25687117650Saalok add_mapping(int lfd, const char *devicename, const char *filename, 25787117650Saalok int *minor_created, int suppress) 2587c478bd9Sstevel@tonic-gate { 2597c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 2607c478bd9Sstevel@tonic-gate int minor; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate if (devicename == NULL) { 2637c478bd9Sstevel@tonic-gate /* pick one */ 2647c478bd9Sstevel@tonic-gate li.li_minor = 0; 26587117650Saalok (void) strlcpy(li.li_filename, filename, 26687117650Saalok sizeof (li.li_filename)); 2677c478bd9Sstevel@tonic-gate minor = ioctl(lfd, LOFI_MAP_FILE, &li); 2687c478bd9Sstevel@tonic-gate if (minor == -1) { 2697c478bd9Sstevel@tonic-gate die(gettext("could not map file %s"), filename); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate wait_until_dev_complete(minor); 2727c478bd9Sstevel@tonic-gate /* print one picked */ 27387117650Saalok if (!suppress) 2747c478bd9Sstevel@tonic-gate (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor); 27587117650Saalok 27687117650Saalok /* fill in the minor if needed */ 27787117650Saalok if (minor_created != NULL) { 27887117650Saalok *minor_created = minor; 27987117650Saalok } 2807c478bd9Sstevel@tonic-gate return; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate /* use device we were given */ 2837c478bd9Sstevel@tonic-gate minor = name_to_minor(devicename); 2847c478bd9Sstevel@tonic-gate if (minor == 0) { 2857c478bd9Sstevel@tonic-gate die(gettext("malformed device name %s\n"), devicename); 2867c478bd9Sstevel@tonic-gate } 28787117650Saalok (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); 2887c478bd9Sstevel@tonic-gate li.li_minor = minor; 2897c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_MAP_FILE_MINOR, &li) == -1) { 2907c478bd9Sstevel@tonic-gate die(gettext("could not map file %s to %s"), filename, 2917c478bd9Sstevel@tonic-gate devicename); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate wait_until_dev_complete(minor); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Remove an association. Delete by device name if non-NULL, or by 2987c478bd9Sstevel@tonic-gate * filename otherwise. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate static void 3013d7072f8Seschrock delete_mapping(int lfd, const char *devicename, const char *filename, 3023d7072f8Seschrock boolean_t force) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 3057c478bd9Sstevel@tonic-gate 3063d7072f8Seschrock li.li_force = force; 30793239addSjohnlev li.li_cleanup = B_FALSE; 30893239addSjohnlev 3097c478bd9Sstevel@tonic-gate if (devicename == NULL) { 3107c478bd9Sstevel@tonic-gate /* delete by filename */ 31187117650Saalok (void) strlcpy(li.li_filename, filename, 31287117650Saalok sizeof (li.li_filename)); 3137c478bd9Sstevel@tonic-gate li.li_minor = 0; 3147c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_UNMAP_FILE, &li) == -1) { 3157c478bd9Sstevel@tonic-gate die(gettext("could not unmap file %s"), filename); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate return; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate /* delete by device */ 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate li.li_minor = name_to_minor(devicename); 3227c478bd9Sstevel@tonic-gate if (li.li_minor == 0) { 3237c478bd9Sstevel@tonic-gate die(gettext("malformed device name %s\n"), devicename); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_UNMAP_FILE_MINOR, &li) == -1) { 3267c478bd9Sstevel@tonic-gate die(gettext("could not unmap device %s"), devicename); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate static void 3317c478bd9Sstevel@tonic-gate print_one_mapping(int lfd, const char *devicename, const char *filename) 3327c478bd9Sstevel@tonic-gate { 3337c478bd9Sstevel@tonic-gate struct lofi_ioctl li; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (devicename == NULL) { 3367c478bd9Sstevel@tonic-gate /* given filename, print devicename */ 3377c478bd9Sstevel@tonic-gate li.li_minor = 0; 33887117650Saalok (void) strlcpy(li.li_filename, filename, 33987117650Saalok sizeof (li.li_filename)); 3407c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_GET_MINOR, &li) == -1) { 3417c478bd9Sstevel@tonic-gate die(gettext("could not find device for %s"), filename); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, li.li_minor); 3447c478bd9Sstevel@tonic-gate return; 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* given devicename, print filename */ 3487c478bd9Sstevel@tonic-gate li.li_minor = name_to_minor(devicename); 3497c478bd9Sstevel@tonic-gate if (li.li_minor == 0) { 3507c478bd9Sstevel@tonic-gate die(gettext("malformed device name %s\n"), devicename); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) { 3537c478bd9Sstevel@tonic-gate die(gettext("could not find filename for %s"), devicename); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate (void) printf("%s\n", li.li_filename); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 35887117650Saalok /* 35987117650Saalok * Uncompress a file. 36087117650Saalok * 36187117650Saalok * First map the file in to establish a device 36287117650Saalok * association, then read from it. On-the-fly 36387117650Saalok * decompression will automatically uncompress 36487117650Saalok * the file if it's compressed 36587117650Saalok * 36687117650Saalok * If the file is mapped and a device association 36787117650Saalok * has been established, disallow uncompressing 36887117650Saalok * the file until it is unmapped. 36987117650Saalok */ 37087117650Saalok static void 37187117650Saalok lofi_uncompress(int lfd, const char *filename) 3727c478bd9Sstevel@tonic-gate { 37387117650Saalok struct lofi_ioctl li; 37487117650Saalok char buf[MAXBSIZE]; 37587117650Saalok char devicename[32]; 37687117650Saalok char tmpfilename[MAXPATHLEN]; 37787117650Saalok char *dir = NULL; 37887117650Saalok char *file = NULL; 37987117650Saalok int minor = 0; 38087117650Saalok struct stat64 statbuf; 38187117650Saalok int compfd = -1; 38287117650Saalok int uncompfd = -1; 38387117650Saalok ssize_t rbytes; 38487117650Saalok 38587117650Saalok /* 38687117650Saalok * Disallow uncompressing the file if it is 38787117650Saalok * already mapped. 38887117650Saalok */ 38987117650Saalok li.li_minor = 0; 39087117650Saalok (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); 39187117650Saalok if (ioctl(lfd, LOFI_GET_MINOR, &li) != -1) 39287117650Saalok die(gettext("%s must be unmapped before uncompressing"), 39387117650Saalok filename); 39487117650Saalok 39587117650Saalok /* Zero length files don't need to be uncompressed */ 39687117650Saalok if (stat64(filename, &statbuf) == -1) 39787117650Saalok die(gettext("stat: %s"), filename); 39887117650Saalok if (statbuf.st_size == 0) 39987117650Saalok return; 40087117650Saalok 40187117650Saalok add_mapping(lfd, NULL, filename, &minor, 1); 40287117650Saalok (void) snprintf(devicename, sizeof (devicename), "/dev/%s/%d", 40387117650Saalok LOFI_BLOCK_NAME, minor); 40487117650Saalok 40587117650Saalok /* If the file isn't compressed, we just return */ 40687117650Saalok if ((ioctl(lfd, LOFI_CHECK_COMPRESSED, &li) == -1) || 407*a423e759Saalok (li.li_algorithm[0] == '\0')) { 40887117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 409*a423e759Saalok die("%s is not compressed\n", filename); 41087117650Saalok } 41187117650Saalok 41287117650Saalok if ((compfd = open64(devicename, O_RDONLY | O_NONBLOCK)) == -1) { 41387117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 41487117650Saalok die(gettext("open: %s"), filename); 41587117650Saalok } 41687117650Saalok /* Create a temp file in the same directory */ 41787117650Saalok dir = strdup(filename); 41887117650Saalok dir = dirname(dir); 41987117650Saalok file = strdup(filename); 42087117650Saalok file = basename(file); 42187117650Saalok (void) snprintf(tmpfilename, sizeof (tmpfilename), 42287117650Saalok "%s/.%sXXXXXX", dir, file); 42387117650Saalok 42487117650Saalok if ((uncompfd = mkstemp64(tmpfilename)) == -1) { 42587117650Saalok (void) close(compfd); 42687117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 42787117650Saalok free(dir); 42887117650Saalok free(file); 429*a423e759Saalok die("%s could not be uncompressed\n", filename); 43087117650Saalok } 43187117650Saalok 43287117650Saalok /* 43387117650Saalok * Set the mode bits and the owner of this temporary 43487117650Saalok * file to be that of the original uncompressed file 43587117650Saalok */ 43687117650Saalok (void) fchmod(uncompfd, statbuf.st_mode); 43787117650Saalok 43887117650Saalok if (fchown(uncompfd, statbuf.st_uid, statbuf.st_gid) == -1) { 43987117650Saalok (void) close(compfd); 44087117650Saalok (void) close(uncompfd); 44187117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 44287117650Saalok free(dir); 44387117650Saalok free(file); 444*a423e759Saalok die("%s could not be uncompressed\n", filename); 44587117650Saalok } 44687117650Saalok 44787117650Saalok /* Now read from the device in MAXBSIZE-sized chunks */ 44887117650Saalok for (;;) { 44987117650Saalok rbytes = read(compfd, buf, sizeof (buf)); 45087117650Saalok 45187117650Saalok if (rbytes <= 0) 45287117650Saalok break; 45387117650Saalok 45487117650Saalok if (write(uncompfd, buf, rbytes) != rbytes) { 45587117650Saalok rbytes = -1; 45687117650Saalok break; 45787117650Saalok } 45887117650Saalok } 45987117650Saalok 46087117650Saalok (void) close(compfd); 46187117650Saalok (void) close(uncompfd); 46287117650Saalok free(dir); 46387117650Saalok free(file); 46487117650Saalok 46587117650Saalok /* Delete the mapping */ 46687117650Saalok delete_mapping(lfd, devicename, filename, B_TRUE); 46787117650Saalok 46887117650Saalok /* 46987117650Saalok * If an error occured while reading or writing, rbytes will 47087117650Saalok * be negative 47187117650Saalok */ 47287117650Saalok if (rbytes < 0) { 47387117650Saalok (void) unlink(tmpfilename); 47487117650Saalok die(gettext("could not read from %s"), filename); 47587117650Saalok } 47687117650Saalok 47787117650Saalok /* Rename the temp file to the actual file */ 47887117650Saalok if (rename(tmpfilename, filename) == -1) 47987117650Saalok (void) unlink(tmpfilename); 48087117650Saalok } 48187117650Saalok 48287117650Saalok /* 48387117650Saalok * Compress a file 48487117650Saalok */ 48587117650Saalok static void 48687117650Saalok lofi_compress(int lfd, const char *filename, int compress_index, 48787117650Saalok uint32_t segsize) 48887117650Saalok { 48987117650Saalok struct lofi_ioctl lic; 49087117650Saalok lofi_compress_info_t *li; 49187117650Saalok char tmpfilename[MAXPATHLEN]; 49287117650Saalok char comp_filename[MAXPATHLEN]; 49387117650Saalok char algorithm[MAXALGLEN]; 49487117650Saalok char *dir = NULL, *file = NULL; 49587117650Saalok uchar_t *uncompressed_seg = NULL; 49687117650Saalok uchar_t *compressed_seg = NULL; 49787117650Saalok uint32_t compressed_segsize; 49887117650Saalok uint32_t len_compressed, count; 49987117650Saalok uint32_t index_entries, index_sz; 50087117650Saalok uint64_t *index = NULL; 50187117650Saalok uint64_t offset; 50287117650Saalok size_t real_segsize; 50387117650Saalok struct stat64 statbuf; 50487117650Saalok int compfd = -1, uncompfd = -1; 50587117650Saalok int tfd = -1; 50687117650Saalok ssize_t rbytes, wbytes, lastread; 50787117650Saalok int i, type; 50887117650Saalok 50987117650Saalok /* 51087117650Saalok * Disallow compressing the file if it is 51187117650Saalok * already mapped 51287117650Saalok */ 51387117650Saalok lic.li_minor = 0; 51487117650Saalok (void) strlcpy(lic.li_filename, filename, sizeof (lic.li_filename)); 51587117650Saalok if (ioctl(lfd, LOFI_GET_MINOR, &lic) != -1) 51687117650Saalok die(gettext("%s must be unmapped before compressing"), 51787117650Saalok filename); 51887117650Saalok 51987117650Saalok li = &lofi_compress_table[compress_index]; 52087117650Saalok 52187117650Saalok /* 52287117650Saalok * The size of the buffer to hold compressed data must 52387117650Saalok * be slightly larger than the compressed segment size. 52487117650Saalok * 52587117650Saalok * The compress functions use part of the buffer as 52687117650Saalok * scratch space to do calculations. 52787117650Saalok * Ref: http://www.zlib.net/manual.html#compress2 52887117650Saalok */ 52987117650Saalok compressed_segsize = segsize + (segsize >> 6); 53087117650Saalok compressed_seg = (uchar_t *)malloc(compressed_segsize + SEGHDR); 53187117650Saalok uncompressed_seg = (uchar_t *)malloc(segsize); 53287117650Saalok 53387117650Saalok if (compressed_seg == NULL || uncompressed_seg == NULL) 53487117650Saalok die(gettext("No memory")); 53587117650Saalok 53687117650Saalok if ((uncompfd = open64(filename, O_RDONLY|O_LARGEFILE, 0)) == -1) 53787117650Saalok die(gettext("open: %s"), filename); 53887117650Saalok 53987117650Saalok if (fstat64(uncompfd, &statbuf) == -1) { 54087117650Saalok (void) close(uncompfd); 54187117650Saalok die(gettext("fstat: %s"), filename); 54287117650Saalok } 54387117650Saalok 54487117650Saalok /* Zero length files don't need to be compressed */ 54587117650Saalok if (statbuf.st_size == 0) { 54687117650Saalok (void) close(uncompfd); 54787117650Saalok return; 54887117650Saalok } 54987117650Saalok 55087117650Saalok /* 55187117650Saalok * Create temporary files in the same directory that 55287117650Saalok * will hold the intermediate data 55387117650Saalok */ 55487117650Saalok dir = strdup(filename); 55587117650Saalok dir = dirname(dir); 55687117650Saalok file = strdup(filename); 55787117650Saalok file = basename(file); 55887117650Saalok (void) snprintf(tmpfilename, sizeof (tmpfilename), 55987117650Saalok "%s/.%sXXXXXX", dir, file); 56087117650Saalok (void) snprintf(comp_filename, sizeof (comp_filename), 56187117650Saalok "%s/.%sXXXXXX", dir, file); 56287117650Saalok 56387117650Saalok if ((tfd = mkstemp64(tmpfilename)) == -1) 56487117650Saalok goto cleanup; 56587117650Saalok 56687117650Saalok if ((compfd = mkstemp64(comp_filename)) == -1) 56787117650Saalok goto cleanup; 56887117650Saalok 56987117650Saalok /* 57087117650Saalok * Set the mode bits and owner of the compressed 57187117650Saalok * file to be that of the original uncompressed file 57287117650Saalok */ 57387117650Saalok (void) fchmod(compfd, statbuf.st_mode); 57487117650Saalok 57587117650Saalok if (fchown(compfd, statbuf.st_uid, statbuf.st_gid) == -1) 57687117650Saalok goto cleanup; 57787117650Saalok 57887117650Saalok /* 57987117650Saalok * Calculate the number of index entries required. 58087117650Saalok * index entries are stored as an array. adding 58187117650Saalok * a '2' here accounts for the fact that the last 58287117650Saalok * segment may not be a multiple of the segment size 58387117650Saalok */ 58487117650Saalok index_sz = (statbuf.st_size / segsize) + 2; 58587117650Saalok index = malloc(sizeof (*index) * index_sz); 58687117650Saalok 58787117650Saalok if (index == NULL) 58887117650Saalok goto cleanup; 58987117650Saalok 59087117650Saalok offset = 0; 59187117650Saalok lastread = segsize; 59287117650Saalok count = 0; 59387117650Saalok 59487117650Saalok /* 59587117650Saalok * Now read from the uncompressed file in 'segsize' 59687117650Saalok * sized chunks, compress what was read in and 59787117650Saalok * write it out to a temporary file 59887117650Saalok */ 59987117650Saalok for (;;) { 60087117650Saalok rbytes = read(uncompfd, uncompressed_seg, segsize); 60187117650Saalok 60287117650Saalok if (rbytes <= 0) 60387117650Saalok break; 60487117650Saalok 60587117650Saalok if (lastread < segsize) 60687117650Saalok goto cleanup; 60787117650Saalok 60887117650Saalok /* 60987117650Saalok * Account for the first byte that 61087117650Saalok * indicates whether a segment is 61187117650Saalok * compressed or not 61287117650Saalok */ 61387117650Saalok real_segsize = segsize - 1; 61487117650Saalok (void) li->l_compress(uncompressed_seg, rbytes, 61587117650Saalok compressed_seg + SEGHDR, &real_segsize, li->l_level); 61687117650Saalok 61787117650Saalok /* 61887117650Saalok * If the length of the compressed data is more 61987117650Saalok * than a threshold then there isn't any benefit 62087117650Saalok * to be had from compressing this segment - leave 62187117650Saalok * it uncompressed. 62287117650Saalok * 62387117650Saalok * NB. In case an error occurs during compression (above) 62487117650Saalok * the 'real_segsize' isn't changed. The logic below 62587117650Saalok * ensures that that segment is left uncompressed. 62687117650Saalok */ 62787117650Saalok len_compressed = real_segsize; 62887117650Saalok if (real_segsize > segsize - COMPRESS_THRESHOLD) { 62987117650Saalok (void) memcpy(compressed_seg + SEGHDR, uncompressed_seg, 63087117650Saalok rbytes); 63187117650Saalok type = UNCOMPRESSED; 63287117650Saalok len_compressed = rbytes; 63387117650Saalok } else { 63487117650Saalok type = COMPRESSED; 63587117650Saalok } 63687117650Saalok 63787117650Saalok /* 63887117650Saalok * Set the first byte or the SEGHDR to 63987117650Saalok * indicate if it's compressed or not 64087117650Saalok */ 64187117650Saalok *compressed_seg = type; 64287117650Saalok wbytes = write(tfd, compressed_seg, len_compressed + SEGHDR); 64387117650Saalok if (wbytes != (len_compressed + SEGHDR)) { 64487117650Saalok rbytes = -1; 64587117650Saalok break; 64687117650Saalok } 64787117650Saalok 64887117650Saalok index[count] = BE_64(offset); 64987117650Saalok offset += wbytes; 65087117650Saalok lastread = rbytes; 65187117650Saalok count++; 65287117650Saalok } 65387117650Saalok 65487117650Saalok (void) close(uncompfd); 65587117650Saalok 65687117650Saalok if (rbytes < 0) 65787117650Saalok goto cleanup; 65887117650Saalok /* 65987117650Saalok * The last index entry is a sentinel entry. It does not point to 66087117650Saalok * an actual compressed segment but helps in computing the size of 66187117650Saalok * the compressed segment. The size of each compressed segment is 66287117650Saalok * computed by subtracting the current index value from the next 66387117650Saalok * one (the compressed blocks are stored sequentially) 66487117650Saalok */ 66587117650Saalok index[count++] = BE_64(offset); 66687117650Saalok 66787117650Saalok /* 66887117650Saalok * Now write the compressed data along with the 66987117650Saalok * header information to this file which will 67087117650Saalok * later be renamed to the original uncompressed 67187117650Saalok * file name 67287117650Saalok * 67387117650Saalok * The header is as follows - 67487117650Saalok * 67587117650Saalok * Signature (name of the compression algorithm) 67687117650Saalok * Compression segment size (a multiple of 512) 67787117650Saalok * Number of index entries 67887117650Saalok * Size of the last block 67987117650Saalok * The array containing the index entries 68087117650Saalok * 68187117650Saalok * the header is always stored in network byte 68287117650Saalok * order 68387117650Saalok */ 68487117650Saalok (void) bzero(algorithm, sizeof (algorithm)); 68587117650Saalok (void) strlcpy(algorithm, li->l_name, sizeof (algorithm)); 68687117650Saalok if (write(compfd, algorithm, sizeof (algorithm)) 68787117650Saalok != sizeof (algorithm)) 68887117650Saalok goto cleanup; 68987117650Saalok 69087117650Saalok segsize = htonl(segsize); 69187117650Saalok if (write(compfd, &segsize, sizeof (segsize)) != sizeof (segsize)) 69287117650Saalok goto cleanup; 69387117650Saalok 69487117650Saalok index_entries = htonl(count); 69587117650Saalok if (write(compfd, &index_entries, sizeof (index_entries)) != 69687117650Saalok sizeof (index_entries)) 69787117650Saalok goto cleanup; 69887117650Saalok 69987117650Saalok lastread = htonl(lastread); 70087117650Saalok if (write(compfd, &lastread, sizeof (lastread)) != sizeof (lastread)) 70187117650Saalok goto cleanup; 70287117650Saalok 70387117650Saalok for (i = 0; i < count; i++) { 70487117650Saalok if (write(compfd, index + i, sizeof (*index)) != 70587117650Saalok sizeof (*index)) 70687117650Saalok goto cleanup; 70787117650Saalok } 70887117650Saalok 70987117650Saalok /* Header is written, now write the compressed data */ 71087117650Saalok if (lseek(tfd, 0, SEEK_SET) != 0) 71187117650Saalok goto cleanup; 71287117650Saalok 71387117650Saalok rbytes = wbytes = 0; 71487117650Saalok 71587117650Saalok for (;;) { 71687117650Saalok rbytes = read(tfd, compressed_seg, compressed_segsize + SEGHDR); 71787117650Saalok 71887117650Saalok if (rbytes <= 0) 71987117650Saalok break; 72087117650Saalok 72187117650Saalok if (write(compfd, compressed_seg, rbytes) != rbytes) 72287117650Saalok goto cleanup; 72387117650Saalok } 72487117650Saalok 72587117650Saalok if (fstat64(compfd, &statbuf) == -1) 72687117650Saalok goto cleanup; 72787117650Saalok 72887117650Saalok /* 72987117650Saalok * Round up the compressed file size to be a multiple of 73087117650Saalok * DEV_BSIZE. lofi(7D) likes it that way. 73187117650Saalok */ 73287117650Saalok if ((offset = statbuf.st_size % DEV_BSIZE) > 0) { 73387117650Saalok 73487117650Saalok offset = DEV_BSIZE - offset; 73587117650Saalok 73687117650Saalok for (i = 0; i < offset; i++) 73787117650Saalok uncompressed_seg[i] = '\0'; 73887117650Saalok if (write(compfd, uncompressed_seg, offset) != offset) 73987117650Saalok goto cleanup; 74087117650Saalok } 74187117650Saalok (void) close(compfd); 74287117650Saalok (void) close(tfd); 74387117650Saalok (void) unlink(tmpfilename); 74487117650Saalok cleanup: 74587117650Saalok if (rbytes < 0) { 74687117650Saalok if (tfd != -1) 74787117650Saalok (void) unlink(tmpfilename); 74887117650Saalok if (compfd != -1) 74987117650Saalok (void) unlink(comp_filename); 75087117650Saalok die(gettext("error compressing file %s"), filename); 75187117650Saalok } else { 75287117650Saalok /* Rename the compressed file to the actual file */ 75387117650Saalok if (rename(comp_filename, filename) == -1) { 75487117650Saalok (void) unlink(comp_filename); 75587117650Saalok die(gettext("error compressing file %s"), filename); 75687117650Saalok } 75787117650Saalok } 75887117650Saalok if (compressed_seg != NULL) 75987117650Saalok free(compressed_seg); 76087117650Saalok if (uncompressed_seg != NULL) 76187117650Saalok free(uncompressed_seg); 76287117650Saalok if (dir != NULL) 76387117650Saalok free(dir); 76487117650Saalok if (file != NULL) 76587117650Saalok free(file); 76687117650Saalok if (index != NULL) 76787117650Saalok free(index); 76887117650Saalok if (compfd != -1) 76987117650Saalok (void) close(compfd); 77087117650Saalok if (uncompfd != -1) 77187117650Saalok (void) close(uncompfd); 77287117650Saalok if (tfd != -1) 77387117650Saalok (void) close(tfd); 77487117650Saalok } 77587117650Saalok 77687117650Saalok static int 77787117650Saalok lofi_compress_select(const char *algname) 77887117650Saalok { 77987117650Saalok int i; 78087117650Saalok 78187117650Saalok for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) { 78287117650Saalok if (strcmp(lofi_compress_table[i].l_name, algname) == 0) 78387117650Saalok return (i); 78487117650Saalok } 78587117650Saalok return (-1); 78687117650Saalok } 78787117650Saalok 78887117650Saalok static void 78987117650Saalok check_algorithm_validity(const char *algname, int *compress_index) 79087117650Saalok { 79187117650Saalok *compress_index = lofi_compress_select(algname); 79287117650Saalok if (*compress_index < 0) 79387117650Saalok die(gettext("invalid algorithm name: %s\n"), algname); 79487117650Saalok } 79587117650Saalok 79687117650Saalok static void 79787117650Saalok check_file_validity(const char *filename) 79887117650Saalok { 7997c478bd9Sstevel@tonic-gate struct stat64 buf; 80087117650Saalok int error; 8017c478bd9Sstevel@tonic-gate int fd = -1; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate fd = open64(filename, O_RDONLY); 8047c478bd9Sstevel@tonic-gate if (fd == -1) { 8057c478bd9Sstevel@tonic-gate die(gettext("open: %s"), filename); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate error = fstat64(fd, &buf); 8087c478bd9Sstevel@tonic-gate if (error == -1) { 8097c478bd9Sstevel@tonic-gate die(gettext("fstat: %s"), filename); 8107c478bd9Sstevel@tonic-gate } else if (!S_ISLOFIABLE(buf.st_mode)) { 8117c478bd9Sstevel@tonic-gate die(gettext("%s is not a regular file, " 8127c478bd9Sstevel@tonic-gate "block, or character device\n"), 8137c478bd9Sstevel@tonic-gate filename); 8147c478bd9Sstevel@tonic-gate } else if ((buf.st_size % DEV_BSIZE) != 0) { 8157c478bd9Sstevel@tonic-gate die(gettext("size of %s is not a multiple " 8167c478bd9Sstevel@tonic-gate "of %d\n"), 8177c478bd9Sstevel@tonic-gate filename, DEV_BSIZE); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate (void) close(fd); 82087117650Saalok 82187117650Saalok if (name_to_minor(filename) != 0) { 8227c478bd9Sstevel@tonic-gate die(gettext("cannot use " LOFI_DRIVER_NAME 82387117650Saalok " on itself\n"), NULL); 8247c478bd9Sstevel@tonic-gate } 82587117650Saalok } 82687117650Saalok 82787117650Saalok static uint32_t 82887117650Saalok convert_to_num(const char *str) 82987117650Saalok { 83087117650Saalok int len; 83187117650Saalok uint32_t segsize, mult = 1; 83287117650Saalok 83387117650Saalok len = strlen(str); 83487117650Saalok if (len && isalpha(str[len - 1])) { 83587117650Saalok switch (str[len - 1]) { 83687117650Saalok case 'k': 83787117650Saalok case 'K': 83887117650Saalok mult = KILOBYTE; 83987117650Saalok break; 84087117650Saalok case 'b': 84187117650Saalok case 'B': 84287117650Saalok mult = BLOCK_SIZE; 84387117650Saalok break; 84487117650Saalok case 'm': 84587117650Saalok case 'M': 84687117650Saalok mult = MEGABYTE; 84787117650Saalok break; 84887117650Saalok case 'g': 84987117650Saalok case 'G': 85087117650Saalok mult = GIGABYTE; 85187117650Saalok break; 85287117650Saalok default: 85387117650Saalok die(gettext("invalid segment size %s\n"), str); 85487117650Saalok } 85587117650Saalok } 85687117650Saalok 85787117650Saalok segsize = atol(str); 85887117650Saalok segsize *= mult; 85987117650Saalok 86087117650Saalok return (segsize); 86187117650Saalok } 86287117650Saalok 86387117650Saalok int 86487117650Saalok main(int argc, char *argv[]) 86587117650Saalok { 86687117650Saalok int lfd; 86787117650Saalok int c; 86887117650Saalok const char *devicename = NULL; 86987117650Saalok const char *filename = NULL; 87087117650Saalok const char *algname = COMPRESS_ALGORITHM; 87187117650Saalok int openflag; 87287117650Saalok int minor; 87387117650Saalok int compress_index; 87487117650Saalok uint32_t segsize = SEGSIZE; 87587117650Saalok static char *lofictl = "/dev/" LOFI_CTL_NAME; 87687117650Saalok boolean_t force = B_FALSE; 87787117650Saalok 87887117650Saalok pname = getpname(argv[0]); 87987117650Saalok 88087117650Saalok (void) setlocale(LC_ALL, ""); 88187117650Saalok (void) textdomain(TEXT_DOMAIN); 88287117650Saalok 88387117650Saalok while ((c = getopt(argc, argv, "a:C:d:s:U:f")) != EOF) { 88487117650Saalok switch (c) { 88587117650Saalok case 'a': 88687117650Saalok addflag = 1; 88787117650Saalok filename = optarg; 88887117650Saalok check_file_validity(filename); 88987117650Saalok 8907c478bd9Sstevel@tonic-gate if (((argc - optind) > 0) && (*argv[optind] != '-')) { 8917c478bd9Sstevel@tonic-gate /* optional device */ 8927c478bd9Sstevel@tonic-gate devicename = argv[optind]; 8937c478bd9Sstevel@tonic-gate optind++; 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate break; 89687117650Saalok case 'C': 89787117650Saalok compressflag = 1; 89887117650Saalok 89987117650Saalok if (((argc - optind) > 0) && 90087117650Saalok (*optarg == '-')) { 90187117650Saalok check_algorithm_validity(algname, 90287117650Saalok &compress_index); 90387117650Saalok optind--; 90487117650Saalok break; 90587117650Saalok } else if (((argc - optind) == 1) && 90687117650Saalok (*argv[optind] != '-')) { 90787117650Saalok algname = optarg; 90887117650Saalok filename = argv[optind]; 90987117650Saalok optind++; 91087117650Saalok } else if (((argc - optind) > 1) && 91187117650Saalok (*argv[optind] == '-')) { 91287117650Saalok algname = optarg; 91387117650Saalok check_algorithm_validity(algname, 91487117650Saalok &compress_index); 91587117650Saalok break; 91687117650Saalok } else { 91787117650Saalok filename = optarg; 91887117650Saalok } 91987117650Saalok 92087117650Saalok check_file_validity(filename); 92187117650Saalok check_algorithm_validity(algname, &compress_index); 92287117650Saalok break; 9237c478bd9Sstevel@tonic-gate case 'd': 9247c478bd9Sstevel@tonic-gate deleteflag = 1; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate minor = name_to_minor(optarg); 9277c478bd9Sstevel@tonic-gate if (minor != 0) 9287c478bd9Sstevel@tonic-gate devicename = optarg; 9297c478bd9Sstevel@tonic-gate else 9307c478bd9Sstevel@tonic-gate filename = optarg; 9317c478bd9Sstevel@tonic-gate break; 9323d7072f8Seschrock case 'f': 9333d7072f8Seschrock force = B_TRUE; 9343d7072f8Seschrock break; 93587117650Saalok case 's': 93687117650Saalok segsize = convert_to_num(optarg); 93787117650Saalok 93887117650Saalok if (segsize == 0 || segsize % DEV_BSIZE) 93987117650Saalok die(gettext("segment size %s is invalid " 94087117650Saalok "or not a multiple of minimum block " 94187117650Saalok "size %ld\n"), optarg, DEV_BSIZE); 94287117650Saalok 94387117650Saalok filename = argv[optind]; 94487117650Saalok check_file_validity(filename); 94587117650Saalok optind++; 94687117650Saalok break; 94787117650Saalok case 'U': 94887117650Saalok uncompressflag = 1; 94987117650Saalok filename = optarg; 95087117650Saalok check_file_validity(filename); 95187117650Saalok break; 9527c478bd9Sstevel@tonic-gate case '?': 9537c478bd9Sstevel@tonic-gate default: 9547c478bd9Sstevel@tonic-gate errflag = 1; 9557c478bd9Sstevel@tonic-gate break; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate } 95887117650Saalok if (errflag || 95987117650Saalok (addflag && deleteflag) || 96087117650Saalok ((compressflag || uncompressflag) && (addflag || deleteflag))) 9617c478bd9Sstevel@tonic-gate usage(); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate switch (argc - optind) { 9647c478bd9Sstevel@tonic-gate case 0: /* no more args */ 9657c478bd9Sstevel@tonic-gate break; 9667c478bd9Sstevel@tonic-gate case 1: /* one arg without options means print the association */ 9677c478bd9Sstevel@tonic-gate if (addflag || deleteflag) 9687c478bd9Sstevel@tonic-gate usage(); 96987117650Saalok if (compressflag || uncompressflag) 97087117650Saalok usage(); 9717c478bd9Sstevel@tonic-gate minor = name_to_minor(argv[optind]); 9727c478bd9Sstevel@tonic-gate if (minor != 0) 9737c478bd9Sstevel@tonic-gate devicename = argv[optind]; 9747c478bd9Sstevel@tonic-gate else 9757c478bd9Sstevel@tonic-gate filename = argv[optind]; 9767c478bd9Sstevel@tonic-gate break; 9777c478bd9Sstevel@tonic-gate default: 9787c478bd9Sstevel@tonic-gate usage(); 9797c478bd9Sstevel@tonic-gate break; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate if (filename && !valid_abspath(filename)) 9837c478bd9Sstevel@tonic-gate exit(E_ERROR); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 9867c478bd9Sstevel@tonic-gate * Here, we know the arguments are correct, the filename is an 9877c478bd9Sstevel@tonic-gate * absolute path, it exists and is a regular file. We don't yet 9887c478bd9Sstevel@tonic-gate * know that the device name is ok or not. 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * Now to the real work. 9927c478bd9Sstevel@tonic-gate */ 9937c478bd9Sstevel@tonic-gate openflag = O_EXCL; 99487117650Saalok if (addflag || deleteflag || compressflag || uncompressflag) 9957c478bd9Sstevel@tonic-gate openflag |= O_RDWR; 9967c478bd9Sstevel@tonic-gate else 9977c478bd9Sstevel@tonic-gate openflag |= O_RDONLY; 9987c478bd9Sstevel@tonic-gate lfd = open(lofictl, openflag); 9997c478bd9Sstevel@tonic-gate if (lfd == -1) { 10007c478bd9Sstevel@tonic-gate if ((errno == EPERM) || (errno == EACCES)) { 10017c478bd9Sstevel@tonic-gate die("you do not have permission to perform " 10027c478bd9Sstevel@tonic-gate "that operation.\n"); 10037c478bd9Sstevel@tonic-gate } else { 10047c478bd9Sstevel@tonic-gate die("%s", lofictl); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate if (addflag) 100987117650Saalok add_mapping(lfd, devicename, filename, NULL, 0); 101087117650Saalok else if (compressflag) 101187117650Saalok lofi_compress(lfd, filename, compress_index, segsize); 101287117650Saalok else if (uncompressflag) 101387117650Saalok lofi_uncompress(lfd, filename); 10147c478bd9Sstevel@tonic-gate else if (deleteflag) 10153d7072f8Seschrock delete_mapping(lfd, devicename, filename, force); 10167c478bd9Sstevel@tonic-gate else if (filename || devicename) 10177c478bd9Sstevel@tonic-gate print_one_mapping(lfd, devicename, filename); 10187c478bd9Sstevel@tonic-gate else 10197c478bd9Sstevel@tonic-gate print_mappings(lfd); 1020579df0adSaalok 10217c478bd9Sstevel@tonic-gate (void) close(lfd); 1022579df0adSaalok closelib(); 10237c478bd9Sstevel@tonic-gate return (E_SUCCESS); 10247c478bd9Sstevel@tonic-gate } 1025