1/*	$NetBSD: newfs_v7fs.c,v 1.5 2017/01/10 20:53:09 christos Exp $ */
2
3/*-
4 * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34__RCSID("$NetBSD: newfs_v7fs.c,v 1.5 2017/01/10 20:53:09 christos Exp $");
35#endif /* not lint */
36
37#include <sys/types.h>
38#include <sys/param.h>
39#include <sys/disklabel.h>
40#include <sys/ioctl.h>
41#include <sys/stat.h>
42
43#include <err.h>
44#include <stdio.h>
45#include <string.h>
46#include <stdlib.h>
47#include <unistd.h>
48#include <fcntl.h>
49
50#include <fs/v7fs/v7fs.h>
51#include "v7fs_impl.h"
52#include "progress.h"
53#include "newfs_v7fs.h"
54
55static void usage(void) __dead;
56static bool progress_bar_enable = false;
57int v7fs_newfs_verbose = 3;	/* newfs compatible */
58
59int
60main(int argc, char **argv)
61{
62	const char *device;
63	struct disklabel d;
64	struct partition *p;
65	struct stat st;
66	uint32_t partsize;
67	int Fflag, Zflag;
68	int part;
69	int fd, ch;
70	int endian = _BYTE_ORDER;
71	int32_t maxfile = 0;
72
73	if (argc < 2)
74		usage();
75
76	Fflag = Zflag = partsize = 0;
77	while ((ch = getopt(argc, argv, "Fs:Zs:n:B:V:")) != -1) {
78		switch (ch) {
79		case 'V':
80			v7fs_newfs_verbose = atoi(optarg);
81			break;
82		case 'F':
83			Fflag = 1;
84			break;
85		case 's':
86			partsize = atoi(optarg);
87			break;
88		case 'n':
89			maxfile = atoi(optarg);
90			break;
91		case 'Z':
92			Zflag = 1;
93			break;
94		case 'B':
95			switch (optarg[0]) {
96			case 'l':
97				endian = _LITTLE_ENDIAN;
98				break;
99			case 'b':
100				endian = _BIG_ENDIAN;
101				break;
102			case 'p':
103				endian = _PDP_ENDIAN;
104				break;
105			}
106			break;
107		default:
108			usage();
109			/*NOTREACHED*/
110		}
111	}
112	argc -= optind;
113	argv += optind;
114
115	if (argc != 1)
116		usage();
117	device = argv[0];
118
119	progress_bar_enable = v7fs_newfs_verbose > 1;
120
121
122	if (progress_bar_enable) {
123		progress_switch(progress_bar_enable);
124		progress_init();
125		progress(&(struct progress_arg){ .cdev = device });
126	}
127
128	if (!Fflag) {
129		if ((fd = open(device, O_RDWR)) == -1) {
130			err(EXIT_FAILURE, "%s", device);
131		}
132		if (fstat(fd, &st) != 0) {
133			goto err_exit;
134		}
135		if (!S_ISCHR(st.st_mode)) {
136			warnx("not a raw device");
137		}
138
139		part = DISKPART(st.st_rdev);
140
141		if (ioctl(fd, DIOCGDINFO, &d) == -1) {
142			goto err_exit;
143		}
144		p = &d.d_partitions[part];
145		if (v7fs_newfs_verbose) {
146			printf("partition=%d size=%d offset=%d fstype=%d"
147			    " secsize=%d\n", part, p->p_size, p->p_offset,
148			    p->p_fstype, d.d_secsize);
149		}
150		if (p->p_fstype != FS_V7) {
151			warnx("not a Version 7 partition");
152			goto err_exit;
153		}
154		partsize = p->p_size;
155	} else {
156		off_t filesize;
157		uint8_t zbuf[8192] = {0, };
158
159		if (partsize == 0) {
160			errx(EXIT_FAILURE, "-F requires -s");
161		}
162
163		filesize = partsize << V7FS_BSHIFT;
164
165		fd = open(device, O_RDWR|O_CREAT|O_TRUNC, 0666);
166		if (fd == -1) {
167			err(EXIT_FAILURE, "%s", device);
168		}
169
170		if (Zflag) {
171			while (filesize > 0) {
172				size_t writenow = MIN(filesize,
173				    (off_t)sizeof(zbuf));
174
175				if ((size_t)write(fd, zbuf, writenow) !=
176				    writenow) {
177					err(EXIT_FAILURE, NULL);
178				}
179				filesize -= writenow;
180			}
181		} else {
182			if (lseek(fd, filesize - 1, SEEK_SET) == -1) {
183				goto err_exit;
184			}
185			if (write(fd, zbuf, 1) != 1) {
186				goto err_exit;
187			}
188			if (lseek(fd, 0, SEEK_SET) == -1) {
189				goto err_exit;
190			}
191		}
192	}
193
194	if (v7fs_newfs(&(struct v7fs_mount_device)
195		{ .device.fd = fd, .endian = endian, .sectors = partsize },
196		maxfile) != 0)
197		goto err_exit;
198
199	close(fd);
200
201	return EXIT_SUCCESS;
202 err_exit:
203	close(fd);
204	err(EXIT_FAILURE, NULL);
205}
206
207void
208progress(const struct progress_arg *p)
209{
210	static struct progress_arg Progress;
211	static char cdev[32];
212	static char label[32];
213
214	if (!progress_bar_enable)
215		return;
216
217	if (p) {
218		Progress = *p;
219		if (p->cdev)
220			strcpy(cdev, p->cdev);
221		if (p->label)
222			strcpy(label, p->label);
223	}
224
225	if (!Progress.tick)
226		return;
227	if (++Progress.cnt > Progress.tick) {
228		Progress.cnt = 0;
229		Progress.total++;
230		progress_bar(cdev, label, Progress.total, PROGRESS_BAR_GRANULE);
231	}
232}
233
234static void
235usage(void)
236{
237
238	(void)fprintf(stderr, "usage: \n%s [-FZ] [-B byte-order]"
239	    " [-n inodes] [-s sectors] [-V verbose] special\n", getprogname());
240
241	exit(EXIT_FAILURE);
242}
243