ACC SHELL
/**
* File: modules/SystemFilesCopy.ycp
* Package: Installation
* Summary: Functionality for copying files from another systems
* Authors: Lukas Ocilka <locilka@suse.cz>
*
* $Id: SystemFilesCopy.ycp 57028 2009-04-29 10:58:09Z lslezak $
*
* Functionality for copying files from any not-mounted systems
* to inst-sys and from inst-sys to just-installed system.
*/
{
textdomain "installation";
module "SystemFilesCopy";
import "Directory";
import "FileUtils";
import "String";
import "Installation";
import "ProductFeatures";
import "Stage";
import "InstData";
// --> Variables
/**
* @struct [
* [ archive_name, copy_to ],
* [ "/tmp/archive_001.tgz", "/etc" ],
* ]
*/
list <list <string> > copy_files_to_installed_system = [];
boolean already_initialized = false;
string inst_sys_tmp_directory = nil;
string tmp_mount_directory = nil;
// max tries when creating a temporary mount-directory
integer counter_max = 10;
integer tmp_archive_counter = 0;
// --> Functions
global define string CreateDirectoryIfMissing (string mnt_tmpdir);
/**
* Checks whether the directory exists and creates it if it is missing
* If the path exists but it is not a directory, it tries to create another
* directory and returns its name. 'nil' is returned when everythig fails.
*
* @param string mnt_tmpdir
* #return string mnt_tmpdir (maybe changed)
*/
global define string CreateDirectoryIfMissing (string create_directory) {
// path already exists
if (FileUtils::Exists(create_directory)) {
// exists as a directory
if (FileUtils::IsDirectory(create_directory)) {
y2milestone("Directory %1 already exists", create_directory);
return create_directory;
// exists but it's not a directory
} else {
y2warning("Path %1 is not a directory", create_directory);
string new_dir = nil;
while (new_dir == nil && counter_max > 0) {
counter_max = counter_max - 1;
create_directory = create_directory + "x";
new_dir = CreateDirectoryIfMissing (create_directory);
}
return new_dir;
}
// path doesn't exist
} else {
SCR::Execute(.target.mkdir, create_directory);
// created successfully
if (FileUtils::Exists (create_directory)) {
y2milestone("Directory %1 created", create_directory);
return create_directory;
// cannot create
} else {
y2error("Cannot create path %1", create_directory);
return nil;
}
}
}
/**
* Sets and creates a temporary directory for files to lay
* in inst-sys until they're copied to the installed system.
* Sets and creates a temporary directory that is used for
* mounting partitions when copying files from them.
*/
boolean Initialize () {
if (already_initialized) return true;
inst_sys_tmp_directory = CreateDirectoryIfMissing("/tmp/tmp_dir_for_SystemFilesCopy_files");
tmp_mount_directory = CreateDirectoryIfMissing("/tmp/tmp_dir_for_SystemFilesCopy_mount");
if (inst_sys_tmp_directory == nil || tmp_mount_directory == nil) {
y2error("Cannot create one of needed directories");
return false;
}
// everything is fine
already_initialized = true;
return true;
}
/**
* Mounts the partition and proceeds the copying files from that partition
* to the inst-sys.
*
* @struct partiton == "/dev/sdb4"
* @struct filenames == [ "/etc/123", "/etc/456" ]
* @struct copy_to == "/root/" (where to copy it to the installed system)
*/
global boolean CopyFilesToTemp (string partition, list <string> filenames, string copy_to) {
if (! Initialize ()) {
y2error("Cannot initialize!");
return false;
}
// creating full archive name (path)
tmp_archive_counter = tmp_archive_counter + 1;
string archive_name = sformat("%1/_inst_archive_%2.tgz", inst_sys_tmp_directory, tmp_archive_counter);
y2milestone("Copying from '%1' files %2 to '%3'. Files will appear in '%4'",
partition, filenames, archive_name, copy_to
);
y2milestone("Mounting %1 to %2", partition, tmp_mount_directory);
if (! (boolean) SCR::Execute(.target.mount, [partition, tmp_mount_directory], "-o ro")) {
y2error("Mounting failed!");
return false;
}
boolean ret = true;
string archive_files = "";
foreach (string filename, filenames, {
// removing the leading slash
if (substring(filename, 0, 1) == "/") filename = substring(filename, 1);
archive_files = archive_files + " '" + String::Quote (filename) + "'";
});
// archive files were already quoted
string command = sformat (
// 'ignore failed read' is for optional files
// but needs to be entered after the archive name
// bugzilla #326055
"cd '%1'; tar --recursion -zcvf '%2' --ignore-failed-read %3",
tmp_mount_directory, String::Quote(archive_name), archive_files
);
map cmd_run = (map) SCR::Execute(.target.bash_output, command);
if ((integer) cmd_run["exit"]:nil != 0) {
y2error(
"Problem during archivation: %1, command >%2<",
cmd_run, command
);
ret = false;
} else {
y2milestone("Archived: %1", cmd_run);
}
y2milestone("Umounting %1", partition);
if (! (boolean) SCR::Execute(.target.umount, tmp_mount_directory)) {
y2warning("Umounting failed!");
}
// add a new entry into the list of archives
copy_files_to_installed_system = add (copy_files_to_installed_system, [archive_name, copy_to]);
return ret;
}
/**
* Proceeds the copying of all files in inst-sys (that were copied from
* another partition before) to the directory.
*
* @param extract_to_dir (Installation::destdir for initial stage of installation)
*/
global boolean CopyFilesToSystem (string extract_to_dir) {
if (! already_initialized) {
y2error("CopyFilesToTemp() needs to be called first...");
return false;
}
boolean ret = true;
// this should run before the SCR root is changed
foreach (list <string> archive_to_extract, copy_files_to_installed_system, {
string archive_name = archive_to_extract[0]:nil;
string where_to_extract = archive_to_extract[1]:nil;
if (archive_name == nil || where_to_extract == nil) {
y2error("Something is wrong with the archive: %1", archive_to_extract);
ret = false;
}
where_to_extract = sformat("%1%2", extract_to_dir, where_to_extract);
string command = sformat (
"mkdir -p '%1'; cd '%1'; tar --preserve-permissions --preserve-order -xvzf '%2'",
String::Quote (where_to_extract),
String::Quote (archive_name)
);
map cmd_run = (map) SCR::Execute(.target.bash_output, command);
if ((integer) cmd_run["exit"]:nil != 0) {
y2error(
"Problem during extracting an archive: %1, command >%2<",
cmd_run, command
);
ret = false;
} else {
y2milestone("Extracted: %1 into %2", cmd_run, where_to_extract);
}
});
return true;
}
// internal functions for SaveInstSysContent -->
string AdjustDirectoryPath (string directory_path) {
list <string> dir_path_list = splitstring (directory_path, "/");
dir_path_list = filter (string one_dir, dir_path_list, {
return (one_dir != "");
});
directory_path = mergestring (dir_path_list, "/");
directory_path = sformat ("/%1/", directory_path);
return directory_path;
}
boolean CopyFilesFromDirToDir (string dir_from, string dir_to) {
string cmd = sformat (
"mkdir -p '%2' && cp -ar '%1.' '%2'",
String::Quote (dir_from),
String::Quote (dir_to)
);
map cmd_run = (map) WFM::Execute (.local.bash_output, cmd);
if (cmd_run["exit"]:-1 != 0) {
y2error ("Command %1 failed %2", cmd, cmd_run);
return false;
} else {
y2milestone ("Command >%1< succeeded", cmd);
return true;
}
}
// <-- internal functions for SaveInstSysContent
/**
* Function reads <globals><save_instsys_content /></globals>
* from control file and copies all content from inst-sys to
* the just installed system.
*
* This function needs to be called in the inst-sys (first stage)
* just before the disk is unmounted.
*
* FATE #301937
*
* @struct
* <globals>
* <save_instsys_content config:type="list">
* <save_instsys_item>
* <instsys_directory>/root/</instsys_directory>
* <system_directory>/root/inst-sys/</system_directory>
* </save_instsys_item>
* </save_instsys_content>
* </globals>
*/
global boolean SaveInstSysContent () {
if (! Stage::initial()) {
y2error ("This function can be called in the initial stage only!");
return false;
}
map <string, any> globals_features = ProductFeatures::GetSection ("globals");
if (globals_features == nil) {
y2warning ("No <globals> defined");
return false;
} else if (globals_features["save_instsys_content"]:[] == []) {
y2milestone ("No items to copy from inst-sys");
return true;
}
list <map <string, string> > save_content =
(list <map <string, string> >) globals_features["save_instsys_content"]:nil;
if (save_content == nil) {
y2error ("Cannot save inst-sys content: %1", globals_features["save_instsys_content"]:nil);
return false;
}
y2milestone ("Save inst-sys content: %1", save_content);
foreach (map <string, string> copy_item, save_content, {
if (copy_item["instsys_directory"]:"" == "") {
y2error ("Error: %1 is not defined", "instsys_directory");
return;
} else if (copy_item["system_directory"]:"" == "") {
y2error ("Error: %1 is not defined", "system_directory");
return;
}
string dir_from = sformat ("/%1/", copy_item["instsys_directory"]:"");
string dir_to = sformat ("/%1/%2/", Installation::destdir, copy_item["system_directory"]:"");
dir_from = AdjustDirectoryPath (dir_from);
dir_to = AdjustDirectoryPath (dir_to);
if (dir_from == dir_to) {
y2error ("Dir 'from (%1)' and 'to (%2)' mustn't be the same", dir_from, dir_to);
return;
}
// search ("/a", "/b") -> nil
// search ("/a/b", "/a") -> 0
// search ("/a/b/", "/b/") -> 2
integer position_str_in_str = search (dir_to, dir_from);
if (position_str_in_str != nil && position_str_in_str == 0) {
y2error ("Cannot copy a directory content to itself (%1 -> %2)", dir_from, dir_to);
return;
}
CopyFilesFromDirToDir (dir_from, dir_to);
});
return true;
}
// FATE #305019: configure the files to copy from a previous installation
// -->
/**
* Sets whether copy_files from control file should be used
*
* @returns boolean whether to use them
* @see SetUseControlFileDef
*/
global boolean GetUseControlFileDef () {
return (InstData::copy_files_use_control_file == true);
}
/**
* Sets whether to use copy_files from control file
*
* @param boolean whether to use them
* @see GetUseControlFileDef
*/
global void SetUseControlFileDef (boolean new_value) {
if (new_value == nil) {
y2error ("Wrong value: %1", new_value);
return;
}
InstData::copy_files_use_control_file = new_value;
y2milestone ("Using copy_to_system from control file set to: %1", new_value);
}
/**
* Returns list of copy_files definitions
* @see SetCopySystemFiles for more info
*/
global list <map> GetCopySystemFiles () {
return InstData::additional_copy_files;
}
/**
* Sets new rules which files will be copied during installation.
*
* @see FATE #305019: configure the files to copy from a previous installation
* @param list <map> of new definitions
*
* @struct
* [
* "copy_to_dir" : (string) "system_directory_to_copy_to",
* "mandatory_files" : (list <string>) [ list of mandatory files ],
* "optional_files" : (list <string>) [ list of optional files ],
* ]
*
* @example
* SetCopySystemFiles ([
* $["copy_to_dir":"/root/backup", "mandatory_files":["/etc/passwd", "/etc/shadow"]]
* $["copy_to_dir":"/root/backup", "mandatory_files":["/etc/ssh/ssh_host_dsa_key"], "optional_files":["/etc/ssh/ssh_host_rsa_key.pub"]]
* ])
*/
global void SetCopySystemFiles (list <map> new_copy_files) {
InstData::additional_copy_files = [];
boolean use_item = true;
foreach (map one_copy_item, new_copy_files, {
string copy_to_dir = tostring (one_copy_item["copy_to_dir"]:Directory::vardir);
if (copy_to_dir == nil || copy_to_dir == "") {
y2error ("(string) 'copy_to_dir' must be defined");
use_item = false;
}
list <string> mandatory_files = (list <string>) one_copy_item["mandatory_files"]:[];
if (mandatory_files == nil || mandatory_files == []) {
y2error ("(list <string>) 'mandatory_files' must be defined");
use_item = false;
}
list <string> optional_files = (list <string>) one_copy_item["optional_files"]:[];
if (optional_files == nil) {
y2error ("(list <string>) 'optional_files' wrong definition");
use_item = false;
}
if (use_item) {
InstData::additional_copy_files = add (InstData::additional_copy_files, one_copy_item);
}
});
}
// <--
/* EOF */
}
ACC SHELL 2018