]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/mkfs.bfs.c
textual: use UTIL_LINUX_VERSION everywhere
[thirdparty/util-linux.git] / disk-utils / mkfs.bfs.c
1 /*
2 * mkfs.bfs - Create SCO BFS filesystem - aeb, 1999-09-07
3 *
4 */
5
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <getopt.h>
9 #include <limits.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <time.h>
15 #include <unistd.h>
16
17 #include "blkdev.h"
18 #include "c.h"
19 #include "closestream.h"
20 #include "nls.h"
21 #include "strutils.h"
22 #include "xalloc.h"
23
24 #define BFS_ROOT_INO 2
25 #define BFS_NAMELEN 14
26 #define BFS_BLOCKSIZE 512
27 #define BFS_SUPER_MAGIC 0x1badface
28
29 /* superblock - 512 bytes */
30 struct bfssb {
31 unsigned int s_magic;
32 unsigned int s_start; /* byte offset of start of data */
33 unsigned int s_end; /* sizeof(slice)-1 */
34
35 /* for recovery during compaction */
36 int s_from, s_to; /* src and dest block of current transfer */
37 int s_backup_from, s_backup_to;
38
39 /* labels - may well contain garbage */
40 char s_fsname[6];
41 char s_volume[6];
42 char s_pad[472];
43 };
44
45 /* inode - 64 bytes */
46 struct bfsi {
47 unsigned short i_ino;
48 unsigned char i_pad1[2];
49 unsigned long i_first_block;
50 unsigned long i_last_block;
51 unsigned long i_bytes_to_end;
52 unsigned long i_type; /* 1: file, 2: the unique dir */
53 unsigned long i_mode;
54 unsigned long i_uid, i_gid;
55 unsigned long i_nlinks;
56 unsigned long i_atime, i_mtime, i_ctime;
57 unsigned char i_pad2[16];
58 };
59
60 #define BFS_DIR_TYPE 2
61
62 /* directory entry - 16 bytes */
63 struct bfsde {
64 unsigned short d_ino;
65 char d_name[BFS_NAMELEN];
66 };
67
68 static void __attribute__ ((__noreturn__)) usage(FILE * out)
69 {
70 fprintf(out,
71 _("Usage: %s [options] device [block-count]\n"),
72 program_invocation_short_name);
73 fprintf(out, _("\nOptions:\n"
74 " -N, --inodes=NUM specify desired number of inodes\n"
75 " -V, --vname=NAME specify volume name\n"
76 " -F, --fname=NAME specify file system name\n"
77 " -v, --verbose explain what is being done\n"
78 " -c this option is silently ignored\n"
79 " -l this option is silently ignored\n"
80 " -V, --version output version information and exit\n"
81 " -V as version must be only option\n"
82 " -h, --help display this help and exit\n\n"));
83
84 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
85 }
86
87 static void __attribute__ ((__noreturn__)) print_version(void)
88 {
89 printf(UTIL_LINUX_VERSION);
90 exit(EXIT_SUCCESS);
91 }
92
93 int main(int argc, char **argv)
94 {
95 char *device, *volume, *fsname;
96 long inodes;
97 unsigned long long total_blocks, ino_bytes, ino_blocks, data_blocks;
98 unsigned long long user_specified_total_blocks = 0;
99 int verbose = 0;
100 int fd;
101 struct bfssb sb;
102 struct bfsi ri;
103 struct bfsde de;
104 struct stat statbuf;
105 time_t now;
106 int c, i, len;
107
108 enum { VERSION_OPTION = CHAR_MAX + 1 };
109 static const struct option longopts[] = {
110 {"inodes", required_argument, NULL, 'N'},
111 {"vname", required_argument, NULL, 'V'},
112 {"fname", required_argument, NULL, 'F'},
113 {"verbose", no_argument, NULL, 'v'},
114 {"version", no_argument, NULL, VERSION_OPTION},
115 {"help", no_argument, NULL, 'h'},
116 {NULL, 0, NULL, 0}
117 };
118
119 setlocale(LC_ALL, "");
120 bindtextdomain(PACKAGE, LOCALEDIR);
121 textdomain(PACKAGE);
122 atexit(close_stdout);
123
124 if (argc < 2)
125 usage(stderr);
126
127 if (argc == 2 && !strcmp(argv[1], "-V"))
128 print_version();
129
130 volume = fsname = " "; /* is there a default? */
131 inodes = 0;
132
133 while ((c = getopt_long(argc, argv, "N:V:F:vhcl", longopts, NULL)) != -1) {
134 switch (c) {
135 case 'N':
136 inodes = strtol_or_err(optarg, _("invalid number of inodes"));
137 break;
138
139 case 'V':
140 len = strlen(optarg);
141 if (len <= 0 || len > 6)
142 errx(EXIT_FAILURE, _("volume name too long"));
143 volume = xstrdup(optarg);
144 break;
145
146 case 'F':
147 len = strlen(optarg);
148 if (len <= 0 || len > 6)
149 errx(EXIT_FAILURE, _("fsname name too long"));
150 fsname = xstrdup(optarg);
151 break;
152
153 case 'v':
154 verbose = 1;
155 break;
156
157 case 'c':
158 case 'l':
159 /* when called via mkfs we may get options c,l,v */
160 break;
161
162 case VERSION_OPTION:
163 print_version();
164 case 'h':
165 usage(stdout);
166 default:
167 usage(stderr);
168 }
169 }
170
171 if (optind == argc)
172 usage(stderr);
173
174 device = argv[optind++];
175
176 if (stat(device, &statbuf) < 0)
177 err(EXIT_FAILURE, _("stat failed %s"), device);
178
179 if (!S_ISBLK(statbuf.st_mode))
180 errx(EXIT_FAILURE, _("%s is not a block special device"), device);
181
182 fd = open(device, O_RDWR | O_EXCL);
183 if (fd < 0)
184 err(EXIT_FAILURE, _("cannot open %s"), device);
185
186 if (optind == argc - 1)
187 user_specified_total_blocks =
188 strtou64_or_err(argv[optind], _("invalid block-count"));
189 else if (optind != argc)
190 usage(stderr);
191
192 if (blkdev_get_sectors(fd, &total_blocks) == -1) {
193 if (!user_specified_total_blocks)
194 err(EXIT_FAILURE, _("cannot get size of %s"), device);
195 total_blocks = user_specified_total_blocks;
196 } else if (user_specified_total_blocks) {
197 if (user_specified_total_blocks > total_blocks)
198 errx(EXIT_FAILURE,
199 _("blocks argument too large, max is %llu"),
200 total_blocks);
201 total_blocks = user_specified_total_blocks;
202 }
203
204 if (!inodes) {
205 /* pick some reasonable default */
206 inodes = 8 * (total_blocks / 800);
207 if (inodes < 48)
208 inodes = 48;
209 if (512 < inodes)
210 inodes = 512;
211 } else {
212 /* believe the user */
213 if (512 < inodes)
214 errx(EXIT_FAILURE, _("too many inodes - max is 512"));
215 }
216
217 ino_bytes = inodes * sizeof(struct bfsi);
218 ino_blocks = (ino_bytes + BFS_BLOCKSIZE - 1) / BFS_BLOCKSIZE;
219 data_blocks = total_blocks - ino_blocks - 1;
220
221 /* mimic the behaviour of SCO's mkfs - maybe this limit is needed */
222 if (data_blocks < 32)
223 errx(EXIT_FAILURE,
224 _("not enough space, need at least %llu blocks"),
225 ino_blocks + 33);
226
227 memset(&sb, 0, sizeof(sb));
228 sb.s_magic = BFS_SUPER_MAGIC;
229 sb.s_start = ino_bytes + sizeof(struct bfssb);
230 sb.s_end = total_blocks * BFS_BLOCKSIZE - 1;
231 sb.s_from = sb.s_to = sb.s_backup_from = sb.s_backup_to = -1;
232 memcpy(sb.s_fsname, fsname, 6);
233 memcpy(sb.s_volume, volume, 6);
234
235 if (verbose) {
236 fprintf(stderr, _("Device: %s\n"), device);
237 fprintf(stderr, _("Volume: <%-6s>\n"), volume);
238 fprintf(stderr, _("FSname: <%-6s>\n"), fsname);
239 fprintf(stderr, _("BlockSize: %d\n"), BFS_BLOCKSIZE);
240 if (ino_blocks == 1)
241 fprintf(stderr, _("Inodes: %lu (in 1 block)\n"),
242 inodes);
243 else
244 fprintf(stderr, _("Inodes: %lu (in %llu blocks)\n"),
245 inodes, ino_blocks);
246 fprintf(stderr, _("Blocks: %lld\n"), total_blocks);
247 fprintf(stderr, _("Inode end: %d, Data end: %d\n"),
248 sb.s_start - 1, sb.s_end);
249 }
250
251 if (write(fd, &sb, sizeof(sb)) != sizeof(sb))
252 err(EXIT_FAILURE, _("error writing superblock"));
253
254 memset(&ri, 0, sizeof(ri));
255 ri.i_ino = BFS_ROOT_INO;
256 ri.i_first_block = 1 + ino_blocks;
257 ri.i_last_block = ri.i_first_block +
258 (inodes * sizeof(de) - 1) / BFS_BLOCKSIZE;
259 ri.i_bytes_to_end = ri.i_first_block * BFS_BLOCKSIZE
260 + 2 * sizeof(struct bfsde) - 1;
261 ri.i_type = BFS_DIR_TYPE;
262 ri.i_mode = S_IFDIR | 0755; /* or just 0755 */
263 ri.i_uid = 0;
264 ri.i_gid = 1; /* random */
265 ri.i_nlinks = 2;
266 time(&now);
267 ri.i_atime = now;
268 ri.i_mtime = now;
269 ri.i_ctime = now;
270
271 if (write(fd, &ri, sizeof(ri)) != sizeof(ri))
272 err(EXIT_FAILURE, _("error writing root inode"));
273
274 memset(&ri, 0, sizeof(ri));
275 for (i = 1; i < inodes; i++)
276 if (write(fd, &ri, sizeof(ri)) != sizeof(ri))
277 err(EXIT_FAILURE, _("error writing inode"));
278
279 if (lseek(fd, (1 + ino_blocks) * BFS_BLOCKSIZE, SEEK_SET) == -1)
280 err(EXIT_FAILURE, _("seek error"));
281
282 memset(&de, 0, sizeof(de));
283 de.d_ino = BFS_ROOT_INO;
284 memcpy(de.d_name, ".", 1);
285 if (write(fd, &de, sizeof(de)) != sizeof(de))
286 err(EXIT_FAILURE, _("error writing . entry"));
287
288 memcpy(de.d_name, "..", 2);
289 if (write(fd, &de, sizeof(de)) != sizeof(de))
290 err(EXIT_FAILURE, _("error writing .. entry"));
291
292 if (close(fd) < 0)
293 err(EXIT_FAILURE, _("error closing %s"), device);
294
295 return EXIT_SUCCESS;
296 }