1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29/*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39#pragma ident	"%Z%%M%	%I%	%E% SMI"
40
41/*
42 * Label a file system volume.
43 */
44
45#include <stdio.h>
46#include <string.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <sys/param.h>
50#include <sys/types.h>
51#include <sys/mntent.h>
52#include <locale.h>
53
54#define	bcopy(f, t, n)    (void) memcpy(t, f, n)
55#define	bzero(s, n)	memset(s, 0, n)
56#define	bcmp(s, d, n)	memcmp(s, d, n)
57
58#define	index(s, r)	strchr(s, r)
59#define	rindex(s, r)	strrchr(s, r)
60
61#include <sys/vnode.h>
62#include <fcntl.h>
63#include <sys/fs/ufs_inode.h>
64#include <sys/fs/ufs_fs.h>
65
66static void usage();
67static void label(char *, char *, char *);
68
69static union sbtag {
70	char		dummy[SBSIZE];
71	struct fs	sblk;
72} sb_un, altsb_un;
73
74#define	sblock sb_un.sblk
75#define	altsblock altsb_un.sblk
76
77extern int	optind;
78extern char	*optarg;
79
80int
81main(int argc, char *argv[])
82{
83	int		opt;
84	char		*special = NULL;
85	char		*fsname = NULL;
86	char		*volume = NULL;
87
88	while ((opt = getopt(argc, argv, "o:")) != EOF) {
89		switch (opt) {
90
91		case 'o':	/* specific options (none defined yet) */
92			break;
93
94		case '?':
95			usage();
96		}
97	}
98	if (optind > (argc - 1)) {
99		usage();
100	}
101	argc -= optind;
102	argv = &argv[optind];
103	special = argv[0];
104	if (argc > 1) {
105		fsname = argv[1];
106		if (strlen(fsname) > 6) {
107			(void) fprintf(stderr, gettext("labelit: "));
108			(void) fprintf(stderr,
109		gettext("fsname can not be longer than 6 characters\n"));
110			exit(31+1);
111		}
112	}
113	if (argc > 2) {
114		volume = argv[2];
115		if (strlen(volume) > 6) {
116			(void) fprintf(stderr, gettext("labelit: "));
117			(void) fprintf(stderr,
118		gettext("volume can not be longer than 6 characters\n"));
119			exit(31+1);
120		}
121	}
122	label(special, fsname, volume);
123	return	(0);
124}
125
126void
127usage()
128{
129
130	(void) fprintf(stderr, gettext(
131	"ufs usage: labelit [-F ufs] [gen opts] special [fsname volume]\n"));
132	exit(31+1);
133}
134
135void
136label(char *special, char *fsname, char *volume)
137{
138	int	f;
139	int	blk;
140	int	i;
141	char	*p;
142	offset_t offset;
143	struct	fs	*fsp, *altfsp;
144
145	if (fsname == NULL) {
146		f = open64(special, O_RDONLY);
147	} else {
148		f = open64(special, O_RDWR);
149	}
150	if (f < 0) {
151		(void) fprintf(stderr, gettext("labelit: "));
152		perror("open");
153		exit(31+1);
154	}
155	if (llseek(f, (offset_t)SBLOCK * DEV_BSIZE, 0) < 0) {
156		(void) fprintf(stderr, gettext("labelit: "));
157		perror("llseek");
158		exit(31+1);
159	}
160	if (read(f, &sblock, SBSIZE) != SBSIZE) {
161		(void) fprintf(stderr, gettext("labelit: "));
162		perror("read");
163		exit(31+1);
164	}
165	if ((sblock.fs_magic != FS_MAGIC) &&
166	    (sblock.fs_magic != MTB_UFS_MAGIC)) {
167		(void) fprintf(stderr, gettext("labelit: "));
168		(void) fprintf(stderr,
169			gettext("bad super block magic number\n"));
170		exit(31+1);
171	}
172	if ((sblock.fs_magic == FS_MAGIC) &&
173	    ((sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2) &&
174	    (sblock.fs_version != UFS_VERSION_MIN))) {
175		(void) fprintf(stderr, gettext("labelit: "));
176		(void) fprintf(stderr,
177			gettext("unrecognized UFS format version: %d\n"),
178			    sblock.fs_version);
179		exit(31+1);
180	}
181	if ((sblock.fs_magic == MTB_UFS_MAGIC) &&
182	    ((sblock.fs_version > MTB_UFS_VERSION_1) ||
183	    (sblock.fs_version < MTB_UFS_VERSION_MIN))) {
184		(void) fprintf(stderr, gettext("labelit: "));
185		(void) fprintf(stderr,
186			gettext("unrecognized UFS format version: %d\n"),
187			    sblock.fs_version);
188		exit(31+1);
189	}
190	fsp = &sblock;
191
192	/*
193	 * Is block layout available?
194	 */
195
196	if (sblock.fs_cpc <= 0 && (fsname || volume)) {
197		(void) fprintf(stderr, gettext("labelit: "));
198		(void) fprintf(stderr,
199	gettext("insufficient superblock space for file system label\n"));
200		return;
201	}
202
203	/*
204	 * calculate the available blocks for each rotational position
205	 */
206	blk = sblock.fs_spc * sblock.fs_cpc / NSPF(&sblock);
207	for (i = 0; i < blk; i += sblock.fs_frag)
208		/* void */;
209	i -= sblock.fs_frag;
210	blk = i / sblock.fs_frag;
211	p = (char *)&(fs_rotbl(fsp)[blk]);
212
213	if (fsname != NULL) {
214		for (i = 0; i < 14; i++)
215			p[i] = '\0';
216		for (i = 0; (i < 6) && (fsname[i]); i++, p++)
217			*p = fsname[i];
218		p++;
219	}
220	if (volume != NULL) {
221		for (i = 0; (i < 6) && (volume[i]); i++, p++)
222			*p = volume[i];
223	}
224	if (fsname != NULL) {
225		if (llseek(f, (offset_t)SBLOCK * DEV_BSIZE, 0) < 0) {
226			(void) fprintf(stderr, gettext("labelit: "));
227			perror("llseek");
228			exit(31+1);
229		}
230		if (write(f, &sblock, SBSIZE) != SBSIZE) {
231			(void) fprintf(stderr, gettext("labelit: "));
232			perror("write");
233			exit(31+1);
234		}
235		for (i = 0; i < sblock.fs_ncg; i++) {
236			/*
237			 * In the case of multi-terabyte ufs file
238			 * systems, only the first ten and last ten
239			 * cylinder groups have copies of the superblock.
240			 */
241			if (sblock.fs_magic == MTB_UFS_MAGIC &&
242			    sblock.fs_ncg > 20 &&
243			    (i >= 10 && i < sblock.fs_ncg - 10))
244				continue;
245			offset =
246			    (offset_t)cgsblock(&sblock, i) * sblock.fs_fsize;
247			if (llseek(f, offset, 0) < 0) {
248				(void) fprintf(stderr, gettext("labelit: "));
249				perror("lseek");
250				exit(31+1);
251			}
252			altfsp = &altsblock;
253			if (read(f, &altsblock, SBSIZE) != SBSIZE) {
254				(void) fprintf(stderr, gettext("labelit: "));
255				perror("read");
256				exit(31+1);
257			}
258			if ((altsblock.fs_magic != FS_MAGIC) &&
259			    (altsblock.fs_magic != MTB_UFS_MAGIC)) {
260			    (void) fprintf(stderr, gettext("labelit: "));
261			    (void) fprintf(stderr,
262		gettext("bad alternate super block(%i) magic number\n"), i);
263				exit(31+1);
264			}
265			if ((altsblock.fs_magic == FS_MAGIC) &&
266			    ((altsblock.fs_version !=
267				UFS_EFISTYLE4NONEFI_VERSION_2) &&
268			    (altsblock.fs_version != UFS_VERSION_MIN))) {
269				(void) fprintf(stderr, gettext("labelit: "));
270				(void) fprintf(stderr,
271		gettext("bad alternate super block UFS format version: %d\n"),
272					    altsblock.fs_version);
273				exit(31+1);
274			}
275			if ((altsblock.fs_magic == MTB_UFS_MAGIC) &&
276			    ((altsblock.fs_version > MTB_UFS_VERSION_1) ||
277			    (altsblock.fs_version < MTB_UFS_VERSION_MIN))) {
278				(void) fprintf(stderr, gettext("labelit: "));
279				(void) fprintf(stderr,
280		gettext("bad alternate super block UFS format version: %d\n"),
281					    altsblock.fs_version);
282				exit(31+1);
283			}
284			bcopy((char *)&(fs_rotbl(fsp)[blk]),
285				(char *)&(fs_rotbl(altfsp)[blk]), 14);
286
287			if (llseek(f, offset, 0) < 0) {
288				(void) fprintf(stderr, gettext("labelit: "));
289				perror("llseek");
290			exit(31+1);
291			}
292			if (write(f, &altsblock, SBSIZE) != SBSIZE) {
293				(void) fprintf(stderr, gettext("labelit: "));
294				perror("write");
295				exit(31+1);
296			}
297		}
298	}
299	p = (char *)&(fs_rotbl(fsp)[blk]);
300	(void) fprintf(stderr, gettext("fsname: "));
301	for (i = 0; (i < 6) && (*p); i++, p++) {
302		(void) fprintf(stderr, "%c", *p);
303	}
304	(void) fprintf(stderr, "\n");
305	(void) fprintf(stderr, gettext("volume: "));
306	p++;
307	for (i = 0; (i < 6); i++, p++) {
308		(void) fprintf(stderr, "%c", *p);
309	}
310	(void) fprintf(stderr, "\n");
311}
312