diff options
Diffstat (limited to 'classes/xen-guest-bundle.bbclass')
| -rw-r--r-- | classes/xen-guest-bundle.bbclass | 272 |
1 files changed, 254 insertions, 18 deletions
diff --git a/classes/xen-guest-bundle.bbclass b/classes/xen-guest-bundle.bbclass index 0e061bfb..3fe7754e 100644 --- a/classes/xen-guest-bundle.bbclass +++ b/classes/xen-guest-bundle.bbclass | |||
| @@ -103,6 +103,14 @@ | |||
| 103 | # Explicit rootfs/kernel paths (for external/3rd-party guests): | 103 | # Explicit rootfs/kernel paths (for external/3rd-party guests): |
| 104 | # XEN_GUEST_ROOTFS[my-vendor-guest] = "vendor-rootfs.ext4" | 104 | # XEN_GUEST_ROOTFS[my-vendor-guest] = "vendor-rootfs.ext4" |
| 105 | # XEN_GUEST_KERNEL[my-vendor-guest] = "vendor-kernel" | 105 | # XEN_GUEST_KERNEL[my-vendor-guest] = "vendor-kernel" |
| 106 | # XEN_GUEST_KERNEL[my-hvm-guest] = "none" # HVM: no kernel | ||
| 107 | # | ||
| 108 | # 3rd-party guest import (convert fetched sources to Xen-ready images): | ||
| 109 | # XEN_GUEST_SOURCE_TYPE[guest] = "rootfs_dir" # import handler type | ||
| 110 | # XEN_GUEST_SOURCE_FILE[guest] = "alpine-rootfs" # file/dir in UNPACKDIR | ||
| 111 | # XEN_GUEST_IMAGE_SIZE[guest] = "128" # target image MB | ||
| 112 | # | ||
| 113 | # Built-in import types: rootfs_dir, qcow2, ext4, raw | ||
| 106 | # | 114 | # |
| 107 | # =========================================================================== | 115 | # =========================================================================== |
| 108 | # Integration with xen-guest-cross-install.bbclass | 116 | # Integration with xen-guest-cross-install.bbclass |
| @@ -124,6 +132,28 @@ XEN_GUEST_EXTRA_DEFAULT ?= "root=/dev/xvda ro ip=dhcp" | |||
| 124 | XEN_GUEST_DISK_DEVICE_DEFAULT ?= "xvda" | 132 | XEN_GUEST_DISK_DEVICE_DEFAULT ?= "xvda" |
| 125 | 133 | ||
| 126 | # =========================================================================== | 134 | # =========================================================================== |
| 135 | # Import system for 3rd-party guests | ||
| 136 | # =========================================================================== | ||
| 137 | # | ||
| 138 | # Convert fetched source formats (tarballs, qcow2, etc.) into Xen-ready disk | ||
| 139 | # images using extensible named handlers. Shell functions named | ||
| 140 | # xen_guest_import_<type>() are dispatched at build time. | ||
| 141 | # | ||
| 142 | # Per-guest varflags: | ||
| 143 | # XEN_GUEST_SOURCE_TYPE[guest] = "rootfs_dir" # import handler type | ||
| 144 | # XEN_GUEST_SOURCE_FILE[guest] = "alpine-rootfs" # file/dir in UNPACKDIR | ||
| 145 | # XEN_GUEST_IMAGE_SIZE[guest] = "128" # target image MB | ||
| 146 | # | ||
| 147 | # Built-in import types: rootfs_dir, qcow2, ext4, raw | ||
| 148 | # Extensible: any class/recipe/bbappend can add xen_guest_import_<type>() | ||
| 149 | |||
| 150 | XEN_GUEST_IMAGE_SIZE_DEFAULT ?= "256" | ||
| 151 | XEN_GUEST_IMPORT_DEPENDS_rootfs_dir = "e2fsprogs-native:do_populate_sysroot" | ||
| 152 | XEN_GUEST_IMPORT_DEPENDS_qcow2 = "qemu-system-native:do_populate_sysroot" | ||
| 153 | XEN_GUEST_IMPORT_DEPENDS_ext4 = "" | ||
| 154 | XEN_GUEST_IMPORT_DEPENDS_raw = "" | ||
| 155 | |||
| 156 | # =========================================================================== | ||
| 127 | # Parse-time dependency generation | 157 | # Parse-time dependency generation |
| 128 | # =========================================================================== | 158 | # =========================================================================== |
| 129 | 159 | ||
| @@ -134,6 +164,7 @@ python __anonymous() { | |||
| 134 | 164 | ||
| 135 | processed = [] | 165 | processed = [] |
| 136 | deps = "" | 166 | deps = "" |
| 167 | external_guests = [] | ||
| 137 | 168 | ||
| 138 | for entry in bundles: | 169 | for entry in bundles: |
| 139 | parts = entry.split(':') | 170 | parts = entry.split(':') |
| @@ -145,6 +176,8 @@ python __anonymous() { | |||
| 145 | # Generate dependency on guest recipe (unless external) | 176 | # Generate dependency on guest recipe (unless external) |
| 146 | if not is_external: | 177 | if not is_external: |
| 147 | deps += " %s:do_image_complete" % guest_name | 178 | deps += " %s:do_image_complete" % guest_name |
| 179 | else: | ||
| 180 | external_guests.append(guest_name) | ||
| 148 | 181 | ||
| 149 | # Store processed entry: guest_name:autostart_flag | 182 | # Store processed entry: guest_name:autostart_flag |
| 150 | autostart_flag = "autostart" if is_autostart else "" | 183 | autostart_flag = "autostart" if is_autostart else "" |
| @@ -153,6 +186,9 @@ python __anonymous() { | |||
| 153 | if deps: | 186 | if deps: |
| 154 | d.appendVarFlag('do_compile', 'depends', deps) | 187 | d.appendVarFlag('do_compile', 'depends', deps) |
| 155 | 188 | ||
| 189 | if external_guests: | ||
| 190 | d.setVar('_XEN_GUEST_EXTERNAL_NAMES', ' '.join(external_guests)) | ||
| 191 | |||
| 156 | d.setVar('_PROCESSED_XEN_BUNDLES', ' '.join(processed)) | 192 | d.setVar('_PROCESSED_XEN_BUNDLES', ' '.join(processed)) |
| 157 | 193 | ||
| 158 | # Build config file map from varflags | 194 | # Build config file map from varflags |
| @@ -190,6 +226,47 @@ python __anonymous() { | |||
| 190 | param_mappings.append("%s=%s" % (guest_name, params)) | 226 | param_mappings.append("%s=%s" % (guest_name, params)) |
| 191 | 227 | ||
| 192 | d.setVar('_XEN_GUEST_PARAMS_MAP', ';'.join(param_mappings)) | 228 | d.setVar('_XEN_GUEST_PARAMS_MAP', ';'.join(param_mappings)) |
| 229 | |||
| 230 | # Build import map from varflags and resolve dependencies | ||
| 231 | # Format: guest=type|file|size;guest2=... | ||
| 232 | import_mappings = [] | ||
| 233 | import_types_used = set() | ||
| 234 | needs_shared_kernel = False | ||
| 235 | |||
| 236 | for entry in bundles: | ||
| 237 | guest_name = entry.split(':')[0] | ||
| 238 | source_type = d.getVarFlag('XEN_GUEST_SOURCE_TYPE', guest_name) | ||
| 239 | if source_type: | ||
| 240 | source_file = d.getVarFlag('XEN_GUEST_SOURCE_FILE', guest_name) or "" | ||
| 241 | image_size = d.getVarFlag('XEN_GUEST_IMAGE_SIZE', guest_name) or d.getVar('XEN_GUEST_IMAGE_SIZE_DEFAULT') | ||
| 242 | import_mappings.append("%s=%s|%s|%s" % (guest_name, source_type, source_file, image_size)) | ||
| 243 | import_types_used.add(source_type) | ||
| 244 | |||
| 245 | # Determine if this guest needs the shared kernel | ||
| 246 | kernel_flag = d.getVarFlag('XEN_GUEST_KERNEL', guest_name) | ||
| 247 | if not kernel_flag or kernel_flag != "none": | ||
| 248 | # No explicit kernel or not "none" → may need shared kernel | ||
| 249 | if not kernel_flag: | ||
| 250 | needs_shared_kernel = True | ||
| 251 | |||
| 252 | d.setVar('_XEN_GUEST_IMPORT_MAP', ';'.join(import_mappings)) | ||
| 253 | |||
| 254 | # Add native tool dependencies for import types used | ||
| 255 | import_deps = "" | ||
| 256 | for itype in import_types_used: | ||
| 257 | dep = d.getVar('XEN_GUEST_IMPORT_DEPENDS_%s' % itype) | ||
| 258 | if dep: | ||
| 259 | import_deps += " %s" % dep | ||
| 260 | if import_deps: | ||
| 261 | d.appendVarFlag('do_compile', 'depends', import_deps) | ||
| 262 | |||
| 263 | # rootfs_dir needs fakeroot for mkfs.ext4 -d ownership | ||
| 264 | if 'rootfs_dir' in import_types_used: | ||
| 265 | d.setVarFlag('do_compile', 'fakeroot', '1') | ||
| 266 | |||
| 267 | # Auto-add virtual/kernel dependency if any guest uses shared kernel | ||
| 268 | if needs_shared_kernel: | ||
| 269 | d.appendVarFlag('do_compile', 'depends', ' virtual/kernel:do_deploy') | ||
| 193 | } | 270 | } |
| 194 | 271 | ||
| 195 | S = "${UNPACKDIR}/sources" | 272 | S = "${UNPACKDIR}/sources" |
| @@ -198,6 +275,113 @@ B = "${WORKDIR}/build" | |||
| 198 | do_patch[noexec] = "1" | 275 | do_patch[noexec] = "1" |
| 199 | do_configure[noexec] = "1" | 276 | do_configure[noexec] = "1" |
| 200 | 277 | ||
| 278 | python xen_guest_external_license_warn() { | ||
| 279 | names = d.getVar('_XEN_GUEST_EXTERNAL_NAMES') | ||
| 280 | if names: | ||
| 281 | bb.warn("Bundling external guest image(s): %s\n" | ||
| 282 | "Ensure you have rights to redistribute these images.\n" | ||
| 283 | "Check the guest license terms before distribution." % names) | ||
| 284 | } | ||
| 285 | do_compile[prefuncs] += "xen_guest_external_license_warn" | ||
| 286 | |||
| 287 | # =========================================================================== | ||
| 288 | # Import handlers for 3rd-party guest formats | ||
| 289 | # =========================================================================== | ||
| 290 | # Shell functions named xen_guest_import_<type>(source, output, size_mb). | ||
| 291 | # Extensible: recipes/bbappends can define additional handlers. | ||
| 292 | |||
| 293 | # rootfs_dir: extracted rootfs directory → ext4 image | ||
| 294 | xen_guest_import_rootfs_dir() { | ||
| 295 | local source_path="$1" | ||
| 296 | local output_path="$2" | ||
| 297 | local size_mb="$3" | ||
| 298 | |||
| 299 | if [ ! -d "$source_path" ]; then | ||
| 300 | bbfatal "rootfs_dir import: source '$source_path' is not a directory" | ||
| 301 | fi | ||
| 302 | |||
| 303 | bbnote "rootfs_dir import: creating ${size_mb}MB ext4 from $source_path" | ||
| 304 | |||
| 305 | # Create sparse file and format with directory contents | ||
| 306 | dd if=/dev/zero of="$output_path" bs=1M count=0 seek="$size_mb" | ||
| 307 | mkfs.ext4 -F -d "$source_path" "$output_path" | ||
| 308 | } | ||
| 309 | |||
| 310 | # qcow2: QCOW2 disk image → raw image | ||
| 311 | xen_guest_import_qcow2() { | ||
| 312 | local source_path="$1" | ||
| 313 | local output_path="$2" | ||
| 314 | local size_mb="$3" | ||
| 315 | |||
| 316 | if [ ! -f "$source_path" ]; then | ||
| 317 | bbfatal "qcow2 import: source '$source_path' not found" | ||
| 318 | fi | ||
| 319 | |||
| 320 | bbnote "qcow2 import: converting $source_path to raw" | ||
| 321 | qemu-img convert -f qcow2 -O raw "$source_path" "$output_path" | ||
| 322 | } | ||
| 323 | |||
| 324 | # ext4: ext4 image → copy | ||
| 325 | xen_guest_import_ext4() { | ||
| 326 | local source_path="$1" | ||
| 327 | local output_path="$2" | ||
| 328 | local size_mb="$3" | ||
| 329 | |||
| 330 | if [ ! -f "$source_path" ]; then | ||
| 331 | bbfatal "ext4 import: source '$source_path' not found" | ||
| 332 | fi | ||
| 333 | |||
| 334 | bbnote "ext4 import: copying $source_path" | ||
| 335 | cp "$source_path" "$output_path" | ||
| 336 | } | ||
| 337 | |||
| 338 | # raw: raw disk image → copy | ||
| 339 | xen_guest_import_raw() { | ||
| 340 | local source_path="$1" | ||
| 341 | local output_path="$2" | ||
| 342 | local size_mb="$3" | ||
| 343 | |||
| 344 | if [ ! -f "$source_path" ]; then | ||
| 345 | bbfatal "raw import: source '$source_path' not found" | ||
| 346 | fi | ||
| 347 | |||
| 348 | bbnote "raw import: copying $source_path" | ||
| 349 | cp "$source_path" "$output_path" | ||
| 350 | } | ||
| 351 | |||
| 352 | # Resolve import source for a guest from _XEN_GUEST_IMPORT_MAP | ||
| 353 | # Returns: type|source_path|size_mb or empty if guest has no import | ||
| 354 | resolve_import_source() { | ||
| 355 | local guest="$1" | ||
| 356 | local import_map="${_XEN_GUEST_IMPORT_MAP}" | ||
| 357 | |||
| 358 | local entry=$(echo "$import_map" | tr ';' '\n' | grep "^${guest}=") | ||
| 359 | if [ -z "$entry" ]; then | ||
| 360 | return 1 | ||
| 361 | fi | ||
| 362 | |||
| 363 | local info=$(echo "$entry" | cut -d= -f2-) | ||
| 364 | local source_type=$(echo "$info" | cut -d'|' -f1) | ||
| 365 | local source_file=$(echo "$info" | cut -d'|' -f2) | ||
| 366 | local size_mb=$(echo "$info" | cut -d'|' -f3) | ||
| 367 | |||
| 368 | # Resolve source path | ||
| 369 | local source_path="" | ||
| 370 | if [ -n "$source_file" ]; then | ||
| 371 | if [ -e "${UNPACKDIR}/$source_file" ]; then | ||
| 372 | source_path="${UNPACKDIR}/$source_file" | ||
| 373 | elif [ -e "$source_file" ]; then | ||
| 374 | source_path="$source_file" | ||
| 375 | fi | ||
| 376 | fi | ||
| 377 | |||
| 378 | if [ -z "$source_path" ]; then | ||
| 379 | bbfatal "Import source '$source_file' not found for guest '$guest'" | ||
| 380 | fi | ||
| 381 | |||
| 382 | echo "${source_type}|${source_path}|${size_mb}" | ||
| 383 | } | ||
| 384 | |||
| 201 | # =========================================================================== | 385 | # =========================================================================== |
| 202 | # do_compile: resolve guests and generate configs | 386 | # do_compile: resolve guests and generate configs |
| 203 | # =========================================================================== | 387 | # =========================================================================== |
| @@ -226,23 +410,48 @@ do_compile() { | |||
| 226 | 410 | ||
| 227 | bbnote "Processing guest: $guest_name (autostart=$autostart_flag)" | 411 | bbnote "Processing guest: $guest_name (autostart=$autostart_flag)" |
| 228 | 412 | ||
| 229 | # Resolve rootfs | 413 | # Resolve rootfs - check import system first, then DEPLOY_DIR_IMAGE |
| 230 | rootfs_path=$(resolve_bundle_rootfs "$guest_name") | 414 | import_info="" |
| 231 | if [ -z "$rootfs_path" ]; then | 415 | if echo "${_XEN_GUEST_IMPORT_MAP}" | tr ';' '\n' | grep -q "^${guest_name}="; then |
| 232 | bbfatal "Cannot resolve rootfs for guest '$guest_name'" | 416 | import_info=$(resolve_import_source "$guest_name") |
| 233 | fi | 417 | fi |
| 234 | rootfs_basename=$(basename "$rootfs_path") | ||
| 235 | 418 | ||
| 236 | # Resolve kernel | 419 | if [ -n "$import_info" ]; then |
| 237 | kernel_path=$(resolve_bundle_kernel "$guest_name") | 420 | # Import path: convert fetched source to disk image |
| 238 | if [ -z "$kernel_path" ]; then | 421 | local import_type=$(echo "$import_info" | cut -d'|' -f1) |
| 239 | bbfatal "Cannot resolve kernel for guest '$guest_name'" | 422 | local import_source=$(echo "$import_info" | cut -d'|' -f2) |
| 423 | local import_size=$(echo "$import_info" | cut -d'|' -f3) | ||
| 424 | |||
| 425 | rootfs_basename="${guest_name}.img" | ||
| 426 | local output_path="${B}/images/${rootfs_basename}" | ||
| 427 | |||
| 428 | bbnote "Importing guest '$guest_name': type=$import_type source=$import_source size=${import_size}MB" | ||
| 429 | |||
| 430 | # Static dispatch - BitBake needs to see function names to include them | ||
| 431 | case "$import_type" in | ||
| 432 | rootfs_dir) xen_guest_import_rootfs_dir "$import_source" "$output_path" "$import_size" ;; | ||
| 433 | qcow2) xen_guest_import_qcow2 "$import_source" "$output_path" "$import_size" ;; | ||
| 434 | ext4) xen_guest_import_ext4 "$import_source" "$output_path" "$import_size" ;; | ||
| 435 | raw) xen_guest_import_raw "$import_source" "$output_path" "$import_size" ;; | ||
| 436 | *) bbfatal "Unknown import type '$import_type' for guest '$guest_name'" ;; | ||
| 437 | esac | ||
| 438 | else | ||
| 439 | # Standard path: resolve from DEPLOY_DIR_IMAGE | ||
| 440 | rootfs_path=$(resolve_bundle_rootfs "$guest_name") | ||
| 441 | if [ -z "$rootfs_path" ]; then | ||
| 442 | bbfatal "Cannot resolve rootfs for guest '$guest_name'" | ||
| 443 | fi | ||
| 444 | rootfs_basename=$(basename "$rootfs_path") | ||
| 445 | cp "$(readlink -f "$rootfs_path")" "${B}/images/${rootfs_basename}" | ||
| 240 | fi | 446 | fi |
| 241 | kernel_basename=$(basename "$kernel_path") | ||
| 242 | 447 | ||
| 243 | # Copy to build dir (readlink -f resolves versioned symlinks) | 448 | # Resolve kernel (supports shared, custom, and HVM/none modes) |
| 244 | cp "$(readlink -f "$rootfs_path")" "${B}/images/${rootfs_basename}" | 449 | kernel_path=$(resolve_bundle_kernel "$guest_name") |
| 245 | cp "$(readlink -f "$kernel_path")" "${B}/images/${kernel_basename}" | 450 | kernel_basename="" |
| 451 | if [ -n "$kernel_path" ]; then | ||
| 452 | kernel_basename=$(basename "$kernel_path") | ||
| 453 | cp "$(readlink -f "$kernel_path")" "${B}/images/${kernel_basename}" | ||
| 454 | fi | ||
| 246 | 455 | ||
| 247 | # Generate or install config | 456 | # Generate or install config |
| 248 | config_map="${_XEN_GUEST_CONFIG_FILE_MAP}" | 457 | config_map="${_XEN_GUEST_CONFIG_FILE_MAP}" |
| @@ -309,29 +518,48 @@ resolve_bundle_rootfs() { | |||
| 309 | return 1 | 518 | return 1 |
| 310 | } | 519 | } |
| 311 | 520 | ||
| 312 | # Resolve guest kernel path from DEPLOY_DIR_IMAGE | 521 | # Resolve guest kernel path |
| 522 | # Three modes: | ||
| 523 | # 1. XEN_GUEST_KERNEL[guest] = "none" → HVM mode, return empty (no kernel) | ||
| 524 | # 2. XEN_GUEST_KERNEL[guest] = "<path>" → check UNPACKDIR then DEPLOY_DIR_IMAGE | ||
| 525 | # 3. (not set) → shared kernel from DEPLOY_DIR_IMAGE/${KERNEL_IMAGETYPE} | ||
| 313 | resolve_bundle_kernel() { | 526 | resolve_bundle_kernel() { |
| 314 | local guest="$1" | 527 | local guest="$1" |
| 315 | local params_map="${_XEN_GUEST_PARAMS_MAP}" | 528 | local params_map="${_XEN_GUEST_PARAMS_MAP}" |
| 316 | 529 | ||
| 317 | # Check for explicit kernel override (field 7) | 530 | # Check for explicit kernel override (field 8) |
| 318 | local guest_params=$(echo "$params_map" | tr ';' '\n' | grep "^${guest}=" | cut -d= -f2-) | 531 | local guest_params=$(echo "$params_map" | tr ';' '\n' | grep "^${guest}=" | cut -d= -f2-) |
| 319 | local override="" | 532 | local override="" |
| 320 | if [ -n "$guest_params" ]; then | 533 | if [ -n "$guest_params" ]; then |
| 321 | override=$(echo "$guest_params" | cut -d'|' -f8) | 534 | override=$(echo "$guest_params" | cut -d'|' -f8) |
| 322 | fi | 535 | fi |
| 323 | 536 | ||
| 537 | # Mode 1: HVM - no kernel needed | ||
| 538 | if [ "$override" = "none" ]; then | ||
| 539 | bbnote "Guest '$guest' uses HVM mode (no kernel)" | ||
| 540 | return 0 | ||
| 541 | fi | ||
| 542 | |||
| 543 | # Mode 2: explicit kernel path | ||
| 324 | if [ -n "$override" ]; then | 544 | if [ -n "$override" ]; then |
| 325 | local path="${DEPLOY_DIR_IMAGE}/$override" | 545 | # Check UNPACKDIR first (for fetched/custom kernels) |
| 546 | local path="${UNPACKDIR}/$override" | ||
| 326 | if [ -e "$path" ]; then | 547 | if [ -e "$path" ]; then |
| 327 | echo "$path" | 548 | echo "$path" |
| 328 | return 0 | 549 | return 0 |
| 329 | fi | 550 | fi |
| 330 | bbwarn "XEN_GUEST_KERNEL override '$override' not found at $path" | 551 | |
| 552 | # Then check DEPLOY_DIR_IMAGE | ||
| 553 | path="${DEPLOY_DIR_IMAGE}/$override" | ||
| 554 | if [ -e "$path" ]; then | ||
| 555 | echo "$path" | ||
| 556 | return 0 | ||
| 557 | fi | ||
| 558 | bbwarn "XEN_GUEST_KERNEL override '$override' not found in UNPACKDIR or DEPLOY_DIR_IMAGE" | ||
| 331 | return 1 | 559 | return 1 |
| 332 | fi | 560 | fi |
| 333 | 561 | ||
| 334 | # Default: shared kernel (same MACHINE) | 562 | # Mode 3: shared kernel (same MACHINE) |
| 335 | local path="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}" | 563 | local path="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}" |
| 336 | if [ -e "$path" ]; then | 564 | if [ -e "$path" ]; then |
| 337 | echo "$path" | 565 | echo "$path" |
| @@ -343,6 +571,8 @@ resolve_bundle_kernel() { | |||
| 343 | } | 571 | } |
| 344 | 572 | ||
| 345 | # Generate a Xen guest configuration file with final target paths | 573 | # Generate a Xen guest configuration file with final target paths |
| 574 | # If kernel_basename is empty (HVM mode), kernel= and extra= lines are omitted. | ||
| 575 | # HVM guests should use XEN_GUEST_CONFIG_FILE for full control. | ||
| 346 | generate_bundle_config() { | 576 | generate_bundle_config() { |
| 347 | local guest="$1" | 577 | local guest="$1" |
| 348 | local rootfs_basename="$2" | 578 | local rootfs_basename="$2" |
| @@ -366,9 +596,15 @@ memory = $memory | |||
| 366 | vcpus = $vcpus | 596 | vcpus = $vcpus |
| 367 | disk = ['file:/var/lib/xen/images/$rootfs_basename,$disk_device,rw'] | 597 | disk = ['file:/var/lib/xen/images/$rootfs_basename,$disk_device,rw'] |
| 368 | vif = ['$vif'] | 598 | vif = ['$vif'] |
| 599 | EOF | ||
| 600 | |||
| 601 | # PV guests get kernel + extra; HVM guests omit these | ||
| 602 | if [ -n "$kernel_basename" ]; then | ||
| 603 | cat >> "$outfile" << EOF | ||
| 369 | kernel = "/var/lib/xen/images/$kernel_basename" | 604 | kernel = "/var/lib/xen/images/$kernel_basename" |
| 370 | extra = "$extra" | 605 | extra = "$extra" |
| 371 | EOF | 606 | EOF |
| 607 | fi | ||
| 372 | } | 608 | } |
| 373 | 609 | ||
| 374 | # =========================================================================== | 610 | # =========================================================================== |
