mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
When detecting disk type, the function disk_get_info() is called. It can fail for various reasons (e.g. when the logial target is not eligible for boot record installation). Once disk_get_info() fails, don't proceed with type detection. Return error instead. When applicable, mark the dump job with "is_ngdump" flag to avoid extra type detection calls. Acked-by: Mikhail Zaslonko <zaslonko@linux.ibm.com> Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
316 lines
8.7 KiB
C
316 lines
8.7 KiB
C
/*
|
|
* zipl - zSeries Initial Program Loader tool
|
|
*
|
|
* Main function
|
|
*
|
|
* Copyright IBM Corp. 2001, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/zt_common.h"
|
|
|
|
#include "boot.h"
|
|
#include "bootmap.h"
|
|
#include "disk.h"
|
|
#include "error.h"
|
|
#include "install.h"
|
|
#include "job.h"
|
|
#include "misc.h"
|
|
#include "zipl.h"
|
|
|
|
|
|
/* Flag deciding the level of verbosity */
|
|
int verbose = 0;
|
|
|
|
/* Flag deciding whether confirmation questions are asked */
|
|
int interactive = 1;
|
|
|
|
/* Flag deciding whether actions should only be simulated */
|
|
int dry_run = 1;
|
|
|
|
/* Full tool name */
|
|
static const char tool_name[] = "zipl: zSeries Initial Program Loader";
|
|
|
|
/* Copyright notice */
|
|
static const char copyright_notice[] = "Copyright IBM Corp. 2001, 2017";
|
|
|
|
/* Usage information */
|
|
static const char* usage_text[] = {
|
|
"Usage: zipl [OPTIONS] [SECTION]",
|
|
"",
|
|
"Prepare a device for initial program load. Use OPTIONS described below or ",
|
|
"provide the name of a SECTION defined in the zIPL configuration file.",
|
|
"",
|
|
"-h, --help Print this help, then exit",
|
|
"-v, --version Print version information, then exit",
|
|
"-c, --config CONFIGFILE Read configuration from CONFIGFILE",
|
|
"-b, --blsdir BLSDIR Parse BootLoaderSpec files from BLSDIR",
|
|
"-t, --target TARGETDIR Write bootmap file to TARGETDIR and install",
|
|
" bootloader on device containing TARGETDIR",
|
|
" --targetbase BASEDEVICE Install bootloader on BASEDEVICE",
|
|
" --targettype TYPE Use device type: CDL, LDL, FBA, SCSI",
|
|
" --targetgeometry C,H,S Use disk geometry: cylinders,heads,sectors",
|
|
" --targetblocksize SIZE Use number of bytes per block",
|
|
" --targetoffset OFFSET Use offset between logical and physical disk",
|
|
"-i, --image IMAGEFILE[,ADDR] Install Linux kernel image from IMAGEFILE",
|
|
"-r, --ramdisk RAMDISK[,ADDR] Install initial ramdisk from file RAMDISK",
|
|
"-p, --parmfile PARMFILE[,ADDR] Use kernel parmline stored in PARMFILE",
|
|
"-P, --parameters PARMLINE Use specified kernel PARMLINE",
|
|
"-T, --tape TAPEDEV Install bootloader on tape device TAPEDEV",
|
|
"-s, --segment SEGMENT,ADDR Install a segment from file SEGMENT",
|
|
"-k, --kdump=auto Install a kdump kernel that can be used as a",
|
|
" stand-alone dump tool",
|
|
"-d, --dumpto DUMPDEV[,SIZE] Install a system dump record on tape device",
|
|
" or disk partition DUMPDEV",
|
|
" --ldipl-dump Install a List-directed dump",
|
|
" --no-compress Do not use zlib compression for DASD dump",
|
|
"-M, --mvdump DEVLIST[,SIZE] Install a multi-volume dump record on each",
|
|
" disk partition listed in file DEVLIST",
|
|
"-f, --force Disable sanity check while producing a",
|
|
" multi-volume dump",
|
|
"-m, --menu MENU Install multi-boot configuration MENU",
|
|
"-n, --noninteractive Answer all confirmation questions with 'yes'",
|
|
"-V, --verbose Provide more verbose output",
|
|
"-a, --add-files Add all referenced files to bootmap file",
|
|
" --dry-run Simulate run but don't modify IPL records",
|
|
"-S, --secure SWITCH Control the zIPL secure boot support.",
|
|
" auto (default):",
|
|
" Write signatures if available and supported",
|
|
" 1: Write signatures regardless of support",
|
|
" 0: Do not write signatures"
|
|
};
|
|
|
|
|
|
/* Print usage information. */
|
|
static void
|
|
print_usage(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i=0; i < ARRAY_SIZE(usage_text); i++)
|
|
printf("%s\n", usage_text[i]);
|
|
}
|
|
|
|
|
|
/* Print version information. */
|
|
static void
|
|
print_version(void)
|
|
{
|
|
printf("%s version %s\n", tool_name, RELEASE_STRING);
|
|
printf("%s\n", copyright_notice);
|
|
}
|
|
|
|
|
|
/* Check whether calling user is root. Return 0 if user is root, non-zero
|
|
* otherwise. */
|
|
static int
|
|
check_for_root(void)
|
|
{
|
|
if (geteuid() != 0) {
|
|
error_clear_text();
|
|
error_reason("Must be root to perform this operation");
|
|
return -1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
struct disk_ext_type ext_type = {0};
|
|
struct install_set bis;
|
|
struct job_data* job;
|
|
int rc;
|
|
|
|
/* Check internals */
|
|
rc = boot_check_data();
|
|
if (rc) {
|
|
error_text("Internal error");
|
|
error_print();
|
|
return 1;
|
|
}
|
|
/* Find out what we're supposed to do */
|
|
rc = job_get(argc, argv, &job);
|
|
if (rc) {
|
|
error_print();
|
|
return 1;
|
|
}
|
|
/* Check for priority options --help and --version */
|
|
if (job->id == job_print_usage) {
|
|
print_usage();
|
|
job_free(job);
|
|
return 0;
|
|
} else if (job->id == job_print_version) {
|
|
print_version();
|
|
job_free(job);
|
|
return 0;
|
|
}
|
|
/* Make sure we're running as root */
|
|
if (check_for_root()) {
|
|
job_free(job);
|
|
error_print();
|
|
return 1;
|
|
}
|
|
/* Set global option variables */
|
|
verbose = job->verbose;
|
|
interactive = !job->noninteractive;
|
|
dry_run = job->dry_run;
|
|
if (dry_run)
|
|
printf("Starting dry-run, target device contents will NOT be "
|
|
"modified\n");
|
|
/* Make sure new files are only user-accessible */
|
|
umask(077);
|
|
/* Do it */
|
|
switch (job->id) {
|
|
case job_dump_partition:
|
|
rc = disk_get_ext_type(job->data.dump.device, &ext_type);
|
|
if (rc)
|
|
break;
|
|
job_dump_check_set_ngdump(job, &ext_type);
|
|
if (!job_dump_is_ngdump(job) &&
|
|
(disk_is_tape(job->data.dump.device) ||
|
|
!disk_type_is_scsi(&ext_type))) {
|
|
rc = install_dump(job->data.dump.device, &job->target,
|
|
job->data.dump.mem, job->data.dump.no_compress);
|
|
break;
|
|
}
|
|
/* Dump to a raw SCSI partition */
|
|
if (job->data.dump.mem != -1uLL) {
|
|
error_reason("Dump size can not be limited for "
|
|
"partition dump on a SCSI disk");
|
|
rc = -1;
|
|
break;
|
|
}
|
|
if (job_dump_is_ngdump(job)) {
|
|
if (disk_type_is_eckd_ldl(&ext_type)) {
|
|
error_reason("List-directed dump on ECKD with LDL not supported");
|
|
rc = -1;
|
|
break;
|
|
}
|
|
rc = check_job_images_ngdump(&job->data.dump, job->name);
|
|
} else {
|
|
rc = check_job_dump_images(&job->data.dump, job->name);
|
|
}
|
|
if (rc != 0)
|
|
break;
|
|
/* Fall through. */
|
|
case job_ipl:
|
|
case job_segment:
|
|
case job_menu:
|
|
rc = prepare_bootloader(job, &bis);
|
|
if (rc) {
|
|
free_bootloader(&bis);
|
|
break;
|
|
}
|
|
rc = install_bootloader(job, &bis);
|
|
if (rc) {
|
|
free_bootloader(&bis);
|
|
break;
|
|
}
|
|
rc = post_install_bootloader(job, &bis);
|
|
free_bootloader(&bis);
|
|
break;
|
|
case job_ipl_tape:
|
|
rc = install_tapeloader(job->data.ipl_tape.device,
|
|
job->data.ipl_tape.common.image,
|
|
job->data.ipl_tape.common.parmline,
|
|
job->data.ipl_tape.common.ramdisk,
|
|
job->data.ipl_tape.common.image_addr,
|
|
job->data.ipl_tape.common.parm_addr,
|
|
job->data.ipl_tape.common.ramdisk_addr);
|
|
break;
|
|
case job_mvdump:
|
|
rc = install_mvdump(job->data.mvdump.device,
|
|
&job->target,
|
|
job->data.mvdump.device_count,
|
|
job->data.mvdump.mem,
|
|
job->data.mvdump.force);
|
|
break;
|
|
case job_print_usage:
|
|
case job_print_version:
|
|
/* Should not happen */
|
|
break;
|
|
}
|
|
switch (rc) {
|
|
case 0: /* Operation completed successfully */
|
|
if (verbose)
|
|
printf("Syncing disks...\n");
|
|
if (!dry_run)
|
|
sync();
|
|
printf("Done.\n");
|
|
break;
|
|
case -2: /* Operation canceled by user */
|
|
break;
|
|
default: /* An error occurred */
|
|
error_print();
|
|
break;
|
|
}
|
|
job_free(job);
|
|
return abs(rc);
|
|
}
|
|
|
|
/**
|
|
* Program Component Footers
|
|
*/
|
|
struct component_footer component_footers[NR_PROGRAM_COMPONENTS] = {
|
|
[COMPONENT_ID_HEAP_AREA] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "heap area"
|
|
},
|
|
[COMPONENT_ID_STACK_AREA] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "stack area"
|
|
},
|
|
[COMPONENT_ID_LOADER_SIGNATURE] = {
|
|
.type = COMPONENT_TYPE_SIGNATURE,
|
|
.desc = "loader signature"
|
|
},
|
|
[COMPONENT_ID_LOADER] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "internal loader"
|
|
},
|
|
[COMPONENT_ID_PARAMETERS] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "parameters"
|
|
},
|
|
[COMPONENT_ID_IMAGE_SIGNATURE] = {
|
|
.type = COMPONENT_TYPE_SIGNATURE,
|
|
.desc = "image signature"
|
|
},
|
|
[COMPONENT_ID_KERNEL_IMAGE] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "kernel image"
|
|
},
|
|
[COMPONENT_ID_PARMLINE] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "parmline"
|
|
},
|
|
[COMPONENT_ID_RAMDISK_SIGNATURE] = {
|
|
.type = COMPONENT_TYPE_SIGNATURE,
|
|
.desc = "ramdisk signature"
|
|
},
|
|
[COMPONENT_ID_RAMDISK] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "initial ramdisk"
|
|
},
|
|
[COMPONENT_ID_ENVBLK] = {
|
|
.type = COMPONENT_TYPE_LOAD,
|
|
.desc = "environment blk"
|
|
},
|
|
[COMPONENT_ID_SEGMENT_FILE] = {
|
|
.type = COMPONENT_TYPE_EXECUTE,
|
|
.desc = "segment file"
|
|
}
|
|
};
|