diff --git a/configure.ac b/configure.ac index fc3c074..398c937 100644 --- a/configure.ac +++ b/configure.ac @@ -202,6 +202,7 @@ AC_CONFIG_FILES([ templates/lxc-fedora-legacy templates/lxc-gentoo templates/lxc-kali + templates/lxc-openeuler templates/lxc-openmandriva templates/lxc-opensuse templates/lxc-oracle diff --git a/templates/Makefile.am b/templates/Makefile.am index b885433..1fff05b 100644 --- a/templates/Makefile.am +++ b/templates/Makefile.am @@ -12,6 +12,7 @@ templates_SCRIPTS = \ lxc-fedora-legacy \ lxc-gentoo \ lxc-kali \ + lxc-openeuler \ lxc-openmandriva \ lxc-opensuse \ lxc-oracle \ diff --git a/templates/lxc-openeuler.in b/templates/lxc-openeuler.in new file mode 100644 index 0000000..e5b6842 --- /dev/null +++ b/templates/lxc-openeuler.in @@ -0,0 +1,762 @@ +#!/bin/bash + +# +# template script for generating OpenEuler container for LXC + +# +# lxc: linux Container library + +# Authors: +# Daniel Lezcano +# Ramez Hanna +# Fajar A. Nugraha +# Michael H. Warfield + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#Configurations +default_path=@LXCPATH@ + +# Some combinations of the tuning knobs below do not exactly make sense. +# but that's ok. +# +# If the "root_password" is non-blank, use it, else set a default. +# This can be passed to the script as an environment variable and is +# set by a shell conditional assignment. Looks weird but it is what it is. +# +# If the root password contains a ding ($) then try to expand it. +# That will pick up things like ${name} and ${RANDOM}. +# If the root password contains more than 3 consecutive X's, pass it as +# a template to mktemp and take the result. +# +# If root_display_password = yes, display the temporary root password at exit. +# If root_store_password = yes, store it in the configuration directory +# If root_prompt_password = yes, invoke "passwd" to force the user to change +# the root password after the container is created. +# If root_expire_password = yes, you will be prompted to change the root +# password at the first login. +# +# These are conditional assignments... The can be overridden from the +# preexisting environment variables... +# +# Make sure this is in single quotes to defer expansion to later! +# :{root_password='Root-${name}-${RANDOM}'} +: ${root_password='Root-${name}-XXXXXX'} + +# Now, it doesn't make much sense to display, store, and force change +# together. But, we gotta test, right??? +: ${root_display_password='no'} +: ${root_store_password='yes'} +# Prompting for something interactive has potential for mayhem +# with users running under the API... Don't default to "yes" +: ${root_prompt_password='no'} + +# Expire root password? Default to yes, but can be overridden from +# the environment variable +: ${root_expire_password='yes'} + +# These are only going into comments in the resulting config... +lxc_network_type=veth +lxc_network_link=lxcbr0 + +# is this OpenEuler? +# Alow for weird remixes like the Raspberry Pi +# +# Use the Mitre standard CPE identifier for the release ID if possible... +# This may be in /etc/os-release or /etc/system-release-cpe. We +# should be able to use EITHER. Give preference to /etc/os-release for now. + +# Detect use under userns (unsupported) +for arg in "$@"; do + [ "$arg" = "--" ] && break + if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then + echo "This template can't be used for unprivileged containers." 1>&2 + echo "You may want to try the \"download\" template instead." 1>&2 + exit 1 + fi +done + +# Make sure the usual locations are in PATH +export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin + +if [ -e /etc/os-release ] +then +# This is a shell friendly configuration file. We can just source it. +# What we're looking for in here is the ID, VERSION_ID and the CPE_NAME + . /etc/os-release +fi + +if [ "${CPE_NAME}" = "" -a -e /etc/system-release-cpe ] +then + CPE_NAME=$(head -n1 /etc/system-release-cpe) + CPE_URI=$(expr ${CPE_NAME} : '\([^:]*:[^:]*\)') + if [ "${CPE_URI}" != "cpe:/o" ] + then + CPE_NAME= + else + # Probably a better way to do this but sill remain posix + # compatible but this works, shrug... + # Must be nice and not introduce convenient bashisms here. + ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)') + VERSION=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)') + VERSION_ID=$(echo $VERSION | sed 's/[a-zA-Z]//g') + echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}" + fi +fi + +if [ "${ID}" = "openEuler" ] && [ -n "${CPE_NAME}" ] && [ -n "${VERSION_ID}" ] +then + openEuler_host_ver=${VERSION_ID} + is_openEuler=true +fi + +force_mknod() +{ + # delete a device node if exists, and create a new one + rm -f $2 && mknod -m $1 $2 $3 $4 $5 +} + +configure_openEuler() +{ + + # disable selinux + mkdir -p $rootfs_path/selinux + echo 0 > $rootfs_path/selinux/enforce + + # Also kill it in the /etc/selinux/config file if it's there... + if [ -f $rootfs_path/etc/selinux/config ] + then + sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' $rootfs_path/etc/selinux/config + fi + + # Nice catch from Dwight Engen in the Oracle template. + # Wantonly plagerized here with much appreciation. + if [ -f $rootfs_path/usr/sbin/selinuxenabled ]; then + mv $rootfs_path/usr/sbin/selinuxenabled $rootfs_path/usr/sbin/selinuxenabled.lxcorig + ln -s /bin/false $rootfs_path/usr/sbin/selinuxenabled + fi + + if [ -f ${rootfs_path}/etc/pam.d/crond ] + then + sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/crond + fi + + # In addition to disabling pam_loginuid in the above config files + # we'll also disable it by linking it to pam_permit to catch any + # we missed or any that get installed after the container is built. + # + # Catch either or both 32 and 64 bit archs. + if [ -f ${rootfs_path}/lib/security/pam_loginuid.so ] + then + ( cd ${rootfs_path}/lib/security/ + mv pam_loginuid.so pam_loginuid.so.disabled + ln -s pam_permit.so pam_loginuid.so + ) + fi + + if [ -f ${rootfs_path}/lib64/security/pam_loginuid.so ] + then + ( cd ${rootfs_path}/lib64/security/ + mv pam_loginuid.so pam_loginuid.so.disabled + ln -s pam_permit.so pam_loginuid.so + ) + fi + + # Set default localtime to the host localtime if not set... + if [ -e /etc/localtime -a ! -e ${rootfs_path}/etc/localtime ] + then + # if /etc/localtime is a symlink, this should preserve it. + cp -a /etc/localtime ${rootfs_path}/etc/localtime + fi + + # configure the network using the dhcp + cat < ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0 +DEVICE=eth0 +BOOTPROTO=dhcp +ONBOOT=yes +HOSTNAME=${utsname} +NM_CONTROLLED=no +TYPE=Ethernet +MTU=${MTU} +DHCP_HOSTNAME=\`hostname\` +EOF + + # set the hostname + cat < ${rootfs_path}/etc/sysconfig/network +NETWORKING=yes +HOSTNAME=${utsname} +EOF + + # set minimal hosts + cat < $rootfs_path/etc/hosts +127.0.0.1 localhost $name +EOF + + # set minimal fstab + cat < $rootfs_path/etc/fstab +/dev/root / rootfs defaults 0 0 +EOF + #set dev nodes + dev_path="${rootfs_path}/dev" + rm -rf $dev_path + mkdir -p $dev_path + mknod -m 666 ${dev_path}/null c 1 3 + mknod -m 666 ${dev_path}/zero c 1 5 + mknod -m 666 ${dev_path}/random c 1 8 + mknod -m 666 ${dev_path}/urandom c 1 9 + mkdir -m 755 ${dev_path}/pts + mkdir -m 1777 ${dev_path}/shm + mknod -m 666 ${dev_path}/tty c 5 0 + local i; for i in $(seq 0 4); do + mknod -m 666 dev/tty$i c 4 $i + chown 0:5 dev/tty$i + done + mknod -m 600 ${dev_path}/console c 5 1 + mknod -m 666 ${dev_path}/full c 1 7 + mknod -m 600 ${dev_path}/initctl p + mknod -m 666 ${dev_path}/ptmx c 5 2 + + # setup console and tty[1-4] for login. note that /dev/console and + # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and + # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks. + # lxc will maintain these links and bind mount ptys over /dev/lxc/* + # since lxc.tty.dir is specified in the config. + + # allow root login on console, tty[1-4], and pts/0 for libvirt + cat <> "${rootfs_path}/etc/securetty" +# LXC (Linux Containers)" +lxc/console +lxc/tty1 +lxc/tty2 +lxc/tty3 +lxc/tty4 +# For libvirt/Virtual Machine Monitor +pts/0 +EOF + + if [ ${root_display_password} = "yes" ] + then + echo "Setting root password to '$root_password'" + fi + if [ ${root_store_password} = "yes" ] + then + touch ${config_path}/tmp_root_pass + chmod 600 ${config_path}/tmp_root_pass + echo ${root_password} > ${config_path}/tmp_root_pass + echo "Storing root password in '${config_path}/tmp_root_pass'" + fi + + echo "root:$root_password" | chroot $rootfs_path chpasswd + + if [ ${root_expire_password} = "yes" ] + then + # Also set this password as expired to force the user to change it! + chroot $rootfs_path passwd -e root + fi + + return 0 +} + +arch=$(uname -m) +download_openEuler() +{ + # download a mini openEuler into a cache + INSTALL_ROOT=$cache/partial + mkdir -p $INSTALL_ROOT + echo "Downloading OpenEuler minimal ..." + YUM0="yum --installroot $INSTALL_ROOT -y --nogpgcheck" + + if yum -h | grep -q 'releasever=RELEASEVER'; then + YUM="$YUM0 --releasever=$release" + else + YUM="$YUM0" + fi + PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils cronie network-scripts coreutils net-tools iputils" + + # use temporary repository definition + # always prefer the repo given by the user + REPO_FILE=$INSTALL_ROOT/etc/yum.repos.d/lxc-openEuler-temp.repo + mkdir -p $(dirname $REPO_FILE) + repo_name=$(echo $PRETTY_NAME | sed 's/[()]//g') + repo_name=$(echo $repo_name | sed 's/ /-/g') + if [ -n "$repo" ]; then + cat < $REPO_FILE +[base] +name=local repository +baseurl="$repo" +EOF + else + cat < $REPO_FILE +[OS] +name=OS +baseurl=http://repo.openeuler.org/$repo_name/OS/$arch/ +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ANOLIS +gpgcheck=0 + +[everything] +name=everything +baseurl=http://repo.openeuler.org/$repo_name/everything/$arch/ +enabled=0 + +[EPOL] +name=EPOL +baseurl=http://repo.openeuler.org/$repo_name/EPOL/main/$arch/ +enabled=0 +EOF + fi + + # create minimal device nodes, needed for "yum install" and "yum update" process + mkdir -p $INSTALL_ROOT/dev + force_mknod 666 $INSTALL_ROOT/dev/null c 1 3 + force_mknod 666 $INSTALL_ROOT/dev/urandom c 1 9 + + $YUM install $PKG_LIST + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + + # use same nameservers as hosts, needed for "yum update later" + cp /etc/resolv.conf $INSTALL_ROOT/etc/ + + # check whether rpmdb is under $HOME + if [ ! -e $INSTALL_ROOT/var/lib/rpm/Packages -a -e $INSTALL_ROOT/$HOME/.rpmdb/Packages ]; then + echo "Fixing rpmdb location ..." + mv $INSTALL_ROOT/$HOME/.rpmdb/[A-Z]* $INSTALL_ROOT/var/lib/rpm/ + rm -rf $INSTALL_ROOT/$HOME/.rpmdb + chroot $INSTALL_ROOT rpm --rebuilddb 2>/dev/null + fi + + # check whether rpmdb version is correct + chroot $INSTALL_ROOT rpm --quiet -q yum 2>/dev/null + ret=$? + + # if "rpm -q" doesn't work due to rpmdb version difference, + # then we need to redo the process using the newly-installed yum + if [ $ret -gt 0 ]; then + echo "Reinstalling packages ..." + mv $REPO_FILE $REPO_FILE.tmp + mkdir $INSTALL_ROOT/etc/yum.repos.disabled + mv $INSTALL_ROOT/etc/yum.repos.d/*.repo $INSTALL_ROOT/etc/yum.repos.disabled/ + mv $REPO_FILE.tmp $REPO_FILE + mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/etc + cp /etc/resolv.conf $INSTALL_ROOT/$INSTALL_ROOT/etc/ + mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/dev + mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/null c 1 3 + mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9 + mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum + cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/ + chroot $INSTALL_ROOT $YUM0 install $PKG_LIST + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + mv $INSTALL_ROOT/$INSTALL_ROOT $INSTALL_ROOT.tmp + rm -rf $INSTALL_ROOT + mv $INSTALL_ROOT.tmp $INSTALL_ROOT + fi + + rm -f $REPO_FILE + rm -rf $INSTALL_ROOT/var/cache/yum/* + + mv "$INSTALL_ROOT" "$cache/rootfs" + echo "Download complete." + + return 0 +} + +copy_openEuler() +{ + + # make a local copy of the mini openEuler + echo -n "Copying rootfs to $rootfs_path ..." + #cp -a $cache/rootfs-$arch $rootfs_path || return 1 + # i prefer rsync (no reason really) + mkdir -p $rootfs_path + rsync -SHaAX $cache/rootfs/ $rootfs_path/ + echo + return 0 +} + +update_openEuler() +{ + YUM="chroot $cache/rootfs yum -y --nogpgcheck" + $YUM update + if [ $? -ne 0 ]; then + return 1 + fi + $YUM clean packages +} + +install_openEuler() +{ + mkdir -p /var/lock/subsys/ + ( + flock -x 9 + if [ $? -ne 0 ]; then + echo "Cache repository is busy." + return 1 + fi + + echo "Checking cache download in $cache/rootfs ... " + if [ ! -e "$cache/rootfs" ]; then + download_openEuler + if [ $? -ne 0 ]; then + echo "Failed to download 'OpenEuler base'" + return 1 + fi + else + echo "Cache found. Updating..." + update_openEuler + if [ $? -ne 0 ]; then + echo "Failed to update 'openEuler base', continuing with last known good cache" + else + echo "Update finished" + fi + fi + + echo "Copy $cache/rootfs to $rootfs_path ... " + copy_openEuler + if [ $? -ne 0 ]; then + echo "Failed to copy rootfs" + return 1 + fi + + return 0 + + ) 9>/var/lock/subsys/lxc-openEuler + + return $? +} + +create_hwaddr() +{ + openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/' +} + +copy_configuration() +{ + mkdir -p $config_path + + grep -q "^lxc.rootfs.path" $config_path/config 2>/dev/null || echo " +lxc.rootfs.path = $rootfs_path +" >> $config_path/config + + # The following code is to create static MAC addresses for each + # interface in the container. This code will work for multiple + # interfaces in the default config. + mv $config_path/config $config_path/config.def + while read LINE + do + # This should catch variable expansions from the default config... + if expr "${LINE}" : '.*\$' > /dev/null 2>&1 + then + LINE=$(eval "echo \"${LINE}\"") + fi + + # There is a tab and a space in the regex bracket below! + # Seems that \s doesn't work in brackets. + KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=') + + if [[ "${KEY}" != "lxc.net.0.hwaddr" ]] + then + echo ${LINE} >> $config_path/config + + if [[ "${KEY}" == "lxc.net.0.link" ]] + then + echo "lxc.net.0.hwaddr = $(create_hwaddr)" >> $config_path/config + fi + fi + done < $config_path/config.def + + rm -f $config_path/config.def + + if [ -e "@LXCTEMPLATECONFIG@/openEuler.common.conf" ]; then + echo " +# Include common configuration +lxc.include = @LXCTEMPLATECONFIG@/openEuler.common.conf +" >> $config_path/config + fi + + # Append things which require expansion here... + cat <> $config_path/config +lxc.arch = $arch +lxc.uts.name = $utsname + +# When using LXC with apparmor, uncomment the next line to run unconfined: +#lxc.apparmor.profile = unconfined + +# example simple networking setup, uncomment to enable +#lxc.net.0.type = $lxc_network_type +#lxc.net.0.flags = up +#lxc.net.0.link = $lxc_network_link +#lxc.net.0.name = eth0 +# Additional example for veth network type +# static MAC address, +#lxc.net.0.hwaddr = 00:16:3e:77:52:20 +# persistent veth device name on host side +# Note: This may potentially collide with other containers of same name! +#lxc.net.0.veth.pair = v-$name-e0 + +EOF + + if [ $? -ne 0 ]; then + echo "Failed to add configuration" + return 1 + fi + + return 0 +} + +clean() +{ + + if [ ! -e $cache ]; then + exit 0 + fi + + # lock, so we won't purge while someone is creating a repository + ( + flock -x 9 + if [ $? != 0 ]; then + echo "Cache repository is busy." + exit 1 + fi + + echo -n "Purging the download cache for OpenEuler-$release..." + rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1 + exit 0 + + ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-openEuler +} + +usage() +{ + cat < + [-p|--path=] [-c|--clean] [-R|--release=] [-a|--arch=] + [-h|--help] +Mandatory args: + -n,--name container name, used to as an identifier for that container from now on +Optional args: + -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc/name. + -c,--clean clean the cache + -R,--release OpenEuler release for the new container. If the host is OpenEuler, then it will default to the host's release. + --fqdn fully qualified domain name (FQDN) for DNS and system naming + --repo repository to use (url) + -a,--arch The container architecture. Can be one of: x86_64, aarch64, arm32, loongarch64. Defaults to host arch. + -h,--help print this help +EOF + return 0 +} + +options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,repo:,arch:,fqdn: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi + +eval set -- "$options" +while true +do + case "$1" in + -h|--help) usage $0 && exit 0;; + -p|--path) path=$2; shift 2;; + --rootfs) rootfs_path=$2; shift 2;; + -n|--name) name=$2; shift 2;; + -c|--clean) clean=1; shift 1;; + -R|--release) release=$2; shift 2;; + --repo) repo="$2"; shift 2;; + -a|--arch) newarch=$2; shift 2;; + --fqdn) utsname=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ ! -z "$clean" -a -z "$path" ]; then + clean || exit 1 + exit 0 +fi + +basearch=${arch} +# Allow the cache base to be set by environment variable +cache_base=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/openEuler/$basearch + +# Let's do something better for the initial root password. +# It's not perfect but it will defeat common scanning brute force +# attacks in the case where ssh is exposed. It will also be set to +# expired, forcing the user to change it at first login. +if [ "${root_password}" = "" ] +then + root_password=Root-${name}-${RANDOM} +else + # If it's got a ding in it, try and expand it! + if [ $(expr "${root_password}" : '.*$.') != 0 ] + then + root_password=$(eval echo "${root_password}") + fi + + # If it has more than 3 consecutive X's in it, feed it + # through mktemp as a template. + if [ $(expr "${root_password}" : '.*XXXX') != 0 ] + then + root_password=$(mktemp -u ${root_password}) + fi +fi + +if [ -z "${utsname}" ]; then + utsname=${name} +fi + +# This follows a standard "resolver" convention that an FQDN must have +# at least two dots or it is considered a local relative host name. +# If it doesn't, append the dns domain name of the host system. +# +# This changes one significant behavior when running +# "lxc_create -n Container_Name" without using the +# --fqdn option. +# +# Old behavior: +# utsname and hostname = Container_Name +# New behavior: +# utsname and hostname = Container_Name.Domain_Name + +if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then + if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then + utsname=${utsname}.$(dnsdomainname) + fi +fi + +type yum >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "'yum' command is missing" + exit 1 +fi + +if [ -z "$path" ]; then + path=$default_path/$name +fi + +if [ -z "$release" ]; then + release=$openEuler_host_ver +fi + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z "$rootfs_path" ]; then + rootfs_path=$path/rootfs + # check for 'lxc.rootfs.path' passed in through default config by lxc-create + if grep -q '^lxc.rootfs.path' $path/config 2>/dev/null ; then + rootfs_path=$(sed -e '/^lxc.rootfs.path\s*=/!d' -e 's/\s*#.*//' \ + -e 's/^lxc.rootfs.path\s*=\s*//' -e q $path/config) + fi +fi +config_path=$path +cache=$cache_base/${VERSION_ID} + +revert() +{ + echo "Interrupted, so cleaning up" + lxc-destroy -n $name + # maybe was interrupted before copy config + rm -rf $path + echo "exiting..." + exit 1 +} + +trap revert SIGHUP SIGINT SIGTERM + +copy_configuration +if [ $? -ne 0 ]; then + echo "failed write configuration file" + exit 1 +fi + +install_openEuler +if [ $? -ne 0 ]; then + echo "failed to install openEuler" + exit 1 +fi + +configure_openEuler +if [ $? -ne 0 ]; then + echo "failed to configure OpenEuler for a container" + exit 1 +fi + +if [ ! -z "$clean" ]; then + clean || exit 1 + exit 0 +fi +echo " +Container rootfs and config have been created. +Edit the config file to check/enable networking setup. +" + +if [ ${root_display_password} = "yes" ] +then + echo "The temporary password for root is: '$root_password' + +You may want to note that password down before starting the container. +" +fi + +if [ ${root_store_password} = "yes" ] +then + echo "The temporary root password is stored in: + + '${config_path}/tmp_root_pass' +" +fi + +if [ ${root_prompt_password} = "yes" ] +then + echo "Invoking the passwd command in the container to set the root password. + + chroot ${rootfs_path} passwd +" + chroot ${rootfs_path} passwd +else + if [ ${root_expire_password} = "yes" ] + then + if ( mountpoint -q -- "${rootfs_path}" ) + then + echo "To reset the root password, you can do: + + lxc-start -n ${name} + lxc-attach -n ${name} -- passwd + lxc-stop -n ${name} +" + else + echo " +The root password is set up as "expired" and will require it to be changed +at first login, which you should do as soon as possible. If you lose the +root password or wish to change it without starting the container, you +can change it from the host by running the following command (which will +also reset the expired flag): + + chroot ${rootfs_path} passwd +" + fi + fi +fi