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