1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7 * Reserved.  This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License').  You may not use this file
10 * except in compliance with the License.  Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24#include <stdio.h>
25#ifndef __linux__
26#include <stdlib.h>
27#include <unistd.h>
28#endif
29#include <string.h>
30#include <errno.h>
31#include <fcntl.h>
32
33#include "io.h"
34#include "errors.h"
35
36#import "pdisk.h"
37#import "partition_map.h"
38#import "dump.h"
39
40#define CMD_FAIL	1
41#define CMD_SUCCESS	0
42
43#define MIN_PARTITION_SIZE 4
44
45typedef int (*funcPtr_t)();
46
47typedef struct {
48    char *		name;
49    funcPtr_t		func;
50    int			nargs;
51    char *		description;
52} cmdline_option_t;
53
54
55static int block_size();
56static int create_partition();
57static int delete_partition();
58static int disk_is_partitioned();
59static int initialize();
60static int our_dump();
61static int partition_display();
62static int split_partition();
63
64cmdline_option_t optionTable[] = {
65    { "-blockSize", block_size, 0, "display the block size used by the map" },
66    { "-createPartition", create_partition, 0, "create a new partition" },
67    { "-deletePartition", delete_partition, 0, "delete a partition" },
68    { "-dump", our_dump, 0, "dump the list of partitions" },
69    { "-initialize", initialize, 0, "initialize the partition map" },
70    { "-isDiskPartitioned", disk_is_partitioned, 0, "is the disk partitioned" },
71    { "-partitionEntry", partition_display, 0, "get the partition name, type, base, and size" },
72    { "-splitPartition", split_partition, 0, "split an existing partition in two pieces" },
73    { 0, 0, 0 },
74};
75
76static int
77initialize(char * name)
78{
79    partition_map_header * map;
80
81    map = create_partition_map(name, NULL, O_RDWR);
82    if (map == NULL)
83	return (CMD_FAIL);
84    add_partition_to_map("Apple", kMapType,
85			 1, (map->media_size <= 128? 2: 63), map);
86    write_partition_map(map);
87    close_partition_map(map);
88    return (CMD_SUCCESS);
89}
90
91static int
92block_size(char * name)
93{
94    partition_map_header *map;
95    int junk;
96
97    map = open_partition_map(name, &junk, 0, O_RDONLY);
98    if (map == NULL) {
99	return (CMD_FAIL);
100    }
101    printf("%d\n", map->logical_block);
102    close_partition_map(map);
103    return (CMD_SUCCESS);
104}
105
106static int
107our_dump(char * name)
108{
109    partition_map_header *map;
110    int junk;
111
112    map = open_partition_map(name, &junk, 0, O_RDONLY);
113    if (map == NULL) {
114	return (CMD_FAIL);
115    }
116
117    dump_partition_map(map, 1);
118
119    close_partition_map(map);
120    return (CMD_SUCCESS);
121}
122
123static int
124disk_is_partitioned(char * name)
125{
126    partition_map_header *map;
127    int junk;
128
129    map = open_partition_map(name, &junk, 0, O_RDONLY);
130    if (map) {
131	close_partition_map(map);
132	return (CMD_SUCCESS);
133    }
134    return (CMD_FAIL);
135}
136
137static int
138partition_display(char * name, int argc, char * * argv)
139{
140    partition_map * 		entry;
141    int				junk;
142    int				j;
143    partition_map_header * 	map;
144    int				rv = CMD_FAIL;
145
146    if (argc < 2) {
147	fprintf(stderr, "pdisk: %s <partition number>\n", *argv);
148	return (CMD_FAIL);
149    }
150
151    map = open_partition_map(name, &junk, 0, O_RDONLY);
152    if (!map) {
153	fprintf(stderr, "pdisk: disk is not partitioned\n");
154	return (CMD_FAIL);
155    }
156    j = atoi(argv[1]);
157    entry = find_entry_by_disk_address(j, map);
158    if (!entry) {
159	fprintf(stderr, "pdisk: partition %d does not exist\n", j);
160    }
161    else {
162	DPME * p = entry->data;
163
164	rv = CMD_SUCCESS;
165
166	printf("%s %s %u %u\n", p->dpme_name, p->dpme_type,
167	    p->dpme_pblock_start, p->dpme_pblocks);
168    }
169    close_partition_map(map);
170    return (rv);
171}
172
173static int
174split_partition(char * name, int argc, char * * argv)
175{
176    partition_map * 		entry;
177    int				junk;
178    partition_map_header * 	map;
179    u32 			new_size;
180    int				part;
181    int				rv = CMD_SUCCESS;
182    char *			split_name;
183    char *			split_type;
184
185    if (argc < 5) {
186	fprintf(stderr, "pdisk %s <partno> <1st part size> <2nd part name> <2nd part type>\n",
187	       argv[0]);
188	return (CMD_FAIL);
189    }
190    map = open_partition_map(name, &junk, 0, O_RDWR);
191    if (!map) {
192	fprintf(stderr, "pdisk: no valid partitions exist\n");
193	return (CMD_FAIL);
194    }
195    part = atoi(argv[1]);
196    new_size = strtoul(argv[2], NULL, 10);
197    split_name = argv[3];
198    split_type = argv[4];
199    entry = find_entry_by_disk_address(part, map);
200    rv = CMD_FAIL;
201    if (!entry) {
202	fprintf(stderr, "pdisk: partition %d does not exist\n", part);
203    }
204    else if (strcmp(entry->data->dpme_type, kFreeType) == 0
205	     || strcmp(entry->data->dpme_type, kMapType) == 0) {
206	fprintf(stderr, "pdisk: cannot split partition %d because its type is %s\n",
207	       part, entry->data->dpme_type);
208    }
209    else if (!((new_size > 0)
210	       && (new_size
211		   <= (entry->data->dpme_pblocks - MIN_PARTITION_SIZE))
212	       && (new_size >= MIN_PARTITION_SIZE))) {
213	fprintf(stderr, "pdisk: split size of"
214	       " partition %d must be between %u and %u\n",
215	       part, (u32)MIN_PARTITION_SIZE,
216	       (entry->data->dpme_pblocks - (u32)MIN_PARTITION_SIZE));
217    }
218    else {
219	DPME save_dpme;
220
221	save_dpme = *entry->data;
222	delete_partition_from_map(entry);
223	add_partition_to_map(save_dpme.dpme_name, save_dpme.dpme_type,
224			     save_dpme.dpme_pblock_start, new_size, map);
225	add_partition_to_map(split_name, split_type,
226			     save_dpme.dpme_pblock_start + new_size,
227			     save_dpme.dpme_pblocks - new_size, map);
228	write_partition_map(map);
229
230        entry = find_entry_by_base(save_dpme.dpme_pblock_start + new_size, map);
231        if (entry) {
232            printf("%lu\n", entry->disk_address);
233        }
234	rv = CMD_SUCCESS;
235    }
236
237    close_partition_map(map);
238    return (rv);
239}
240
241static int
242create_partition(char * name, int argc, char * * argv)
243{
244    partition_map * 		entry;
245    int				junk;
246    partition_map_header * 	map;
247    int				rv = CMD_SUCCESS;
248    u32				part_base;
249    char *			part_name;
250    u32 			part_size;
251    char *			part_type;
252
253    if (argc < 5) {
254	fprintf(stderr, "%s <name> <type> <base> <size>\n",
255	       argv[0]);
256	return (CMD_FAIL);
257    }
258    map = open_partition_map(name, &junk, 0, O_RDWR);
259    if (!map) {
260	fprintf(stderr, "pdisk: disk is not partitioned\n");
261	return (CMD_FAIL);
262    }
263    part_name = argv[1];
264    part_type = argv[2];
265    part_base = strtoul(argv[3], NULL, 10);
266    part_size = strtoul(argv[4], NULL, 10);
267    rv = CMD_FAIL;
268    if (add_partition_to_map(part_name, part_type, part_base, part_size, map)
269	== 1) {
270	write_partition_map(map);
271	entry = find_entry_by_base(part_base, map);
272	if (entry) {
273	    printf("%lu\n", entry->disk_address);
274	    rv = CMD_SUCCESS;
275	}
276    }
277    close_partition_map(map);
278    return (rv);
279}
280
281static int
282delete_partition(char * name, int argc, char * * argv)
283{
284    partition_map * 		cur;
285    int				junk;
286    partition_map_header * 	map;
287    int				rv = CMD_SUCCESS;
288    u32				part_num;
289
290    if (argc < 2) {
291        fprintf(stderr, "%s <part>\n",
292               argv[0]);
293        return (CMD_FAIL);
294    }
295    map = open_partition_map(name, &junk, 0, O_RDWR);
296    if (!map) {
297        fprintf(stderr, "pdisk: disk is not partitioned\n");
298        return (CMD_FAIL);
299    }
300    part_num = atoi(argv[1]);
301    rv = CMD_FAIL;
302
303    cur = find_entry_by_disk_address(part_num, map);
304    if (cur == NULL) {
305        fprintf(stderr, "No such partition\n");
306    } else {
307        delete_partition_from_map(cur);
308    }
309    write_partition_map(map);
310    rv = CMD_SUCCESS;
311
312    close_partition_map(map);
313    return (rv);
314}
315
316void
317do_command_help()
318{
319    cmdline_option_t * tbl_p;
320
321    fprintf(stderr, "command:\n");
322    for (tbl_p = optionTable; tbl_p->name; tbl_p++) {
323	fprintf(stderr, "\t%-20s %s\n", tbl_p->name, tbl_p->description);
324    }
325}
326
327int
328do_command_line(int argc, char * argv[])
329{
330    char * 		devName = *argv;
331    cmdline_option_t * 	options_p;
332
333    argv++;
334    argc--;
335    if (!argc) {
336        return (CMD_FAIL);
337    }
338    for (options_p = &optionTable[0]; options_p->func; options_p++) {
339        if (strcmp(options_p->name, *argv) == 0) {
340               exit ((options_p->func)(devName, argc, argv));
341        }
342    }
343    return (CMD_FAIL);
344}
345
346