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