image.c revision 268236
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 268236 2014-07-03 20:31:43Z 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	off_t ofs;
98268236Smarcel	int error;
99268236Smarcel
100268236Smarcel	error = image_copyout_region(fd, 0, image_size);
101268236Smarcel	if (error)
102268236Smarcel		return (error);
103268236Smarcel
104268236Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
105268236Smarcel	if (ofs == -1)
106268236Smarcel		return (0);
107268236Smarcel	error = (ftruncate(fd, ofs) == -1) ? errno : 0;
108268236Smarcel	return (error);
109268236Smarcel}
110268236Smarcel
111268236Smarcelint
112268236Smarcelimage_copyout_region(int fd, lba_t blk, lba_t size)
113268236Smarcel{
114265618Smarcel	char *buffer;
115265618Smarcel	off_t ofs;
116268236Smarcel	size_t sz;
117265618Smarcel	ssize_t rdsz, wrsz;
118265618Smarcel	int error;
119265574Smarcel
120265618Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
121265618Smarcel
122268236Smarcel	blk *= secsz;
123268236Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
124266509Smarcel		return (errno);
125265618Smarcel	buffer = malloc(BUFFER_SIZE);
126265618Smarcel	if (buffer == NULL)
127265618Smarcel		return (errno);
128265618Smarcel	error = 0;
129268236Smarcel	size *= secsz;
130268236Smarcel	while (size > 0) {
131268236Smarcel		sz = (BUFFER_SIZE < size) ? BUFFER_SIZE : size;
132268236Smarcel		rdsz = read(image_fd, buffer, sz);
133265618Smarcel		if (rdsz <= 0) {
134265618Smarcel			error = (rdsz < 0) ? errno : 0;
135265618Smarcel			break;
136265618Smarcel		}
137265618Smarcel		wrsz = (ofs == -1) ?
138265618Smarcel		    write(fd, buffer, rdsz) :
139265618Smarcel		    sparse_write(fd, buffer, rdsz);
140265618Smarcel		if (wrsz < 0) {
141265618Smarcel			error = errno;
142265618Smarcel			break;
143265618Smarcel		}
144268236Smarcel		assert(wrsz == rdsz);
145268236Smarcel		size -= rdsz;
146265618Smarcel	}
147265618Smarcel	free(buffer);
148265618Smarcel	return (error);
149265618Smarcel}
150265618Smarcel
151265725Smarcellba_t
152265725Smarcelimage_get_size(void)
153265725Smarcel{
154265725Smarcel
155265725Smarcel	return (image_size);
156265725Smarcel}
157265725Smarcel
158265618Smarcelint
159265618Smarcelimage_set_size(lba_t blk)
160265618Smarcel{
161265618Smarcel
162265725Smarcel	image_size = blk;
163265618Smarcel	if (ftruncate(image_fd, blk * secsz) == -1)
164265618Smarcel		return (errno);
165265574Smarcel	return (0);
166265574Smarcel}
167265574Smarcel
168265574Smarcelint
169265618Smarcelimage_write(lba_t blk, void *buf, ssize_t len)
170265574Smarcel{
171265574Smarcel
172265618Smarcel	blk *= secsz;
173265618Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
174265618Smarcel		return (errno);
175265618Smarcel	len *= secsz;
176265685Smarcel	if (sparse_write(image_fd, buf, len) != len)
177265618Smarcel		return (errno);
178265574Smarcel	return (0);
179265574Smarcel}
180265618Smarcel
181265618Smarcelint
182265618Smarcelimage_init(void)
183265618Smarcel{
184266556Smarcel	const char *tmpdir;
185265618Smarcel
186265618Smarcel	if (atexit(cleanup) == -1)
187265618Smarcel		return (errno);
188266556Smarcel	if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
189266556Smarcel		tmpdir = _PATH_TMP;
190266556Smarcel	snprintf(image_tmpfile, sizeof(image_tmpfile), "%s/mkimg-XXXXXX",
191266556Smarcel	    tmpdir);
192265618Smarcel	image_fd = mkstemp(image_tmpfile);
193265618Smarcel	if (image_fd == -1)
194265618Smarcel		return (errno);
195265618Smarcel	return (0);
196265618Smarcel}
197