1/*	$NetBSD: chg_pid.c,v 1.8 2009/03/31 11:48:15 tsutsui Exp $	*/
2
3/*
4 * Copyright (c) 1995 L. Weppelman
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 *
30 * This program changes the partition id field (p_id) in the GEM
31 * partition info. NetBSD uses these id-fields to determine the kind
32 * of partition. Sensible id's to set are:
33 *  NBU : NetBSD User partition
34 *  NBR : NetBSD Root partition
35 *  NBS : NetBSD Swap partition
36 *  NBD : General NetBSD partition
37 *  RAW : Partition hidden for GEMDOS
38 *
39 * When NetBSD auto boots, the first 'NBR' partition found when scanning the
40 * SCSI-disks becomes the active root partition. The same goes for 'NBS'.
41 * Drives are scanned in 'SCSI-id' order.
42 */
43#include <sys/types.h>
44#include <osbind.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48#include <stdio.h>
49#include "libtos.h"
50
51#ifndef Dmawrite
52#define	Dmawrite DMAwrite
53#endif
54#ifndef Dmaread
55#define	Dmaread	 DMAread
56#endif
57
58/*
59 * Format of GEM root sector
60 */
61typedef struct gem_part {
62	u_char	p_flg;		/* bit 0 is in-use flag			*/
63	char	p_id[3];	/* id: GEM, BGM, XGM, UNX, MIX		*/
64	u_long	p_st;		/* block where partition starts		*/
65	u_long	p_size;		/* partition size			*/
66} GEM_PART;
67
68/*
69 * Defines for p_flg
70 */
71#define	P_VALID		0x01	/* info is valid			*/
72#define	P_ACTIVE	0x80	/* partition is active			*/
73
74#define	NGEM_PARTS	4	/* Max. partition infos in root sector	*/
75
76typedef struct gem_root {
77	u_char	    fill[0x1c2];	/* Filler, can be boot code	*/
78	u_long	    hd_siz;		/* size of entire volume	*/
79	GEM_PART    parts[NGEM_PARTS];	/* see above			*/
80	u_long	    bsl_st;		/* start of bad-sector list	*/
81	u_long	    bsl_cnt;	  	/* nr. blocks in bad-sector list*/
82	u_short	    csum;		/* checksum	correction	*/
83} GEM_ROOT;
84
85void	help 		PROTO((void));
86void	usage		PROTO((void));
87int	chg_tosparts	PROTO((int, int, char *));
88void	change_it	PROTO((int, GEM_PART *, char *));
89int	read_block	PROTO((void *, int, int));
90int	write_block	PROTO((void *, int, int));
91void	set_csum	PROTO((char *));
92
93const char version[] = "$Revision: 1.9 $";
94
95char	*Progname = NULL;		/* What are we called		*/
96int	t_flag    = 0;			/* Test -- don't actually do it	*/
97int	v_flag    = 0;			/* show version			*/
98int	h_flag    = 0;			/* show help			*/
99
100int
101main(int argc, char *argv[])
102{
103	/*
104	 * Option parsing
105	 */
106	extern	int	optind;
107	extern	char	*optarg;
108
109	int	driveno  = 0;
110	int	partno   = 0;
111	char	*newname = NULL;
112	int	c;
113
114	init_toslib(argv[0]);
115	Progname = argv[0];
116
117	while ((c = getopt(argc, argv, "htVwo:")) != -1) {
118		switch (c) {
119			case 'h':
120				h_flag = 1;
121				break;
122			case 'o':
123				redirect_output(optarg);
124				break;
125			case 't':
126				t_flag = 1;
127				break;
128			case 'V':
129				v_flag = 1;
130				break;
131			case 'w':
132				set_wait_for_key();
133				break;
134			default:
135				usage();
136		}
137	}
138	argc -= optind;
139	argv += optind;
140
141	if (h_flag)
142		help();
143
144	if (v_flag) {
145		eprintf("%s\r\n", version);
146		if (argc != 3)
147			xexit(0);
148	}
149
150	if (argc != 3)
151		usage();
152
153	eprintf("Note: >>> Both drive and partition numbers start "
154		"at 0! <<<\r\n");
155
156	driveno = atoi(argv[0]);
157	partno  = atoi(argv[1]);
158	newname = argv[2];
159	eprintf("About to change id of partition %d on drive %d to %s\r\n",
160						partno, driveno, newname);
161
162	if (!t_flag)
163		c = key_wait("Are you sure (y/n)? ");
164	else c = 'y';
165	switch(c) {
166		case 'y':
167		case 'Y':
168			if(chg_tosparts(partno, driveno, newname)) {
169				if (!t_flag)
170					eprintf("Done\r\n");
171				else eprintf("Not Done\r\n");
172				xexit(0);
173			}
174			else eprintf("Partition number not found\r\n");
175			break;
176		default :
177			eprintf("Aborted\r\n");
178			xexit(1);
179			break;
180	}
181	xexit(0);
182}
183
184int chg_tosparts(chg_part, drive, newname)
185int	chg_part, drive;
186char	*newname;
187{
188    GEM_ROOT	*g_root;
189    GEM_PART	g_local[NGEM_PARTS];
190    char	buf[512];
191    int		pno  = 0;
192    int		i;
193
194    /*
195     * Read root sector
196     */
197    if (read_block(buf, 0, drive) == 0)
198	fatal(-1, "Cannot read block 0\r\n");
199
200    /*
201     * Make local copy of partition info, we may need to re-use
202     * the buffer in case of 'XGM' partitions.
203     */
204    g_root  = (GEM_ROOT*)buf;
205    memcpy(g_local, g_root->parts, NGEM_PARTS*sizeof(GEM_PART));
206
207    for (i = 0; i < NGEM_PARTS; i++) {
208	if (!(g_local[i].p_flg & 1))
209	    continue;
210	if (!strncmp(g_local[i].p_id, "XGM", 3)) {
211	    int	j;
212	    daddr_t	new_root = g_local[i].p_st;
213
214	    /*
215	     * Loop through extended partition list
216	     */
217	    for(;;) {
218		if (read_block(buf, new_root, drive) == 0)
219		    fatal(-1, "Cannot read block %d\r\n", new_root);
220		for (j = 0; j < NGEM_PARTS; j++) {
221		    if (!(g_root->parts[j].p_flg & 1))
222			continue;
223		    if (!strncmp(g_root->parts[j].p_id, "XGM", 3)) {
224			new_root = g_local[i].p_st + g_root->parts[j].p_st;
225			break;
226		    }
227		    else {
228			if (pno == chg_part) {
229			    change_it(pno, &g_root->parts[j], newname);
230			    if (t_flag)
231				return(1);
232			    if (write_block(buf, new_root, drive) == 0)
233				fatal(-1, "Cannot write block %d\r\n",new_root);
234			    return(1);
235			}
236			pno++;
237		    }
238		}
239		if (j == NGEM_PARTS)
240		    break;
241	    }
242	}
243	else {
244	    if (pno == chg_part) {
245		/*
246		 * Re-read block 0
247		 */
248		if (read_block(buf, 0, drive) == 0)
249		    fatal(-1, "Cannot read block 0\r\n");
250		change_it(pno, &g_root->parts[i], newname);
251		if (t_flag)
252		    return(1);
253		set_csum(buf);
254		if (write_block(buf, 0, drive) == 0)
255		    fatal(-1, "Cannot write block 0\r\n");
256		return(1);
257	    }
258	    pno++;
259	}
260    }
261    return(0);
262}
263
264void change_it(pno, gp, newname)
265int		pno;
266GEM_PART	*gp;
267char		*newname;
268{
269	char	s1[4], s2[4];
270
271	strncpy(s1, gp->p_id, 3);
272	strncpy(s2, newname, 3);
273	s1[3] = s2[3] = '\0';
274	eprintf("Changing partition %d: %s -> %s ...", pno, s1, s2);
275	gp->p_id[0] = s2[0]; gp->p_id[1] = s2[1]; gp->p_id[2] = s2[2];
276}
277
278int read_block(buf, blkno, drive)
279void	*buf;
280int	blkno;
281int	drive;
282{
283	if(Dmaread(blkno, 1, buf, drive + 8) != 0)
284		return(0);
285	return(1);
286}
287
288int write_block(buf, blkno, drive)
289void	*buf;
290int	blkno;
291int	drive;
292{
293	if(Dmawrite(blkno, 1, buf, drive + 8) != 0)
294		return(0);
295	return(1);
296}
297
298void set_csum(buf)
299char	*buf;
300{
301	unsigned short	*p = (unsigned short *)buf;
302	unsigned short	csum = 0;
303	int		i;
304
305	p[255] = 0;
306	for(i = 0; i < 256; i++)
307		csum += *p++;
308	*--p = (0x1234 - csum) & 0xffff;
309}
310
311void usage(void)
312{
313	eprintf("Usage: %s [-hVwt] [ -o <output file>] <driveno> <partno> "
314		    "<newid>\r\n", Progname);
315	xexit(1);
316}
317
318void
319help(void)
320{
321	eprintf("\r
322Change partition identifiers\r
323\r
324Usage: %s [-hVwt] [ -o <output file>] <driveno> <partno> <newid>\r
325\r
326Description of options:\r
327\r
328\t-h  What you're getting right now.\r
329\t-o  Write output to both <output file> and stdout.\r
330\t-V  Print program version.\r
331\t-w  Wait for a keypress before exiting.\r
332\t-t  Test mode. It does everyting except the modifications on disk.\r
333\r
334The <driveno> and <partno> arguments specify the drive and the partition\r
335this program acts on. Both are zero based.\r
336The <newid> argument specifies a 3 letter string that will become the new\r
337partition-id.\r
338Finally note that the actions of %s are reversable.\r
339", Progname, Progname);
340	xexit(0);
341}
342