1#!/bin/bash
2# test gdisk and sgdisk by creating a dd file
3# Copyright (C) 2011 Guillaume Delacour <gui@iroqwa.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18#
19#
20# Requires: coreutils (mktemp, dd) and 64M of disk space in /tmp (temp dd disk)
21#
22# This script test gdisk commands through the following scenario:
23# - Initialize a new GPT table
24# - Create a single Linux partition
25# - Change name of partition
26# - Change type of partition
27# - Backup to file the GPT table
28# - Delete the single partition
29# - Restore from backup file the GPT table
30# - Wipe the GPT table
31
32# TODO
33# Try to generate a wrong GPT table to detect problems (test --verify)
34# Create MBR partition table with fdisk and migrate it with gdisk
35
36GDISK_BIN=./gdisk
37SGDISK_BIN=./sgdisk
38
39OPT_CLEAR="o"
40OPT_NEW="n"
41OPT_CHANGE_NAME="c"
42OPT_CHANGE_TYPE="t"
43OPT_BACKUP="b"
44OPT_DELETE="d"
45OPT_ZAP="z"
46
47# temp disk for testing gdisk
48TEMP_DISK=$(mktemp)
49# 64 MiB
50TEMP_DISK_SIZE=65536
51
52# the test partition to create
53TEST_PART_TYPE="8300"
54TEST_PART_DEFAULT_NAME="Linux filesystem"
55
56# newname for the partition
57TEST_PART_NEWNAME=$(tr -dc "[:alpha:]" < /dev/urandom | head -c 8)
58# and new type (swap for example)
59TEST_PART_NEWTYPE="8200"
60
61# GPT data backup to filename
62GPT_BACKUP_FILENAME=$(mktemp)
63
64# Pretty print string (Red if FAILED or green if SUCCESS)
65# $1: string to pretty print
66pretty_print() {
67	if [ "$1" = "SUCCESS" ]
68	then
69		# green
70		color="32"
71	else
72		# red
73		color="31"
74	fi
75
76	printf "\033[0;${color}m**$1**\033[m $2\n"
77}
78
79# Verify that the partition exist and has the given type/name
80# $1: Partition type to verify (ex.: 8300)
81# $2: Partition name to verify (ex.: Linux filesystem)
82# $3: Text to print
83verify_part() {
84	partition=$($GDISK_BIN -l $TEMP_DISK | tail -n 1)
85	echo $partition | grep -q "$1[[:space:]]$2$"
86
87	if [ $? -eq 0 ]
88	then
89		pretty_print "SUCCESS" "$3"
90	else
91		pretty_print "FAILED" "$3"
92		exit 1
93	fi
94}
95
96
97#####################################
98# Get GUID of disk
99#####################################
100get_diskguid() {
101	DISK_GUID=$($GDISK_BIN -l $TEMP_DISK | grep "^Disk identifier (GUID):" | awk '{print $4}')
102	return $DISK_GUID
103}
104
105
106#####################################
107# Create a new empty table
108#####################################
109create_table() {
110	case $1 in
111		gdisk)
112			$GDISK_BIN $TEMP_DISK << EOF
113$OPT_CLEAR
114Y
115w
116Y
117EOF
118		;;
119		sgdisk)
120			$SGDISK_BIN $TEMP_DISK -${OPT_CLEAR}
121		;;
122	esac
123
124	# verify that the table is empty
125	# only the columns should appear in the table
126	verify_part "Code" "Name" "Create new empty GPT table"
127	echo ""
128}
129
130
131
132#####################################
133# First create a new partition
134#####################################
135create_partition() {
136	case $1 in
137		gdisk)
138			$GDISK_BIN $TEMP_DISK << EOF
139$OPT_NEW
1401
141
142
143$TEST_PART_TYPE
144w
145Y
146EOF
147		;;
148
149		sgdisk)
150			$SGDISK_BIN $TEMP_DISK -${OPT_NEW} 1 -${OPT_CHANGE_NAME} 1:"${TEST_PART_DEFAULT_NAME}"
151		;;
152	esac
153
154	verify_part "$TEST_PART_TYPE" "$TEST_PART_DEFAULT_NAME" "Create new partition"
155	echo ""
156}
157
158
159#####################################
160# Change name of partition
161#####################################
162change_partition_name() {
163	case $1 in
164		gdisk)
165			$GDISK_BIN $TEMP_DISK << EOF
166$OPT_CHANGE_NAME
167$TEST_PART_NEWNAME
168w
169Y
170EOF
171		;;
172
173		sgdisk)
174			$SGDISK_BIN $TEMP_DISK -${OPT_CHANGE_NAME} 1:${TEST_PART_NEWNAME}
175		;;
176	esac
177
178	verify_part "$TEST_PART_TYPE" "$TEST_PART_NEWNAME" "Change partition 1 name ($TEST_PART_DEFAULT_NAME -> $TEST_PART_NEWNAME)"
179	echo ""
180}
181
182
183change_partition_type() {
184#####################################
185# Change type of partition
186#####################################
187	case $1 in
188		gdisk)
189			$GDISK_BIN $TEMP_DISK << EOF
190$OPT_CHANGE_TYPE
191$TEST_PART_NEWTYPE
192w
193Y
194EOF
195		;;
196
197		sgdisk)
198			$SGDISK_BIN $TEMP_DISK -${OPT_CHANGE_TYPE} 1:${TEST_PART_NEWTYPE}
199		;;
200	esac
201
202	verify_part "$TEST_PART_NEWTYPE" "$TEST_PART_NEWNAME" "Change partition 1 type ($TEST_PART_TYPE -> $TEST_PART_NEWTYPE)"
203	echo ""
204}
205
206
207#####################################
208# Backup GPT data to file
209#####################################
210backup_table() {
211	case $1 in
212		gdisk)
213			$GDISK_BIN $TEMP_DISK << EOF
214$OPT_BACKUP
215$GPT_BACKUP_FILENAME
216q
217EOF
218echo ""
219		;;
220
221		sgdisk)
222			$SGDISK_BIN $TEMP_DISK -${OPT_BACKUP} ${GPT_BACKUP_FILENAME}
223		;;
224	esac
225
226	# if exist and not empty; we will test it after
227	if [ -s $GPT_BACKUP_FILENAME ]
228	then
229		pretty_print "SUCCESS" "GPT data backuped sucessfully"
230	else
231		pretty_print "FAILED" "Unable to create GPT backup file !"
232		exit 1
233	fi
234}
235
236
237#####################################
238# Now, we can delete the partition
239#####################################
240delete_partition() {
241	case $1 in
242		gdisk)
243			$GDISK_BIN $TEMP_DISK << EOF
244$OPT_DELETE
245w
246Y
247EOF
248		;;
249
250		sgdisk)
251			$SGDISK_BIN $TEMP_DISK -${OPT_DELETE} 1
252		;;
253	esac
254
255	# verify that the table is empty (just one partition):
256	# only the columns should appear in the table
257	verify_part "Code" "Name" "Delete partition 1"
258	echo ""
259}
260
261
262#####################################
263# Restore GPT table
264#####################################
265restore_table() {
266	$GDISK_BIN $TEMP_DISK << EOF
267r
268r
269l
270$GPT_BACKUP_FILENAME
271w
272Y
273EOF
274
275	verify_part "$TEST_PART_NEWTYPE" "$TEST_PART_NEWNAME" "Restore the GPT backup"
276	echo ""
277}
278
279
280#####################################
281# Change UID of disk
282#####################################
283change_disk_uid() {
284
285	# get UID of disk before changing it
286	GUID=get_diskguid
287
288
289	case $1 in
290		gdisk)
291			$GDISK_BIN $TEMP_DISK << EOF
292x
293g
294R
295w
296Y
297EOF
298		;;
299
300		sgdisk)
301			$SGDISK_BIN $TEMP_DISK -U=R
302		;;
303	esac
304
305	# get GUID after change
306	NEW_DISK_GUID=get_diskguid
307
308	# compare them
309	if [ "$DISK_GUID" != "$NEW_DISK_GUID" ]
310	then
311		pretty_print "SUCCESS" "GUID of disk has been sucessfully changed"
312	else
313		pretty_print "FAILED" "GUID of disk is the same as the previous one"
314	fi
315}
316
317#####################################
318# Wipe GPT table
319#####################################
320wipe_table() {
321	case $1 in
322		gdisk)
323			$GDISK_BIN $TEMP_DISK << EOF
324x
325$OPT_ZAP
326Y
327Y
328EOF
329		;;
330
331		sgdisk)
332			$SGDISK_BIN $TEMP_DISK -${OPT_ZAP}
333	esac
334
335	# verify that the table is empty (just one partition):
336	# only the columns should appear in the table
337	verify_part "Code" "Name" "Wipe GPT table"
338	echo ""
339}
340
341#####################################
342# Test stdin EOF
343#####################################
344eof_stdin() {
345	$SGDISK_BIN $TEMP_DISK << EOF
346^D
347EOF
348	pretty_print "SUCCESS" "EOF successfully exit gdisk"
349}
350
351###################################
352# Main
353###################################
354
355# create a file to simulate a real device
356dd if=/dev/zero of=$TEMP_DISK bs=1024 count=$TEMP_DISK_SIZE
357
358if [ -s $TEMP_DISK ]
359then
360	pretty_print "SUCCESS" "Temp disk sucessfully created"
361else
362	pretty_print "FAILED" "Unable to create temp disk !"
363	exit 1
364fi
365
366# test gdisk and sgdisk
367for binary in gdisk sgdisk
368do
369	echo ""
370	printf "\033[0;34m**Testing $binary binary**\033[m\n"
371	echo ""
372	create_table          "$binary"
373	create_partition      "$binary"
374	change_partition_name "$binary"
375	change_partition_type "$binary"
376	backup_table          "$binary"
377	delete_partition      "$binary"
378	restore_table         # only with gdisk
379	change_disk_uid       "$binary"
380	wipe_table            "$binary"
381	eof_stdin             # only with gdisk
382done
383
384# remove temp files
385rm -f $TEMP_DISK $GPT_BACKUP_FILENAME
386
387exit 0
388