]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/mkfs.bfs.c
mkfs.bfs: use xstrdup from xalloc.h
[thirdparty/util-linux.git] / disk-utils / mkfs.bfs.c
CommitLineData
eb63b9b8
KZ
1/*
2 * mkfs.bfs - Create SCO BFS filesystem - aeb, 1999-09-07
3 *
4 * Usage: mkfs.bfs [-N nr-of-inodes] [-V volume-name] [-F fsname] device
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <stdarg.h>
11#include <sys/types.h>
12#include <sys/stat.h>
eb63b9b8
KZ
13#include <fcntl.h>
14#include <errno.h>
15#include <string.h>
16#include <time.h>
de8b064b 17#include <getopt.h>
c36f105d
SK
18
19#include "c.h"
66ee8158 20#include "nls.h"
098fa6b1 21#include "blkdev.h"
e0c67b83 22#include "xalloc.h"
eb63b9b8 23
eb63b9b8
KZ
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 */
30struct 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 */
46struct 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 */
63struct bfsde {
de8b064b
SK
64 unsigned short d_ino;
65 char d_name[BFS_NAMELEN];
eb63b9b8
KZ
66};
67
de8b064b
SK
68static 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}
eb63b9b8 86
de8b064b
SK
87static void __attribute__ ((__noreturn__)) print_version(void)
88{
89 printf(_("%s (%s)\n"), program_invocation_short_name, PACKAGE_STRING);
90 exit(EXIT_SUCCESS);
eb63b9b8
KZ
91}
92
93int
94main(int argc, char *argv[]) {
95 char *device, *volume, *fsname;
96 int inodes;
098fa6b1
ST
97 unsigned long long total_blocks, ino_bytes, ino_blocks, data_blocks;
98 unsigned long long user_specified_total_blocks = 0;
eb63b9b8
KZ
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;
eb63b9b8 107
de8b064b
SK
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 };
eb63b9b8
KZ
118
119 if (argc < 2)
de8b064b 120 usage(stderr);
eb63b9b8 121
de8b064b
SK
122 if (argc == 2 && !strcmp(argv[1], "-V"))
123 print_version();
eb63b9b8
KZ
124
125 volume = fsname = " "; /* is there a default? */
126 inodes = 0;
127
de8b064b 128 while ((c = getopt_long(argc, argv, "N:V:F:vhcl", longopts, NULL)) != -1) {
eb63b9b8
KZ
129 switch (c) {
130 case 'N':
131 inodes = atol(optarg);
132 break;
133
134 case 'V':
135 len = strlen(optarg);
136 if (len <= 0 || len > 6)
c36f105d 137 errx(EXIT_FAILURE, _("volume name too long"));
e0c67b83 138 volume = xstrdup(optarg);
eb63b9b8
KZ
139 break;
140
141 case 'F':
142 len = strlen(optarg);
143 if (len <= 0 || len > 6)
c36f105d 144 errx(EXIT_FAILURE, _("fsname name too long"));
e0c67b83 145 fsname = xstrdup(optarg);
eb63b9b8
KZ
146 break;
147
148 case 'v':
149 verbose = 1;
150 break;
151
152 /* when called via mkfs we may get options c,l,v */
153 case 'c':
154 case 'l':
155 break;
156
de8b064b
SK
157 case VERSION_OPTION:
158 print_version();
159 case 'h':
160 usage(stdout);
eb63b9b8 161 default:
de8b064b 162 usage(stderr);
eb63b9b8
KZ
163 }
164 }
165
166 if (optind == argc)
de8b064b 167 usage(stderr);
eb63b9b8
KZ
168
169 device = argv[optind++];
170
c36f105d
SK
171 if (stat(device, &statbuf) == -1)
172 err(EXIT_FAILURE, _("cannot stat device %s"), device);
eb63b9b8
KZ
173
174 if (!S_ISBLK(statbuf.st_mode))
c36f105d 175 errx(EXIT_FAILURE, _("%s is not a block special device"), device);
eb63b9b8 176
20186299 177 fd = open(device, O_RDWR | O_EXCL);
c36f105d
SK
178 if (fd == -1)
179 err(EXIT_FAILURE, _("cannot open %s"), device);
eb63b9b8
KZ
180
181 if (optind == argc-1)
098fa6b1 182 user_specified_total_blocks = atoll(argv[optind]);
eb63b9b8 183 else if (optind != argc)
de8b064b 184 usage(stderr);
eb63b9b8 185
098fa6b1 186 if (blkdev_get_sectors(fd, &total_blocks) == -1) {
c36f105d
SK
187 if (!user_specified_total_blocks)
188 err(EXIT_FAILURE, _("cannot get size of %s"), device);
eb63b9b8
KZ
189 total_blocks = user_specified_total_blocks;
190 } else if (user_specified_total_blocks) {
191 if (user_specified_total_blocks > total_blocks)
c36f105d 192 errx(EXIT_FAILURE, _("blocks argument too large, max is %llu"),
eb63b9b8
KZ
193 total_blocks);
194 total_blocks = user_specified_total_blocks;
195 }
196
197 if (!inodes) {
198 /* pick some reasonable default */
199 inodes = 8*(total_blocks/800);
200 if (inodes < 48)
201 inodes = 48;
202 if (inodes > 512)
203 inodes = 512;
204 } else {
205 /* believe the user */
206 if (inodes > 512)
c36f105d 207 errx(EXIT_FAILURE, _("too many inodes - max is 512"));
eb63b9b8
KZ
208 }
209
210 ino_bytes = inodes * sizeof(struct bfsi);
211 ino_blocks = (ino_bytes + BFS_BLOCKSIZE - 1) / BFS_BLOCKSIZE;
212 data_blocks = total_blocks - ino_blocks - 1;
213
214 /* mimic the behaviour of SCO's mkfs - maybe this limit is needed */
215 if (data_blocks < 32)
c36f105d 216 errx(EXIT_FAILURE, _("not enough space, need at least %llu blocks"),
eb63b9b8
KZ
217 ino_blocks + 33);
218
219 memset(&sb, 0, sizeof(sb));
220 sb.s_magic = BFS_SUPER_MAGIC;
221 sb.s_start = ino_bytes + sizeof(struct bfssb);
222 sb.s_end = total_blocks * BFS_BLOCKSIZE - 1;
223 sb.s_from = sb.s_to = sb.s_backup_from = sb.s_backup_to = -1;
224 memcpy(sb.s_fsname, fsname, 6);
225 memcpy(sb.s_volume, volume, 6);
226
227 if (verbose) {
66ee8158
KZ
228 fprintf(stderr, _("Device: %s\n"), device);
229 fprintf(stderr, _("Volume: <%-6s>\n"), volume);
230 fprintf(stderr, _("FSname: <%-6s>\n"), fsname);
231 fprintf(stderr, _("BlockSize: %d\n"), BFS_BLOCKSIZE);
232 if (ino_blocks==1)
233 fprintf(stderr, _("Inodes: %d (in 1 block)\n"),
234 inodes);
235 else
098fa6b1 236 fprintf(stderr, _("Inodes: %d (in %lld blocks)\n"),
66ee8158 237 inodes, ino_blocks);
098fa6b1 238 fprintf(stderr, _("Blocks: %lld\n"), total_blocks);
66ee8158 239 fprintf(stderr, _("Inode end: %d, Data end: %d\n"),
eb63b9b8
KZ
240 sb.s_start-1, sb.s_end);
241 }
242
243 if (write(fd, &sb, sizeof(sb)) != sizeof(sb))
c36f105d 244 errx(EXIT_FAILURE, _("error writing superblock"));
eb63b9b8
KZ
245
246 memset(&ri, 0, sizeof(ri));
247 ri.i_ino = BFS_ROOT_INO;
248 ri.i_first_block = 1 + ino_blocks;
249 ri.i_last_block = ri.i_first_block +
250 (inodes * sizeof(de) - 1) / BFS_BLOCKSIZE;
251 ri.i_bytes_to_end = ri.i_first_block * BFS_BLOCKSIZE
252 + 2 * sizeof(struct bfsde) - 1;
253 ri.i_type = BFS_DIR_TYPE;
254 ri.i_mode = S_IFDIR | 0755; /* or just 0755 */
255 ri.i_uid = 0;
256 ri.i_gid = 1; /* random */
257 ri.i_nlinks = 2;
258 time(&now);
259 ri.i_atime = now;
260 ri.i_mtime = now;
261 ri.i_ctime = now;
262
263 if (write(fd, &ri, sizeof(ri)) != sizeof(ri))
c36f105d 264 errx(EXIT_FAILURE, _("error writing root inode"));
eb63b9b8
KZ
265
266 memset(&ri, 0, sizeof(ri));
267 for (i=1; i<inodes; i++)
268 if (write(fd, &ri, sizeof(ri)) != sizeof(ri))
c36f105d 269 errx(EXIT_FAILURE, _("error writing inode"));
eb63b9b8
KZ
270
271 if (lseek(fd, (1 + ino_blocks)*BFS_BLOCKSIZE, SEEK_SET) == -1)
c36f105d 272 errx(EXIT_FAILURE, _("seek error"));
eb63b9b8
KZ
273
274 memset(&de, 0, sizeof(de));
275 de.d_ino = BFS_ROOT_INO;
276 memcpy(de.d_name, ".", 1);
277 if (write(fd, &de, sizeof(de)) != sizeof(de))
c36f105d 278 errx(EXIT_FAILURE, _("error writing . entry"));
eb63b9b8
KZ
279
280 memcpy(de.d_name, "..", 2);
281 if (write(fd, &de, sizeof(de)) != sizeof(de))
c36f105d 282 errx(EXIT_FAILURE, _("error writing .. entry"));
eb63b9b8 283
c36f105d
SK
284 if (close(fd) == -1)
285 err(EXIT_FAILURE, _("error closing %s"), device);
eb63b9b8 286
c36f105d 287 return EXIT_SUCCESS;
eb63b9b8 288}