image.c revision 266556
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 266556 2014-05-22 20:24:30Z 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{
97265618Smarcel	char *buffer;
98265618Smarcel	off_t ofs;
99265618Smarcel	ssize_t rdsz, wrsz;
100265618Smarcel	int error;
101265574Smarcel
102265618Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
103265618Smarcel
104266509Smarcel	if (lseek(image_fd, 0, SEEK_SET) != 0)
105266509Smarcel		return (errno);
106265618Smarcel	buffer = malloc(BUFFER_SIZE);
107265618Smarcel	if (buffer == NULL)
108265618Smarcel		return (errno);
109265618Smarcel	error = 0;
110265618Smarcel	while (1) {
111265618Smarcel		rdsz = read(image_fd, buffer, BUFFER_SIZE);
112265618Smarcel		if (rdsz <= 0) {
113265618Smarcel			error = (rdsz < 0) ? errno : 0;
114265618Smarcel			break;
115265618Smarcel		}
116265618Smarcel		wrsz = (ofs == -1) ?
117265618Smarcel		    write(fd, buffer, rdsz) :
118265618Smarcel		    sparse_write(fd, buffer, rdsz);
119265618Smarcel		if (wrsz < 0) {
120265618Smarcel			error = errno;
121265618Smarcel			break;
122265618Smarcel		}
123265618Smarcel	}
124265618Smarcel	free(buffer);
125266512Smarcel	if (error)
126266512Smarcel		return (error);
127265623Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
128266512Smarcel	if (ofs == -1)
129266512Smarcel		return (errno);
130266512Smarcel	error = (ftruncate(fd, ofs) == -1) ? errno : 0;
131265618Smarcel	return (error);
132265618Smarcel}
133265618Smarcel
134265725Smarcellba_t
135265725Smarcelimage_get_size(void)
136265725Smarcel{
137265725Smarcel
138265725Smarcel	return (image_size);
139265725Smarcel}
140265725Smarcel
141265618Smarcelint
142265618Smarcelimage_set_size(lba_t blk)
143265618Smarcel{
144265618Smarcel
145265725Smarcel	image_size = blk;
146265618Smarcel	if (ftruncate(image_fd, blk * secsz) == -1)
147265618Smarcel		return (errno);
148265574Smarcel	return (0);
149265574Smarcel}
150265574Smarcel
151265574Smarcelint
152265618Smarcelimage_write(lba_t blk, void *buf, ssize_t len)
153265574Smarcel{
154265574Smarcel
155265618Smarcel	blk *= secsz;
156265618Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
157265618Smarcel		return (errno);
158265618Smarcel	len *= secsz;
159265685Smarcel	if (sparse_write(image_fd, buf, len) != len)
160265618Smarcel		return (errno);
161265574Smarcel	return (0);
162265574Smarcel}
163265618Smarcel
164265618Smarcelint
165265618Smarcelimage_init(void)
166265618Smarcel{
167266556Smarcel	const char *tmpdir;
168265618Smarcel
169265618Smarcel	if (atexit(cleanup) == -1)
170265618Smarcel		return (errno);
171266556Smarcel	if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
172266556Smarcel		tmpdir = _PATH_TMP;
173266556Smarcel	snprintf(image_tmpfile, sizeof(image_tmpfile), "%s/mkimg-XXXXXX",
174266556Smarcel	    tmpdir);
175265618Smarcel	image_fd = mkstemp(image_tmpfile);
176265618Smarcel	if (image_fd == -1)
177265618Smarcel		return (errno);
178265618Smarcel	return (0);
179265618Smarcel}
180