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