1*52244c09SJohn Wren Kennedy /*
2*52244c09SJohn Wren Kennedy  * This file and its contents are supplied under the terms of the
3*52244c09SJohn Wren Kennedy  * Common Development and Distribution License ("CDDL"), version 1.0.
4*52244c09SJohn Wren Kennedy  * You may only use this file in accordance with the terms of version
5*52244c09SJohn Wren Kennedy  * 1.0 of the CDDL.
6*52244c09SJohn Wren Kennedy  *
7*52244c09SJohn Wren Kennedy  * A full copy of the text of the CDDL should have accompanied this
8*52244c09SJohn Wren Kennedy  * source.  A copy of the CDDL is also available via the Internet at
9*52244c09SJohn Wren Kennedy  * http://www.illumos.org/license/CDDL.
10*52244c09SJohn Wren Kennedy  */
11*52244c09SJohn Wren Kennedy 
12*52244c09SJohn Wren Kennedy /*
13*52244c09SJohn Wren Kennedy  * Copyright (c) 2014 by Delphix. All rights reserved.
14*52244c09SJohn Wren Kennedy  */
15*52244c09SJohn Wren Kennedy 
16*52244c09SJohn Wren Kennedy #include <stdio.h>
17*52244c09SJohn Wren Kennedy #include <fcntl.h>
18*52244c09SJohn Wren Kennedy #include <unistd.h>
19*52244c09SJohn Wren Kennedy #include <stdlib.h>
20*52244c09SJohn Wren Kennedy #include <umem.h>
21*52244c09SJohn Wren Kennedy #include <stddef.h>
22*52244c09SJohn Wren Kennedy #include <string.h>
23*52244c09SJohn Wren Kennedy #include <sys/types.h>
24*52244c09SJohn Wren Kennedy #include <sys/errno.h>
25*52244c09SJohn Wren Kennedy #include <sys/list.h>
26*52244c09SJohn Wren Kennedy 
27*52244c09SJohn Wren Kennedy extern int errno;
28*52244c09SJohn Wren Kennedy 
29*52244c09SJohn Wren Kennedy typedef enum {
30*52244c09SJohn Wren Kennedy 	SEG_HOLE,
31*52244c09SJohn Wren Kennedy 	SEG_DATA,
32*52244c09SJohn Wren Kennedy 	SEG_TYPES
33*52244c09SJohn Wren Kennedy } seg_type_t;
34*52244c09SJohn Wren Kennedy 
35*52244c09SJohn Wren Kennedy typedef struct segment {
36*52244c09SJohn Wren Kennedy 	list_node_t	seg_node;
37*52244c09SJohn Wren Kennedy 	seg_type_t	seg_type;
38*52244c09SJohn Wren Kennedy 	off_t		seg_offset;
39*52244c09SJohn Wren Kennedy 	off_t		seg_len;
40*52244c09SJohn Wren Kennedy } seg_t;
41*52244c09SJohn Wren Kennedy 
42*52244c09SJohn Wren Kennedy static int
no_memory(void)43*52244c09SJohn Wren Kennedy no_memory(void) {
44*52244c09SJohn Wren Kennedy 	(void) fprintf(stderr, "malloc failed\n");
45*52244c09SJohn Wren Kennedy 	return (UMEM_CALLBACK_EXIT(255));
46*52244c09SJohn Wren Kennedy }
47*52244c09SJohn Wren Kennedy 
48*52244c09SJohn Wren Kennedy static void
usage(char * msg,int exit_value)49*52244c09SJohn Wren Kennedy usage(char *msg, int exit_value)
50*52244c09SJohn Wren Kennedy {
51*52244c09SJohn Wren Kennedy 	(void) fprintf(stderr, "mkholes [-d|h offset:length] ... filename\n");
52*52244c09SJohn Wren Kennedy 	(void) fprintf(stderr, "%s\n", msg);
53*52244c09SJohn Wren Kennedy 	exit(exit_value);
54*52244c09SJohn Wren Kennedy }
55*52244c09SJohn Wren Kennedy 
56*52244c09SJohn Wren Kennedy static char *
get_random_buffer(size_t len)57*52244c09SJohn Wren Kennedy get_random_buffer(size_t len)
58*52244c09SJohn Wren Kennedy {
59*52244c09SJohn Wren Kennedy 	int	rand_fd;
60*52244c09SJohn Wren Kennedy 	char	*buf;
61*52244c09SJohn Wren Kennedy 
62*52244c09SJohn Wren Kennedy 	buf = umem_alloc(len, UMEM_NOFAIL);
63*52244c09SJohn Wren Kennedy 
64*52244c09SJohn Wren Kennedy 	/*
65*52244c09SJohn Wren Kennedy 	 * Fill the buffer from /dev/urandom to counteract the
66*52244c09SJohn Wren Kennedy 	 * effects of compression.
67*52244c09SJohn Wren Kennedy 	 */
68*52244c09SJohn Wren Kennedy 	if ((rand_fd = open("/dev/urandom", O_RDONLY)) < 0) {
69*52244c09SJohn Wren Kennedy 		perror("open /dev/urandom failed");
70*52244c09SJohn Wren Kennedy 		exit(1);
71*52244c09SJohn Wren Kennedy 	}
72*52244c09SJohn Wren Kennedy 
73*52244c09SJohn Wren Kennedy 	if (read(rand_fd, buf, len) < 0) {
74*52244c09SJohn Wren Kennedy 		perror("read /dev/urandom failed");
75*52244c09SJohn Wren Kennedy 		exit(1);
76*52244c09SJohn Wren Kennedy 	}
77*52244c09SJohn Wren Kennedy 
78*52244c09SJohn Wren Kennedy 	(void) close(rand_fd);
79*52244c09SJohn Wren Kennedy 
80*52244c09SJohn Wren Kennedy 	return (buf);
81*52244c09SJohn Wren Kennedy }
82*52244c09SJohn Wren Kennedy 
83*52244c09SJohn Wren Kennedy static void
push_segment(list_t * seg_list,seg_type_t seg_type,char * optarg)84*52244c09SJohn Wren Kennedy push_segment(list_t *seg_list, seg_type_t seg_type, char *optarg)
85*52244c09SJohn Wren Kennedy {
86*52244c09SJohn Wren Kennedy 	char		*off_str, *len_str;
87*52244c09SJohn Wren Kennedy 	static off_t	file_size = 0;
88*52244c09SJohn Wren Kennedy 	off_t		off, len;
89*52244c09SJohn Wren Kennedy 	seg_t		*seg;
90*52244c09SJohn Wren Kennedy 
91*52244c09SJohn Wren Kennedy 	off_str = strtok(optarg, ":");
92*52244c09SJohn Wren Kennedy 	len_str = strtok(NULL, ":");
93*52244c09SJohn Wren Kennedy 
94*52244c09SJohn Wren Kennedy 	if (off_str == NULL || len_str == NULL)
95*52244c09SJohn Wren Kennedy 		usage("Bad offset or length", 1);
96*52244c09SJohn Wren Kennedy 
97*52244c09SJohn Wren Kennedy 	off = strtoull(off_str, NULL, 0);
98*52244c09SJohn Wren Kennedy 	len = strtoull(len_str, NULL, 0);
99*52244c09SJohn Wren Kennedy 
100*52244c09SJohn Wren Kennedy 	if (file_size >= off + len)
101*52244c09SJohn Wren Kennedy 		usage("Ranges must ascend and may not overlap.", 1);
102*52244c09SJohn Wren Kennedy 	file_size = off + len;
103*52244c09SJohn Wren Kennedy 
104*52244c09SJohn Wren Kennedy 	seg = umem_alloc(sizeof (seg_t), UMEM_NOFAIL);
105*52244c09SJohn Wren Kennedy 	seg->seg_type = seg_type;
106*52244c09SJohn Wren Kennedy 	seg->seg_offset = off;
107*52244c09SJohn Wren Kennedy 	seg->seg_len = len;
108*52244c09SJohn Wren Kennedy 
109*52244c09SJohn Wren Kennedy 	list_insert_tail(seg_list, seg);
110*52244c09SJohn Wren Kennedy }
111*52244c09SJohn Wren Kennedy 
112*52244c09SJohn Wren Kennedy int
main(int argc,char * argv[])113*52244c09SJohn Wren Kennedy main(int argc, char *argv[])
114*52244c09SJohn Wren Kennedy {
115*52244c09SJohn Wren Kennedy 	int	c, fd;
116*52244c09SJohn Wren Kennedy 	char	*fname;
117*52244c09SJohn Wren Kennedy 	list_t	seg_list;
118*52244c09SJohn Wren Kennedy 	seg_t	*seg;
119*52244c09SJohn Wren Kennedy 
120*52244c09SJohn Wren Kennedy 	umem_nofail_callback(no_memory);
121*52244c09SJohn Wren Kennedy 	list_create(&seg_list, sizeof (seg_t), offsetof(seg_t, seg_node));
122*52244c09SJohn Wren Kennedy 
123*52244c09SJohn Wren Kennedy 	while ((c = getopt(argc, argv, "d:h:")) != -1) {
124*52244c09SJohn Wren Kennedy 		switch (c) {
125*52244c09SJohn Wren Kennedy 		case 'd':
126*52244c09SJohn Wren Kennedy 			push_segment(&seg_list, SEG_DATA, optarg);
127*52244c09SJohn Wren Kennedy 			break;
128*52244c09SJohn Wren Kennedy 		case 'h':
129*52244c09SJohn Wren Kennedy 			push_segment(&seg_list, SEG_HOLE, optarg);
130*52244c09SJohn Wren Kennedy 			break;
131*52244c09SJohn Wren Kennedy 		}
132*52244c09SJohn Wren Kennedy 	}
133*52244c09SJohn Wren Kennedy 	argc -= optind;
134*52244c09SJohn Wren Kennedy 	argv += optind;
135*52244c09SJohn Wren Kennedy 
136*52244c09SJohn Wren Kennedy 	if ((fname = argv[0]) == NULL)
137*52244c09SJohn Wren Kennedy 		usage("No filename specified", 1);
138*52244c09SJohn Wren Kennedy 	fname = argv[0];
139*52244c09SJohn Wren Kennedy 
140*52244c09SJohn Wren Kennedy 	if ((fd = open(fname, O_LARGEFILE | O_RDWR | O_CREAT | O_SYNC,
141*52244c09SJohn Wren Kennedy 	    00666)) < 0) {
142*52244c09SJohn Wren Kennedy 		perror("open failed");
143*52244c09SJohn Wren Kennedy 		exit(1);
144*52244c09SJohn Wren Kennedy 	}
145*52244c09SJohn Wren Kennedy 
146*52244c09SJohn Wren Kennedy 	while ((seg = list_remove_head(&seg_list)) != NULL) {
147*52244c09SJohn Wren Kennedy 		char	*buf, *vbuf;
148*52244c09SJohn Wren Kennedy 		off_t	off = seg->seg_offset;
149*52244c09SJohn Wren Kennedy 		off_t	len = seg->seg_len;
150*52244c09SJohn Wren Kennedy 
151*52244c09SJohn Wren Kennedy 		if (seg->seg_type == SEG_HOLE) {
152*52244c09SJohn Wren Kennedy 			struct flock	fl;
153*52244c09SJohn Wren Kennedy 			off_t bytes_read = 0;
154*52244c09SJohn Wren Kennedy 			ssize_t readlen = 1024 * 1024 * 16;
155*52244c09SJohn Wren Kennedy 
156*52244c09SJohn Wren Kennedy 			fl.l_whence = SEEK_SET;
157*52244c09SJohn Wren Kennedy 			fl.l_start = off;
158*52244c09SJohn Wren Kennedy 			fl.l_len = len;
159*52244c09SJohn Wren Kennedy 			if (fcntl(fd, F_FREESP, &fl) != 0) {
160*52244c09SJohn Wren Kennedy 				perror("freesp failed");
161*52244c09SJohn Wren Kennedy 				exit(1);
162*52244c09SJohn Wren Kennedy 			}
163*52244c09SJohn Wren Kennedy 
164*52244c09SJohn Wren Kennedy 			buf = (char *)umem_alloc(readlen, UMEM_NOFAIL);
165*52244c09SJohn Wren Kennedy 			vbuf = (char *)umem_zalloc(readlen, UMEM_NOFAIL);
166*52244c09SJohn Wren Kennedy 			while (bytes_read < len) {
167*52244c09SJohn Wren Kennedy 				ssize_t bytes = pread(fd, buf, readlen, off);
168*52244c09SJohn Wren Kennedy 				if (bytes < 0) {
169*52244c09SJohn Wren Kennedy 					perror("pread hole failed");
170*52244c09SJohn Wren Kennedy 					exit(1);
171*52244c09SJohn Wren Kennedy 				}
172*52244c09SJohn Wren Kennedy 
173*52244c09SJohn Wren Kennedy 				if (memcmp(buf, vbuf, bytes) != 0) {
174*52244c09SJohn Wren Kennedy 					(void) fprintf(stderr, "Read back hole "
175*52244c09SJohn Wren Kennedy 					    "didn't match.\n");
176*52244c09SJohn Wren Kennedy 					exit(1);
177*52244c09SJohn Wren Kennedy 				}
178*52244c09SJohn Wren Kennedy 				bytes_read += bytes;
179*52244c09SJohn Wren Kennedy 				off += bytes;
180*52244c09SJohn Wren Kennedy 			}
181*52244c09SJohn Wren Kennedy 
182*52244c09SJohn Wren Kennedy 			umem_free(buf, readlen);
183*52244c09SJohn Wren Kennedy 			umem_free(vbuf, readlen);
184*52244c09SJohn Wren Kennedy 			umem_free(seg, sizeof (seg_t));
185*52244c09SJohn Wren Kennedy 		} else if (seg->seg_type == SEG_DATA) {
186*52244c09SJohn Wren Kennedy 			buf = get_random_buffer(len);
187*52244c09SJohn Wren Kennedy 			vbuf = (char *)umem_alloc(len, UMEM_NOFAIL);
188*52244c09SJohn Wren Kennedy 			if ((pwrite(fd, buf, len, off)) < 0) {
189*52244c09SJohn Wren Kennedy 				perror("pwrite failed");
190*52244c09SJohn Wren Kennedy 				exit(1);
191*52244c09SJohn Wren Kennedy 			}
192*52244c09SJohn Wren Kennedy 
193*52244c09SJohn Wren Kennedy 			if ((pread(fd, vbuf, len, off)) != len) {
194*52244c09SJohn Wren Kennedy 				perror("pread failed");
195*52244c09SJohn Wren Kennedy 				exit(1);
196*52244c09SJohn Wren Kennedy 			}
197*52244c09SJohn Wren Kennedy 
198*52244c09SJohn Wren Kennedy 			if (memcmp(buf, vbuf, len) != 0) {
199*52244c09SJohn Wren Kennedy 				(void) fprintf(stderr, "Read back buf didn't "
200*52244c09SJohn Wren Kennedy 				    "match.\n");
201*52244c09SJohn Wren Kennedy 				exit(1);
202*52244c09SJohn Wren Kennedy 			}
203*52244c09SJohn Wren Kennedy 
204*52244c09SJohn Wren Kennedy 			umem_free(buf, len);
205*52244c09SJohn Wren Kennedy 			umem_free(vbuf, len);
206*52244c09SJohn Wren Kennedy 			umem_free(seg, sizeof (seg_t));
207*52244c09SJohn Wren Kennedy 		}
208*52244c09SJohn Wren Kennedy 	}
209*52244c09SJohn Wren Kennedy 
210*52244c09SJohn Wren Kennedy 	(void) close(fd);
211*52244c09SJohn Wren Kennedy 	return (0);
212*52244c09SJohn Wren Kennedy }
213