xref: /haiku/src/tools/create_image.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2007, Marcus Overhagen. All Rights Reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <getopt.h>
10 #include <limits.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 
17 
18 #define EXIT_FAILURE 1
19 
20 
21 static void
22 print_usage(bool error)
23 {
24 	printf("\n");
25 	printf("create_image\n");
26 	printf("\n");
27 	printf("usage: create_image -i <imagesize> [-c] [-f] <file>\n");
28 	printf("       -i, --imagesize    size of raw partition image file\n");
29 	printf("       -f, --file         the raw partition image file\n");
30 	printf("       -c, --clear-image  set the image content to zero\n");
31 	exit(error ? EXIT_FAILURE : 0);
32 }
33 
34 
35 int
36 main(int argc, char *argv[])
37 {
38 	off_t imageSize = 0;
39 	const char *file = NULL;
40 	bool clearImage = false;
41 
42 	while (1) {
43 		int c;
44 		static struct option long_options[] = {
45 			{"file", required_argument, 0, 'f'},
46 			{"clear-image", no_argument, 0, 'c'},
47 			{"help", no_argument, 0, 'h'},
48 			{"imagesize", required_argument, 0, 'i'},
49 			{0, 0, 0, 0}
50 		};
51 
52 		opterr = 0; /* don't print errors */
53 		c = getopt_long(argc, argv, "+hi:cf:", long_options, NULL);
54 		if (c == -1)
55 			break;
56 
57 		switch (c) {
58 			case 'h':
59 				print_usage(false);
60 				break;
61 
62 			case 'i':
63 				imageSize = strtoull(optarg, NULL, 10);
64 				if (strchr(optarg, 'G') || strchr(optarg, 'g'))
65 					imageSize *= 1024 * 1024 * 1024;
66 				else if (strchr(optarg, 'M') || strchr(optarg, 'm'))
67 					imageSize *= 1024 * 1024;
68 				else if (strchr(optarg, 'K') || strchr(optarg, 'k'))
69 					imageSize *= 1024;
70 				break;
71 
72 			case 'f':
73 				file = optarg;
74 				break;
75 
76 			case 'c':
77 				clearImage = true;
78 				break;
79 
80 			default:
81 				print_usage(true);
82 		}
83 	}
84 
85 	if (file == NULL && optind == argc - 1)
86 		file = argv[optind];
87 
88 	if (!imageSize || !file)
89 		print_usage(true);
90 
91 	if (imageSize < 0) {
92 		fprintf(stderr, "Error: invalid image size\n");
93 		exit(EXIT_FAILURE);
94 	}
95 
96 	if (imageSize % 512) {
97 		fprintf(stderr, "Error: image size must be a multiple of 512 bytes\n");
98 		exit(EXIT_FAILURE);
99 	}
100 
101 	int fd = open(file, O_RDWR | O_CREAT, 0666);
102 	if (fd < 0) {
103 		fprintf(stderr, "Error: couldn't open file %s (%s)\n", file,
104 			strerror(errno));
105 		exit(EXIT_FAILURE);
106 	}
107 
108 	struct stat st;
109 	if (fstat(fd, &st) < 0) {
110 		fprintf(stderr, "Error: stat()ing file %s failed (%s)\n", file,
111 			strerror(errno));
112 		exit(EXIT_FAILURE);
113 	}
114 
115 	if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
116 		fprintf(stderr, "Error: type of file %s not supported\n", file);
117 		exit(EXIT_FAILURE);
118 	}
119 
120 	if (S_ISREG(st.st_mode)) {
121 		// regular file -- use ftruncate() to resize it
122 		if ((clearImage && ftruncate(fd, 0) != 0)
123 			|| ftruncate(fd, imageSize) != 0) {
124 			fprintf(stderr, "Error: resizing file %s failed (%s)\n", file,
125 				strerror(errno));
126 			exit(EXIT_FAILURE);
127 		}
128 	} else {
129 		// some kind of device -- clear it manually, if we have to
130 		if (clearImage) {
131 			char buffer[1024 * 1024];
132 			memset(buffer, 0, sizeof(buffer));
133 
134 			off_t totalWritten = 0;
135 			ssize_t written;
136 			while ((written = write(fd, buffer, sizeof(buffer))) > 0)
137 				totalWritten += written;
138 
139 			// Only fail, if an error occurs and we haven't written anything at
140 			// all yet.
141 			// TODO: We should probably first determine the size of the device
142 			// and try to write only that much.
143 			if (totalWritten == 0 && written < 0) {
144 				fprintf(stderr, "Error: writing to device file %s failed "
145 					"(%s)\n", file, strerror(errno));
146 				exit(EXIT_FAILURE);
147 			}
148 		}
149 	}
150 
151 	close(fd);
152 	return 0;
153 }
154