summaryrefslogtreecommitdiffstats
path: root/include/loopdev.h
blob: 6d400d1f3ff7ebb8c1dfb3f90a44435939b8dbc0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#ifndef UTIL_LINUX_LOOPDEV_H
#define UTIL_LINUX_LOOPDEV_H

#include "sysfs.h"

/*
 * loop_info.lo_encrypt_type
 */
#define LO_CRYPT_NONE	0
#define LO_CRYPT_XOR	1
#define LO_CRYPT_DES	2
#define LO_CRYPT_CRYPTOAPI 18

#define LOOP_SET_FD		0x4C00
#define LOOP_CLR_FD		0x4C01
/*
 * Obsolete (kernel < 2.6)
 *
 * #define LOOP_SET_STATUS	0x4C02
 * #define LOOP_GET_STATUS	0x4C03
 */
#define LOOP_SET_STATUS64	0x4C04
#define LOOP_GET_STATUS64	0x4C05
/* #define LOOP_CHANGE_FD	0x4C06 */
#define LOOP_SET_CAPACITY	0x4C07
#define LOOP_SET_DIRECT_IO	0x4C08
#define LOOP_SET_BLOCK_SIZE	0x4C09

/* /dev/loop-control interface */
#ifndef LOOP_CTL_ADD
# define LOOP_CTL_ADD		0x4C80
# define LOOP_CTL_REMOVE	0x4C81
# define LOOP_CTL_GET_FREE	0x4C82
#endif

/*
 * loop_info.lo_flags
 */
enum {
	LO_FLAGS_READ_ONLY  = 1,
	LO_FLAGS_USE_AOPS   = 2,
	LO_FLAGS_AUTOCLEAR  = 4,	/* kernel >= 2.6.25 */
	LO_FLAGS_PARTSCAN   = 8,	/* kernel >= 3.2 */
	LO_FLAGS_DIRECT_IO  = 16,	/* kernel >= 4.2 */
};

#define LO_NAME_SIZE	64
#define LO_KEY_SIZE	32

/*
 * Linux LOOP_{SET,GET}_STATUS64 ioctl struct
 */
struct loop_info64 {
	uint64_t	lo_device;
	uint64_t	lo_inode;
	uint64_t	lo_rdevice;
	uint64_t	lo_offset;
	uint64_t	lo_sizelimit; /* bytes, 0 == max available */
	uint32_t	lo_number;
	uint32_t	lo_encrypt_type;
	uint32_t	lo_encrypt_key_size;
	uint32_t	lo_flags;
	uint8_t		lo_file_name[LO_NAME_SIZE];
	uint8_t		lo_crypt_name[LO_NAME_SIZE];
	uint8_t		lo_encrypt_key[LO_KEY_SIZE];
	uint64_t	lo_init[2];
};

#ifndef LOOP_CONFIGURE
/*
 * Since Linux v5.8-rc1 (commit 3448914e8cc550ba792d4ccc74471d1ca4293aae)
 */
# define LOOP_CONFIGURE		0x4C0A
struct loop_config {
  uint32_t fd;
  uint32_t block_size;
  struct loop_info64 info;
  uint64_t __reserved[8];
};
#endif

#define LOOPDEV_MAJOR		7	/* loop major number */
#define LOOPDEV_DEFAULT_NNODES	8	/* default number of loop devices */

struct loopdev_iter {
	FILE		*proc;		/* /proc/partitions */
	DIR		*sysblock;	/* /sys/block */
	int		ncur;		/* current position */
	int		*minors;	/* ary of minor numbers (when scan whole /dev) */
	int		nminors;	/* number of items in *minors */
	int		ct_perm;	/* count permission problems */
	int		ct_succ;	/* count number of detected devices */

	unsigned int	done:1;		/* scanning done */
	unsigned int	default_check:1;/* check first LOOPDEV_NLOOPS */
	int		flags;		/* LOOPITER_FL_* flags */
};

enum {
	LOOPITER_FL_FREE	= (1 << 0),
	LOOPITER_FL_USED	= (1 << 1)
};

/*
 * handler for work with loop devices
 */
struct loopdev_cxt {
	char		device[128];	/* device path (e.g. /dev/loop<N>) */
	char		*filename;	/* backing file for loopcxt_set_... */
	int		fd;		/* open(/dev/looo<N>) */
	int		mode;		/* fd mode O_{RDONLY,RDWR} */
	uint64_t	blocksize;	/* used by loopcxt_setup_device() */

	int		flags;		/* LOOPDEV_FL_* flags */
	unsigned int	has_info:1;	/* .info contains data */
	unsigned int	extra_check:1;	/* unusual stuff for iterator */
	unsigned int	info_failed:1;	/* LOOP_GET_STATUS ioctl failed */
	unsigned int    control_ok:1;	/* /dev/loop-control success */

	struct path_cxt		*sysfs; /* pointer to /sys/dev/block/<maj:min>/ */
	struct loop_config 	config;	/* for GET/SET ioctl */
	struct loopdev_iter	iter;	/* scans /sys or /dev for used/free devices */
};

#define UL_LOOPDEVCXT_EMPTY { .fd = -1  }

/*
 * loopdev_cxt.flags
 */
enum {
	LOOPDEV_FL_RDONLY	= (1 << 0),	/* open(/dev/loop) mode; default */
	LOOPDEV_FL_RDWR		= (1 << 1),	/* necessary for loop setup only */
	LOOPDEV_FL_OFFSET	= (1 << 4),
	LOOPDEV_FL_NOSYSFS	= (1 << 5),
	LOOPDEV_FL_NOIOCTL	= (1 << 6),
	LOOPDEV_FL_DEVSUBDIR	= (1 << 7),
	LOOPDEV_FL_CONTROL	= (1 << 8),	/* system with /dev/loop-control */
	LOOPDEV_FL_SIZELIMIT	= (1 << 9)
};

/*
 * High-level
 */
extern int loopmod_supports_partscan(void);

extern int is_loopdev(const char *device);
extern int loopdev_is_autoclear(const char *device);

extern char *loopdev_get_backing_file(const char *device);
extern int loopdev_has_backing_file(const char *device);
extern int loopdev_is_used(const char *device, const char *filename,
			   uint64_t offset, uint64_t sizelimit, int flags);
extern char *loopdev_find_by_backing_file(const char *filename,
				uint64_t offset, uint64_t sizelimit, int flags);
extern int loopcxt_find_unused(struct loopdev_cxt *lc);
extern int loopdev_delete(const char *device);
extern int loopdev_count_by_backing_file(const char *filename, char **loopdev);

/*
 * Low-level
 */
extern int loopcxt_init(struct loopdev_cxt *lc, int flags)
				__attribute__ ((warn_unused_result));
extern void loopcxt_deinit(struct loopdev_cxt *lc);

extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
				__attribute__ ((warn_unused_result));
extern int loopcxt_has_device(struct loopdev_cxt *lc);
extern int loopcxt_add_device(struct loopdev_cxt *lc);
extern char *loopcxt_strdup_device(struct loopdev_cxt *lc);
extern const char *loopcxt_get_device(struct loopdev_cxt *lc);
extern struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc);

extern int loopcxt_get_fd(struct loopdev_cxt *lc);
extern int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode);

extern int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags);
extern int loopcxt_deinit_iterator(struct loopdev_cxt *lc);
extern int loopcxt_next(struct loopdev_cxt *lc);

extern int loopcxt_setup_device(struct loopdev_cxt *lc);
extern int loopcxt_delete_device(struct loopdev_cxt *lc);

extern int loopcxt_ioctl_status(struct loopdev_cxt *lc);
extern int loopcxt_ioctl_capacity(struct loopdev_cxt *lc);
extern int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio);
extern int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);

int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags);
int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename);

extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc);
extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno);
extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino);
extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset);
extern int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize);
extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size);
extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type);
extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc);
extern int loopcxt_is_autoclear(struct loopdev_cxt *lc);
extern int loopcxt_is_readonly(struct loopdev_cxt *lc);
extern int loopcxt_is_dio(struct loopdev_cxt *lc);
extern int loopcxt_is_partscan(struct loopdev_cxt *lc);
extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc,
				const char *filename,
				uint64_t offset, uint64_t sizelimit,
				int flags);
extern int loopcxt_find_overlap(struct loopdev_cxt *lc,
				const char *filename,
				uint64_t offset, uint64_t sizelimit);

extern int loopcxt_is_used(struct loopdev_cxt *lc,
                    struct stat *st,
                    const char *backing_file,
                    uint64_t offset,
                    uint64_t sizelimit,
                    int flags);

#endif /* UTIL_LINUX_LOOPDEV_H */