/usr/sbin/cast

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	## @Synopsis cast is the spell installation utility. It can be called by the user or by sorcery
     4	## @Copyright Original version Copyright 2001 by Kyle Sallee
     5	## @Copyright Some parts copyright 2002 Anders Bruun Olsen et al
     6	## @Copyright Other additions/corrections Copyright 2002 by the Source Mage Team
     7	## Script to cast spells.
     8	#---------------------------------------------------------------------
     9	
    10	#-----
    11	## Help... hmm... I wonder what it does...
    12	#-----
    13	function help">help">help() {
    14	
    15	  cat  <<  EOF
    16	
    17	Cast installs single or multiple spells
    18	
    19	Example:          cast  nano hdparm sudo
    20	Usage:            cast  [parameters]  [spell]
    21	
    22	Optional Parameters:
    23	
    24	       --cflags   "flags"       Custom CFLAGS
    25	       --cxxflags "flags"       Custom CXXFLAGS
    26	       --cppflags "flags"       Custom CPPFLAGS
    27	       --ldflags  "flags"       Custom LDFLAGS
    28	       --no-opts                Turn off setting optimization flags, except
    29	                                for those found in --cflags, --cxxflags,
    30	                                --cppflags and --ldflags.
    31	
    32	-V [on|off]                     Override \$VOYEUR setting
    33	
    34	-d  |  --download               Force download of sources (overwrite existing
    35	                                files)
    36	
    37	-s                              Download all given spells before compiling
    38	       --deps                   Configure spells and determine dependencies,
    39	                                only cast dependencies, not spells themselves
    40	
    41	-c  |  --compile                Recompile the spells (don't install from cache).
    42	-r  |  --reconfigure            Select new dependencies for spells (implies -c)
    43	
    44	-g  |  --grimoire  [...]        Use only the specified grimoires for this cast
    45	                                NOTE: If there are any cross-grimoire
    46	                                dependencies on unspecified grimoires they
    47	                                will not work. The target spell will
    48	                                not be found. To avoid this, specify all
    49	                                relevant grimoires to the -g parameter
    50	                                in the order you wish them to be searched.
    51	
    52	-R  |  --recast-down            Recursively recast depended-upon spells, even
    53	                                if they are already installed. You probably
    54	                                also want to pass the -c flag to make sure they
    55	                                are recompiled, not resurrected.
    56	
    57	-B  |  --recast-up              Recursively recast dependent spells. You
    58	                                probably also want to pass the -c flag to make
    59	                                sure they are recompiled, not resurrected.
    60	
    61	-O  |  --recast-optional [option] If a spell being built has spells which
    62	                                   could optionally depend on it, but those
    63	                                   dependencies are disabled, ask to recast
    64	                                   the dependee. Optional parameter can be
    65	                                   option can be one of: "always", "ask-yes",
    66	                                   "ask-no", or "ignore"; it defaults to what
    67	                                   is set via the sorcery menu. Implies -c.
    68	
    69	-Z  |  --lazy-updates [option]  Perform updates on installed spells that
    70	                                need updates. Optional parameter same as
    71	                                above.
    72	
    73	-b  |  --force-base-dep         Force all spells to depend on basesystem
    74	
    75	       --from   directory       Specify an alternate for $SOURCE_CACHE
    76	
    77	       --queue                  Cast all spells listed in $INSTALL_QUEUE
    78	
    79	EOF
    80	
    81	  exit  1
    82	
    83	}
    84	
    85	#---------------------------------------------------------------------
    86	## @Aguments Arguments of cast
    87	## @Globals DEPS_ONLY RECONFIGURE COMPILE
    88	## @Globals FORCE_DOWNLOAD SOURCE_CACHE SILENT SEPARATE
    89	## @Globals INSTALL_QUEUE
    90	##
    91	#---------------------------------------------------------------------
    92	function process_parameters">process_parameters">process_parameters()  {
    93	
    94	  local n
    95	  while  [  -n  "$1"  ];  do
    96	
    97	    if  echo  "" $1  |  grep  -q  "^ -";  then
    98	
    99	      case  $1  in
   100	
   101	            --cflags)  export OVERRIDE_CFLAGS="$2";    COMPILE="-c"; shift 2  ;;
   102	          --cxxflags)  export OVERRIDE_CXXFLAGS="$2";  COMPILE="-c"; shift 2  ;;
   103	          --cppflags)  export OVERRIDE_CPPFLAGS="$2";  COMPILE="-c"; shift 2  ;;
   104	           --ldflags)  export OVERRIDE_LDFLAGS="$2";   COMPILE="-c"; shift 2  ;;
   105	           --no-opts)  export NO_OPTIMIZATION_FLAGS=1; COMPILE="-c"; shift 1  ;;
   106	                  -V)  export VOYEUR_OVERRIDE="$2";                  shift 2  ;;
   107	              --deps)  export  DEPS_ONLY="$1";                       shift 1  ;;
   108	      -g|--grimoire*)  override_grimoires "$2";                      shift 2  ;;
   109	    -r|--reconfigure)  RECONFIGURE="$1"; COMPILE="-c";               shift 1  ;;
   110	    -R|--recast-down)  RECAST_DOWN="$1";                             shift 1  ;;
   111	      -B|--recast-up)  RECAST_UP="$1";                               shift 1  ;;
   112	-O|--recast-optional) get_option "$2" "$DEFAULT_RECAST_OPTIONALS" \
   113	                                 RECAST_OPTIONALS n; COMPILE="-c";
   114	                                                                     shift $n ;;
   115	   -Z|--lazy-updates) get_option "$2" "$DEFAULT_LAZY_DEPENDS_UPDATE" \
   116	                                 LAZY_DEPENDS_UPDATES n
   117	                                                                     shift $n ;;
   118	 -b|--force-base-dep)  FORCE_BASESYSTEM_DEPENDS=on;                  shift 1  ;;
   119	        -c|--compile)  COMPILE="$1";                                 shift 1  ;;
   120	       -d|--download)  export  FORCE_DOWNLOAD="$1"; COMPILE="-c";    shift 1  ;;
   121	              --from)  export  SOURCE_CACHE=$2;                      shift 2  ;;
   122	            --silent)  SILENT="$1";                                  shift 1  ;;
   123	                  -s)  export  SEPARATE="$1";                        shift 1  ;;
   124	             --queue)  CAST_QUEUE=yes ; COMPILE=$1;                  shift 1  ;;
   125	                   *)  help">help">help                                   ;;
   126	      esac
   127	
   128	    else
   129	
   130	      shift
   131	
   132	   fi
   133	
   134	  done
   135	
   136	}
   137	
   138	#---------------------------------------------------------------------
   139	## @Arguments cast's arguments
   140	## Goes through arguments and prints spells or parameters that are no
   141	## switches rather.
   142	#---------------------------------------------------------------------
   143	function strip_parameters">strip_parameters()  {
   144	  local x n
   145	
   146	  while  [  -n  "$1"  ];  do
   147	
   148	    if  echo  "" $1  |  grep  -q  "^ -";  then
   149	
   150	      case  $1  in
   151	
   152	                  --deps)  shift 1  ;;
   153	                --cflags)  shift 2  ;;
   154	              --cxxflags)  shift 2  ;;
   155	              --cppflags)  shift 2  ;;
   156	               --ldflags)  shift 2  ;;
   157	               --no-opts)  shift 1  ;;
   158	                      -V)  shift 2  ;;
   159	          -g|--grimoire*)  shift 2  ;;
   160	        -R|--recast-down)  shift 1  ;;
   161	          -B|--recast-up)  shift 1  ;;
   162	    -O|--recast-optional)  get_option "$2" "" x n ; shift $n  ;;
   163	       -Z|--lazy-updates)  get_option "$2" "" x n ; shift $n  ;;
   164	     -b|--force-base-dep)  shift 1  ;;
   165	        -r|--reconfigure)  shift 1  ;;
   166	                  --from)  shift 2  ;;
   167	                --silent)  shift 1  ;;
   168	            -c|--compile)  shift 1  ;;
   169	           -d|--download)  shift 1  ;;
   170	                      -s)  shift 1  ;;
   171	                 --queue)  shift 1  ;;
   172	                       *)  shift 1  ;;
   173	
   174	      esac
   175	
   176	    else
   177	
   178	      echo  $1
   179	      shift
   180	
   181	   fi
   182	
   183	  done
   184	
   185	}
   186	
   187	#---------------------------------------------------------------------
   188	## Look for optional parameter and use default otherwise
   189	## specify via upvar how much to shift parameters
   190	#---------------------------------------------------------------------
   191	function get_option() {
   192	  local param=$1
   193	  local default=$2
   194	  local answer=$3
   195	  local up_shift=$4
   196	  local _answer=$2
   197	  local _up_shift=1
   198	  case "$param" in
   199	    always|ask-yes|ask-no|ignore) _answer=$param; _up_shift=2 ;;
   200	    *) _answer=$default ;;
   201	  esac
   202	  upvar "$answer" "$_answer"
   203	  upvar "$up_shift" "$_up_shift"
   204	}
   205	
   206	#---------------------------------------------------------------------
   207	## Cast a single spell. When this function is called, all dependencies
   208	## have been taken care of and we are allowed to cast this.
   209	## @Globals SPELL
   210	#---------------------------------------------------------------------
   211	function cast_spell()  { (
   212	
   213	  debug "cast" "Casting spell [$SPELL]"
   214	  set_term_title "Casting spell [$SPELL]"
   215	
   216	  run_details
   217	  load_build_api || return 1
   218	
   219	  dispel_conflicts $SPELL || return 1
   220	
   221	  # show_downloading tail -f's (essentially) the download log as it
   222	  # comes in, or if downloading is complete, cats the download log, in
   223	  # either case it blocks until downloading is complete by the presence of
   224	  # a ${download_log}.done file. If SEPARATE is set, then all downloading
   225	  # is done first, so there is no need to wait for it to complete.
   226	  if [[ ! $SEPARATE ]] ; then
   227	    show_downloading $SPELL
   228	  fi
   229	
   230	  verify_sources ||   return 1
   231	
   232	  # wait for solo casts, to finish and ensure that others can't
   233	  acquire_cast_lock
   234	
   235	  # all this needs to reorganized and stuff...later
   236	
   237	  export IW_LOG="$TMP_DIR/$SPELL.iw"
   238	
   239	  #some minor discussion occured about having this, i'll leave it out for now
   240	  activity_log  "cast"  "$SPELL"  "$VERSION"  "start"
   241	
   242	  # must declare OPTS before sourcing config
   243	  local OPTS
   244	  export OPTS
   245	  run_spell_config
   246	
   247	  libtrack_init
   248	
   249	  local spell_depends spell_sub_depends
   250	  get_uncommitted_depends_file $SPELL spell_depends
   251	  test -e $spell_depends &&
   252	  OPTS="$OPTS $(get_depends_options $spell_depends $SPELL)"
   253	
   254	  get_uncommitted_sub_depends_file $SPELL spell_sub_depends
   255	  test -e $spell_sub_depends &&
   256	  local PROCESSED_SUB_DEPENDS=$(cut -f3 -d: $spell_sub_depends|tr '\n' ' ')
   257	
   258	  # HACK for bug 2910 and 10546
   259	  local saved_lc_all=$LC_ALL
   260	  export LC_ALL=C
   261	
   262	  export DISTCC_DIR="$SOURCE_DIRECTORY/.distcc"
   263	
   264	  # this will run through the whole build process
   265	  run_build_spell">run_build_spell
   266	  rc=$?
   267	
   268	  # HACK for bug 2910 and 10546
   269	  if [[ -n ${saved_lc_all} ]] ; then
   270	    export LC_ALL=$saved_lc_all
   271	  else
   272	    unset LC_ALL
   273	  fi
   274	
   275	  # This is the home for anything and everything we do
   276	  # when a phase4 succeeds or fails, no more spreading things out
   277	  # into multiple functions.
   278	
   279	  cd /
   280	
   281	  # hooks back out to the build_api to do whatever needs to be done
   282	  if [ $rc == 0 ] ; then
   283	    run_spell_success
   284	  else
   285	    run_spell_failure $rc
   286	  fi
   287	
   288	
   289	  unlock_resources "cast" "$SPELL"
   290	  #It's OK to try to release a lock you don't have
   291	  unlock_resources "solo" "cast"
   292	
   293	  return $rc
   294	
   295	) }
   296	
   297	##Removed *_solo functions, Duff 2002/11/01
   298	
   299	#---------------------------------------------------------------------
   300	## @Globals SPELLS
   301	## @Stdout User information ("Collating dependencies")
   302	## @Globals SPELL DEPS_ONLY
   303	##
   304	## Do dependency resolution. Takes the spells in the $SPELLS variable
   305	## and resolves them. A superset list is created called $SPELLS_TO_CAST
   306	#---------------------------------------------------------------------
   307	function pass_one()  {
   308	  #  This pass does configuration and dependency identification.
   309	  debug "cast" "Starting pass_one()"
   310	
   311	  echo -n "Computing previously installed dependencies..."
   312	  compute_installed_depends "dep_f_hash"
   313	  echo
   314	  compute_uninstalled_depends "to_cast" "back_hash" "bad_spells" $SPELLS
   315	
   316	  SPELLS_TO_CAST=$(hash_get_table_fields "to_cast"|tr '\n' ' ')
   317	
   318	  SPELLS="$SPELLS ${BONUS_SPELLS[*]}"
   319	
   320	  # special case of no spell making it through dependency resolution
   321	  # or if DEPS_ONLY is set, there arent any dependent spells to cast
   322	  if [ -z "$SPELLS_TO_CAST" ] ; then
   323	    local cannot_cast=$(hash_get_table_fields "bad_spells")
   324	    message "${PROBLEM_COLOR}No spells to cast!${DEFAULT_COLOR}"
   325	    message "${MESSAGE_COLOR}Cannot cast these spells:${DEFAULT_COLOR}"
   326	    message "---------------------------$PROBLEM_COLOR"
   327	
   328	    local failure_reason_log=$CAST_BACKUPDIR/failure_reason_log
   329	    local spell
   330	    for spell in $cannot_cast; do
   331	      grep -s "^$spell " $failure_reason_log ||
   332	      message "$spell"
   333	    done | sort -u | column
   334	    rm -f $failure_reason_log
   335	
   336	    message "${DEFAULT_COLOR}"
   337	    exit 1
   338	  fi
   339	
   340	  # if only doing the deps, find the dependencies and make them the
   341	  # SPELLS list, then recompute the full list of spells that needs to be cast
   342	  if  [[ "$DEPS_ONLY" ]] ;  then
   343	    local dep_spell
   344	    SPELLS=$(
   345	      for spell in $SPELLS; do
   346	        local dep_spells
   347	        hash_get_ref to_cast $spell dep_spells
   348	        for dep_spell in $dep_spells; do
   349	          spell_ok $dep_spell || echo $dep_spell
   350	        done
   351	      done|sort -u)
   352	    spells=( $SPELLS )
   353	    hash_reset deps_only
   354	    hash_reset looked_at
   355	    for ((i=0;$i<${#spells[@]}; i++)); do
   356	      if [[ "${spells[$i]}" ]] &&
   357	         ! [[ $(hash_get looked_at "${spells[$i]}") ]] ; then
   358	        hash_put looked_at "${spells[$i]}" done
   359	        if ! spell_ok ${spells[$i]}; then
   360	          hash_put deps_only ${spells[$i]} done
   361	          hash_get_ref to_cast "${spells[$i]}" new_spells
   362	        fi
   363	        spells=( ${spells[@]} $new_spells )
   364	        unset new_spells
   365	      fi
   366	    done
   367	    SPELLS_TO_CAST=$(hash_get_table_fields "deps_only"|tr '\n' ' ')
   368	    hash_reset deps_only
   369	    hash_reset looked_at
   370	    if [ -z "$SPELLS_TO_CAST" ] ; then
   371	      local parents=$(hash_get_table_fields "to_cast")
   372	      message "${PROBLEM_COLOR}No spells to cast!${DEFAULT_COLOR}"
   373	      message "${MESSAGE_COLOR}None of the spells have dependencies" \
   374	              "to cast:${DEFAULT_COLOR}"
   375	      message "---------------------------"
   376	      message "${PROBLEM_COLOR}${parents}" | tr '[:blank:]' '\n' | sort | column
   377	      message "${DEFAULT_COLOR}"
   378	      exit 1
   379	    fi
   380	  fi
   381	
   382	  message "${MESSAGE_COLOR}Collating dependencies...${DEFAULT_COLOR}"
   383	
   384	  # have new depends overwrite existing ones
   385	  for i in $SPELLS_TO_CAST; do
   386	    local dependencies
   387	    hash_get_ref to_cast $i dependencies
   388	    hash_put dep_f_hash $i "$dependencies"
   389	  done
   390	
   391	  debug "cast" "pass_one, done with SPELLS=$SPELLS"
   392	
   393	}
   394	
   395	
   396	#---------------------------------------------------------------------
   397	## @Arguments Spells to be cast
   398	## @Stdout the "Spells are to be cast" message.
   399	## @Stdin User interface, y or n
   400	## @Globals SEPARATE
   401	## Asks whether you want to cast the listed spells or not.
   402	## Returns if not.
   403	## Then it starts pass three and four by calling make.
   404	## Depending on SEPARATE it starts pass three in the background
   405	## or not.
   406	#---------------------------------------------------------------------
   407	function pass_two()  {
   408	  #  This pass downloads required sources.
   409	  #  And starts the make process
   410	  debug "cast" "Starting pass_two()"
   411	
   412	  unset_details
   413	
   414	  message "${MESSAGE_COLOR}Spells are to be cast:${DEFAULT_COLOR}"
   415	  message "---------------------------"
   416	  message "${SPELL_COLOR}${SPELLS_TO_CAST}" | tr '[:blank:]' '\n' | column
   417	  message "${DEFAULT_COLOR}"
   418	
   419	  if ! query "Do you want to cast these spells?" "y" ; then
   420	    message "Ok, quitting cast. Figure out what you want."
   421	    # conflicts are already registered, but they weren't removed, so don't show them
   422	    :> $CONFLICT_LIST
   423	    return 1
   424	  fi
   425	
   426	  echo
   427	
   428	  rm -f $TMP_DIR/pass_three.done # don't return until this file exists
   429	  MINUS_K=yes
   430	  if  [[  $SEPARATE   ]] ; then
   431	    ( CAST_PASS="three"
   432	      depengine_entry_point "$SPELLS" "$SPELLS_TO_CAST"
   433	      if [[ $SCREEN_NAME ]] ; then
   434	        screen_notify "$SCREEN_NAME" "Done downloading"
   435	        screen_kill_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN
   436	      fi
   437	      touch $TMP_DIR/pass_three.done
   438	    )
   439	  else
   440	    ( CAST_PASS="three"
   441	      trap "exit 1" INT TERM # this keep a rather nasty message
   442	                                    # from appearing if we get killed
   443	      depengine_entry_point "$SPELLS" "$SPELLS_TO_CAST"
   444	      if [[ $SCREEN_NAME ]] ; then
   445	        screen_notify "$SCREEN_NAME" "Done downloading"
   446	        screen_kill_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN
   447	      fi
   448	      touch $TMP_DIR/pass_three.done &>/dev/null
   449	    ) &
   450	  fi
   451	
   452	  debug "cast" "Starting stage four make."
   453	
   454	  (
   455	    CAST_PASS="four"
   456	    depengine_entry_point "$SPELLS" "$SPELLS_TO_CAST"
   457	    touch $TMP_DIR/pass_four.done
   458	  )
   459	
   460	
   461	  # pass three might not finish, give it a short amount of time to complete
   462	  # in case its near the end of a download or something, if after a minute
   463	  # it doesn't finish just kill everything off.
   464	  # in 1.14 this may be improved, see bug 8763
   465	  local i
   466	  let i=0
   467	  if ! test -e $TMP_DIR/pass_three.done; then
   468	    message "Download pass has not completed yet, pausing momentarily"
   469	  fi
   470	  while ! test -e $TMP_DIR/pass_three.done; do
   471	    sleep 5
   472	    let i+=5
   473	    if [[ $i -gt 60 ]] ; then
   474	      message "Download pass did not finish, killing it off."
   475	      # this is rather violent, but job control in bash lame and theres
   476	      # no other way to kill everything off effectively :-(
   477	      ps x|grep $TMP_DIR|awk '{print $1}'|grep -v $$|xargs kill &>/dev/null
   478	      echo -n .; sleep 1
   479	      ps x|grep $TMP_DIR|awk '{print $1}'|grep -v $$|xargs kill &>/dev/null
   480	      echo -n .; sleep 1
   481	      ps x|grep $TMP_DIR|awk '{print $1}'|grep -v $$|xargs kill -9 &>/dev/null
   482	      echo -n .;  sleep 1
   483	      echo
   484	      break
   485	    fi
   486	  done
   487	
   488	}
   489	
   490	#---------------------------------------------------------------------
   491	## @param spellname
   492	## @Globals SPELL
   493	## Sets SPELL to the spellname and calls summon_spell with spellname
   494	## as argument. This is equivalent to calling summon, but without the
   495	## overhead.
   496	## (Is being called by make)
   497	## If in screen mode it also execs a tail to the summon window
   498	#---------------------------------------------------------------------
   499	function pass_three()  {
   500	  debug "cast" "pass_three - $*"
   501	  unset CAST_PASS
   502	  trap "exit 1" INT TERM
   503	  local SPELL=$1
   504	
   505	  # download_log is removed with it's .done in libcast
   506	  local download_log=$(get_spell_dl_log $SPELL)
   507	
   508	  if [[ $SCREEN_NAME ]] && [ ! -p $TMP_DIR/download.fifo ] ; then
   509	    # Create the summon window
   510	    mkfifo $TMP_DIR/download.fifo
   511	    # Neither tail not cat work properly on FIFOs so a while loop will
   512	    # have to be used
   513	    screen_new_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN "Summon $SPELL" \
   514	      /bin/bash -c  'while : ; do
   515	          read LINE && echo $LINE || sleep 0.1 ;
   516	        done < '$TMP_DIR/download.fifo
   517	    sleep 0.1
   518	  fi
   519	  if [[ $SCREEN_NAME ]] ; then
   520	    # A summon window is already up, just change the name
   521	    screen_name_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN "Summon $SPELL"
   522	    # symlink the d/l log to the fifo
   523	    ln -s $TMP_DIR/download.fifo $download_log
   524	  else
   525	    # normal non-screen cast, create a normal file
   526	    touch $download_log
   527	  fi
   528	
   529	  # check if this is being resurrected and if so, don't summon
   530	  # this will go away when resurrect support and dependency resolution merge
   531	  if ! [[ $COMPILE ]] ; then
   532	    VERSION=$(codex_set_current_spell_by_name $SPELL &> /dev/null;echo $VERSION)
   533	    if [[ $VERSION ]] && can_resurrect $SPELL $VERSION &> /dev/null ; then
   534	      # The 2>/dev/null is necessary because the dir may not exist
   535	      echo "pass_three thought that $SPELL was being resurrected" \
   536	        > $download_log 2>/dev/null
   537	      # touch the 'log' file just in case the spell disagreed so cast doesnt
   538	      # hang forever
   539	      touch ${download_log}.done &>/dev/null
   540	      return
   541	    fi
   542	  fi
   543	
   544	  if  [[  $SEPARATE   ]] ; then
   545	    summon_spell "$SPELL" &> "$download_log"
   546	  else
   547	    lock_file   $download_log
   548	    summon_spell "$SPELL" &> "$download_log"
   549	    unlock_file   $download_log
   550	  fi
   551	
   552	  # This is to notify show_downloading/cast_spell that it is done with
   553	  # this source
   554	  touch "${download_log}.done"
   555	}
   556	
   557	#---------------------------------------------------------------------
   558	## @param spellname
   559	## @Globals SPELL COMPILE
   560	## Sets SPELL to spellname.
   561	## Calls trigger "pre_cast"
   562	## If COMPILE is not set, the spell doesn't need an update and it can
   563	## be resurrected (can_resurrect SPELL) it calls resurrect with SPELL.
   564	## Otherwise it calls cast_spell.
   565	## If resurrect or cast_spell returned 0 it calls trigger "cast"
   566	## (Is being called by make)
   567	#---------------------------------------------------------------------
   568	function pass_four()  {
   569	
   570	  debug "cast" "pass_four - $*"
   571	  local do_resurrect=no
   572	  local VERSION
   573	  unset CAST_PASS
   574	  SPELL=$1
   575	
   576	  trigger "pre_cast"
   577	
   578	  if ! [[ $COMPILE ]] ; then
   579	    # hacky way to get the latest version
   580	    VERSION=$(codex_set_current_spell_by_name $SPELL &> /dev/null;echo $VERSION)
   581	    if [[ ! $VERSION ]] ; then
   582	      message "Can't find spell version for some reason, is $SPELL a spell?"
   583	    else
   584	      can_resurrect $SPELL $VERSION &> /dev/null &&
   585	      ! does_spell_need_update $SPELL &> /dev/null &&
   586	      do_resurrect=yes
   587	    fi
   588	  fi
   589	
   590	  # this is a hacky way to tell what version we're updating from
   591	  # if any, we can use it to find md5 logs for installing config type
   592	  # files, it mostly is here for libresurrect.real_install_config_file
   593	  local OLD_SPELL_VERSION=$(installed_version $SPELL)
   594	
   595	  local rc
   596	  if [[ "$do_resurrect" == "yes" ]] ; then
   597	    resurrect_spell $SPELL $VERSION
   598	    rc=$?
   599	    # this is here for safety in case resurrect bails out somewhere
   600	    # we didnt expect it to
   601	    unlock_resources "libgrimoire" "install"
   602	    unlock_resources "cast" "$SPELL"
   603	    unlock_resources "solo" "cast"
   604	  else
   605	    cast_spell $*
   606	    rc=$?
   607	  fi
   608	
   609	  return $rc
   610	}
   611	
   612	
   613	#---------------------------------------------------------------------
   614	## @Globals SUCCESS_LIST FAILED_LIST CHECK_TRIGGERS_SUCCESS
   615	## CHECK_TRIGGERS_FAILURE
   616	## Does report generation.
   617	#---------------------------------------------------------------------
   618	function pass_five()  {
   619	
   620	  debug "cast" "Function : pass_five"
   621	  local rc=0
   622	  local notice_log=$TMP_DIR/notice_log
   623	
   624	  if [[ -s $notice_log ]]; then
   625	    message "$DEFAULT_COLOR"
   626	    message "${MESSAGE_COLOR}Spell notices are repeated below:"
   627	    message "-----------------------------------------------$DEFAULT_COLOR"
   628	    cp $notice_log $CAST_BACKUPDIR
   629	    if (( $(wc -l < $notice_log) > 40 )); then
   630	      cat - $notice_log > $notice_log.2 <<< "Spell notices are repeated below:"
   631	      mv $notice_log.2 $notice_log
   632	      timeout_pager $notice_log
   633	    else
   634	      cat $notice_log
   635	    fi
   636	    message "These notices are backed up to $CAST_BACKUPDIR/notice_log ."
   637	    message "$DEFAULT_COLOR"
   638	  fi
   639	
   640	  # must exist or we get problems with checks here.
   641	  touch $SUCCESS_LIST
   642	  touch $FAILED_LIST
   643	  touch $CHECK_TRIGGERS_SUCCESS
   644	  touch $CHECK_TRIGGERS_FAILURE
   645	  touch $CONFLICT_LIST
   646	
   647	  debug "pass_five" "SUCCESS LIST is : `cat $SUCCESS_LIST 2>/dev/null`"
   648	  debug "pass_five" "FAILED LIST is : `cat $FAILED_LIST 2>/dev/null`"
   649	  debug "pass_five" "CONFLICT LIST is : `cat $CONFLICT_LIST 2>/dev/null`"
   650	  debug "pass_five" "CHECK_TRIGGERS_SUCCESS is : `cat $CHECK_TRIGGERS_SUCCESS 2>/dev/null`"
   651	  debug "pass_five" "bad_spells is : `hash_get_table_fields bad_spells`"
   652	  debug "pass_five" "to_cast is : `hash_get_table_fields to_cast`"
   653	
   654	  if [ -s $SUCCESS_LIST ] ; then
   655	
   656	    message "${MESSAGE_COLOR}Finished processing install requests."
   657	    message ""
   658	    message "Spells installed successfully:"
   659	    message "------------------------------${SPELL_COLOR}"
   660	
   661	    for item in `cat $SUCCESS_LIST 2>/dev/null`; do
   662	      message "$item"
   663	    done | sort | column
   664	
   665	    set_term_title "Casting successful."
   666	    message "${DEFAULT_COLOR}"
   667	
   668	  fi
   669	
   670	  if  [  -s  $CHECK_TRIGGERS_SUCCESS ] ; then
   671	    message "${DEFAULT_COLOR}"
   672	    message "${MESSAGE_COLOR}Spells that had a check_self trigger succeed:"
   673	    message "---------------------------------------------${SPELL_COLOR}"
   674	    for item in `cat $CHECK_TRIGGERS_SUCCESS 2>/dev/null`; do
   675	      message "$item"
   676	    done | sort | column
   677	    message "${DEFAULT_COLOR}"
   678	  fi
   679	
   680	  if  [  -s  $CHECK_TRIGGERS_FAILURE ] ; then
   681	    message "${DEFAULT_COLOR}"
   682	    message "${MESSAGE_COLOR}Spells that had a check_self trigger fail:"
   683	    message "------------------------------------------${SPELL_COLOR}"
   684	    for item in `cat $CHECK_TRIGGERS_FAILURE 2>/dev/null`; do
   685	      message "$item"
   686	    done | sort | column
   687	    message "${DEFAULT_COLOR}"
   688	  fi
   689	
   690	  local NOT_CAST
   691	  NOT_CAST=$( { hash_get_table_fields to_cast
   692	    hash_get_table_fields bad_spells
   693	    cat $SUCCESS_LIST $FAILED_LIST $CHECK_TRIGGERS_SUCCESS
   694	    } | sort | uniq -u ) # all not caught otherwise
   695	  if [[ "$NOT_CAST" ]] ;then
   696	    message "${DEFAULT_COLOR}" #being paranoid
   697	    message "${MESSAGE_COLOR}Spells that have been dropped:"
   698	    message "------------------------------${QUERY_COLOR}"
   699	    message "$NOT_CAST" | sort | column
   700	    message "${DEFAULT_COLOR}"
   701	  fi
   702	
   703	  if  [  -s  $CONFLICT_LIST   ] ; then
   704	    message "${DEFAULT_COLOR}"
   705	    message "${MESSAGE_COLOR}Spells that have been removed due to conflicts:"
   706	    message "-----------------------------------------------${QUERY_COLOR}"
   707	    for item in $(cut -d" " -f2- $CONFLICT_LIST 2>/dev/null); do
   708	      message "$item"
   709	    done | sort | column
   710	    message "${DEFAULT_COLOR}"
   711	  fi
   712	
   713	  #
   714	  # To check for failed spells, we only need to see what is remaining in the
   715	  # install queue.
   716	  #
   717	  if  [  -s  $FAILED_LIST   ] ; then
   718	    local failure_reason_log=$CAST_BACKUPDIR/failure_reason_log
   719	    message "${DEFAULT_COLOR}"
   720	    message "${MESSAGE_COLOR}Spells that encountered problems:"
   721	    message "---------------------------------${PROBLEM_COLOR}"
   722	
   723	    while read item; do
   724	      grep -s "^$item " $failure_reason_log ||
   725	      message "$item"
   726	    done < $FAILED_LIST | sort -u | column
   727	    rm -f $failure_reason_log
   728	
   729	    set_term_title "Casting failed."
   730	    message "${DEFAULT_COLOR}"
   731	    rc=1
   732	
   733	  fi
   734	
   735	  if [[ "$CAST_QUEUE" == "yes" ]] ; then
   736	    if  [  -s  $INSTALL_QUEUE  ] ; then
   737	      message "${MESSAGE_COLOR}The install queue is not empty, "
   738	      message "it still contains the following spells: "
   739	      message "---------------------------------------${PROBLEM_COLOR}"
   740	      for item in `cat $INSTALL_QUEUE 2>/dev/null`; do
   741	        message "$item"
   742	      done | sort | column
   743	      message "${DEFAULT_COLOR}"
   744	      rc=1
   745	    fi
   746	  fi
   747	
   748	  # check if confmeld should be run
   749	  local spell deferred_list
   750	  while read spell; do
   751	    # ignore the date - previously deferred files should be merged too
   752	    if [[ -d $CONFIG_STAGE_DIRECTORY/$spell ]]; then
   753	      deferred_list="$spell $deferred_list"
   754	    fi
   755	  done < $SUCCESS_LIST
   756	  if [[ $deferred_list ]]; then
   757	    message "${MESSAGE_COLOR}Cast deferred installing some configuration files."
   758	    message "The following spells have new pending updates: "
   759	    message "----------------------------------------------$SPELL_COLOR"
   760	    message "$deferred_list" | sort | column
   761	    message "${MESSAGE_COLOR}Please run confmeld to merge them into your system."
   762	    message "$DEFAULT_COLOR"
   763	  fi
   764	
   765	  debug "cast" "End of pass_five"
   766	  return $rc
   767	}
   768	
   769	#---------------------------------------------------------------------
   770	## @Arguments Spells to cast
   771	## @Globals CAST_PASS
   772	##
   773	## Starts the passes and sets CAST_PASS accordingly.
   774	#---------------------------------------------------------------------
   775	function pass_zero()  {
   776	
   777	  debug "cast" "Starting pass_zero()"
   778	  debug "pass_zero" "Starting passes 1,2,3,4 with : '$*'"
   779	  debug "pass_zero" "   and with spells : '$SPELLS'"
   780	  export  CAST_PASS="one";    pass_one $*  &&
   781	  export  CAST_PASS="two";    pass_two $SPELLS
   782	  #pass_three and _four are run via pass_two
   783	  debug "pass_zero" "Starting pass 5 with: '$@'"
   784	  export  CAST_PASS="five";  pass_five "$@"
   785	
   786	
   787	}
   788	
   789	#---------------------------------------------------------------------
   790	## @STDOUT User information ("Cleaning up as well as I can...")
   791	## That function is being called when the process receives
   792	## SIGINT. It then calls cleanup.
   793	#---------------------------------------------------------------------
   794	function int_trap()
   795	{
   796	  message "${PROBLEM_COLOR}SIGINT${DEFAULT_COLOR}"
   797	  message "Cleaning up as well as I can..."
   798	  cast_cleanup
   799	  if [[ $SCREEN_NAME ]] ; then
   800	    message -n "Press a key to exit screen."
   801	    read -n 1
   802	    screen_quit "$SCREEN_NAME"
   803	  fi
   804	  exit 1
   805	}
   806	
   807	#---------------------------------------------------------------------
   808	## Used for cleaning up. Deleting some files and $TMP_DIR.
   809	#---------------------------------------------------------------------
   810	function cast_cleanup() {
   811	  $STD_DEBUG
   812	  cleanup_tmp_dir $TMP_DIR
   813	  rmdir $CAST_BACKUPDIR 2>/dev/null
   814	  clean_resources
   815	}
   816	
   817	#---------------------------------------------------------------------
   818	## @Arguments arguments of cast
   819	## @Globals CAST_PASS
   820	## @return 0 always
   821	## Starts prameter processing and casts the given spells.
   822	## The list of given spells is being searched for invalid spells
   823	## which are then being reported. Then the passes are being started
   824	## according to CAST_PASS
   825	#---------------------------------------------------------------------
   826	function main">main">main">main">main()  {
   827	  debug "cast" "main">main">main">main">main() - $*"
   828	  local T_SPELLS
   829	  process_parameters">process_parameters">process_parameters        "$@"
   830	
   831	  if [[ "$CAST_QUEUE" == yes ]] ; then
   832	
   833	    touch "$INSTALL_QUEUE"
   834	    local tfile
   835	    lock_start_transaction "$INSTALL_QUEUE" tfile
   836	    grep -Ev '^$' $INSTALL_QUEUE > $tfile
   837	    lock_commit_transaction "$INSTALL_QUEUE"
   838	    if  [  -s $INSTALL_QUEUE  ]; then
   839	      message -n "${MESSAGE_COLOR}Casting install queue..."
   840	      message    "${DEFAULT_COLOR}"
   841	
   842	      # remove possible empty lines from queue.
   843	      if query "Would you like to review the queue history for each spell?" n ; then
   844	        sorcery review-queue
   845	      fi
   846	
   847	      SPELLS=$(<$INSTALL_QUEUE)
   848	    else
   849	      message "${MESSAGE_COLOR}Install queue is empty${DEFAULT_COLOR}"
   850	      exit
   851	    fi
   852	  else
   853	    SPELLS=`strip_parameters">strip_parameters  "$@"`
   854	  fi
   855	
   856	  if [[ $OVERRIDE_GRIMOIRES ]] ; then
   857	    codex_set_grimoires $OVERRIDE_GRIMOIRES
   858	  fi
   859	
   860	  for spell in $SPELLS ; do
   861	    codex_does_spell_exist $spell
   862	    if [ $? -eq 0 ] ; then
   863	      T_SPELLS="$T_SPELLS $spell"
   864	    fi
   865	  done
   866	  SPELLS=$T_SPELLS
   867	
   868	  if ! [[ $SPELLS ]]; then
   869	    return 1
   870	  fi
   871	
   872	  case  $CAST_PASS  in
   873	     one)  pass_one    $SPELLS  ;; #Never matches
   874	     two)  pass_two    $SPELLS  ;; #Never matches
   875	   three)  pass_three  $SPELLS  ;; #d/l sources, Never matches
   876	    four)  pass_four   $SPELLS  ;; #real casting, Never matches
   877	    five)  pass_five   $SPELLS  ;; #cast report
   878	       *)  pass_zero   $SPELLS  ;; #start everything
   879	  esac
   880	  local rc=$?
   881	
   882	  return $rc
   883	}
   884	
   885	
   886	. /etc/sorcery/config
   887	[[ $VOYEUR_OVERRIDE ]] && VOYEUR="$VOYEUR_OVERRIDE"
   888	if    [  $#      -eq  0  ];  then  help">help">help  |  $PAGER
   889	
   890	elif  [[  $1 == -h  ]]  ||  [[  $1 == --help  ]] ; then help">help">help
   891	elif  [  "$UID"  -gt  0  ];  then
   892	  # validate the parameters before su-ing, since we may still drop out
   893	  process_parameters">process_parameters">process_parameters "$@"
   894	
   895	  echo  "Enter the root password, please."
   896	  PARAMS=$(consolidate_params "$@")
   897	  exec su -c "cast $PARAMS" root
   898	
   899	elif  [  ${0:0:5} !=  "/tmp/"  ];  then
   900	
   901	  # Make a nice dir structure to put stuff in, this exits if it fails
   902	  mk_tmp_dirs backup /tmp/cast
   903	  export CAST_BACKUPDIR=$TMP_DIR
   904	  mk_tmp_dirs cast
   905	  export CAST_TMPDIR=$TMP_DIR
   906	
   907	  export SAFE_CAST="$TMP_DIR/casting.safe"
   908	  export SUCCESS_LIST="$TMP_DIR/success_list"
   909	  export FAILED_LIST="$TMP_DIR/failed_list"
   910	  export CONFLICT_LIST="$TMP_DIR/conflict_list"
   911	  export CHECK_TRIGGERS_SUCCESS="$TMP_DIR/check_trigger_success_list"
   912	  export CHECK_TRIGGERS_FAILURE="$TMP_DIR/check_trigger_failure_list"
   913	  lock_file $SAFE_CAST
   914	
   915	  # $0 can be bashdb, but we want to copy cast
   916	  smgl_which cast PATH_TO_CAST
   917	  cp "$PATH_TO_CAST" $SAFE_CAST
   918	
   919	  chmod +x $SAFE_CAST
   920	  exec bash $SAFE_CAST "$@"
   921	
   922	else
   923	  export TOP_LEVEL=${TOP_LEVEL:-$SHLVL}
   924	  if  [[  $NICE != "0"  ]] ; then
   925	    renice $NICE -p $$  >/dev/null
   926	  fi
   927	
   928	  # If we are in a screen, weird things happen if we make another screen.
   929	  # So disable screen mode if we are in a screen aready which wasn't started
   930	  # by smgl. We also have to make sure this is the top level cast so the SA
   931	  # won't see the message over and over and over
   932	  if  [[ $TERM == screen ]]       &&
   933	      [[ $TOP_LEVEL == $SHLVL ]]  &&
   934	      [[ $SCREEN == on ]]         &&
   935	      [[ ! $SCREEN_NAME ]]
   936	  then
   937	    export SCREEN_OVERRIDE=no
   938	    message "${MESSAGE_COLOR}Although screen mode is enabled, you already seem to be in a another"
   939	    message "screen session. Screen-in-screen is disabled."
   940	    message "Continuing with screen mode off.${DEFAULT_COLOR}"
   941	  fi
   942	
   943	  # Disable screen mode if the appropriate env var is set
   944	  if  [[ $SCREEN_OVERRIDE ]]       &&
   945	      [[ $SCREEN == on ]]
   946	  then
   947	    export SCREEN=$SCREEN_OVERRIDE
   948	    debug "cast" "Turning $SCREEN_OVERRIDE screen mode"
   949	  fi
   950	
   951	  # If screen mode is on, but we aren't in screen, start a new session
   952	  # Call to screen_start never exits
   953	  if  [[ $SCREEN == on ]]         &&
   954	      [[ $TERM != screen ]]
   955	  then
   956	    SCREEN_NAME="ScreenCast $*"
   957	    export SCREEN_NAME="${SCREEN_NAME:0:64}$(echo $SCREEN_NAME | md5sum)"
   958	    screen_start "$SCREEN_NAME" "$0" "$@"
   959	    echo "WTF?? We should not get here. screen_start execs!"
   960	    exit 1
   961	  fi
   962	
   963	  # If running in screen, screen mode is on, screen was started by us
   964	  # and finally, it hasn't been initialized yet.
   965	  if  [[ $TERM == screen ]]       &&
   966	      [[ $SCREEN == on ]]         &&
   967	      [[ $SCREEN_NAME ]]          &&
   968	      [[ ! $SCREEN_INITIALIZED ]]
   969	  then
   970	    debug "cast" "Initializing screen windows"
   971	    screen_name_window "$SCREEN_NAME" $SCREEN_MAIN_WIN "Main"
   972	
   973	    # Start debugging window if debugging is on and not set to /dev*
   974	    if  [[ $DEBUG ]]              &&
   975	        [[ ${DEBUG#/dev} == $DEBUG ]]
   976	    then
   977	      touch $DEBUG
   978	      screen_new_window "$SCREEN_NAME" $SCREEN_DEBUG_WIN "Debug" \
   979	      tail -f -n 0 -s 0.1 $DEBUG
   980	      #screen_unmonitor_window "$SCREEN_NAME" $SCREEN_DEBUG_WIN
   981	    fi
   982	
   983	    screen_switch_window "$SCREEN_NAME" $SCREEN_MAIN_WIN
   984	    screen_monitor_window "$SCREEN_NAME" $SCREEN_MAIN_WIN
   985	    screen_quick_intro
   986	    export SCREEN_INITIALIZED=yes
   987	  fi
   988	
   989	  trap int_trap INT
   990	  main">main">main">main">main  "$@"
   991	  rc=$?
   992	  if [ $SHLVL -eq $TOP_LEVEL ] ; then
   993	    unlock_file $SAFE_CAST
   994	    cast_cleanup
   995	  fi
   996	  if [[ $SCREEN_NAME ]] && [[ $TOP_LEVEL -eq $SHLVL ]] ;  then
   997	    screen_notify "$SCREEN_NAME" "Done casting"
   998	    message -n "Press enter to exit screen."
   999	    read
  1000	    screen_quit "$SCREEN_NAME"
  1001	  fi
  1002	  exit $rc
  1003	fi
  1004	
  1005	debug "cast" "exiting..."
  1006	
  1007	#---------------------------------------------------------------------
  1008	##=back
  1009	##
  1010	##=head1 LICENSE
  1011	##
  1012	## This software is free software; you can redistribute it and/or modify
  1013	## it under the terms of the GNU General Public License as published by
  1014	## the Free Software Foundation; either version 2 of the License, or
  1015	## (at your option) any later version.
  1016	##
  1017	## This software is distributed in the hope that it will be useful,
  1018	## but WITHOUT ANY WARRANTY; without even the implied warranty of
  1019	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1020	## GNU General Public License for more details.
  1021	##
  1022	## You should have received a copy of the GNU General Public License
  1023	## along with this software; if not, write to the Free Software
  1024	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  1025	##
  1026	#---------------------------------------------------------------------