32 |
32 |
# or implied, of GRNET S.A.
|
33 |
33 |
|
34 |
34 |
from image_creator import get_os_class
|
|
35 |
from image_creator import __version__ as version
|
35 |
36 |
from image_creator.disk import Disk
|
36 |
37 |
import sys
|
37 |
38 |
import os
|
|
39 |
import optparse
|
|
40 |
from pbs import dd
|
|
41 |
|
|
42 |
|
|
43 |
class FatalError(Exception):
|
|
44 |
pass
|
|
45 |
|
|
46 |
|
|
47 |
def check_writable_dir(option, opt_str, value, parser):
|
|
48 |
if not os.path.isdir(value):
|
|
49 |
raise OptionValueError("%s is not a valid directory name" % value)
|
|
50 |
setattr(parser.values, option.dest, value)
|
|
51 |
|
|
52 |
|
|
53 |
def parse_options(input_args):
|
|
54 |
usage = "Usage: %prog [options] <input_media> <name>"
|
|
55 |
parser = optparse.OptionParser(version=version, usage=usage)
|
|
56 |
|
|
57 |
parser.add_option("-o", "--outdir", type="string", dest="outdir",
|
|
58 |
default=".", action="callback", callback=check_writable_dir,
|
|
59 |
help="Output files to DIR [default: working dir]",
|
|
60 |
metavar="DIR")
|
|
61 |
|
|
62 |
parser.add_option("-f", "--force", dest="force", default=False,
|
|
63 |
action="store_true", help="Overwrite output files if they exist")
|
|
64 |
|
|
65 |
parser.add_option("--no-shrink", dest="shrink", default=True,
|
|
66 |
help="Don't shrink any partition before extracting the image",
|
|
67 |
action="store_false")
|
|
68 |
|
|
69 |
options, args = parser.parse_args(input_args)
|
|
70 |
|
|
71 |
if len(args) != 2:
|
|
72 |
parser.error('input media or name are missing')
|
|
73 |
options.source = args[0]
|
|
74 |
options.name = args[1]
|
|
75 |
|
|
76 |
if not os.path.exists(options.source):
|
|
77 |
parser.error('Input media is not accessible')
|
|
78 |
|
|
79 |
return options
|
38 |
80 |
|
39 |
81 |
|
40 |
82 |
def main():
|
41 |
|
if len(sys.argv) != 3:
|
42 |
|
sys.exit("Usage: %s <source> <output_file>" %
|
43 |
|
os.path.basename(sys.argv[0]))
|
44 |
|
source = sys.argv[1]
|
45 |
|
dest = sys.argv[2]
|
46 |
83 |
|
47 |
|
disk = Disk(source)
|
|
84 |
options = parse_options(sys.argv[1:])
|
|
85 |
|
|
86 |
if os.geteuid() != 0:
|
|
87 |
raise FatalError("You must run %s as root" \
|
|
88 |
% os.path.basename(sys.argv[0]))
|
|
89 |
|
|
90 |
if not options.force:
|
|
91 |
for ext in ('diskdump', 'meta'):
|
|
92 |
filename = "%s/%s.%s" % (options.outdir, options.name, ext)
|
|
93 |
if os.path.exists(filename):
|
|
94 |
raise FatalError("Output file %s exists "
|
|
95 |
"(use --force to overwrite it)." % filename)
|
|
96 |
|
|
97 |
disk = Disk(options.source)
|
48 |
98 |
try:
|
49 |
99 |
dev = disk.get_device()
|
50 |
100 |
dev.mount()
|
51 |
101 |
osclass = get_os_class(dev.distro, dev.ostype)
|
52 |
102 |
image_os = osclass(dev.root, dev.g)
|
53 |
103 |
metadata = image_os.get_metadata()
|
54 |
|
for key in metadata.keys():
|
55 |
|
print "%s=%s" % (key, metadata[key])
|
56 |
104 |
image_os.data_cleanup()
|
57 |
105 |
dev.umount()
|
58 |
|
#dev.shrink()
|
|
106 |
size = options.shrink and dev.shrink() or dev.size()
|
|
107 |
metadata['size'] = str(size // 2 ** 20)
|
59 |
108 |
|
|
109 |
dd('if=%s' % dev.device,
|
|
110 |
'of=%s/%s.%s' % (options.outdir, options.name, 'diskdump'),
|
|
111 |
'bs=4M', 'count=%d' % ((size + 1) // 2 ** 22))
|
|
112 |
|
|
113 |
f = open('%s/%s.%s' % (options.outdir, options.name, 'meta'), 'w')
|
|
114 |
for key in metadata.keys():
|
|
115 |
f.write("%s=%s\n" % (key, metadata[key]))
|
|
116 |
f.close()
|
60 |
117 |
finally:
|
61 |
118 |
disk.cleanup()
|
62 |
119 |
|
|
120 |
return 0
|
|
121 |
|
|
122 |
COLOR_BLACK = "\033[00m"
|
|
123 |
COLOR_RED = "\033[1;31m"
|
|
124 |
|
63 |
125 |
if __name__ == '__main__':
|
64 |
|
main()
|
|
126 |
try:
|
|
127 |
ret = main()
|
|
128 |
sys.exit(ret)
|
|
129 |
except FatalError as e:
|
|
130 |
print >> sys.stderr, "\n%sError: %s%s\n" % (COLOR_RED, e, COLOR_BLACK)
|
|
131 |
sys.exit(1)
|
65 |
132 |
|
66 |
133 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
|