Commit 76c49205f9ba2be06a140fb8d151c3df3614c485

  • avatar
  • The Android Open Source Project <initial-contribution @and…id.com>
  • Wed Mar 04 03:28:13 CET 2009
auto import from //depot/cupcake/@135843
Android.mk
(0 / 26)
  
1LOCAL_PATH := $(call my-dir)
2include $(CLEAR_VARS)
3
4ifeq ($(TARGET_USE_DISKINSTALLER),true)
5
6LOCAL_SRC_FILES := \
7 installer.c
8
9LOCAL_C_INCLUDES := $(LOCAL_PATH)/libdiskconfig
10
11LOCAL_CFLAGS := -O2 -g -W -Wall -Werror
12
13LOCAL_MODULE := diskinstaller
14LOCAL_MODULE_TAGS := system_builder
15
16LOCAL_STATIC_LIBRARIES := $(TARGET_DISK_CONFIG_LIB)
17LOCAL_SYSTEM_SHARED_LIBRARIES := \
18 libdiskconfig \
19 libcutils \
20 liblog \
21 libc
22
23include $(BUILD_EXECUTABLE)
24
25include $(call first-makefiles-under,$(LOCAL_PATH))
26endif
config.mk
(0 / 191)
  
1# note: requires x86 because we assume grub is the mbr bootloader.
2ifeq ($(TARGET_ARCH),x86)
3ifeq ($(TARGET_USE_DISKINSTALLER),true)
4
5diskinstaller_root := bootable/diskinstaller
6
7android_sysbase_modules := \
8 libc \
9 libcutils \
10 libdl \
11 liblog \
12 libm \
13 libstdc++ \
14 linker \
15 sh \
16 toolbox \
17 logcat \
18 gdbserver \
19 strace \
20 netcfg
21android_sysbase_files = \
22 $(call module-installed-files,$(android_sysbase_modules))
23
24# $(1): source base dir
25# $(2): target base dir
26define sysbase-copy-files
27$(hide) $(foreach _f,$(android_sysbase_files), \
28 f=$(patsubst $(1)/%,$(2)/%,$(_f)); \
29 mkdir -p `dirname $$f`; \
30 echo "Copy: $$f" ; \
31 cp -fR $(_f) $$f; \
32)
33endef
34
35installer_base_modules := \
36 libdiskconfig \
37 libext2fs \
38 libext2_com_err \
39 libext2_e2p \
40 libext2_blkid \
41 libext2_uuid \
42 libext2_profile \
43 badblocks \
44 resize2fs \
45 tune2fs \
46 mke2fs \
47 e2fsck
48installer_base_files = \
49 $(call module-built-files,$(installer_base_modules))
50
51# $(1): source base dir
52# $(2): target base dir
53define installer-copy-modules
54$(hide) $(foreach m,$(installer_base_modules), \
55 src=$(firstword $(strip $(call module-built-files,$(m)))); \
56 dest=$(patsubst $(strip $(1))/%,$(strip $(2))/%,\
57 $(firstword $(strip $(call module-installed-files,$(m))))); \
58 echo "Copy: $$src -> $$dest"; \
59 mkdir -p `dirname $$dest`; \
60 cp -fdp $$src $$dest; \
61)
62endef
63
64# Build the installer ramdisk image
65installer_initrc := $(diskinstaller_root)/init.rc
66installer_kernel := $(INSTALLED_KERNEL_TARGET)
67installer_ramdisk := $(TARGET_INSTALLER_OUT)/ramdisk-installer.img
68installer_build_prop := $(INSTALLED_BUILD_PROP_TARGET)
69installer_config := $(diskinstaller_root)/installer.conf
70installer_binary := \
71 $(call intermediates-dir-for,EXECUTABLES,diskinstaller)/diskinstaller
72
73$(installer_ramdisk): $(diskinstaller_root)/config.mk \
74 $(MKBOOTFS) \
75 $(INSTALLED_RAMDISK_TARGET) \
76 $(INSTALLED_BOOTIMAGE_TARGET) \
77 $(TARGET_DISK_LAYOUT_CONFIG) \
78 $(installer_binary) \
79 $(installer_initrc) \
80 $(installer_kernel) \
81 $(installer_config) \
82 $(android_sysbase_files) \
83 $(installer_base_files) \
84 $(installer_build_prop)
85 @echo ----- Making installer image ------
86 rm -rf $(TARGET_INSTALLER_OUT)
87 mkdir -p $(TARGET_INSTALLER_OUT)
88 mkdir -p $(TARGET_INSTALLER_ROOT_OUT)
89 mkdir -p $(TARGET_INSTALLER_ROOT_OUT)/sbin
90 mkdir -p $(TARGET_INSTALLER_ROOT_OUT)/data
91 mkdir -p $(TARGET_INSTALLER_SYSTEM_OUT)
92 mkdir -p $(TARGET_INSTALLER_SYSTEM_OUT)/etc
93 mkdir -p $(TARGET_INSTALLER_SYSTEM_OUT)/bin
94 @echo Copying baseline ramdisk...
95 cp -fR $(TARGET_ROOT_OUT) $(TARGET_INSTALLER_OUT)
96 @echo Copying sysbase files...
97 $(call sysbase-copy-files,$(TARGET_OUT),$(TARGET_INSTALLER_SYSTEM_OUT))
98 @echo Copying installer base files...
99 $(call installer-copy-modules,$(TARGET_OUT),\
100 $(TARGET_INSTALLER_SYSTEM_OUT))
101 @echo Modifying ramdisk contents...
102 cp -f $(installer_initrc) $(TARGET_INSTALLER_ROOT_OUT)/
103 cp -f $(TARGET_DISK_LAYOUT_CONFIG) \
104 $(TARGET_INSTALLER_SYSTEM_OUT)/etc/disk_layout.conf
105 cp -f $(installer_config) \
106 $(TARGET_INSTALLER_SYSTEM_OUT)/etc/installer.conf
107 cp -f $(installer_binary) $(TARGET_INSTALLER_SYSTEM_OUT)/bin/installer
108 $(hide) chmod ug+rw $(TARGET_INSTALLER_ROOT_OUT)/default.prop
109 cat $(installer_build_prop) >> $(TARGET_INSTALLER_ROOT_OUT)/default.prop
110 $(MKBOOTFS) $(TARGET_INSTALLER_ROOT_OUT) | gzip > $(installer_ramdisk)
111 @echo ----- Made installer ramdisk -[ $@ ]-
112
113######################################################################
114# Now the installer boot image which includes the kernel and the ramdisk
115internal_installerimage_args := \
116 --kernel $(installer_kernel) \
117 --ramdisk $(installer_ramdisk)
118
119internal_installerimage_files := \
120 $(filter-out --%,$(internal_installerimage_args))
121
122BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))
123ifdef BOARD_KERNEL_CMDLINE
124 internal_installerimage_args += --cmdline "$(BOARD_KERNEL_CMDLINE)"
125endif
126
127installer_tmp_img := $(TARGET_INSTALLER_OUT)/installer_tmp.img
128tmp_dir_for_inst_image := \
129 $(call intermediates-dir-for,EXECUTABLES,installer_img)/installer_img
130internal_installerimage_args += --tmpdir $(tmp_dir_for_inst_image)
131internal_installerimage_args += --genext2fs $(MKEXT2IMG)
132$(installer_tmp_img): $(MKEXT2IMG) $(internal_installerimage_files)
133 $(call pretty,"Target installer image: $@")
134 $(hide) $(MKEXT2BOOTIMG) $(internal_installerimage_args) --output $@
135
136######################################################################
137# Now make a data image that contains all the target image files for the
138# installer.
139bootldr_bin := $(PRODUCT_OUT)/grub/grub.bin
140installer_target_data_files := \
141 $(INSTALLED_BOOTIMAGE_TARGET) \
142 $(INSTALLED_SYSTEMIMAGE) \
143 $(INSTALLED_USERDATAIMAGE_TARGET) \
144 $(bootldr_bin)
145
146installer_data_img := $(TARGET_INSTALLER_OUT)/installer_data.img
147$(installer_data_img): $(diskinstaller_root)/config.mk \
148 $(installer_target_data_files) \
149 $(MKEXT2IMG) \
150 $(installer_ramdisk)
151 @echo --- Making installer data image ------
152 mkdir -p $(TARGET_INSTALLER_OUT)
153 mkdir -p $(TARGET_INSTALLER_OUT)/data
154 cp -f $(bootldr_bin) $(TARGET_INSTALLER_OUT)/data/bootldr.bin
155 cp -f $(INSTALLED_BOOTIMAGE_TARGET) $(TARGET_INSTALLER_OUT)/data/boot.img
156 cp -f $(INSTALLED_SYSTEMIMAGE) \
157 $(TARGET_INSTALLER_OUT)/data/system.img
158 cp -f $(INSTALLED_USERDATAIMAGE_TARGET) \
159 $(TARGET_INSTALLER_OUT)/data/userdata.img
160 $(call build-userimage-ext2-target,$(TARGET_INSTALLER_OUT)/data,$@,\
161 inst_data,)
162 @echo --- Finished installer data image -[ $@ ]-
163
164######################################################################
165# now combine the installer image with the grub bootloader
166grub_bin := $(PRODUCT_OUT)/grub/grub.bin
167installer_layout := $(diskinstaller_root)/installer_img_layout.conf
168edit_mbr := $(HOST_OUT_EXECUTABLES)/editdisklbl
169
170INSTALLED_DISKINSTALLERIMAGE_TARGET := $(PRODUCT_OUT)/installer.img
171$(INSTALLED_DISKINSTALLERIMAGE_TARGET): \
172 $(installer_tmp_img) \
173 $(installer_data_img) \
174 $(grub_bin) \
175 $(edit_mbr) \
176 $(installer_layout)
177 @echo "Creating bootable installer image: $@"
178 @rm -f $@
179 @cat $(grub_bin) > $@
180 @$(edit_mbr) -l $(installer_layout) -i $@ \
181 inst_boot=$(installer_tmp_img) \
182 inst_data=$(installer_data_img)
183 @echo "Done with bootable installer image -[ $@ ]-"
184
185else # ! TARGET_USE_DISKINSTALLER
186INSTALLED_DISKINSTALLERIMAGE_TARGET :=
187endif
188endif # TARGET_ARCH == x86
189
190.PHONY: installer_img
191installer_img: $(INSTALLED_DISKINSTALLERIMAGE_TARGET)
  
1LOCAL_PATH := $(call my-dir)
2
3include $(CLEAR_VARS)
4
5ifneq ($(TARGET_SIMULATOR),true)
6ifeq ($(TARGET_ARCH),x86)
7
8LOCAL_SRC_FILES := \
9 editdisklbl.c
10
11LOCAL_C_INCLUDES := \
12 $(LOCAL_PATH)/../libdiskconfig
13
14LOCAL_CFLAGS := -O2 -g -W -Wall -Werror
15
16LOCAL_MODULE := editdisklbl
17LOCAL_STATIC_LIBRARIES := libdiskconfig_host libcutils liblog
18
19include $(BUILD_HOST_EXECUTABLE)
20
21endif # TARGET_ARCH == x86
22endif # !TARGET_SIMULATOR
  
1/* tools/editdisklbl/editdisklbl.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define __USE_LARGEFILE64
19#define __USE_FILE_OFFSET64
20#include <errno.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28
29#include "diskconfig.h"
30
31/* give us some room */
32#define EXTRA_LBAS 100
33
34static struct pf_map {
35 struct part_info *pinfo;
36 const char *filename;
37} part_file_map[MAX_NUM_PARTS] = { {0, 0} };
38
39static int
40usage(void)
41{
42 fprintf(stderr,
43 "\nusage: editdisklbl <options> part1=file1 [part2=file2,...]\n"
44 "Where options can be one of:\n"
45 "\t\t-l <layout conf> -- The image layout config file.\n"
46 "\t\t-i <image file> -- The image file to edit.\n"
47 "\t\t-t -- Test mode (optional)\n"
48 "\t\t-v -- Be verbose\n"
49 "\t\t-h -- This message (optional)\n"
50 );
51 return 1;
52}
53
54static int
55parse_args(int argc, char *argv[], struct disk_info **dinfo, int *test,
56 int *verbose)
57{
58 char *layout_conf = NULL;
59 char *img_file = NULL;
60 struct stat filestat;
61 int x;
62 int update_lba = 0;
63
64 while ((x = getopt (argc, argv, "thl:i:")) != EOF) {
65 switch (x) {
66 case 'h':
67 return usage();
68 case 'l':
69 layout_conf = optarg;
70 break;
71 case 't':
72 *test = 1;
73 break;
74 case 'i':
75 img_file = optarg;
76 break;
77 case 'v':
78 *verbose = 1;
79 break;
80 default:
81 fprintf(stderr, "Unknown argument: %c\n", (char)optopt);
82 return usage();
83 }
84 }
85
86 if (!img_file || !layout_conf) {
87 fprintf(stderr, "Image filename and configuration file are required\n");
88 return usage();
89 }
90
91 /* we'll need to parse the command line later for partition-file
92 * mappings, so make sure there's at least something there */
93 if (optind >= argc) {
94 fprintf(stderr, "Must provide partition -> file mappings\n");
95 return usage();
96 }
97
98 if (stat(img_file, &filestat)) {
99 perror("Cannot stat image file");
100 return 1;
101 }
102
103 /* make sure we don't screw up and write to a block device on the host
104 * and wedge things. I just don't trust myself. */
105 if (!S_ISREG(filestat.st_mode)) {
106 fprintf(stderr, "This program should only be used on regular files.");
107 return 1;
108 }
109
110 /* load the disk layout file */
111 if (!(*dinfo = load_diskconfig(layout_conf, img_file))) {
112 fprintf(stderr, "Errors encountered while loading disk conf file %s",
113 layout_conf);
114 return 1;
115 }
116
117 if ((*dinfo)->num_lba == 0) {
118 (*dinfo)->num_lba = (*dinfo)->skip_lba + EXTRA_LBAS;
119 update_lba = 1;
120 }
121
122 /* parse the filename->partition mappings from the command line and patch
123 * up a loaded config file's partition table entries to have
124 * length == filesize */
125 x = 0;
126 while (optind < argc) {
127 char *pair = argv[optind++];
128 char *part_name;
129 struct part_info *pinfo;
130 struct stat tmp_stat;
131
132 if (x >= MAX_NUM_PARTS) {
133 fprintf(stderr, "Error: Too many partitions specified (%d)!\n", x);
134 return 1;
135 }
136
137 if (!(part_name = strsep(&pair, "=")) || !pair || !(*pair)) {
138 fprintf(stderr, "Error parsing partition mappings\n");
139 return usage();
140 }
141
142 if (!(pinfo = find_part(*dinfo, part_name))) {
143 fprintf(stderr, "Partition '%s' not found.\n", part_name);
144 return 1;
145 }
146
147 /* here pair points to the filename (after the '=') */
148 part_file_map[x].pinfo = pinfo;
149 part_file_map[x++].filename = pair;
150
151 if (stat(pair, &tmp_stat) < 0) {
152 fprintf(stderr, "Could not stat file: %s\n", pair);
153 return 1;
154 }
155
156 pinfo->len_kb = (uint32_t) ((tmp_stat.st_size + 1023) >> 10);
157 if (update_lba)
158 (*dinfo)->num_lba +=
159 ((uint64_t)pinfo->len_kb * 1024) / (*dinfo)->sect_size;
160 printf("Updated %s length to be %uKB\n", pinfo->name, pinfo->len_kb);
161 }
162
163 return 0;
164}
165
166int
167main(int argc, char *argv[])
168{
169 struct disk_info *dinfo = NULL;
170 int test = 0;
171 int verbose = 0;
172 int cnt;
173
174 if (parse_args(argc, argv, &dinfo, &test, &verbose))
175 return 1;
176
177 if (verbose)
178 dump_disk_config(dinfo);
179
180 if (test)
181 printf("Test mode enabled. Actions will not be committed to disk!\n");
182
183 if (apply_disk_config(dinfo, test)) {
184 fprintf(stderr, "Could not apply disk configuration!\n");
185 return 1;
186 }
187
188 printf("Copying images to specified partition offsets\n");
189 /* now copy the images to their appropriate locations on disk */
190 for (cnt = 0; cnt < MAX_NUM_PARTS && part_file_map[cnt].pinfo; ++cnt) {
191 loff_t offs = part_file_map[cnt].pinfo->start_lba * dinfo->sect_size;
192 const char *dest_fn = dinfo->device;
193 if (write_raw_image(dest_fn, part_file_map[cnt].filename, offs, test)) {
194 fprintf(stderr, "Could not write images after editing label.\n");
195 return 1;
196 }
197 }
198 printf("File edit complete. Wrote %d images.\n", cnt);
199
200 return 0;
201}
init.rc
(0 / 30)
  
1on init
2 export PATH /sbin:/system/sbin:/system/bin
3 export ANDROID_ROOT /system
4 export ANDROID_DATA /data
5
6 symlink /system/etc /etc
7
8 mkdir /data
9 mkdir /cache
10 mount /tmp /tmp tmpfs
11
12# mount the installer needed partitions
13# mount ext2 /dev/block/sdb2 /data ro
14
15on boot
16 ifup lo
17 hostname localhost
18 domainname localdomain
19
20 class_start default
21
22service installer /system/bin/installer -p /dev/block/sdb2
23 console
24 oneshot
25
26service logcat /system/bin/logcat
27 console
28
29service console /system/bin/sh
30 console
installer.c
(0 / 477)
  
1/* commands/sysloader/installer/installer.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "installer"
19
20#include <sys/types.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include <sys/mount.h>
29#include <sys/stat.h>
30#include <sys/wait.h>
31
32
33#include <cutils/config_utils.h>
34#include <cutils/log.h>
35
36#include "diskconfig.h"
37#include "installer.h"
38
39#define MKE2FS_BIN "/system/bin/mke2fs"
40#define E2FSCK_BIN "/system/bin/e2fsck"
41#define TUNE2FS_BIN "/system/bin/tune2fs"
42#define RESIZE2FS_BIN "/system/bin/resize2fs"
43
44static int
45usage(void)
46{
47 fprintf(stderr, "Usage: %s\n", LOG_TAG);
48 fprintf(stderr, "\t-c <path> - Path to installer conf file "
49 "(/system/etc/installer.conf)\n");
50 fprintf(stderr, "\t-l <path> - Path to device disk layout conf file "
51 "(/system/etc/disk_layout.conf)\n");
52 fprintf(stderr, "\t-h - This help message\n");
53 fprintf(stderr, "\t-d - Dump the compiled in partition info.\n");
54 fprintf(stderr, "\t-p <path> - Path to device that should be mounted"
55 " to /data.\n");
56 fprintf(stderr, "\t-t - Test mode. Don't write anything to disk.\n");
57 return 1;
58}
59
60static cnode *
61read_conf_file(const char *fn)
62{
63 cnode *root = config_node("", "");
64 config_load_file(root, fn);
65
66 if (root->first_child == NULL) {
67 LOGE("Could not read config file %s", fn);
68 return NULL;
69 }
70
71 return root;
72}
73
74static int
75exec_cmd(const char *cmd, ...) /* const char *arg, ...) */
76{
77 va_list ap;
78 int size = 0;
79 char *str;
80 char *outbuf;
81 int rv;
82
83 /* compute the size for the command buffer */
84 size = strlen(cmd) + 1;
85 va_start(ap, cmd);
86 while ((str = va_arg(ap, char *))) {
87 size += strlen(str) + 1; /* need room for the space separator */
88 }
89 va_end(ap);
90
91 if (!(outbuf = malloc(size + 1))) {
92 LOGE("Can't allocate memory to exec cmd");
93 return -1;
94 }
95
96 /* this is a bit inefficient, but is trivial, and works */
97 strcpy(outbuf, cmd);
98 va_start(ap, cmd);
99 while ((str = va_arg(ap, char *))) {
100 strcat(outbuf, " ");
101 strcat(outbuf, str);
102 }
103 va_end(ap);
104
105 LOGI("Executing: %s", outbuf);
106 rv = system(outbuf);
107 free(outbuf);
108 if (rv < 0) {
109 LOGI("Error while trying to execute '%s'", cmd);
110 return -1;
111 }
112 rv = WEXITSTATUS(rv);
113 LOGI("Done executing %s (%d)", outbuf, rv);
114 return rv;
115}
116
117
118static int
119do_fsck(const char *dst, int force)
120{
121 int rv;
122 const char *opts = force ? "-fy" : "-y";
123
124
125 LOGI("Running e2fsck... (force=%d) This MAY take a while.", force);
126 if ((rv = exec_cmd(E2FSCK_BIN, "-C 0", opts, dst, NULL)) < 0)
127 return 1;
128 if (rv >= 4) {
129 LOGE("Error while running e2fsck: %d", rv);
130 return 1;
131 }
132 sync();
133 LOGI("e2fsck succeeded (exit code: %d)", rv);
134
135 return 0;
136}
137
138static int
139process_ext2_image(const char *dst, const char *src, uint32_t flags, int test)
140{
141 int rv;
142
143 /* First, write the image to disk. */
144 if (write_raw_image(dst, src, 0, test))
145 return 1;
146
147 if (test)
148 return 0;
149
150 /* Next, let's e2fsck the fs to make sure it got written ok, and
151 * everything is peachy */
152 if (do_fsck(dst, 1))
153 return 1;
154
155 /* set the mount count to 1 so that 1st mount on boot doesn't complain */
156 if ((rv = exec_cmd(TUNE2FS_BIN, "-C", "1", dst, NULL)) < 0)
157 return 1;
158 if (rv) {
159 LOGE("Error while running tune2fs: %d", rv);
160 return 1;
161 }
162
163 /* If the user requested that we resize, let's do it now */
164 if (flags & INSTALL_FLAG_RESIZE) {
165 if ((rv = exec_cmd(RESIZE2FS_BIN, "-F", dst, NULL)) < 0)
166 return 1;
167 if (rv) {
168 LOGE("Error while running resize2fs: %d", rv);
169 return 1;
170 }
171 sync();
172 if (do_fsck(dst, 0))
173 return 1;
174 }
175
176 /* make this an ext3 fs? */
177 if (flags & INSTALL_FLAG_ADDJOURNAL) {
178 if ((rv = exec_cmd(TUNE2FS_BIN, "-j", dst, NULL)) < 0)
179 return 1;
180 if (rv) {
181 LOGE("Error while running tune2fs: %d", rv);
182 return 1;
183 }
184 sync();
185 if (do_fsck(dst, 0))
186 return 1;
187 }
188
189 return 0;
190}
191
192
193/* TODO: PLEASE break up this function into several functions that just
194 * do what they need with the image node. Many of them will end up
195 * looking at same strings, but it will be sooo much cleaner */
196static int
197process_image_node(cnode *img, struct disk_info *dinfo, int test)
198{
199 struct part_info *pinfo = NULL;
200 loff_t offset = (loff_t)-1;
201 const char *filename = NULL;
202 char *dest_part = NULL;
203 const char *tmp;
204 uint32_t flags = 0;
205 uint8_t type = 0;
206 int rv;
207 int func_ret = 1;
208
209 filename = config_str(img, "filename", NULL);
210
211 /* process the 'offset' image parameter */
212 if ((tmp = config_str(img, "offset", NULL)) != NULL)
213 offset = strtoull(tmp, NULL, 0);
214
215 /* process the 'partition' image parameter */
216 if ((tmp = config_str(img, "partition", NULL)) != NULL) {
217 if (offset != (loff_t)-1) {
218 LOGE("Cannot specify the partition name AND an offset for %s",
219 img->name);
220 goto fail;
221 }
222
223 if (!(pinfo = find_part(dinfo, tmp))) {
224 LOGE("Cannot find partition %s while processing %s",
225 tmp, img->name);
226 goto fail;
227 }
228
229 if (!(dest_part = find_part_device(dinfo, pinfo->name))) {
230 LOGE("Could not get the device name for partition %s while"
231 " processing image %s", pinfo->name, img->name);
232 goto fail;
233 }
234 offset = pinfo->start_lba * dinfo->sect_size;
235 }
236
237 /* process the 'mkfs' parameter */
238 if ((tmp = config_str(img, "mkfs", NULL)) != NULL) {
239 char *journal_opts;
240 char vol_lbl[16]; /* ext2/3 has a 16-char volume label */
241
242 if (!pinfo) {
243 LOGE("Target partition required for mkfs for '%s'", img->name);
244 goto fail;
245 } else if (filename) {
246 LOGE("Providing filename and mkfs parameters is meaningless");
247 goto fail;
248 }
249
250 if (!strcmp(tmp, "ext2"))
251 journal_opts = "";
252 else if (!strcmp(tmp, "ext3"))
253 journal_opts = "-j";
254 else {
255 LOGE("Unknown filesystem type for mkfs: %s", tmp);
256 goto fail;
257 }
258
259 /* put the partition name as the volume label */
260 strncpy(vol_lbl, pinfo->name, sizeof(vol_lbl));
261
262 /* since everything checked out, lets make the fs, and return since
263 * we don't need to do anything else */
264 rv = exec_cmd(MKE2FS_BIN, "-L", vol_lbl, journal_opts, dest_part, NULL);
265 if (rv < 0)
266 goto fail;
267 else if (rv > 0) {
268 LOGE("Error while running mke2fs: %d", rv);
269 goto fail;
270 }
271 sync();
272 if (do_fsck(dest_part, 0))
273 goto fail;
274 goto done;
275 }
276
277 /* since we didn't mkfs above, all the rest of the options assume
278 * there's a filename involved */
279 if (!filename) {
280 LOGE("Filename is required for image %s", img->name);
281 goto fail;
282 }
283
284 /* process the 'flags' image parameter */
285 if ((tmp = config_str(img, "flags", NULL)) != NULL) {
286 char *flagstr, *flagstr_orig;
287
288 if (!(flagstr = flagstr_orig = strdup(tmp))) {
289 LOGE("Cannot allocate memory for dup'd flags string");
290 goto fail;
291 }
292 while ((tmp = strsep(&flagstr, ","))) {
293 if (!strcmp(tmp, "resize"))
294 flags |= INSTALL_FLAG_RESIZE;
295 else if (!strcmp(tmp, "addjournal"))
296 flags |= INSTALL_FLAG_ADDJOURNAL;
297 else {
298 LOGE("Unknown flag '%s' for image %s", tmp, img->name);
299 free(flagstr_orig);
300 goto fail;
301 }
302 }
303 free(flagstr_orig);
304 }
305
306 /* process the 'type' image parameter */
307 if (!(tmp = config_str(img, "type", NULL))) {
308 LOGE("Type is required for image %s", img->name);
309 goto fail;
310 } else if (!strcmp(tmp, "raw")) {
311 type = INSTALL_IMAGE_RAW;
312 } else if (!strcmp(tmp, "ext2")) {
313 type = INSTALL_IMAGE_EXT2;
314 } else if (!strcmp(tmp, "ext3")) {
315 type = INSTALL_IMAGE_EXT3;
316 } else {
317 LOGE("Unknown image type '%s' for image %s", tmp, img->name);
318 goto fail;
319 }
320
321 /* at this point we MUST either have a partition in 'pinfo' or a raw
322 * 'offset', otherwise quit */
323 if (!pinfo && (offset == (loff_t)-1)) {
324 LOGE("Offset to write into the disk is unknown for %s", img->name);
325 goto fail;
326 }
327
328 if (!pinfo && (type != INSTALL_IMAGE_RAW)) {
329 LOGE("Only raw images can specify direct offset on the disk. Please"
330 " specify the target partition name instead. (%s)", img->name);
331 goto fail;
332 }
333
334 switch(type) {
335 case INSTALL_IMAGE_RAW:
336 if (write_raw_image(dinfo->device, filename, offset, test))
337 goto fail;
338 break;
339
340 case INSTALL_IMAGE_EXT3:
341 /* makes the error checking in the imager function easier */
342 if (flags & INSTALL_FLAG_ADDJOURNAL) {
343 LOGW("addjournal flag is meaningless for ext3 images");
344 flags &= ~INSTALL_FLAG_ADDJOURNAL;
345 }
346 /* ...fall through... */
347
348 case INSTALL_IMAGE_EXT2:
349 if (process_ext2_image(dest_part, filename, flags, test))
350 goto fail;
351 break;
352
353 default:
354 LOGE("Unknown image type: %d", type);
355 goto fail;
356 }
357
358done:
359 func_ret = 0;
360
361fail:
362 if (dest_part)
363 free(dest_part);
364 return func_ret;
365}
366
367int
368main(int argc, char *argv[])
369{
370 char *disk_conf_file = "/system/etc/disk_layout.conf";
371 char *inst_conf_file = "/system/etc/installer.conf";
372 char *inst_data_dir = "/data";
373 char *inst_data_dev = NULL;
374 char *data_fstype = "ext2";
375 cnode *config;
376 cnode *images;
377 cnode *img;
378 int cnt = 0;
379 struct disk_info *device_disk_info;
380 int dump = 0;
381 int test = 0;
382 int x;
383
384 while ((x = getopt (argc, argv, "thdc:l:p:")) != EOF) {
385 switch (x) {
386 case 'h':
387 return usage();
388 case 'c':
389 inst_conf_file = optarg;
390 break;
391 case 'l':
392 disk_conf_file = optarg;
393 break;
394 case 't':
395 test = 1;
396 break;
397 case 'p':
398 inst_data_dev = optarg;
399 break;
400 case 'd':
401 dump = 1;
402 break;
403 default:
404 fprintf(stderr, "Unknown argument: %c\n", (char)optopt);
405 return usage();
406 }
407 }
408
409 /* If the user asked us to wait for data device, wait for it to appear,
410 * and then mount it onto /data */
411 if (inst_data_dev && !dump) {
412 struct stat filestat;
413
414 LOGI("Waiting for device: %s", inst_data_dev);
415 while (stat(inst_data_dev, &filestat))
416 sleep(1);
417 LOGI("Device %s ready", inst_data_dev);
418 if (mount(inst_data_dev, inst_data_dir, data_fstype, MS_RDONLY, NULL)) {
419 LOGE("Could not mount %s on %s as %s", inst_data_dev, inst_data_dir,
420 data_fstype);
421 return 1;
422 }
423 }
424
425 /* Read and process the disk configuration */
426 if (!(device_disk_info = load_diskconfig(disk_conf_file, NULL))) {
427 LOGE("Errors encountered while loading disk conf file %s",
428 disk_conf_file);
429 return 1;
430 }
431
432 if (process_disk_config(device_disk_info)) {
433 LOGE("Errors encountered while processing disk config from %s",
434 disk_conf_file);
435 return 1;
436 }
437
438 /* Was all of this for educational purposes? If so, quit. */
439 if (dump) {
440 dump_disk_config(device_disk_info);
441 return 0;
442 }
443
444 /* This doesnt do anything but load the config file */
445 if (!(config = read_conf_file(inst_conf_file)))
446 return 1;
447
448 /* First, partition the drive */
449 if (apply_disk_config(device_disk_info, test))
450 return 1;
451
452 /* Now process the installer config file and write the images to disk */
453 if (!(images = config_find(config, "images"))) {
454 LOGE("Invalid configuration file %s. Missing 'images' section",
455 inst_conf_file);
456 return 1;
457 }
458
459 for (img = images->first_child; img; img = img->next) {
460 if (process_image_node(img, device_disk_info, test))
461 return 1;
462 ++cnt;
463 }
464
465 /*
466 * We have to do the apply() twice. We must do it once before the image
467 * writes to layout the disk partitions so that we can write images to
468 * them. We then do the apply() again in case one of the images
469 * replaced the MBR with a new bootloader, and thus messed with
470 * partition table.
471 */
472 if (apply_disk_config(device_disk_info, test))
473 return 1;
474
475 LOGI("Done processing installer config. Configured %d images", cnt);
476 return 0;
477}
  
1images {
2 bootldr {
3 offset 0
4 filename /data/bootldr.bin
5 type raw
6 }
7
8 boot {
9 partition boot
10 filename /data/boot.img
11 type raw
12 }
13
14 system {
15 partition system
16 filename /data/system.img
17 type ext2
18 flags resize,addjournal
19 }
20
21 data {
22 partition data
23 filename /data/userdata.img
24 type ext2
25 flags resize,addjournal
26 }
27
28 cache {
29 partition cache
30 mkfs ext3
31 }
32
33 third_party {
34 partition third_party
35 mkfs ext3
36 }
37
38## TODO: Add the support for this later?
39# system {
40# partition system
41# filename /data/system.tar.gz
42# type targz
43# mkfs ext3
44# }
45}
installer.h
(0 / 34)
  
1/* commands/sysloader/installer/installer.h
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef __COMMANDS_SYSLOADER_INSTALLER_INSTALLER_H
19#define __COMMANDS_SYSLOADER_INSTALLER_INSTALLER_H
20
21#include <stdint.h>
22
23/* image types */
24#define INSTALL_IMAGE_RAW 1
25#define INSTALL_IMAGE_EXT2 2
26#define INSTALL_IMAGE_EXT3 3
27#define INSTALL_IMAGE_TARGZ 10
28
29
30/* flags */
31#define INSTALL_FLAG_RESIZE 0x1
32#define INSTALL_FLAG_ADDJOURNAL 0x2
33
34#endif /* __COMMANDS_SYSLOADER_INSTALLER_INSTALLER_H */
  
1device {
2 scheme mbr
3
4 # bytes in a disk "block", must be a power of 2!
5 sector_size 512
6
7 # What LBA should the partitions start at?
8 start_lba 2048
9
10 # Autodetect disk size if == 0
11 num_lba 0
12
13 partitions {
14 inst_boot {
15 active y
16 type linux
17 }
18
19 inst_data {
20 type linux
21 }
22 }
23}
  
1LOCAL_PATH := $(call my-dir)
2include $(CLEAR_VARS)
3
4commonSources := \
5 diskconfig.c \
6 diskutils.c \
7 write_lst.c \
8 config_mbr.c
9
10ifneq ($(TARGET_SIMULATOR),true)
11ifeq ($(TARGET_ARCH),x86)
12
13###########################
14# static library for host
15LOCAL_SRC_FILES := $(commonSources)
16
17LOCAL_CFLAGS := -O2 -g -W -Wall -Werror -D_LARGEFILE64_SOURCE
18
19LOCAL_MODULE := libdiskconfig_host
20LOCAL_STATIC_LIBRARIES := libcutils
21include $(BUILD_HOST_STATIC_LIBRARY)
22
23## Build a test executable for host (to dump configuration files).
24include $(CLEAR_VARS)
25LOCAL_SRC_FILES := $(commonSources)
26LOCAL_SRC_FILES += dump_diskconfig.c
27LOCAL_MODULE := dump_diskconfig
28LOCAL_STATIC_LIBRARIES := libdiskconfig_host libcutils
29include $(BUILD_HOST_EXECUTABLE)
30
31###########################
32# shared library for target
33include $(CLEAR_VARS)
34
35LOCAL_SRC_FILES := $(commonSources)
36
37LOCAL_CFLAGS := -O2 -g -W -Wall -Werror
38
39LOCAL_MODULE := libdiskconfig
40LOCAL_MODULE_TAGS := system_builder
41LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
42
43include $(BUILD_SHARED_LIBRARY)
44
45endif # ! TARGET_SIMULATOR
46endif # TARGET_ARCH == x86
  
1/* libs/diskconfig/diskconfig.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "config_mbr"
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <stdio.h>
23
24#include <cutils/log.h>
25
26#include "diskconfig.h"
27
28
29/* start and len are in LBA units */
30static void
31cfg_pentry(struct pc_partition *pentry, uint8_t status, uint8_t type,
32 uint32_t start, uint32_t len)
33{
34 if (len > 0) {
35 /* seems that somes BIOSens can get wedged on boot while verifying
36 * the mbr if these are 0 */
37 memset(&pentry->start, 0xff, sizeof(struct chs));
38 memset(&pentry->end, 0xff, sizeof(struct chs));
39 } else {
40 /* zero out the c/h/s entries.. they are not used */
41 memset(&pentry->start, 0, sizeof(struct chs));
42 memset(&pentry->end, 0, sizeof(struct chs));
43 }
44
45 pentry->status = status;
46 pentry->type = type;
47 pentry->start_lba = start;
48 pentry->len_lba = len;
49
50 LOGI("Configuring pentry. status=0x%x type=0x%x start_lba=%u len_lba=%u",
51 pentry->status, pentry->type, pentry->start_lba, pentry->len_lba);
52}
53
54
55static inline uint32_t
56kb_to_lba(uint32_t len_kb, uint32_t sect_size)
57{
58 uint64_t lba;
59
60 lba = (uint64_t)len_kb * 1024;
61 /* bump it up to the next LBA boundary just in case */
62 lba = (lba + (uint64_t)sect_size - 1) & ~((uint64_t)sect_size - 1);
63 lba /= (uint64_t)sect_size;
64 if (lba >= 0xffffffffULL)
65 LOGE("Error converting kb -> lba. 32bit overflow, expect weirdness");
66 return (uint32_t)(lba & 0xffffffffULL);
67}
68
69
70static struct write_list *
71mk_pri_pentry(struct disk_info *dinfo, struct part_info *pinfo, int pnum,
72 uint32_t *lba)
73{
74 struct write_list *item;
75 struct pc_partition *pentry;
76
77 if (pnum >= PC_NUM_BOOT_RECORD_PARTS) {
78 LOGE("Maximum number of primary partition exceeded.");
79 return NULL;
80 }
81
82 if (!(item = alloc_wl(sizeof(struct pc_partition)))) {
83 LOGE("Unable to allocate memory for partition entry.");
84 return NULL;
85 }
86
87 {
88 /* DO NOT DEREFERENCE */
89 struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
90 /* grab the offset in mbr where to write this partition entry. */
91 item->offset = (loff_t)((uint32_t)((uint8_t *)(&mbr->ptable[pnum])));
92 }
93
94 pentry = (struct pc_partition *) &item->data;
95
96 /* need a standard primary partition entry */
97 if (pinfo) {
98 /* need this to be 64 bit in case len_kb is large */
99 uint64_t len_lba;
100
101 if (pinfo->len_kb != (uint32_t)-1) {
102 /* bump it up to the next LBA boundary just in case */
103 len_lba = ((uint64_t)pinfo->len_kb * 1024);
104 len_lba += ((uint64_t)dinfo->sect_size - 1);
105 len_lba &= ~((uint64_t)dinfo->sect_size - 1);
106 len_lba /= (uint64_t)dinfo->sect_size;
107 } else {
108 /* make it fill the rest of disk */
109 len_lba = dinfo->num_lba - *lba;
110 }
111
112 cfg_pentry(pentry, ((pinfo->flags & PART_ACTIVE_FLAG) ?
113 PC_PART_ACTIVE : PC_PART_NORMAL),
114 pinfo->type, *lba, (uint32_t)len_lba);
115
116 pinfo->start_lba = *lba;
117 *lba += (uint32_t)len_lba;
118 } else {
119 /* this should be made an extended partition, and should take
120 * up the rest of the disk as a primary partition */
121 cfg_pentry(pentry, PC_PART_NORMAL, PC_PART_TYPE_EXTENDED,
122 *lba, dinfo->num_lba - *lba);
123
124 /* note that we do not update the *lba because we now have to
125 * create a chain of extended partition tables, and first one is at
126 * *lba */
127 }
128
129 return item;
130}
131
132
133/* This function configures an extended boot record at the beginning of an
134 * extended partition. This creates a logical partition and a pointer to
135 * the next EBR.
136 *
137 * ext_lba == The start of the toplevel extended partition (pointed to by the
138 * entry in the MBR).
139 */
140static struct write_list *
141mk_ext_pentry(struct disk_info *dinfo, struct part_info *pinfo, uint32_t *lba,
142 uint32_t ext_lba, struct part_info *pnext)
143{
144 struct write_list *item;
145 struct pc_boot_record *ebr;
146 uint32_t len; /* in lba units */
147
148 if (!(item = alloc_wl(sizeof(struct pc_boot_record)))) {
149 LOGE("Unable to allocate memory for EBR.");
150 return NULL;
151 }
152
153 /* we are going to write the ebr at the current LBA, and then bump the
154 * lba counter since that is where the logical data partition will start */
155 item->offset = (*lba) * dinfo->sect_size;
156 (*lba)++;
157
158 ebr = (struct pc_boot_record *) &item->data;
159 memset(ebr, 0, sizeof(struct pc_boot_record));
160 ebr->mbr_sig = PC_BIOS_BOOT_SIG;
161
162 if (pinfo->len_kb != (uint32_t)-1)
163 len = kb_to_lba(pinfo->len_kb, dinfo->sect_size);
164 else {
165 if (pnext) {
166 LOGE("Only the last partition can be specified to fill the disk "
167 "(name = '%s')", pinfo->name);
168 goto fail;
169 }
170 len = dinfo->num_lba - *lba;
171 /* update the pinfo structure to reflect the new size, for
172 * bookkeeping */
173 pinfo->len_kb =
174 (uint32_t)(((uint64_t)len * (uint64_t)dinfo->sect_size) /
175 ((uint64_t)1024));
176 }
177
178 cfg_pentry(&ebr->ptable[PC_EBR_LOGICAL_PART], PC_PART_NORMAL,
179 pinfo->type, 1, len);
180
181 pinfo->start_lba = *lba;
182 *lba += len;
183
184 /* If this is not the last partition, we have to create a link to the
185 * next extended partition.
186 *
187 * Otherwise, there's nothing to do since the "pointer entry" is
188 * already zero-filled.
189 */
190 if (pnext) {
191 /* The start lba for next partition is an offset from the beginning
192 * of the top-level extended partition */
193 uint32_t next_start_lba = *lba - ext_lba;
194 uint32_t next_len_lba;
195 if (pnext->len_kb != (uint32_t)-1)
196 next_len_lba = 1 + kb_to_lba(pnext->len_kb, dinfo->sect_size);
197 else
198 next_len_lba = dinfo->num_lba - *lba;
199 cfg_pentry(&ebr->ptable[PC_EBR_NEXT_PTR_PART], PC_PART_NORMAL,
200 PC_PART_TYPE_EXTENDED, next_start_lba, next_len_lba);
201 }
202
203 return item;
204
205fail:
206 free_wl(item);
207 return NULL;
208}
209
210
211struct write_list *
212config_mbr(struct disk_info *dinfo)
213{
214 struct part_info *pinfo;
215 uint32_t cur_lba = dinfo->skip_lba;
216 uint32_t ext_lba = 0;
217 struct write_list *wr_list = NULL;
218 struct write_list *temp_wr = NULL;
219 int cnt = 0;
220 int extended = 0;
221
222 if (!dinfo->part_lst)
223 return NULL;
224
225 for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
226 pinfo = &dinfo->part_lst[cnt];
227
228 /* Should we create an extedned partition? */
229 if (cnt == (PC_NUM_BOOT_RECORD_PARTS - 1)) {
230 if (cnt + 1 < dinfo->num_parts) {
231 extended = 1;
232 ext_lba = cur_lba;
233 if ((temp_wr = mk_pri_pentry(dinfo, NULL, cnt, &cur_lba)))
234 wlist_add(&wr_list, temp_wr);
235 else {
236 LOGE("Cannot create primary extended partition.");
237 goto fail;
238 }
239 }
240 }
241
242 /* if extended, need 1 lba for ebr */
243 if ((cur_lba + extended) >= dinfo->num_lba)
244 goto nospace;
245 else if (pinfo->len_kb != (uint32_t)-1) {
246 uint32_t sz_lba = (pinfo->len_kb / dinfo->sect_size) * 1024;
247 if ((cur_lba + sz_lba + extended) > dinfo->num_lba)
248 goto nospace;
249 }
250
251 if (!extended)
252 temp_wr = mk_pri_pentry(dinfo, pinfo, cnt, &cur_lba);
253 else {
254 struct part_info *pnext;
255 pnext = cnt + 1 < dinfo->num_parts ? &dinfo->part_lst[cnt+1] : NULL;
256 temp_wr = mk_ext_pentry(dinfo, pinfo, &cur_lba, ext_lba, pnext);
257 }
258
259 if (temp_wr)
260 wlist_add(&wr_list, temp_wr);
261 else {
262 LOGE("Cannot create partition %d (%s).", cnt, pinfo->name);
263 goto fail;
264 }
265 }
266
267 /* fill in the rest of the MBR with empty parts (if needed). */
268 for (; cnt < PC_NUM_BOOT_RECORD_PARTS; ++cnt) {
269 struct part_info blank;
270 cur_lba = 0;
271 memset(&blank, 0, sizeof(struct part_info));
272 if (!(temp_wr = mk_pri_pentry(dinfo, &blank, cnt, &cur_lba))) {
273 LOGE("Cannot create blank partition %d.", cnt);
274 goto fail;
275 }
276 wlist_add(&wr_list, temp_wr);
277 }
278
279 return wr_list;
280
281nospace:
282 LOGE("Not enough space to add parttion '%s'.", pinfo->name);
283
284fail:
285 wlist_free(wr_list);
286 return NULL;
287}
288
289
290/* Returns the device path of the partition referred to by 'name'
291 * Must be freed by the caller.
292 */
293char *
294find_mbr_part(struct disk_info *dinfo, const char *name)
295{
296 struct part_info *plist = dinfo->part_lst;
297 int num = 0;
298 char *dev_name = NULL;
299 int has_extended = (dinfo->num_parts > PC_NUM_BOOT_RECORD_PARTS);
300
301 for(num = 1; num <= dinfo->num_parts; ++num) {
302 if (!strcmp(plist[num-1].name, name))
303 break;
304 }
305
306 if (num > dinfo->num_parts)
307 return NULL;
308
309 if (has_extended && (num >= PC_NUM_BOOT_RECORD_PARTS))
310 num++;
311
312 if (!(dev_name = malloc(MAX_NAME_LEN))) {
313 LOGE("Cannot allocate memory.");
314 return NULL;
315 }
316
317 num = snprintf(dev_name, MAX_NAME_LEN, "%s%d", dinfo->device, num);
318 if (num >= MAX_NAME_LEN) {
319 LOGE("Device name is too long?!");
320 free(dev_name);
321 return NULL;
322 }
323
324 return dev_name;
325}
  
1/* libs/diskconfig/diskconfig.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "diskconfig"
19
20#include <errno.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/ioctl.h>
27#include <sys/stat.h>
28
29#include <linux/fs.h>
30
31#include <cutils/config_utils.h>
32#include <cutils/log.h>
33
34#include "diskconfig.h"
35
36
37static int
38parse_len(const char *str, uint64_t *plen)
39{
40 char tmp[64];
41 int len_str;
42 uint32_t multiple = 1;
43
44 strncpy(tmp, str, sizeof(tmp));
45 tmp[sizeof(tmp)-1] = '\0';
46 len_str = strlen(tmp);
47 if (!len_str) {
48 LOGE("Invalid disk length specified.");
49 return 1;
50 }
51
52 switch(tmp[len_str - 1]) {
53 case 'M': case 'm':
54 /* megabyte */
55 multiple <<= 10;
56 case 'K': case 'k':
57 /* kilobytes */
58 multiple <<= 10;
59 tmp[len_str - 1] = '\0';
60 break;
61 default:
62 break;
63 }
64
65 *plen = strtoull(tmp, NULL, 0);
66 if (!*plen) {
67 LOGE("Invalid length specified: %s", str);
68 return 1;
69 }
70
71 if (*plen == (uint64_t)-1) {
72 if (multiple > 1) {
73 LOGE("Size modifier illegal when len is -1");
74 return 1;
75 }
76 } else {
77 /* convert len to kilobytes */
78 if (multiple > 1024)
79 multiple >>= 10;
80 *plen *= multiple;
81
82 if (*plen > 0xffffffffULL) {
83 LOGE("Length specified is too large!: %llu KB", *plen);
84 return 1;
85 }
86 }
87
88 return 0;
89}
90
91
92static int
93load_partitions(cnode *root, struct disk_info *dinfo)
94{
95 cnode *partnode;
96
97 dinfo->num_parts = 0;
98 for (partnode = root->first_child; partnode; partnode = partnode->next) {
99 struct part_info *pinfo = &dinfo->part_lst[dinfo->num_parts];
100 const char *tmp;
101
102 /* bleh, i will leak memory here, but i DONT CARE since
103 * the only right thing to do when this function fails
104 * is to quit */
105 pinfo->name = strdup(partnode->name);
106
107 if(config_bool(partnode, "active", 0))
108 pinfo->flags |= PART_ACTIVE_FLAG;
109
110 if (!(tmp = config_str(partnode, "type", NULL))) {
111 LOGE("Partition type required: %s", pinfo->name);
112 return 1;
113 }
114
115 /* possible values are: linux */
116 if (!strcmp(tmp, "linux")) {
117 pinfo->type = PC_PART_TYPE_LINUX;
118 } else {
119 LOGE("Unsupported partition type found: %s", tmp);
120 return 1;
121 }
122
123 if ((tmp = config_str(partnode, "len", NULL)) != NULL) {
124 uint64_t len;
125 if (parse_len(tmp, &len))
126 return 1;
127 pinfo->len_kb = (uint32_t) len;
128 } else
129 pinfo->len_kb = 0;
130
131 ++dinfo->num_parts;
132 }
133
134 return 0;
135}
136
137struct disk_info *
138load_diskconfig(const char *fn, char *path_override)
139{
140 struct disk_info *dinfo;
141 cnode *devroot;
142 cnode *partnode;
143 cnode *root = config_node("", "");
144 const char *tmp;
145
146 if (!(dinfo = malloc(sizeof(struct disk_info)))) {
147 LOGE("Could not malloc disk_info");
148 return NULL;
149 }
150 memset(dinfo, 0, sizeof(struct disk_info));
151
152 if (!(dinfo->part_lst = malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) {
153 LOGE("Could not malloc part_lst");
154 goto fail;
155 }
156 memset(dinfo->part_lst, 0,
157 sizeof(MAX_NUM_PARTS * sizeof(struct part_info)));
158
159 config_load_file(root, fn);
160 if (root->first_child == NULL) {
161 LOGE("Could not read config file %s", fn);
162 goto fail;
163 }
164
165 if (!(devroot = config_find(root, "device"))) {
166 LOGE("Could not find device section in config file '%s'", fn);
167 goto fail;
168 }
169
170
171 if (!(tmp = config_str(devroot, "path", path_override))) {
172 LOGE("device path is requried");
173 goto fail;
174 }
175 dinfo->device = strdup(tmp);
176
177 /* find the partition scheme */
178 if (!(tmp = config_str(devroot, "scheme", NULL))) {
179 LOGE("partition scheme is required");
180 goto fail;
181 } else if (!strcmp(tmp, "mbr")) {
182 dinfo->scheme = PART_SCHEME_MBR;
183 } else if (!strcmp(tmp, "gpt")) {
184 LOGE("'gpt' partition scheme not supported yet.");
185 goto fail;
186 } else {
187 LOGE("Unknown partition scheme specified: %s", tmp);
188 goto fail;
189 }
190
191 /* grab the sector size (in bytes) */
192 tmp = config_str(devroot, "sector_size", "512");
193 dinfo->sect_size = strtol(tmp, NULL, 0);
194 if (!dinfo->sect_size) {
195 LOGE("Invalid sector size: %s", tmp);
196 goto fail;
197 }
198
199 /* first lba where the partitions will start on disk */
200 if (!(tmp = config_str(devroot, "start_lba", NULL))) {
201 LOGE("start_lba must be provided");
202 goto fail;
203 }
204
205 if (!(dinfo->skip_lba = strtol(tmp, NULL, 0))) {
206 LOGE("Invalid starting LBA (or zero): %s", tmp);
207 goto fail;
208 }
209
210 /* Number of LBAs on disk */
211 if (!(tmp = config_str(devroot, "num_lba", NULL))) {
212 LOGE("num_lba is required");
213 goto fail;
214 }
215 dinfo->num_lba = strtoul(tmp, NULL, 0);
216
217 if (!(partnode = config_find(devroot, "partitions"))) {
218 LOGE("Device must specify partition list");
219 goto fail;
220 }
221
222 if (load_partitions(partnode, dinfo))
223 goto fail;
224
225 return dinfo;
226
227fail:
228 if (dinfo->part_lst)
229 free(dinfo->part_lst);
230 if (dinfo->device)
231 free(dinfo->device);
232 free(dinfo);
233 return NULL;
234}
235
236static int
237sync_ptable(int fd)
238{
239 struct stat stat;
240 int rv;
241
242 sync();
243
244 if (fstat(fd, &stat)) {
245 LOGE("Cannot stat, errno=%d.", errno);
246 return -1;
247 }
248
249 if (S_ISBLK(stat.st_mode) && ((rv = ioctl(fd, BLKRRPART, NULL)) < 0)) {
250 LOGE("Could not re-read partition table. REBOOT!. (errno=%d)", errno);
251 return -1;
252 }
253
254 return 0;
255}
256
257/* This function verifies that the disk info provided is valid, and if so,
258 * returns an open file descriptor.
259 *
260 * This does not necessarily mean that it will later be successfully written
261 * though. If we use the pc-bios partitioning scheme, we must use extended
262 * partitions, which eat up some hd space. If the user manually provisioned
263 * every single partition, but did not account for the extra needed space,
264 * then we will later fail.
265 *
266 * TODO: Make validation more complete.
267 */
268static int
269validate(struct disk_info *dinfo)
270{
271 int fd;
272 int sect_sz;
273 uint64_t disk_size;
274 uint64_t total_size;
275 int cnt;
276 struct stat stat;
277
278 if (!dinfo)
279 return -1;
280
281 if ((fd = open(dinfo->device, O_RDWR)) < 0) {
282 LOGE("Cannot open device '%s' (errno=%d)", dinfo->device, errno);
283 return -1;
284 }
285
286 if (fstat(fd, &stat)) {
287 LOGE("Cannot stat file '%s', errno=%d.", dinfo->device, errno);
288 goto fail;
289 }
290
291
292 /* XXX: Some of the code below is kind of redundant and should probably
293 * be refactored a little, but it will do for now. */
294
295 /* Verify that we can operate on the device that was requested.
296 * We presently only support block devices and regular file images. */
297 if (S_ISBLK(stat.st_mode)) {
298 /* get the sector size and make sure we agree */
299 if (ioctl(fd, BLKSSZGET, &sect_sz) < 0) {
300 LOGE("Cannot get sector size (errno=%d)", errno);
301 goto fail;
302 }
303
304 if (!sect_sz || sect_sz != dinfo->sect_size) {
305 LOGE("Device sector size is zero or sector sizes do not match!");
306 goto fail;
307 }
308
309 /* allow the user override the "disk size" if they provided num_lba */
310 if (!dinfo->num_lba) {
311 if (ioctl(fd, BLKGETSIZE64, &disk_size) < 0) {
312 LOGE("Could not get block device size (errno=%d)", errno);
313 goto fail;
314 }
315 /* XXX: we assume that the disk has < 2^32 sectors :-) */
316 dinfo->num_lba = (uint32_t)(disk_size / (uint64_t)dinfo->sect_size);
317 } else
318 disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size;
319 } else if (S_ISREG(stat.st_mode)) {
320 LOGI("Requesting operation on a regular file, not block device.");
321 if (!dinfo->sect_size) {
322 LOGE("Sector size for regular file images cannot be zero");
323 goto fail;
324 }
325 if (dinfo->num_lba)
326 disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size;
327 else {
328 dinfo->num_lba = (uint32_t)(stat.st_size / dinfo->sect_size);
329 disk_size = (uint64_t)stat.st_size;
330 }
331 } else {
332 LOGE("Device does not refer to a regular file or a block device!");
333 goto fail;
334 }
335
336#if 0
337 LOGV("Device/file %s: size=%llu bytes, num_lba=%u, sect_size=%d",
338 dinfo->device, disk_size, dinfo->num_lba, dinfo->sect_size);
339#endif
340
341 /* since this is our offset into the disk, we start off with that as
342 * our size of needed partitions */
343 total_size = dinfo->skip_lba * dinfo->sect_size;
344
345 /* add up all the partition sizes and make sure it fits */
346 for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
347 struct part_info *part = &dinfo->part_lst[cnt];
348 if (part->len_kb != (uint32_t)-1) {
349 total_size += part->len_kb * 1024;
350 } else if (part->len_kb == 0) {
351 LOGE("Zero-size partition '%s' is invalid.", part->name);
352 goto fail;
353 } else {
354 /* the partition requests the rest of the disk. */
355 if (cnt + 1 != dinfo->num_parts) {
356 LOGE("Only the last partition in the list can request to fill "
357 "the rest of disk.");
358 goto fail;
359 }
360 }
361
362 if (part->type != PC_PART_TYPE_LINUX) {
363 LOGE("Unknown partition type (0x%x) encountered for partition "
364 "'%s'\n", part->type, part->name);
365 goto fail;
366 }
367 }
368
369 /* only matters for disks, not files */
370 if (S_ISBLK(stat.st_mode) && total_size > disk_size) {
371 LOGE("Total requested size of partitions (%llu) is greater than disk "
372 "size (%llu).", total_size, disk_size);
373 goto fail;
374 }
375
376 return fd;
377
378fail:
379 close(fd);
380 return -1;
381}
382
383static int
384validate_and_config(struct disk_info *dinfo, int *fd, struct write_list **lst)
385{
386 *lst = NULL;
387 *fd = -1;
388
389 if ((*fd = validate(dinfo)) < 0)
390 return 1;
391
392 switch (dinfo->scheme) {
393 case PART_SCHEME_MBR:
394 *lst = config_mbr(dinfo);
395 return *lst == NULL;
396 case PART_SCHEME_GPT:
397 /* not supported yet */
398 default:
399 LOGE("Uknown partition scheme.");
400 break;
401 }
402
403 close(*fd);
404 *lst = NULL;
405 return 1;
406}
407
408/* validate and process the disk layout configuration.
409 * This will cause an update to the partitions' start lba.
410 *
411 * Basically, this does the same thing as apply_disk_config in test mode,
412 * except that wlist_commit is not called to print out the data to be
413 * written.
414 */
415int
416process_disk_config(struct disk_info *dinfo)
417{
418 struct write_list *lst;
419 int fd;
420
421 if (validate_and_config(dinfo, &fd, &lst) != 0)
422 return 1;
423
424 close(fd);
425 wlist_free(lst);
426 return 0;
427}
428
429
430int
431apply_disk_config(struct disk_info *dinfo, int test)
432{
433 int fd;
434 struct write_list *wr_lst = NULL;
435 int rv;
436
437 if (validate_and_config(dinfo, &fd, &wr_lst) != 0) {
438 LOGE("Configuration is invalid.");
439 goto fail;
440 }
441
442 if ((rv = wlist_commit(fd, wr_lst, test)) >= 0)
443 rv = test ? 0 : sync_ptable(fd);
444
445 close(fd);
446 wlist_free(wr_lst);
447 return rv;
448
449fail:
450 close(fd);
451 if (wr_lst)
452 wlist_free(wr_lst);
453 return 1;
454}
455
456int
457dump_disk_config(struct disk_info *dinfo)
458{
459 int cnt;
460 struct part_info *part;
461
462 printf("Device: %s\n", dinfo->device);
463 printf("Scheme: ");
464 switch (dinfo->scheme) {
465 case PART_SCHEME_MBR:
466 printf("MBR");
467 break;
468 case PART_SCHEME_GPT:
469 printf("GPT (unsupported)");
470 break;
471 default:
472 printf("Unknown");
473 break;
474 }
475 printf ("\n");
476
477 printf("Sector size: %d\n", dinfo->sect_size);
478 printf("Skip leading LBAs: %u\n", dinfo->skip_lba);
479 printf("Number of LBAs: %u\n", dinfo->num_lba);
480 printf("Partitions:\n");
481
482 for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
483 part = &dinfo->part_lst[cnt];
484 printf("\tname = %s\n", part->name);
485 printf("\t\tflags = %s\n",
486 part->flags & PART_ACTIVE_FLAG ? "Active" : "None");
487 printf("\t\ttype = %s\n",
488 part->type == PC_PART_TYPE_LINUX ? "Linux" : "Unknown");
489 if (part->len_kb == (uint32_t)-1)
490 printf("\t\tlen = rest of disk\n");
491 else
492 printf("\t\tlen = %uKB\n", part->len_kb);
493 }
494 printf("Total number of partitions: %d\n", cnt);
495 printf("\n");
496
497 return 0;
498}
499
500struct part_info *
501find_part(struct disk_info *dinfo, const char *name)
502{
503 struct part_info *pinfo;
504 int cnt;
505
506 for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
507 pinfo = &dinfo->part_lst[cnt];
508 if (!strcmp(pinfo->name, name))
509 return pinfo;
510 }
511
512 return NULL;
513}
514
515/* NOTE: If the returned ptr is non-NULL, it must be freed by the caller. */
516char *
517find_part_device(struct disk_info *dinfo, const char *name)
518{
519 switch (dinfo->scheme) {
520 case PART_SCHEME_MBR:
521 return find_mbr_part(dinfo, name);
522 case PART_SCHEME_GPT:
523 LOGE("GPT is presently not supported");
524 break;
525 default:
526 LOGE("Unknown partition table scheme");
527 break;
528 }
529
530 return NULL;
531}
  
1/* libs/diskconfig/diskconfig.h
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef __LIBS_DISKCONFIG_H
19#define __LIBS_DISKCONFIG_H
20
21#include <stdint.h>
22
23#define MAX_NAME_LEN 512
24#define MAX_NUM_PARTS 16
25
26/* known partition schemes */
27#define PART_SCHEME_MBR 0x1
28#define PART_SCHEME_GPT 0x2
29
30/* PC Bios partition status */
31#define PC_PART_ACTIVE 0x80
32#define PC_PART_NORMAL 0x0
33
34/* Known (rather, used by us) partition types */
35#define PC_PART_TYPE_LINUX 0x83
36#define PC_PART_TYPE_EXTENDED 0x05
37
38#define PC_NUM_BOOT_RECORD_PARTS 4
39
40#define PC_EBR_LOGICAL_PART 0
41#define PC_EBR_NEXT_PTR_PART 1
42
43#define PC_BIOS_BOOT_SIG 0xAA55
44
45#define PC_MBR_DISK_OFFSET 0
46#define PC_MBR_SIZE 512
47
48#define PART_ACTIVE_FLAG 0x1
49
50struct chs {
51 uint8_t head;
52 uint8_t sector;
53 uint8_t cylinder;
54} __attribute__((__packed__));
55
56/* 16 byte pc partition descriptor that sits in MBR and EPBR.
57 * Note: multi-byte entities have little-endian layout on disk */
58struct pc_partition {
59 uint8_t status; /* byte 0 */
60 struct chs start; /* bytes 1-3 */
61 uint8_t type; /* byte 4 */
62 struct chs end; /* bytes 5-7 */
63 uint32_t start_lba; /* bytes 8-11 */
64 uint32_t len_lba; /* bytes 12-15 */
65} __attribute__((__packed__));
66
67struct pc_boot_record {
68 uint8_t code[440]; /* bytes 0-439 */
69 uint32_t disk_sig; /* bytes 440-443 */
70 uint16_t pad; /* bytes 444-445 */
71 struct pc_partition ptable[PC_NUM_BOOT_RECORD_PARTS]; /* bytes 446-509 */
72 uint16_t mbr_sig; /* bytes 510-511 */
73} __attribute__((__packed__));
74
75struct part_info {
76 char *name;
77 uint8_t flags;
78 uint8_t type;
79 uint32_t len_kb; /* in 1K-bytes */
80 uint32_t start_lba; /* the LBA where this partition begins */
81};
82
83struct disk_info {
84 char *device;
85 uint8_t scheme;
86 int sect_size; /* expected sector size in bytes. MUST BE POWER OF 2 */
87 uint32_t skip_lba; /* in sectors (1 unit of LBA) */
88 uint32_t num_lba; /* the size of the disk in LBA units */
89 struct part_info *part_lst;
90 int num_parts;
91};
92
93struct write_list {
94 struct write_list *next;
95 loff_t offset;
96 uint32_t len;
97 uint8_t data[0];
98};
99
100
101struct write_list *alloc_wl(uint32_t data_len);
102void free_wl(struct write_list *item);
103struct write_list *wlist_add(struct write_list **lst, struct write_list *item);
104void wlist_free(struct write_list *lst);
105int wlist_commit(int fd, struct write_list *lst, int test);
106
107struct disk_info *load_diskconfig(const char *fn, char *path_override);
108int dump_disk_config(struct disk_info *dinfo);
109int apply_disk_config(struct disk_info *dinfo, int test);
110char *find_part_device(struct disk_info *dinfo, const char *name);
111int process_disk_config(struct disk_info *dinfo);
112struct part_info *find_part(struct disk_info *dinfo, const char *name);
113
114int write_raw_image(const char *dst, const char *src, loff_t offset, int test);
115
116/* For MBR partition schemes */
117struct write_list *config_mbr(struct disk_info *dinfo);
118char *find_mbr_part(struct disk_info *dinfo, const char *name);
119
120#endif /* __LIBS_DISKCONFIG_H */
  
1/* libs/diskconfig/diskutils.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "diskutils"
19
20#include <errno.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/stat.h>
27
28#include <cutils/log.h>
29
30#include "diskconfig.h"
31
32int
33write_raw_image(const char *dst, const char *src, loff_t offset, int test)
34{
35 int dst_fd = -1;
36 int src_fd = -1;
37 uint8_t buffer[2048];
38 int nr_bytes;
39 int tmp;
40 int done = 0;
41 uint64_t total = 0;
42
43 LOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, offset);
44 if ((src_fd = open(src, O_RDONLY)) < 0) {
45 LOGE("Could not open %s for reading (errno=%d).", src, errno);
46 goto fail;
47 }
48
49 if (!test) {
50 if ((dst_fd = open(dst, O_RDWR)) < 0) {
51 LOGE("Could not open '%s' for read/write (errno=%d).", dst, errno);
52 goto fail;
53 }
54
55 if (lseek64(dst_fd, offset, SEEK_SET) != offset) {
56 LOGE("Could not seek to offset %lld in %s.", offset, dst);
57 goto fail;
58 }
59 }
60
61 while (!done) {
62 if ((nr_bytes = read(src_fd, buffer, sizeof(buffer))) < 0) {
63 /* XXX: Should we not even bother with EINTR? */
64 if (errno == EINTR)
65 continue;
66 LOGE("Error (%d) while reading from '%s'", errno, src);
67 goto fail;
68 }
69
70 if (!nr_bytes) {
71 /* we're done. */
72 done = 1;
73 break;
74 }
75
76 total += nr_bytes;
77
78 /* skip the write loop if we're testing */
79 if (test)
80 nr_bytes = 0;
81
82 while (nr_bytes > 0) {
83 if ((tmp = write(dst_fd, buffer, nr_bytes)) < 0) {
84 /* XXX: Should we not even bother with EINTR? */
85 if (errno == EINTR)
86 continue;
87 LOGE("Error (%d) while writing to '%s'", errno, dst);
88 goto fail;
89 }
90 if (!tmp)
91 continue;
92 nr_bytes -= tmp;
93 }
94 }
95
96 if (!done) {
97 LOGE("Exited read/write loop without setting flag! WTF?!");
98 goto fail;
99 }
100
101 if (dst_fd >= 0)
102 fsync(dst_fd);
103
104 LOGI("Wrote %llu bytes to %s @ %lld", total, dst, offset);
105
106 close(src_fd);
107 if (dst_fd >= 0)
108 close(dst_fd);
109 return 0;
110
111fail:
112 if (dst_fd >= 0)
113 close(dst_fd);
114 if (src_fd >= 0)
115 close(src_fd);
116 return 1;
117}
  
1/* libs/diskconfig/dump_diskconfig.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "dump_diskconfig"
19#include <stdio.h>
20
21#include <cutils/log.h>
22
23#include "diskconfig.h"
24
25int
26main(int argc, char *argv[])
27{
28 struct disk_info *dinfo;
29
30 if (argc < 2) {
31 LOGE("usage: %s <conf file>", argv[0]);
32 return 1;
33 }
34
35 if (!(dinfo = load_diskconfig(argv[1], NULL)))
36 return 1;
37
38 dump_disk_config(dinfo);
39
40 return 0;
41}
  
1/* libs/diskconfig/write_lst.c
2 *
3 * Copyright 2008, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "write_lst"
19#include <sys/types.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <unistd.h>
24
25#include <cutils/log.h>
26
27#include "diskconfig.h"
28
29struct write_list *
30alloc_wl(uint32_t data_len)
31{
32 struct write_list *item;
33
34 if (!(item = malloc(sizeof(struct write_list) + data_len))) {
35 LOGE("Unable to allocate memory.");
36 return NULL;
37 }
38
39 item->len = data_len;
40 return item;
41}
42
43void
44free_wl(struct write_list *item)
45{
46 if (item)
47 free(item);
48}
49
50struct write_list *
51wlist_add(struct write_list **lst, struct write_list *item)
52{
53 item->next = (*lst);
54 *lst = item;
55 return item;
56}
57
58void
59wlist_free(struct write_list *lst)
60{
61 struct write_list *temp_wr;
62 while (lst) {
63 temp_wr = lst->next;
64 free_wl(lst);
65 lst = temp_wr;
66 }
67}
68
69int
70wlist_commit(int fd, struct write_list *lst, int test)
71{
72 for(; lst; lst = lst->next) {
73 if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) {
74 LOGE("Cannot seek to the specified position (%lld).", lst->offset);
75 goto fail;
76 }
77
78 if (!test) {
79 if (write(fd, lst->data, lst->len) != (int)lst->len) {
80 LOGE("Failed writing %u bytes at position %lld.", lst->len,
81 lst->offset);
82 goto fail;
83 }
84 } else
85 LOGI("Would write %d bytes @ offset %lld.", lst->len, lst->offset);
86 }
87
88 return 0;
89
90fail:
91 return -1;
92}