/var/lib/sorcery/modules/libdispel

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	##
     4	## @Synopsis Functions for dispelling a spell
     5	##
     6	##
     7	## @Copyright Original version Copyright 2001 by Kyle Sallee
     8	## @Copyright Additions/Corrections Copyright 2002-4 by the SourceMage Team
     9	##
    10	## Functions for dispelling spells.
    11	#---------------------------------------------------------------------
    12	
    13	
    14	#---------------------------------------------------------------------
    15	## @Stdin list of files
    16	##
    17	## Given a list of files from standard input, deletes each file.
    18	## Performs a "rm -f" on each file given in standard input, so be
    19	## careful using this function!
    20	##
    21	#---------------------------------------------------------------------
    22	function reap_regular_files()  {
    23	  debug "libsorcery" "reap_regular_files()"
    24	  local FILE
    25	  while read FILE; do
    26	    rm  -f   "$FILE"
    27	  done
    28	}
    29	
    30	
    31	#---------------------------------------------------------------------
    32	## @Stdin list of files
    33	##
    34	## Reads a list of files from standard input.  If the file has been
    35	## modified (md5sum doesn't match the stored md5sum), then function
    36	## C<reap_modified_file> is called.  Otherwise, the file is deleted.
    37	##
    38	#---------------------------------------------------------------------
    39	function reap_config_files()  {
    40	  debug "libsorcery" "reap_config_files()"
    41	  local FILE md5
    42	  while  read  FILE;  do
    43	    [[ $FILE ]] || continue
    44	    if [[ $TOTAL_DISPEL ]] ; then
    45	      rm -f "$FILE"
    46	      continue
    47	    fi
    48	
    49	    md5=$(md5sum "$FILE")
    50	    orig="$SCRIPT_DIRECTORY/init.d/${FILE##*/}.conf"
    51	    if grep -qx "$md5" "$MD5S"; then
    52	      debug libdispel "$FILE is a config file that hasnt changed, removing..."
    53	      rm -f "$FILE"
    54	    # this check only handles sysconfig files, since they're the only ones
    55	    # nicely available at this point
    56	    elif [[ -f $orig ]] &&
    57	    [[ $(cut -d" " -f1 <<< "$md5") == $(md5sum "$orig" | cut -d" " -f1) ]]; then
    58	      debug libdispel "$FILE is a config file that was reverted to the default, removing..."
    59	      rm -f "$FILE"
    60	    else
    61	      reap_modified_file "$FILE"
    62	    fi
    63	  done
    64	}
    65	
    66	#---------------------------------------------------------------------
    67	## @param file
    68	##
    69	## If C<PRESERVE> is off, will move the file to filename.YYYYMMDD.  If
    70	## C<PRESERVE> is on, the file will not be moved.
    71	##
    72	#---------------------------------------------------------------------
    73	function reap_modified_file()  {
    74	  local SAVE
    75	  message  "${FILE_COLOR}${1}${DEFAULT_COLOR}"
    76	  message  "${MESSAGE_COLOR}was previously modified by SA?"
    77	  case  $PRESERVE  in
    78	     on)  message  "Therefore, it was not reaped."  ;;
    79	    off)  SAVE="$1.`date  -u  +%Y%m%d`"
    80	          mv  $1  $SAVE
    81	          message  "Therefore, it was moved to"
    82	          message  "${FILE_COLOR}${SAVE}"  ;;
    83	  esac
    84	  message  "${DEFAULT_COLOR}"
    85	
    86	}
    87	
    88	#---------------------------------------------------------------------
    89	## Removes spell config stages if there are any
    90	#---------------------------------------------------------------------
    91	function reap_spell_config_stage()  {
    92	  lock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
    93	  # it's locked - we also don't have to care about the unlikely "current" stage
    94	  rm -fr "$CONFIG_STAGE_DIRECTORY/$SPELL"
    95	  unlock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
    96	}
    97	
    98	#---------------------------------------------------------------------
    99	## Removes depends entries for what the spell depends on
   100	#---------------------------------------------------------------------
   101	function reap_depends()  {
   102	  # save the old depends data as abandoned stuff so its seen later on
   103	  # recasts as the default
   104	  mkdir -p $ABANDONED_DEPENDS
   105	  local t_file
   106	  lock_start_transaction "$ABANDONED_DEPENDS/$SPELL" t_file
   107	  search_depends_status $DEPENDS_STATUS $SPELL > $t_file
   108	  lock_commit_transaction "$ABANDONED_DEPENDS/$SPELL"
   109	
   110	  # This conditional is here because the iso team wants to be able to
   111	  # save dependencies after dispel (bug 8109), average users are expected
   112	  # to always run this code to remove old depends.
   113	  if [[ $NO_REAP_DEPENDS != "on" ]] ; then
   114	    remove_depends_status $DEPENDS_STATUS $SPELL
   115	    remove_sub_depends "$SUB_DEPENDS_STATUS" "$SPELL" ".*"
   116	  fi
   117	}
   118	
   119	
   120	#---------------------------------------------------------------------
   121	## @param file
   122	## @param file
   123	##
   124	## First argument is a file containing a list of files to reap.
   125	## Second argument is a file containing md5 sums of those files, used
   126	## to detect if a config file has been modified.  Config files are any
   127	## files in /etc or any of its sub-directories.
   128	##
   129	#---------------------------------------------------------------------
   130	function reaper()  {
   131	#  Example:  reaper "$INSTALL_LOG"  "$MD5_LOG"
   132	
   133	  debug  "libdispel" "Running reaper() on $1"
   134	
   135	  if  !  [  "$REAP"  ==  "on"  ]   ||
   136	      !  [  -f  $1             ];  then  return
   137	  fi
   138	
   139	  local MD5S=$2
   140	
   141	  local UNIQUE="$$.$RANDOM"
   142	  local REAPER_FILES="$TMP_DIR/reaper.$UNIQUE.files"
   143	  local REAPER_DIRS="$TMP_DIR/reaper.$UNIQUE.dirs"
   144	  local REAPER_SYMS="$TMP_DIR/reaper.$UNIQUE.syms"
   145	  local REAPER_SPECIAL="$TMP_DIR/reaper.$UNIQUE.special"
   146	
   147	  rm  -f  $REAPER_FILES  $REAPER_DIRS  $REAPER_SYMS
   148	
   149	  # convert from TRACK_ROOT to / for protected filtering,
   150	  # then to INSTALL_ROOT.
   151	  # INSTALL_ROOT is relative to /, TRACK_ROOT is arbitrary.
   152	  seperate_state_files $1 /dev/stdout /dev/null       |
   153	  log_adjuster /dev/stdin /dev/stdout log filterable  |
   154	  filter_protected                                    |
   155	  log_adjuster /dev/stdin /dev/stdout filterable root |
   156	  while read ITEM; do
   157	    if   test -h  "$ITEM"; then echo "$ITEM" >> $REAPER_SYMS
   158	    elif test -f  "$ITEM"; then echo "$ITEM" >> $REAPER_FILES
   159	    elif test -d  "$ITEM"; then echo "$ITEM" >> $REAPER_DIRS
   160	    # if it isn't a symlink, regular file or directory, assume it is a
   161	    # special file (character, block, or fifo)
   162	    elif test -e  "$ITEM"; then echo "$ITEM" >> $REAPER_SPECIAL
   163	    fi
   164	  done
   165	
   166	  if test -f $REAPER_FILES ; then
   167	    sed "s:^$INSTALL_ROOT::" $REAPER_FILES |
   168	    grep -v /var/log/sorcery               |
   169	    filter_configs -v                      |
   170	    sed "s:^:$INSTALL_ROOT:"               |
   171	    reap_config_files
   172	
   173	    sed "s:^$INSTALL_ROOT::" $REAPER_FILES |
   174	    grep -v /var/log/sorcery               |
   175	    filter_configs                         |
   176	    sed "s:^:$INSTALL_ROOT:"               |
   177	    reap_regular_files
   178	  fi
   179	
   180	  [ -f $REAPER_SYMS ] && rm -f `cat $REAPER_SYMS` 2>/dev/null
   181	  [ -f $REAPER_SPECIAL ] && rm -f `cat $REAPER_SPECIAL` 2>/dev/null
   182	  [ -f $REAPER_DIRS ] && rmdir `sort -r $REAPER_DIRS` 2>/dev/null
   183	  [ -f $REAPER_FILES ] && rmdir `get_dirnames < $REAPER_FILES |uniq|sort -r` 2>/dev/null
   184	
   185	  rm  -f  $REAPER_FILES  $REAPER_DIRS  $REAPER_SYMS $REAPER_SPECIAL
   186	}
   187	
   188	#---------------------------------------------------------------------
   189	## @param file
   190	##
   191	## First argument is a file containing install log, removes state files
   192	##
   193	#---------------------------------------------------------------------
   194	function reap_state_files()  {
   195	#  Example:  reaper "$INSTALL_LOG"  "$MD5_LOG"
   196	
   197	  debug  "libdispel" "Running reap_state_files() on $1"
   198	
   199	  local UNIQUE="$$.$RANDOM"
   200	  local REAPER_FILES="$TMP_DIR/reaper.$UNIQUE.files"
   201	  local REAPER_DIRS="$TMP_DIR/reaper.$UNIQUE.dirs"
   202	  local REAPER_SYMS="$TMP_DIR/reaper.$UNIQUE.syms"
   203	
   204	  rm  -f  $REAPER_FILES  $REAPER_DIRS  $REAPER_SYMS
   205	
   206	  # convert from TRACK_ROOT to / for protected filtering,
   207	  # then to INSTALL_ROOT.
   208	  # INSTALL_ROOT is relative to /, TRACK_ROOT is arbitrary.
   209	  seperate_state_files $1 /dev/null /dev/stdout       |
   210	  log_adjuster /dev/stdin /dev/stdout log root        |
   211	  grep -v ${LOG_DIRECTORY#$STATE_ROOT}                |
   212	  while read ITEM; do
   213	    if   test -h  "$ITEM"; then echo "$ITEM" >> $REAPER_SYMS
   214	    elif test -f  "$ITEM"; then echo "$ITEM" >> $REAPER_FILES
   215	    elif test -d  "$ITEM"; then echo "$ITEM" >> $REAPER_DIRS
   216	    fi
   217	  done
   218	
   219	  if test -f $REAPER_FILES ; then
   220	    cat $REAPER_FILES | xargs rm
   221	  fi
   222	
   223	  [ -f $REAPER_SYMS ] && rm -f `cat $REAPER_SYMS` 2>/dev/null
   224	  [ -f $REAPER_DIRS ] && rmdir `sort -r $REAPER_DIRS` 2>/dev/null
   225	  [ -f $REAPER_FILES ] && rmdir `get_dirnames < $REAPER_FILES |uniq|sort -r` 2>/dev/null
   226	
   227	  rm  -f  $REAPER_FILES  $REAPER_DIRS  $REAPER_SYMS
   228	
   229	  # bug 8826, if we dont explicitly remove the directory it can form
   230	  # a corrupt zombified tablet page
   231	  [[ "$TABLET_PAGE" ]] && test -d "$TABLET_PAGE" && rm -rf "$TABLET_PAGE"
   232	  return 0
   233	}
   234	
   235	#-----
   236	## Checks that a spell is indeed installed.
   237	## @return true Can be dispelled
   238	## @return false Cannot be dispelled
   239	#-----
   240	function dispel_not_possible()  {
   241	
   242	  if  ! spell_ok $SPELL ; then
   243	    message  "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}"              \
   244	             "${PROBLEM_COLOR}is not installed${DEFAULT_COLOR}."
   245	  else
   246	    false
   247	  fi
   248	
   249	}
   250	
   251	#-----
   252	## Does the sustained checks for spells
   253	#-----
   254	function dispel_sustained()  {
   255	
   256	  if  [  "$SUSTAIN"  ==  "on"  ]  &&
   257	      grep  -q  "^$SPELL$"  $SUSTAINED
   258	  then
   259	    message "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}"          \
   260	            "${PROBLEM_COLOR}is sustained${DEFAULT_COLOR}."
   261	  else
   262	    false
   263	  fi
   264	
   265	}
   266	
   267	#-----
   268	## Find out where a spell is located
   269	## @Globals SPELL
   270	#-----
   271	function load_spell()  {
   272	  local SPELL=$1
   273	  if tablet_set_spell $SPELL ; then
   274	    load_functions_file
   275	  else
   276	    SCRIPT_DIRECTORY="`codex_find_spell_by_name $SPELL`"
   277	
   278	    VERSION=`private_installed_version  $SPELL`
   279	    INST_LOG=$INSTALL_LOGS/$SPELL-$VERSION
   280	    MD5_LOG=$MD5SUM_LOGS/$SPELL-$VERSION
   281	    if [[ $SCRIPT_DIRECTORY ]] ; then
   282	      codex_set_current_spell $SCRIPT_DIRECTORY
   283	      load_functions_file
   284	    else
   285	      message "Spell is missing from grimoires"
   286	      message "unable to run any PRE or POST_REMOVE scripts it once had."
   287	      if ! query "Continue anyway?" y; then
   288	        return 1
   289	      fi
   290	    fi
   291	  fi
   292	}
   293	
   294	#-----
   295	## Run the PRE_REMOVE script if it exists
   296	#-----
   297	function pre_remove() {
   298	  debug  "libdispel" "pre_remove()"
   299	  if  [[ $SCRIPT_DIRECTORY ]] ; then
   300	    run_spell_file PRE_REMOVE pre_remove
   301	  fi
   302	  return 0
   303	}
   304	
   305	#-----
   306	## Run the POST_REMOVE script if it exists.
   307	#-----
   308	function post_remove() {
   309	  debug  "libdispel" "post_remove()"
   310	  if  [[ $SCRIPT_DIRECTORY ]] ; then
   311	    run_spell_file POST_REMOVE post_remove
   312	  fi
   313	  return 0
   314	}
   315	
   316	#---------------------------------------------------------------------
   317	## Dispel a spell
   318	#---------------------------------------------------------------------
   319	function dispel_spell() {
   320	
   321	    local SPELL=$1
   322	    # fake dispel, only remove sorcery metadata
   323	    if [[ $DEBUG_DISPEL ]] ; then
   324	        echo "pretending to dispel $SPELL"
   325	        load_spell $SPELL           &&
   326	        remove_spell  $SPELL &&
   327	        reap_depends &&
   328	        message  "${DISPEL_COLOR}Partly dispelled spell:"  \
   329	                 "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}"
   330	        return
   331	    fi
   332	
   333	    if  dispel_sustained  || dispel_not_possible ; then
   334	      DISPEL_EXIT_STATUS=1
   335	      return 1
   336	    fi
   337	
   338	    [[ $TRIGGER == off ]] || trigger "pre_dispel"
   339	
   340	    (
   341	      # this function messes with the environment a lot leave it in a subshell
   342	      load_spell $SPELL           &&
   343	      pre_remove                  &&
   344	      reaper  $INST_LOG  $MD5_LOG &&
   345	      post_remove                 &&
   346	      reap_state_files $INST_LOG  &&
   347	      reap_spell_config_stage     &&
   348	      remove_spell  $SPELL        &&
   349	      remove_version_cache "$VERSION_STATUS" $SPELL &&
   350	      { [[ $TRIGGER == off ]] || trigger "dispel";} &&
   351	      remove_triggers $SPELL      &&
   352	      { [[ $DEQUEUE == off ]] || pop_install_queue $SPELL; true; } &&
   353	      message  "${DISPEL_COLOR}Dispelled spell:"  \
   354	               "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}" &&
   355	      activity_log  "dispel"  "$SPELL"  "$VERSION"  "success"
   356	    ) &&
   357	    reap_depends
   358	    local rc=$?
   359	    if [[ "$rc" != 0 ]] ; then
   360	        message "${PROBLEM_COLOR}Dispel of${DEFAULT_COLOR}" \
   361	                "${SPELL_COLOR}$SPELL${DEFAULT_COLOR}" \
   362	                "${PROBLEM_COLOR}failed!${DEFAULT_COLOR}"
   363	        return $rc
   364	    fi
   365	    return 0
   366	}
   367	
   368	#---------------------------------------------------------------------
   369	## @param    default value
   370	## Set one of always, ask_yes, ask_no, and ignore to on based
   371	## on the value of default, leave the remaining as off.
   372	#---------------------------------------------------------------------
   373	function dispel_depends_value_to_items() {
   374	  always=off
   375	  ask_yes=off
   376	  ask_no=off
   377	  ignore=off
   378	  case $1 in
   379	     always) always=on ;;
   380	    ask-yes) ask_yes=on ;;
   381	     ask-no) ask_no=on ;;
   382	     ignore) ignore=on ;;
   383	          *) ignore=on ;;
   384	  esac
   385	}
   386	
   387	
   388	#---------------------------------------------------------------------
   389	## @param    Title of the menu
   390	## @param    Name of the parameter being set
   391	## @param    Default value of the parameter being set
   392	##
   393	## Present a radiolist menu with the quad-options for one of various
   394	## dependency following options.
   395	#---------------------------------------------------------------------
   396	function dispel_depends_menu_template() {
   397	  local TITLE=$1
   398	  local DEFAULT_NAME=$2
   399	  local DEFAULT=$3
   400	  local always ask_yes ask_no ignore rc
   401	  dispel_depends_value_to_items $DEFAULT
   402	  RESULT=`eval $DIALOG ' --title "$TITLE"   \
   403	           --radiolist                     \
   404	           ""                              \
   405	           0 0 0                           \
   406	           always  "" $always              \
   407	           ask-yes "" $ask_yes             \
   408	           ask-no  "" $ask_no              \
   409	           ignore  "" $ignore'`
   410	  rc=$?
   411	  if [[ $rc == 0 ]] ; then
   412	    # remove spurious ""
   413	    RESULT=`echo "${RESULT}" | sed -e 's/^"//' -e 's/"$//'`
   414	    modify_local_config $DEFAULT_NAME "$RESULT"
   415	    eval "$DEFAULT_NAME=\"$RESULT\""
   416	  fi
   417	}
   418	
   419	#---------------------------------------------------------------------
   420	## Present menus for each of the four dependency following options.
   421	#---------------------------------------------------------------------
   422	function dispel_depends_defaults_menu() {
   423	  dispel_depends_menu_template \
   424	               "Default action for orphaned spells"   \
   425	               "ORPHAN_MENU_DEFAULT" "$ORPHAN_MENU_DEFAULT"
   426	  dispel_depends_menu_template \
   427	               "Default action for non-orphaned spells"   \
   428	               "NONORPHAN_MENU_DEFAULT" "$NONORPHAN_MENU_DEFAULT"
   429	  dispel_depends_menu_template \
   430	               "Default action for recasting repairable parents spells"   \
   431	               "RECAST_PARENT_MENU_DEFAULT" "$RECAST_PARENT_MENU_DEFAULT"
   432	  dispel_depends_menu_template \
   433	               "Default action for broken parent spells"   \
   434	               "DISPEL_PARENT_MENU_DEFAULT" "$DISPEL_PARENT_MENU_DEFAULT"
   435	
   436	}
   437	
   438	#---------------------------------------------------------------------
   439	##
   440	## This software is free software; you can redistribute it and/or modify
   441	## it under the terms of the GNU General Public License as published by
   442	## the Free Software Foundation; either version 2 of the License, or
   443	## (at your option) any later version.
   444	##
   445	## This software is distributed in the hope that it will be useful,
   446	## but WITHOUT ANY WARRANTY; without even the implied warranty of
   447	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   448	## GNU General Public License for more details.
   449	##
   450	## You should have received a copy of the GNU General Public License
   451	## along with this software; if not, write to the Free Software
   452	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   453	##
   454	#---------------------------------------------------------------------