latest and greatest.
[oweals/busybox.git] / losetup.c
1 /*
2  * losetup.c - setup and control loop devices
3  */
4
5
6 #include "internal.h"
7
8 const char      losetup_usage[] = "losetup\n"
9 "\n"
10 "\tlosetup loop_device                          give info\n"
11 "\tlosetup -d loop_device                               delete\n"
12 "\tlosetup [ -o offset ] loop_device file               setup\n";
13
14 /* from mount-2.6d */
15
16 /*
17  * losetup.c - setup and control loop devices
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <getopt.h>
26 #include <errno.h>
27 #include <sys/ioctl.h>
28 #include <linux/fs.h>
29 /* #include "loop.h" */
30
31 /*
32  * include/linux/loop.h
33  *
34  * Written by Theodore Ts'o, 3/29/93.
35  *
36  * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
37  * permitted under the GNU Public License.
38  */
39
40 #define LO_NAME_SIZE    64
41 #define LO_KEY_SIZE     32
42        
43 struct loop_info {
44         int             lo_number;      /* ioctl r/o */
45         dev_t           lo_device;      /* ioctl r/o */
46         unsigned long   lo_inode;       /* ioctl r/o */
47         dev_t           lo_rdevice;     /* ioctl r/o */
48         int             lo_offset;
49         int             lo_encrypt_type;
50         int             lo_encrypt_key_size;    /* ioctl w/o */
51         int             lo_flags;       /* ioctl r/o */
52         char            lo_name[LO_NAME_SIZE];
53         unsigned char   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
54         unsigned long   lo_init[2];
55         char            reserved[4];
56 };
57
58 /*
59  * IOCTL commands --- we will commandeer 0x4C ('L')
60  */
61
62 #define LOOP_SET_FD     0x4C00
63 #define LOOP_CLR_FD     0x4C01
64 #define LOOP_SET_STATUS 0x4C02
65 #define LOOP_GET_STATUS 0x4C03
66
67 /* #include "lomount.h" */
68
69 extern int set_loop (const char *, const char *, int, int *);
70 extern int del_loop (const char *);
71
72 static void show_loop(const char *device)
73 {
74         struct  loop_info       loopinfo;
75         int                     fd;
76         
77         if ((fd = open(device, O_RDWR)) < 0) {
78                 perror(device);
79                 return;
80         }
81         if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
82                 perror("Cannot get loop info");
83                 close(fd);
84                 return;
85         }
86         printf("%s: [%04x]:%ld (%s) offset %d\n",
87                device, (unsigned int)loopinfo.lo_device, loopinfo.lo_inode,
88                loopinfo.lo_name, loopinfo.lo_offset);
89         close(fd);
90 }
91
92
93 int set_loop(const char *device, const char *file, int offset, int *loopro)
94 {
95         struct loop_info loopinfo;
96         int     fd, ffd, mode;
97         
98         mode = *loopro ? O_RDONLY : O_RDWR;
99         if ((ffd = open (file, mode)) < 0 && !*loopro
100             && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) {
101           perror (file);
102           return 1;
103         }
104         if ((fd = open (device, mode)) < 0) {
105           close(ffd);
106           perror (device);
107           return 1;
108         }
109         *loopro = (mode == O_RDONLY);
110
111         memset(&loopinfo, 0, sizeof(loopinfo));
112         strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
113         loopinfo.lo_name[LO_NAME_SIZE-1] = 0;
114
115         loopinfo.lo_offset = offset;
116
117         loopinfo.lo_encrypt_key_size = 0;
118         if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
119                 perror("ioctl: LOOP_SET_FD");
120                 exit(1);
121         }
122         if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
123                 (void) ioctl(fd, LOOP_CLR_FD, 0);
124                 perror("ioctl: LOOP_SET_STATUS");
125                 exit(1);
126         }
127         close(fd);
128         close(ffd);
129         return 0;
130 }
131
132 int del_loop(const char *device)
133 {
134         int fd;
135
136         if ((fd = open(device, O_RDONLY)) < 0) {
137                 perror(device);
138                 exit(1);
139         }
140         if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
141                 perror("ioctl: LOOP_CLR_FD");
142                 exit(1);
143         }
144         close(fd);
145         return(0);
146 }
147
148
149 static int losetup_usage_fn(void)
150 {
151         fprintf(stderr, losetup_usage);
152         exit(1);
153 }
154
155 int losetup_main(struct FileInfo * i, int argc, char * * argv)
156 {
157         char *offset;
158         int delete,off,c;
159         int ro = 0;
160
161         delete = off = 0;
162         offset = NULL;
163         while ((c = getopt(argc,argv,"do:")) != EOF) {
164                 switch (c) {
165                         case 'd':
166                                 delete = 1;
167                                 break;
168                         case 'o':
169                                 offset = optarg;
170                                 break;
171                         default:
172                                 losetup_usage_fn();
173                 }
174         }
175         if (argc == 1) losetup_usage_fn();
176         if ((delete && (argc != optind+1 || offset)) ||
177             (!delete && (argc < optind+1 || argc > optind+2)))
178                 losetup_usage_fn();
179         if (argc == optind+1)
180                 if (delete)
181                         del_loop(argv[optind]);
182                 else
183                         show_loop(argv[optind]);
184         else {
185                 if (offset && sscanf(offset,"%d",&off) != 1)
186                         losetup_usage_fn();
187                 set_loop(argv[optind],argv[optind+1],off,&ro);
188         }
189         return 0;
190 }