/var/lib/sorcery/modules/libstage

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	## @Synopsis Functions for desling with the stage root and installing files from the stage root
     4	## @Copyright Copyright (C) 2004 The Source Mage Team <http://www.sourcemage.org>
     5	## Functions for desling with the stage root and installing files from the stage root
     6	#---------------------------------------------------------------------
     7	
     8	#---------------------------------------------------------------------
     9	## @param stage root
    10	## Main for installing staged spell called imediatly after devoking
    11	## installwatch and stage root
    12	#---------------------------------------------------------------------
    13	function transfer_staged_spell()
    14	{
    15	  stage_install_ordinary
    16	
    17	  # restore any hardlinks, since they were copied over normally
    18	  local hlist
    19	  if [[ -n $CAST_TMPDIR ]]; then
    20	    hlist="$CAST_TMPDIR/hardlinks"
    21	  else
    22	    hlist="$TMP_DIR/hardlinks"
    23	  fi
    24	  if [[ -s $hlist ]]; then
    25	    local inode last_inode filename last_filename
    26	    sort "$hlist" |
    27	    while read inode filename; do
    28	      if [[ $last_inode == $inode ]]; then
    29	        ln -f "$last_filename" "$filename"
    30	      fi
    31	      last_filename="$filename"
    32	      last_inode=$inode
    33	    done
    34	    rm -f "$hlist"
    35	  fi
    36	
    37	  lock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
    38	  mkdir -p "$CONFIG_STAGE_DIRECTORY/$SPELL/current"
    39	  stage_install_configs
    40	  unlock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
    41	}
    42	
    43	function filter_spell_configs()
    44	{
    45	  filter_generic "$*" configs $CONFIGS codex
    46	}
    47	
    48	#---------------------------------------------------------------------
    49	## Install config files to a staged location on the system or if
    50	## they are also excluded, just install them normally.
    51	#---------------------------------------------------------------------
    52	function stage_install_configs()
    53	{
    54	  local spell_configs=$(get_all_package_files | filter_spell_configs -v)
    55	
    56	  # install excluded configs as ordinary files - do not stage them
    57	  message "${MESSAGE_COLOR}Installing excluded config files${DEFAULT_COLOR}"
    58	  echo "$spell_configs"      |
    59	  filter_excluded -v         |
    60	  stage_install_files
    61	
    62	  message "${MESSAGE_COLOR}Staging config files into the system${DEFAULT_COLOR}"
    63	  echo "$spell_configs"      |
    64	  filter_excluded            |
    65	  stage_install_files config
    66	}
    67	
    68	#---------------------------------------------------------------------
    69	## Install non-configs in the stage root
    70	#---------------------------------------------------------------------
    71	function stage_install_ordinary()
    72	{
    73	  message "${MESSAGE_COLOR}Installing ordinary files${DEFAULT_COLOR}"
    74	  get_all_package_files        |
    75	  filter_spell_configs         |
    76	  stage_install_files
    77	}
    78	
    79	#---------------------------------------------------------------------
    80	## @Stdout list of files installed by package
    81	## lists all files the package installs relative to /
    82	#---------------------------------------------------------------------
    83	function get_all_package_files()
    84	{
    85	  # no point in using -printf "/%P\n" since it would cause a difference:
    86	  # the searchpath is now returned as empty; there it would be /
    87	  find "$STAGE_DIRECTORY/TRANSL" | sed "s:$STAGE_DIRECTORY/TRANSL::" | sort
    88	}
    89	
    90	#---------------------------------------------------------------------
    91	## @Stdin list of files to install
    92	## install the files from the stage directory to the system
    93	#---------------------------------------------------------------------
    94	function stage_install_files()
    95	{
    96	  local file
    97	  while read file ; do
    98	    [ "$file" ] || continue
    99	    stage_install_list "$file" "$1"
   100	  done
   101	}
   102	
   103	function stage_install_directory()
   104	{
   105	  local DIR=$1
   106	  local stat=( $(stat --printf "%a\n%U\n%G\n" "$STAGE_DIRECTORY/TRANSL/$DIR" ) )
   107	  local PERMISSION=${stat[0]}
   108	  local OWNER=${stat[1]}
   109	  local GROUP=${stat[2]}
   110	  if [[ ! -d $(smgl_dirname "${INSTALL_ROOT}/$DIR") ]]
   111	  then
   112	    # this shouldn't happen but just in case
   113	    message "${PROBLEM_COLOR}Ah, not preserving permissions making $(smgl_dirname $DIR)${DEFAULT_COLOR}" &&
   114	    mkdir -p $(smgl_dirname "${INSTALL_ROOT}/$DIR")
   115	  fi &&
   116	  message "${FILE_COLOR}$PERMISSION $OWNER:$GROUP $DIR${DEFAULT_COLOR}" &&
   117	  if [[ -d "${INSTALL_ROOT}/$DIR" ]]
   118	  then
   119	    chmod "$PERMISSION" "${INSTALL_ROOT}/$DIR" &&
   120	    chown $OWNER:$GROUP "${INSTALL_ROOT}/$DIR"
   121	  else
   122	    mkdir "${INSTALL_ROOT}/$DIR"   &&
   123	    chmod "$PERMISSION" "${INSTALL_ROOT}/$DIR" &&
   124	    chown $OWNER:$GROUP "${INSTALL_ROOT}/$DIR"
   125	  fi
   126	}
   127	
   128	function stage_install_file()
   129	{
   130	  local FILE=$1
   131	  local stat=( $(stat --printf "%a\n%U\n%G\n%h\n%i\n" "$STAGE_DIRECTORY/TRANSL/$FILE" ) )
   132	  local PERMISSION=${stat[0]}
   133	  local OWNER=${stat[1]}
   134	  local GROUP=${stat[2]}
   135	  local link_count=${stat[3]}
   136	  local inode=${stat[4]}
   137	  local SAVE="$CONFIG_STAGE_DIRECTORY/$SPELL/current/$FILE"
   138	  message "${FILE_COLOR}$PERMISSION $OWNER:$GROUP $FILE${DEFAULT_COLOR}"
   139	  case $2 in
   140	    config)
   141	      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
   142	      then
   143	        if cmp -s "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
   144	        then
   145	          : # nothing to do, we already have the same file
   146	        else
   147	          message "${MESSAGE_COLOR}Staging config to $CONFIG_STAGE_DIRECTORY${DEFAULT_COLOR}"
   148	          mkdir -p "$(smgl_dirname $SAVE)" &&
   149	          cp -dp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$SAVE"
   150	        fi
   151	      else
   152	        cp -dp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
   153	      fi
   154	      ;;
   155	    *)
   156	      cp -fdp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
   157	      # we can't fix symlinks now, since the other file is often not on the system yet
   158	      # doing it later in TRANSFER also avoids the search for matching inodes
   159	      if [[ $link_count != 1 ]]; then
   160	        if [[ -n $CAST_TMPDIR ]]; then
   161	          echo "$inode ${INSTALL_ROOT}/$FILE" >> "$CAST_TMPDIR/hardlinks"
   162	        else
   163	          echo "$inode ${INSTALL_ROOT}/$FILE" >> "$TMP_DIR/hardlinks"
   164	        fi
   165	      fi
   166	      ;;
   167	  esac
   168	}
   169	
   170	function stage_install_symlink()
   171	{
   172	  local FILE=$1
   173	  local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
   174	  local LINK=$(readlink "$STAGE_DIRECTORY/TRANSL/$FILE")
   175	  message "${FILE_COLOR}Symlink $FILE -> $LINK${DEFAULT_COLOR}"
   176	  case $2 in
   177	    config)
   178	      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
   179	      then
   180	        touch "${INSTALL_ROOT}/$FILE" &&
   181	        mkdir -p $(smgl_dirname $SAVE) &&
   182	        ln -sfn "$LINK" "${INSTALL_ROOT}/$SAVE"
   183	      else
   184	        ln -sfn "$LINK" "${INSTALL_ROOT}/$FILE"
   185	      fi
   186	      ;;
   187	    *)
   188	      ln -sfn $(readlink "$STAGE_DIRECTORY/TRANSL/$FILE") "${INSTALL_ROOT}/$FILE"
   189	      ;;
   190	  esac
   191	}
   192	
   193	function stage_install_fifo()
   194	{
   195	  local FILE=$1
   196	  local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
   197	  local stat=( $(stat --printf "%a\n%U\n%G\n" "$STAGE_DIRECTORY/TRANSL/$FILE" ) )
   198	  local PERMISSION=${stat[0]}
   199	  local OWNER=${stat[1]}
   200	  local GROUP=${stat[2]}
   201	  message "${FILE_COLOR}Fifo $PERMISSION $OWNER:$GROUP $FILE${DEFAULT_COLOR}"
   202	  case $2 in
   203	    config)
   204	      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
   205	      then
   206	        touch "${INSTALL_ROOT}/$FILE" &&
   207	        mkdir -p $(smgl_dirname $SAVE) &&
   208	        mkfifo "${INSTALL_ROOT}/$SAVE" &&
   209	        chmod $PERMISSION "${INSTALL_ROOT}/$SAVE" &&
   210	        chown $OWNER:$GROUP "${INSTALL_ROOT}/$SAVE"
   211	      else
   212	        mkfifo "${INSTALL_ROOT}/$FILE" &&
   213	        chmod $PERMISSION "${INSTALL_ROOT}/$FILE" &&
   214	        chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
   215	      fi
   216	      ;;
   217	    *)
   218	      mkfifo "${INSTALL_ROOT}/$FILE" &&
   219	      chmod $PERMISSION "${INSTALL_ROOT}/$FILE" &&
   220	      chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
   221	      ;;
   222	  esac
   223	}
   224	
   225	function stage_install_char_block()
   226	{
   227	  local FILE=$1
   228	  local stat=( $(stat --printf "%a\n%U\n%G\n%t\n%T\n" "$STAGE_DIRECTORY/TRANSL/$FILE" ) )
   229	  local PERMISSION=${stat[0]}
   230	  local OWNER=${stat[1]}
   231	  local GROUP=${stat[2]}
   232	  local MAJOR=${stat[3]}
   233	  local MINOR=${stat[4]}
   234	  local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
   235	  local TYPE=$3
   236	  message "${FILE_COLOR}${PERMISSION} $OWNER:$GROUP $TYPE $MAJOR $MINOR $FILE${DEFAULT_COLOR}"
   237	  case $2 in
   238	    config)
   239	      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
   240	      then
   241	        touch "${INSTALL_ROOT}/$FILE" &&
   242	        mkdir -p $(smgl_dirname $SAVE) &&
   243	        mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$SAVE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
   244	        chown $OWNER:$GROUP "${INSTALL_ROOT}/$SAVE"
   245	      else
   246	        mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$FILE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
   247	        chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
   248	      fi
   249	      ;;
   250	    *)
   251	      mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$FILE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
   252	      chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
   253	      ;;
   254	  esac
   255	}
   256	
   257	#---------------------------------------------------------------------
   258	## @param file
   259	## install the file from the stage root to the system does check for
   260	## dir so that the file can be moved
   261	#---------------------------------------------------------------------
   262	function stage_install_list()
   263	{
   264	  if [[ -h $STAGE_DIRECTORY/TRANSL/$1 ]]
   265	  then
   266	    stage_install_symlink "$@"
   267	  elif [[ -b $STAGE_DIRECTORY/TRANSL/$1 ]]
   268	  then
   269	    stage_install_char_block "$@" b
   270	  elif [[ -c $STAGE_DIRECTORY/TRANSL/$1 ]]
   271	  then
   272	    stage_install_char_block "$@" c
   273	  elif [[ -p $STAGE_DIRECTORY/TRANSL/$1 ]]
   274	  then
   275	    stage_install_fifo "$@"
   276	  elif [[ -f $STAGE_DIRECTORY/TRANSL/$1 ]]
   277	  then
   278	    stage_install_file "$@"
   279	  elif [[ -d $STAGE_DIRECTORY/TRANSL/$1 ]]
   280	  then
   281	    stage_install_directory "$@"
   282	  else
   283	    message "${PROBLEM_COLOR}Oh, God I don't know what to do..."
   284	    message "${FILE_COLOR}$(smgl_dirname ${1})${PROBLEM_COLOR}"
   285	    message "is some other kind of a file and not a directory${DEFAULT_COLOR}"
   286	  fi
   287	}
   288	
   289	#--------------------------------------------------------------------
   290	## Removes the passed file and possibly its parent directories up
   291	## to $CONFIG_STAGE_DIRECTORY if they are empty
   292	##
   293	## @param file
   294	## @param spell  owner of the file, so we don't need to look that up
   295	#--------------------------------------------------------------------
   296	function recursive_config_stage_cleanup()
   297	{
   298	  local file=$1 dirname
   299	  local spell=$2
   300	
   301	  smgl_dirname "$file" dirname
   302	  # make it a relative path for rmdir -p
   303	  dirname="${dirname#$CONFIG_STAGE_DIRECTORY/}"
   304	
   305	  # lock_file works on dirs too
   306	  lock_file "$CONFIG_STAGE_DIRECTORY/$spell"
   307	  rm "$file"
   308	  {
   309	    pushd $CONFIG_STAGE_DIRECTORY
   310	    rmdir -p "$dirname"
   311	    popd
   312	  } &> /dev/null
   313	  unlock_file "$CONFIG_STAGE_DIRECTORY/$spell"
   314	}