#!/bin/bash # # Copyright (c) 2016 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # . /usr/bin/tsconfig OPT_BANNER_BACKUP="/opt/banner.bk" PLATFORM_BANNER_DIR="${CONFIG_PATH}/banner" # # set BANNER_VERBOSE to enable info logs # export BANNER_VERBOSE info_log () { if [ -n "${BANNER_VERBOSE}" ]; then echo "INFO: customize-banner: $@" >&2 fi } warn_log () { echo "WARNING: customize-banner: $@" >&2 } error_log () { echo "ERROR: customize-banner: $@" >&2 } # some checks to see if the user does something odd # Return: 1 if the file is not sane # 0 if the file is normal looking # # Symbolic links are followed to their ultimate destination before # further checks are made file_is_sane () { local fname=$1 if [ -z "${fname}" ]; then error_log "no file specified" return 1 fi # resolve symlinks if [ -h "${fname}" ]; then local resolved=$(readlink -f "${fname}") if [ -z "${resolved}" ]; then error_log "file does not exist; did not resolve symbolic link" return 1 fi file_is_sane_no_link "${resolved}" return $? fi file_is_sane_no_link "${fname}" return $? } file_is_sane_no_link () { local fname=$1 # a sanity check, the banner file has to be a regular file # symbolic links are handled in file_is_sane() if [ ! -f "${fname}" -o -h "${fname}" ]; then error_log "file is not a regular file: ${fname}" return 1 fi # root usually has access to write readonly files... if [ ! -w "${fname}" ]; then error_log "file is readonly: ${fname}" return 1 fi # Warn only if [ -x "${fname}" ]; then warn_log "file is executable: ${fname}" fi } # # Prints list of files to stdout # get_banner_files () { local flist=" \ /etc/issue \ /etc/issue.net \ /etc/motd.head \ /etc/motd.tail \ " echo ${flist} } # # This is to be executed either by config_controller or by the user # through apply_banner_customization # # For each customizable file, if a customization is present do a bit of # sanity and copy the file to the platform config for banner # customization. # # Return 0 on success # Return 1 for error conditions, if any customization file failed sanity # customize_banner () { if [ ! -d "${CONFIG_PATH}" ]; then error_log "config path does not exist" return 1 fi banner_dir="$1" if [ -z "${banner_dir}" ]; then error_log "path containing customization files is required" return 1 fi if [ ! -d "${banner_dir}" ]; then warn_log "directory does not exist: ${banner_dir}" return 0 fi local inputok=0 local count=0 local fname="" for fname in $(get_banner_files); do { local bname="$(basename $fname)" # confname includes 'etc'; newfname does not. This seems easier # for the user; at least until a file with a duplicate name is # customizable local confname="${PLATFORM_BANNER_DIR}/${fname}" local newfname="${banner_dir}/${bname}" if [ -e "${newfname}" ]; then count=$(expr $count + 1) if ! file_is_sane ${newfname}; then inputok=1 continue fi if [ -f "${confname}" ]; then info_log "updating customization of ${fname}" rm ${confname} else info_log "adding customization of ${fname}" fi mkdir -p $(dirname ${confname}) cp ${newfname} ${confname} elif [ -f "${confname}" ]; then info_log "maintaining previous customization of ${fname}" fi }; done if [ "$count" -eq 0 ]; then warn_log "no customization files were found in $banner_dir" fi return $inputok } # # Compare two banner files # # Return 0 if they are the same # 1 if they are different # compare_file () { diff -q "$1" "$2" 2>&1 > /dev/null return $? } # # copy the file with a bkx extension, but only if it is not identical to # another; look for an unused filename # # put a hard limit on the number of iterations # backup_file () { local fname=$1 local dname=$(dirname $fname) local bname=$(basename $fname) local bkdir=${OPT_BANNER_BACKUP}/${dname} local count=0 local newname="" if [ ! -f "${fname}" ]; then warn_log "file does not exist: $fname" return 0 fi for count in $(seq 0 9); do { newname=${bkdir}/${bname}.bk${count} if [ -e "${newname}" ]; then if compare_file "${newname}" "${fname}"; then info_log "file is previously backed up ${fname} as ${newname}" touch ${newname} return 0 fi info_log "skipping name ${newname}" else if [ "$count" -gt 7 ]; then warn_log "consider cleaning up $(dirname ${newname})" fi info_log "backing up ${fname} as ${newname}" mkdir -p ${bkdir} cp ${fname} ${newname} return 0 fi }; done # find the oldest file and delete it. newname=$(find ${bkdir} -maxdepth 1 -type f -name "${bname}.bk[0-9]" \ | xargs -r ls -1t | tail -n 1) if [ -z "${newname}" -o ! -f "${newname}" ]; then error_log "did not find backup files for ${fname}" return 1 fi warn_log "deleting oldest backed up file ${newname}" rm ${newname} cp ${fname} ${newname} return $? } # # For each customizable file, if the file exists under # PLATFORM_BANNER_DIR, and it passes some sanity checks, then install # the file onto the root fs # install_banner_files () { # quietly stop if the PLATFORM_BANNER_DIR is not setup if [ ! -d ${PLATFORM_BANNER_DIR} ]; then return 0 fi local banner_files=$(get_banner_files) local bfile="" for bfile in ${banner_files}; do { # do not attempt to install files if the directory on the root # fs is absent; this is an unexpected condition if [ ! -d "$(dirname ${bfile})" ]; then error_log "directory does not exist for ${bfile}" continue fi # proceed only if the user provided a customization for the file if [ ! -f "${PLATFORM_BANNER_DIR}/${bfile}" ]; then info_log "file is not customized: ${bfile}" continue fi if [ -e "${bfile}" ]; then if ! file_is_sane ${bfile}; then continue fi if compare_file "${PLATFORM_BANNER_DIR}/${bfile}" "${bfile}"; then info_log "file already installed: ${bfile}" continue fi info_log "installing over existing file: ${bfile}" backup_file ${bfile} \ || continue else info_log "installing: ${bfile}" fi cp ${PLATFORM_BANNER_DIR}/${bfile} ${bfile} }; done; }