image.c revision 268646
1265574Smarcel/*-
2265574Smarcel * Copyright (c) 2014 Juniper Networks, Inc.
3265574Smarcel * All rights reserved.
4265574Smarcel *
5265574Smarcel * Redistribution and use in source and binary forms, with or without
6265574Smarcel * modification, are permitted provided that the following conditions
7265574Smarcel * are met:
8265574Smarcel * 1. Redistributions of source code must retain the above copyright
9265574Smarcel *    notice, this list of conditions and the following disclaimer.
10265574Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11265574Smarcel *    notice, this list of conditions and the following disclaimer in the
12265574Smarcel *    documentation and/or other materials provided with the distribution.
13265574Smarcel *
14265574Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15265574Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16265574Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17265574Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18265574Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19265574Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20265574Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21265574Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22265574Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23265574Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24265574Smarcel * SUCH DAMAGE.
25265574Smarcel */
26265574Smarcel
27265574Smarcel#include <sys/cdefs.h>
28265574Smarcel__FBSDID("$FreeBSD: head/usr.bin/mkimg/image.c 268646 2014-07-15 04:39:23Z marcel $");
29265574Smarcel
30265574Smarcel#include <sys/types.h>
31265574Smarcel#include <assert.h>
32265574Smarcel#include <errno.h>
33266556Smarcel#include <limits.h>
34266556Smarcel#include <paths.h>
35266556Smarcel#include <stdio.h>
36265574Smarcel#include <stdlib.h>
37265574Smarcel#include <unistd.h>
38265574Smarcel
39265579Smarcel#include "image.h"
40265574Smarcel#include "mkimg.h"
41265574Smarcel
42265574Smarcel#define	BUFFER_SIZE	(1024*1024)
43265574Smarcel
44266556Smarcelstatic char image_tmpfile[PATH_MAX];
45265618Smarcelstatic int image_fd = -1;
46265725Smarcelstatic lba_t image_size;
47265618Smarcel
48265618Smarcelstatic void
49265618Smarcelcleanup(void)
50265618Smarcel{
51265618Smarcel
52265618Smarcel	if (image_fd != -1)
53265618Smarcel		close(image_fd);
54265618Smarcel	unlink(image_tmpfile);
55265618Smarcel}
56265618Smarcel
57265574Smarcelint
58265574Smarcelimage_copyin(lba_t blk, int fd, uint64_t *sizep)
59265574Smarcel{
60265574Smarcel	char *buffer;
61265574Smarcel	uint64_t bytesize;
62265574Smarcel	ssize_t bcnt, rdsz;
63265574Smarcel	int error, partial;
64265574Smarcel
65265574Smarcel	assert(BUFFER_SIZE % secsz == 0);
66265574Smarcel
67265574Smarcel	buffer = malloc(BUFFER_SIZE);
68265574Smarcel	if (buffer == NULL)
69265574Smarcel		return (ENOMEM);
70265574Smarcel	bytesize = 0;
71265574Smarcel	partial = 0;
72265574Smarcel	while (1) {
73265574Smarcel		rdsz = read(fd, buffer, BUFFER_SIZE);
74265574Smarcel		if (rdsz <= 0) {
75265574Smarcel			error = (rdsz < 0) ? errno : 0;
76265574Smarcel			break;
77265574Smarcel		}
78265574Smarcel		if (partial)
79265574Smarcel			abort();
80265574Smarcel		bytesize += rdsz;
81265574Smarcel		bcnt = (rdsz + secsz - 1) / secsz;
82265574Smarcel		error = image_write(blk, buffer, bcnt);
83265574Smarcel		if (error)
84265574Smarcel			break;
85265574Smarcel		blk += bcnt;
86266137Smarcel		partial = ((ssize_t)(bcnt * secsz) != rdsz) ? 1 : 0;
87265574Smarcel	}
88265574Smarcel	free(buffer);
89265574Smarcel	if (sizep != NULL)
90265574Smarcel		*sizep = bytesize;
91265574Smarcel	return (error);
92265574Smarcel}
93265574Smarcel
94265574Smarcelint
95265618Smarcelimage_copyout(int fd)
96265574Smarcel{
97268236Smarcel	int error;
98268236Smarcel
99268236Smarcel	error = image_copyout_region(fd, 0, image_size);
100268646Smarcel	if (!error)
101268646Smarcel		error = image_copyout_done(fd);
102268646Smarcel	return (error);
103268646Smarcel}
104268236Smarcel
105268646Smarcelint
106268646Smarcelimage_copyout_done(int fd)
107268646Smarcel{
108268646Smarcel	off_t ofs;
109268646Smarcel	int error;
110268646Smarcel
111268236Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
112268236Smarcel	if (ofs == -1)
113268236Smarcel		return (0);
114268236Smarcel	error = (ftruncate(fd, ofs) == -1) ? errno : 0;
115268236Smarcel	return (error);
116268236Smarcel}
117268236Smarcel
118268236Smarcelint
119268236Smarcelimage_copyout_region(int fd, lba_t blk, lba_t size)
120268236Smarcel{
121265618Smarcel	char *buffer;
122265618Smarcel	off_t ofs;
123268236Smarcel	size_t sz;
124265618Smarcel	ssize_t rdsz, wrsz;
125265618Smarcel	int error;
126265574Smarcel
127265618Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
128265618Smarcel
129268236Smarcel	blk *= secsz;
130268236Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
131266509Smarcel		return (errno);
132265618Smarcel	buffer = malloc(BUFFER_SIZE);
133265618Smarcel	if (buffer == NULL)
134265618Smarcel		return (errno);
135265618Smarcel	error = 0;
136268236Smarcel	size *= secsz;
137268236Smarcel	while (size > 0) {
138268236Smarcel		sz = (BUFFER_SIZE < size) ? BUFFER_SIZE : size;
139268236Smarcel		rdsz = read(image_fd, buffer, sz);
140265618Smarcel		if (rdsz <= 0) {
141265618Smarcel			error = (rdsz < 0) ? errno : 0;
142265618Smarcel			break;
143265618Smarcel		}
144265618Smarcel		wrsz = (ofs == -1) ?
145265618Smarcel		    write(fd, buffer, rdsz) :
146265618Smarcel		    sparse_write(fd, buffer, rdsz);
147265618Smarcel		if (wrsz < 0) {
148265618Smarcel			error = errno;
149265618Smarcel			break;
150265618Smarcel		}
151268236Smarcel		assert(wrsz == rdsz);
152268236Smarcel		size -= rdsz;
153265618Smarcel	}
154265618Smarcel	free(buffer);
155265618Smarcel	return (error);
156265618Smarcel}
157265618Smarcel
158268646Smarcelint
159268646Smarcelimage_data(lba_t blk, lba_t size)
160268646Smarcel{
161268646Smarcel	char *buffer, *p;
162268646Smarcel
163268646Smarcel	blk *= secsz;
164268646Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
165268646Smarcel		return (1);
166268646Smarcel
167268646Smarcel	size *= secsz;
168268646Smarcel	buffer = malloc(size);
169268646Smarcel	if (buffer == NULL)
170268646Smarcel		return (1);
171268646Smarcel
172268646Smarcel	if (read(image_fd, buffer, size) != (ssize_t)size) {
173268646Smarcel		free(buffer);
174268646Smarcel		return (1);
175268646Smarcel	}
176268646Smarcel
177268646Smarcel	p = buffer;
178268646Smarcel	while (size > 0 && *p == '\0')
179268646Smarcel		size--, p++;
180268646Smarcel
181268646Smarcel	free(buffer);
182268646Smarcel	return ((size == 0) ? 0 : 1);
183268646Smarcel}
184268646Smarcel
185265725Smarcellba_t
186265725Smarcelimage_get_size(void)
187265725Smarcel{
188265725Smarcel
189265725Smarcel	return (image_size);
190265725Smarcel}
191265725Smarcel
192265618Smarcelint
193265618Smarcelimage_set_size(lba_t blk)
194265618Smarcel{
195265618Smarcel
196265725Smarcel	image_size = blk;
197265618Smarcel	if (ftruncate(image_fd, blk * secsz) == -1)
198265618Smarcel		return (errno);
199265574Smarcel	return (0);
200265574Smarcel}
201265574Smarcel
202265574Smarcelint
203265618Smarcelimage_write(lba_t blk, void *buf, ssize_t len)
204265574Smarcel{
205265574Smarcel
206265618Smarcel	blk *= secsz;
207265618Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
208265618Smarcel		return (errno);
209265618Smarcel	len *= secsz;
210265685Smarcel	if (sparse_write(image_fd, buf, len) != len)
211265618Smarcel		return (errno);
212265574Smarcel	return (0);
213265574Smarcel}
214265618Smarcel
215265618Smarcelint
216265618Smarcelimage_init(void)
217265618Smarcel{
218266556Smarcel	const char *tmpdir;
219265618Smarcel
220265618Smarcel	if (atexit(cleanup) == -1)
221265618Smarcel		return (errno);
222266556Smarcel	if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
223266556Smarcel		tmpdir = _PATH_TMP;
224266556Smarcel	snprintf(image_tmpfile, sizeof(image_tmpfile), "%s/mkimg-XXXXXX",
225266556Smarcel	    tmpdir);
226265618Smarcel	image_fd = mkstemp(image_tmpfile);
227265618Smarcel	if (image_fd == -1)
228265618Smarcel		return (errno);
229265618Smarcel	return (0);
230265618Smarcel}
231