1ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley/* losetup.c - Loopback setup 2ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley * 3ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley * Copyright 2012 Rob Landley <rob@landley.net> 4ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley * 5ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley * No standard. (Sigh.) 6ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 7ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob LandleyUSE_LOSETUP(NEWTOY(losetup, ">2S(sizelimit)#s(show)ro#j:fdca[!afj]", TOYFLAG_SBIN)) 8ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 9ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landleyconfig LOSETUP 10ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley bool "losetup" 11ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley default y 12ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley help 13ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley usage: losetup [-cdrs] [-o OFFSET] [-S SIZE] {-d DEVICE...|-j FILE|-af|{DEVICE FILE}} 14ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 15ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley Associate a loopback device with a file, or show current file (if any) 16ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley associated with a loop device. 17ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 18ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley Instead of a device: 19ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -a Iterate through all loopback devices 20ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -f Find first unused loop device (may create one) 21ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -j Iterate through all loopback devices associated with FILE 22ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 23ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley existing: 24ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -c Check capacity (file size changed) 25ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -d Detach loopback device 26ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 27ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley new: 28ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -s Show device name (alias --show) 29ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -o Start assocation at OFFSET into FILE 30ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -r Read only 31ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley -S Limit SIZE of loopback association (alias --sizelimit) 32ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley*/ 33ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 34ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley#define FOR_losetup 35ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley#include "toys.h" 36ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley#include <linux/loop.h> 37ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 38ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob LandleyGLOBALS( 39ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley char *jfile; 40ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley long offset; 41ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley long size; 42ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 43ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley int openflags; 44ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley dev_t jdev; 45ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley ino_t jino; 46ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley) 47ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 48ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley/* 49ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landleytodo: basic /dev file association 50ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley associate DEV FILE 51ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley #-a 52ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley cdfjosS 53ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley allocate new loop device: 54ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley /dev/loop-control 55ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley https://lkml.org/lkml/2011/7/26/148 56ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley*/ 57ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 58ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley// -f: *device is NULL 59ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 60ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley// Perform requested operation on one device. Returns 1 if handled, 0 if error 61ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landleystatic void loopback_setup(char *device, char *file) 62ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley{ 63ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley struct loop_info64 *loop = (void *)(toybuf+32); 641a33c6b07a20af27b23f62f5c88a422eb96e463cRob Landley int lfd = -1, ffd = ffd; 65ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley unsigned flags = toys.optflags; 66ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 67ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Open file (ffd) and loop device (lfd) 68ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 69ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (file) ffd = xopen(file, TT.openflags); 70ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (!device) { 71ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley int i, cfd = open("/dev/loop-control", O_RDWR); 72ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 73ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // We assume /dev is devtmpfs so device creation has no lag. Otherwise 74ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // just preallocate loop devices and stay within them. 75ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 76ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // mount -o loop depends on found device being at the start of toybuf. 77ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (cfd != -1) { 78af0011995826b635658e29b107d33cf9ee7cdd42Rob Landley if (0 <= (i = ioctl(cfd, 0x4C82))) // LOOP_CTL_GET_FREE 79ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley sprintf(device = toybuf, "/dev/loop%d", i); 80ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley close(cfd); 81ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 82ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 83ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 84ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (device) lfd = open(device, TT.openflags); 85ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 86ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Stat the loop device to see if there's a current association. 87ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley memset(loop, 0, sizeof(struct loop_info64)); 88ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (-1 == lfd || ioctl(lfd, LOOP_GET_STATUS64, loop)) { 893d56716d362d6a827c5f81029ac64c71b56a2f5cRob Landley if (errno == ENXIO && (flags & (FLAG_a|FLAG_j))) goto done; 90ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (errno != ENXIO || !file) { 91d3a435e53c94ec25b4ae5fa2614f49ef8884e08aRob Landley perror_msg_raw(device ? device : "-f"); 92ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley goto done; 93ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 94ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 95ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 96ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Skip -j filtered devices 97ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (TT.jfile && (loop->lo_device != TT.jdev || loop->lo_inode != TT.jino)) 98ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley goto done; 99ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 100ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Check size of file or delete existing association 101ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (flags & (FLAG_c|FLAG_d)) { 102af0011995826b635658e29b107d33cf9ee7cdd42Rob Landley // The constant is LOOP_SET_CAPACITY 103af0011995826b635658e29b107d33cf9ee7cdd42Rob Landley if (ioctl(lfd, (flags & FLAG_c) ? 0x4C07 : LOOP_CLR_FD, 0)) { 104d3a435e53c94ec25b4ae5fa2614f49ef8884e08aRob Landley perror_msg_raw(device); 105ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley goto done; 106ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 107ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Associate file with this device? 108ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } else if (file) { 1093c69835d6e0b4f8e72e441ae5e34439612790844Rob Landley char *s = xabspath(file, 1); 110ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 1113c69835d6e0b4f8e72e441ae5e34439612790844Rob Landley if (!s) perror_exit("file"); // already opened, but if deleted since... 112ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (ioctl(lfd, LOOP_SET_FD, ffd)) perror_exit("%s=%s", device, file); 113ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley loop->lo_offset = TT.offset; 114ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley loop->lo_sizelimit = TT.size; 11582effc97f9f2d1c258ea50cb11b130753b8ba805Rob Landley xstrncpy((char *)loop->lo_file_name, s, LO_NAME_SIZE); 116ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley s[LO_NAME_SIZE-1] = 0; 117ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (ioctl(lfd, LOOP_SET_STATUS64, loop)) perror_exit("%s=%s", device, file); 118ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (flags & FLAG_s) printf("%s", device); 119ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley free(s); 120ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } else if (flags & FLAG_f) printf("%s", device); 121ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley else { 122ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley xprintf("%s: [%04llx]:%llu (%s)", device, loop->lo_device, loop->lo_inode, 123ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley loop->lo_file_name); 124ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (loop->lo_offset) xprintf(", offset %llu", loop->lo_offset); 125ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (loop->lo_sizelimit) xprintf(", sizelimit %llu", loop->lo_sizelimit); 126ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley xputc('\n'); 127ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 128ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 129ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landleydone: 130ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (file) close(ffd); 131ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (lfd != -1) close(lfd); 132ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley} 133ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 134ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley// Perform an action on all currently existing loop devices 135ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landleystatic int dash_a(struct dirtree *node) 136ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley{ 137ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley char *s = node->name; 138ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 139ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Initial /dev node needs to recurse down one level, then only loop[0-9]* 140ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (*s == '/') return DIRTREE_RECURSE; 141ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (strncmp(s, "loop", 4) || !isdigit(s[4])) return 0; 142ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 143ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley s = dirtree_path(node, 0); 144ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley loopback_setup(s, 0); 145ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley free(s); 146ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 147ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley return 0; 148ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley} 149ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 150ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landleyvoid losetup_main(void) 151ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley{ 152ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley char **s; 153ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 154ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley TT.openflags = (toys.optflags & FLAG_r) ? O_RDONLY : O_RDWR; 155ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 156ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (TT.jfile) { 157ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley struct stat st; 158ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 159ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley xstat(TT.jfile, &st); 160ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley TT.jdev = st.st_dev; 161ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley TT.jino = st.st_ino; 162ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 163ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 164ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // With just device, display current association 165ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // -a, -f substitute for device 166ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // -j substitute for device 167ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 168ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // new association: S size o offset rs - need a file 169ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // existing association: cd 170ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 171ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // -f(dc FILE) 172ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 173ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (toys.optflags & FLAG_f) { 174ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (toys.optc > 1) perror_exit("max 1 arg"); 175ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley loopback_setup(NULL, *toys.optargs); 176ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } else if (toys.optflags & (FLAG_a|FLAG_j)) { 177ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley if (toys.optc) error_exit("bad args"); 178ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley dirtree_read("/dev", dash_a); 179ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley // Do we need one DEVICE argument? 180ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } else { 181ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley char *file = (toys.optflags & (FLAG_d|FLAG_c)) ? NULL : toys.optargs[1]; 182ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley 183e5354ca12a232b3f97726214254a868771cb70d1Rob Landley if (!toys.optc || (file && toys.optc != 2)) 184e5354ca12a232b3f97726214254a868771cb70d1Rob Landley help_exit("needs %d arg%s", 1+!!file, file ? "s" : ""); 185c6fcf1d25da72a45d59a3791062bd5241034eb8aRob Landley for (s = toys.optargs; *s; s++) { 186c6fcf1d25da72a45d59a3791062bd5241034eb8aRob Landley loopback_setup(*s, file); 187c6fcf1d25da72a45d59a3791062bd5241034eb8aRob Landley if (file) break; 188ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 189ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley } 190ef2af2e4d6ddb25cc9b17167e9db5a49b1265abeRob Landley} 191