1/*	$NetBSD: newfs_v7fs.c,v 1.2 2011/08/10 11:31:49 uch 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.2 2011/08/10 11:31:49 uch Exp $");
35#endif /* not lint */
36
37#include <sys/types.h>
38#include <sys/param.h>
39#include <err.h>
40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43#include <unistd.h>
44#include <fcntl.h>
45#include <sys/ioctl.h>
46#include <sys/disklabel.h>
47
48#include <fs/v7fs/v7fs.h>
49#include "v7fs_impl.h"
50#include "progress.h"
51#include "newfs_v7fs.h"
52
53static void usage(void) __dead;
54static bool progress_bar_enable = false;
55int v7fs_newfs_verbose = 3;	/* newfs compatible */
56
57int
58main(int argc, char **argv)
59{
60	const char *device;
61	struct disklabel d;
62	struct partition *p;
63	struct stat st;
64	uint32_t partsize;
65	int Fflag, Zflag;
66	int part;
67	int fd, ch;
68	int endian = _BYTE_ORDER;
69	int32_t maxfile = 0;
70
71	if (argc < 2)
72		usage();
73
74	Fflag = Zflag = partsize = 0;
75	while ((ch = getopt(argc, argv, "Fs:Zs:n:B:V:")) != -1) {
76		switch (ch) {
77		case 'V':
78			v7fs_newfs_verbose = atoi(optarg);
79			break;
80		case 'F':
81			Fflag = 1;
82			break;
83		case 's':
84			partsize = atoi(optarg);
85			break;
86		case 'n':
87			maxfile = atoi(optarg);
88			break;
89		case 'Z':
90			Zflag = 1;
91			break;
92		case 'B':
93			switch (optarg[0]) {
94			case 'l':
95				endian = _LITTLE_ENDIAN;
96				break;
97			case 'b':
98				endian = _BIG_ENDIAN;
99				break;
100			case 'p':
101				endian = _PDP_ENDIAN;
102				break;
103			}
104			break;
105		default:
106			usage();
107			/*NOTREACHED*/
108		}
109	}
110	argc -= optind;
111	argv += optind;
112
113	if (argc != 1)
114		usage();
115	device = argv[0];
116
117	progress_bar_enable = v7fs_newfs_verbose > 1;
118
119
120	if (progress_bar_enable) {
121		progress_switch(progress_bar_enable);
122		progress_init();
123		progress(&(struct progress_arg){ .cdev = device });
124	}
125
126	if (!Fflag) {
127		if ((fd = open(device, O_RDWR)) == -1) {
128			err(EXIT_FAILURE, "%s", device);
129		}
130		if (fstat(fd, &st) != 0) {
131			goto err_exit;
132		}
133		if (!S_ISCHR(st.st_mode)) {
134			warnx("not a raw device.\n");
135		}
136
137		part = DISKPART(st.st_rdev);
138
139		if (ioctl(fd, DIOCGDINFO, &d) == -1) {
140			goto err_exit;
141		}
142		p = &d.d_partitions[part];
143		if (v7fs_newfs_verbose) {
144			printf("partition=%d size=%d offset=%d fstype=%d"
145			    " secsize=%d\n", part, p->p_size, p->p_offset,
146			    p->p_fstype, d.d_secsize);
147		}
148		if (p->p_fstype != FS_V7) {
149			warnx("not a Version 7 partition.");
150			goto err_exit;
151		}
152		partsize = p->p_size;
153	} else {
154		off_t filesize;
155		uint8_t zbuf[8192] = {0, };
156
157		if (partsize == 0) {
158			errx(EXIT_FAILURE, "-F requires -s");
159		}
160
161		filesize = partsize << V7FS_BSHIFT;
162
163		fd = open(device, O_RDWR|O_CREAT|O_TRUNC, 0666);
164		if (fd == -1) {
165			err(EXIT_FAILURE, "%s", device);
166		}
167
168		if (Zflag) {
169			while (filesize > 0) {
170				size_t writenow = MIN(filesize,
171				    (off_t)sizeof(zbuf));
172
173				if ((size_t)write(fd, zbuf, writenow) !=
174				    writenow) {
175					err(EXIT_FAILURE, NULL);
176				}
177				filesize -= writenow;
178			}
179		} else {
180			if (lseek(fd, filesize - 1, SEEK_SET) == -1) {
181				goto err_exit;
182			}
183			if (write(fd, zbuf, 1) != 1) {
184				goto err_exit;
185			}
186			if (lseek(fd, 0, SEEK_SET) == -1) {
187				goto err_exit;
188			}
189		}
190	}
191
192	if (v7fs_newfs(&(struct v7fs_mount_device)
193		{ .device.fd = fd, .endian = endian, .sectors = partsize },
194		maxfile) != 0)
195		goto err_exit;
196
197	close(fd);
198
199	return EXIT_SUCCESS;
200 err_exit:
201	close(fd);
202	err(EXIT_FAILURE, NULL);
203}
204
205void
206progress(const struct progress_arg *p)
207{
208	static struct progress_arg Progress;
209	static char cdev[32];
210	static char label[32];
211
212	if (!progress_bar_enable)
213		return;
214
215	if (p) {
216		Progress = *p;
217		if (p->cdev)
218			strcpy(cdev, p->cdev);
219		if (p->label)
220			strcpy(label, p->label);
221	}
222
223	if (!Progress.tick)
224		return;
225	if (++Progress.cnt > Progress.tick) {
226		Progress.cnt = 0;
227		Progress.total++;
228		progress_bar(cdev, label, Progress.total, PROGRESS_BAR_GRANULE);
229	}
230}
231
232static void
233usage(void)
234{
235
236	(void)fprintf(stderr, "usage: \n%s [-FZ] [-B byte-order]"
237	    " [-n inodes] [-s sectors] [-V verbose] special\n", getprogname());
238
239	exit(EXIT_FAILURE);
240}
241