/var/lib/sorcery/modules/libcast

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	## @Synopsis Functions for dealing with the actual
     4	## @Synopsis compiling/installation of spells and walking through cast's 'pass 4' pipeline.
     5	## @Copyright Copyright (C) 2002 The Source Mage Team
     6	## @Copyright <http://www.sourcemage.org>
     7	## @Globals $SGL_LIBRARY_MODULES $GRIMOIRE $BUILD_API $USE_FUNCTIONS
     8	## A spell follows the following path during its installation:
     9	## PREPARE -> DETAILS -> PRE_BUILD -> BUILD, or COMPILE/INSTALL ->
    10	## POST_BUILD -> POST_INSTALL -> TRIGGERS
    11	## Each of these steps, along with some interim steps of dealing with
    12	## conflicts and security are handled here as well.
    13	#---------------------------------------------------------------------
    14	
    15	#---------------------------------------------------------------------
    16	## This is used to dynamically setup an api environment for a spell
    17	## into the build api that it is specified to use. (ie split BUILD or
    18	## no split BUILD).
    19	#---------------------------------------------------------------------
    20	function load_build_api() {
    21	
    22	  debug "libcast" "Starting load_build_api"
    23	
    24	  source $SGL_LIBRARY_MODULES/build_api/common
    25	  case $BUILD_API in
    26	    1) source $SGL_LIBRARY_MODULES/build_api/api1 ;;
    27	    2) source $SGL_LIBRARY_MODULES/build_api/api2 ;;
    28	    *) message "${PROBLEM_COLOR}Unknown build api version $BUILD_API, for" \
    29	               "$SPELL!!${DEFAULT_COLOR}"
    30	       message "Please update sorcery and see if the problem goes away."
    31	       message "If it doesnt this may be a bug, please contact" \
    32	               "the sorcery team. Thanks."
    33	       return 1 ;;
    34	  esac
    35	  load_functions_file
    36	}
    37	
    38	#---------------------------------------------------------------------
    39	## Load the grimoire and section level FUNCTIONS file
    40	#---------------------------------------------------------------------
    41	function load_functions_file() {
    42	  # the following allows spell writers to override certain functions
    43	  # in the build pipeline
    44	  USE_FUNCTIONS=${USE_FUNCTIONS:-on}
    45	  if [[ $USE_FUNCTIONS == "on" ]] ; then
    46	    [ -x $GRIMOIRE/FUNCTIONS ] && . $GRIMOIRE/FUNCTIONS
    47	    [ -x $SECTION_DIRECTORY/FUNCTIONS ] && . $SECTION_DIRECTORY/FUNCTIONS
    48	  elif [[ $USE_FUNCTIONS == "grimoire" ]] ; then
    49	    [ -x $GRIMOIRE/FUNCTIONS ] && . $GRIMOIRE/FUNCTIONS
    50	  elif [[ $USE_FUNCTIONS == "section" ]] ; then
    51	    [ -x $SECTION_DIRECTORY/FUNCTIONS ] && . $SECTION_DIRECTORY/FUNCTIONS
    52	  fi
    53	  return 0
    54	}
    55	
    56	#---------------------------------------------------------------------
    57	## Load the grimoire and section level 'libcompat' file
    58	## Spells use this for compatibility checking. It is supposed to be
    59	## lighter-weight than FUNCTIONS.
    60	#---------------------------------------------------------------------
    61	function load_libcompat() {
    62	  [ -x $GRIMOIRE/libcompat ] && . $GRIMOIRE/libcompat
    63	  [ -x $SECTION_DIRECTORY/libcompat ] && . $SECTION_DIRECTORY/libcompat
    64	  return 0
    65	}
    66	
    67	#---------------------------------------------------------------------
    68	## Loads up this environment with the special configuration values
    69	## that the spell needs. Typically the mode of communication between
    70	## CONFIGURE/DEPENDS to PRE_BUILD, BUILD, COMPILE, INSTALL, etc.
    71	## @Globals $SPELL_CONFIG $DEPENDS_CONFIG
    72	#---------------------------------------------------------------------
    73	function prepare_spell_config()  {
    74	
    75	  SPELL_CONFIG=$DEPENDS_CONFIG/$SPELL
    76	  if  !  [  -x  $SPELL_CONFIG  ];  then
    77	    touch       $SPELL_CONFIG
    78	    chmod  a+x  $SPELL_CONFIG
    79	  fi
    80	
    81	  . $SPELL_CONFIG
    82	
    83	}
    84	
    85	#---------------------------------------------------------------------
    86	## Prompts the user about spells that are in conflict with the current
    87	## spell for later dispelling. If the user chooses not to
    88	## dispel the conflicting spell, the function returns 1
    89	## @param dis-allow conflict with anything in this list, normally used to prevent self conflicts
    90	## @param file to store output (conflicts to be removed), defaults to $CONFLICT_LIST
    91	## @return nothing if the user chose to dispel the conflicting spell
    92	## @return 1 if the user chooses not to dispel the conflicting spell
    93	## @return 1 or if there was a problem parsing the CONFLICTS file
    94	#---------------------------------------------------------------------
    95	function query_conflicts() {
    96	  debug "build_api/common" "Starting query_conflicts() on $SPELL"
    97	  local ignore_conflict=$1
    98	  local output=${2:-$CONFLICT_LIST}
    99	
   100	  # skip if the spell was already processed (avoids a double query for in-cast resurrects)
   101	  [[ -s $output ]] && awk -v s=$SPELL '{ if ($1 == s) {rc=1} } END {exit !rc}' $output && return 0
   102	
   103	  if [[ -x $SCRIPT_DIRECTORY/CONFLICTS ]]; then
   104	    local CONFLICTS=$(run_spell_file CONFLICTS conflicts) || return 1
   105	
   106	    local tmp conflicts to_dispel=""
   107	    for tmp in $CONFLICTS; do
   108	      local spell_and_default
   109	      explode $tmp ':' spell_and_default
   110	
   111	      # skip the spells we were told to ignore
   112	      list_find "$ignore_conflict" ${spell_and_default[0]} && continue
   113	
   114	      local text="${SPELL_COLOR}${SPELL}${MESSAGE_COLOR} conflicts with"
   115	      text="$text ${SPELL_COLOR}${spell_and_default[0]}${DEFAULT_COLOR}${QUERY_COLOR}."
   116	      text="$text Dispel"
   117	      text="$text ${SPELL_COLOR}${spell_and_default[0]}${MESSAGE_COLOR}?"
   118	
   119	      if query "$text" ${spell_and_default[1]}; then
   120	        list_add conflicts "${spell_and_default[0]}"
   121	      else
   122	        log_failure_reason "conflicts"
   123	        return 1
   124	      fi
   125	    done
   126	    if [[ $conflicts ]]; then
   127	      echo $SPELL $conflicts >> $output
   128	    fi
   129	  fi
   130	
   131	  return 0
   132	}
   133	
   134	#---------------------------------------------------------------------
   135	## Dispels the spells that are scheduled for a dispel due to conflicting
   136	## @param spell whose conflicts to dispel
   137	## @param file containing the list of conflicts
   138	#---------------------------------------------------------------------
   139	function dispel_conflicts() {
   140	  local spell=$1
   141	  local conflict_list=${2:-$CONFLICT_LIST}
   142	  local conflict
   143	
   144	  if [[ -s $conflict_list ]]; then
   145	    message "${MESSAGE_COLOR}Dispelling conflicts...$DEFAULT_COLOR"
   146	  else
   147	    return 0
   148	  fi
   149	
   150	  # no conflict is repeated, since we use list_add (idempotent) to construct it
   151	  for conflict in $(awk '{ if($1 == "'$1'") { $1=""; print $0;} }' "$conflict_list"); do
   152	    # don't break if it was already removed by another conflict
   153	    if spell_ok $conflict; then
   154	      dispel --nosustain --noqueue $conflict || return 1
   155	    fi
   156	  done
   157	}
   158	
   159	#---------------------------------------------------------------------
   160	## Prompts the user about possible security problems with the current
   161	## spell. Allows a safe way of failing a spell due to security problems.
   162	## @return 0 if there are no security problem or the user acknowledges them.
   163	## @return 1 if the user decides not to accept the security concerns
   164	#---------------------------------------------------------------------
   165	function run_security() {
   166	    debug "build_api/common" "Starting run_security() on $SPELL"
   167	    local rc=0
   168	    if [[ -f $SCRIPT_DIRECTORY/SECURITY ]]; then
   169	      message "${SPELL_COLOR}${SPELL}:${DEFAULT_COLOR}"
   170	      tee -a $SECURITY_LOG < $SCRIPT_DIRECTORY/SECURITY
   171	      if grep -q critical $SCRIPT_DIRECTORY/SECURITY; then
   172	        query "${RED}SECURITY CRITICAL: ${QUERY_COLOR}Do you still want to cast ${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}${QUERY_COLOR}?" "n"
   173	      else
   174	        query "SECURITY: Do you still want to cast ${SPELL_COLOR}$SPELL${DEFAULT_COLOR}${QUERY_COLOR}?" "y"
   175	      fi
   176	      rc=$?
   177	    fi
   178	    [[ $rc != 0 ]] && log_failure_reason "security"
   179	    return $rc
   180	}
   181	
   182	function query_custom_cflags() {
   183	  if [[ $PER_SPELL_CFLAGS == on ]]; then
   184	    query "Would you like to set custom optimizations for this spell?" n ||
   185	      return 0
   186	
   187	    persistent_add USER_SPELL_CFLAGS
   188	    persistent_add USER_SPELL_CXXFLAGS
   189	    persistent_add USER_SPELL_LDFLAGS
   190	    persistent_add USER_SPELL_CPPFLAGS
   191	    local RESULTS KEY rc
   192	    while true ; do
   193	      # input box returns things of the form "RENAMED CFLAGS -O3 -march=foo ..."
   194	      # the ( ) interprits as an array, then using the magic power of set we
   195	      # get to use shift and $@ to get things done
   196	      RESULTS=(`eval dialog --stdout ' --extra-label Adjust --inputmenu \
   197	                              "Custom Optimizations Menu" \
   198	                               17 50 9 \
   199	                               CFLAGS "$USER_SPELL_CFLAGS" \
   200	                               CXXFLAGS "$USER_SPELL_CXXFLAGS" \
   201	                               LDFLAGS "$USER_SPELL_LDFLAGS" \
   202	                               CPPFLAGS "$USER_SPELL_CPPFLAGS"'`)
   203	      rc=$?
   204	      [[ $rc == 0 ]] || [[ $rc == 1 ]] && break
   205	      set ${RESULTS[*]}
   206	      KEY=$2
   207	      shift 2
   208	      case "$KEY" in
   209	        CFLAGS) USER_SPELL_CFLAGS="$@"  ;;
   210	        CXXFLAGS) USER_SPELL_CXXFLAGS="$@" ;;
   211	        LDFLAGS) USER_SPELL_LDFLAGS="$@" ;;
   212	        CPPFLAGS) USER_SPELL_CPPFLAGS="$@" ;;
   213	      esac
   214	    done
   215	  fi
   216	}
   217	
   218	#---------------------------------------------------------------------
   219	## Asks the user about init and xinetd services
   220	##
   221	## expects $SCRIPT_DIRECTORY to be setable, any file one level deep in
   222	## $SCRIPT_DIRECTORY/xinetd.d or $SCRIPT_DIRECTORY/init.d is assumed to be
   223	## a service
   224	##
   225	## the following persistent variables may be set:
   226	## XINETD_ENABLED XINETD_DISABLED
   227	## INIT_ENABLED INIT_DISABLED
   228	## XINETD_INSTALLED XINETD_NOT_INSTALLED
   229	## INIT_INSTALLED INIT_NOT_INSTALLED
   230	##
   231	## They are all lists used by the list_add/list_find functions. The union
   232	## of FOO_ENABLED and FOO_DISABLED should be exactly equivalent to
   233	## FOO_INSTALLED. FOO_ENABLED and FOO_DISABLED have an empty intersection set.
   234	#---------------------------------------------------------------------
   235	function query_services() {
   236	  local XINETD_SCRIPTS
   237	  local INIT_SCRIPTS
   238	  local btmp xtmp itmp
   239	  local tmp retvar
   240	  local XINETD INIT BOTH found
   241	  local new_init_provides
   242	
   243	  test -d $SCRIPT_DIRECTORY/xinetd.d &&
   244	  XINETD_SCRIPTS=$(find $SCRIPT_DIRECTORY/xinetd.d -maxdepth 1 -type f \
   245	                                                         -a -not -name '.*')
   246	
   247	  test -d $SCRIPT_DIRECTORY/init.d &&
   248	  INIT_SCRIPTS=$(find $SCRIPT_DIRECTORY/init.d -maxdepth 1 -type f \
   249	                                  -a -not -name '.*' -a -not -name '*.conf')
   250	
   251	  local new_init_inst new_init_ninst new_init_enab new_init_disab
   252	  local new_xinetd_inst new_xinetd_ninst new_xinetd_enab new_xinetd_disab
   253	
   254	  local xtmp_base itmp_base
   255	  for xtmp in $XINETD_SCRIPTS; do
   256	    smgl_basename $xtmp xtmp_base
   257	    for itmp in $INIT_SCRIPTS; do
   258	      smgl_basename $itmp itmp_base
   259	      if [[ $xtmp_base == $itmp_base ]] ; then
   260	        list_add BOTH $itmp_base
   261	        found=1
   262	        break
   263	      fi
   264	    done
   265	  done
   266	
   267	  for tmp in $INIT_SCRIPTS; do
   268	    smgl_basename "$tmp" tmp
   269	    list_find $tmp $BOTH || list_add INIT $tmp
   270	    # if the script is ESSENTIAL or RECOMMENDED default to yes unless
   271	    # the user previously said no
   272	    if grep -Fq 'ESSENTIAL=yes' $SCRIPT_DIRECTORY/init.d/$tmp ||
   273	       grep -Fq 'RECOMMENDED=yes' $SCRIPT_DIRECTORY/init.d/$tmp &&
   274	       ! list_find $tmp $INIT_NOT_INSTALLED; then
   275	       list_add INIT_INSTALLED $tmp
   276	       list_add INIT_ENABLED $tmp
   277	       list_remove INIT_DISABLED $tmp
   278	     fi
   279	  done
   280	
   281	  for tmp in $XINETD_SCRIPTS; do
   282	    smgl_basename "$tmp" tmp
   283	    list_find $tmp $BOTH || list_add XINETD $tmp
   284	  done
   285	
   286	  local d1 d2
   287	  for tmp in $BOTH ; do
   288	    message "${QUERY_COLOR}Would you like to install the init and/or" \
   289	            "xinetd script for $tmp?${DEFAULT_COLOR}"
   290	
   291	    if [[ $DEF_INIT_VS_XINETD == on ]]; then
   292	      d1=$DEF_INSTALL_INIT; d2=n
   293	    else
   294	      d1=n; d2=$DEF_INSTALL_XINETD
   295	    fi
   296	    dual_service_query $tmp choice "$XINETD_INSTALLED" "$XINETD_NOT_INSTALLED" \
   297	                                   "$INIT_INSTALLED" "$INIT_NOT_INSTALLED" \
   298	                                   "$d1" "$d2"
   299	    if [[ $choice == both ]] ; then
   300	      list_add new_init_inst $tmp
   301	      list_add new_xinetd_inst $tmp
   302	      message "${QUERY_COLOR}Would you like to enable $tmp through init" \
   303	              "and/or xinetd?${DEFAULT_COLOR}"
   304	
   305	      if [[ $DEF_INIT_VS_XINETD ]]; then
   306	        d1=$DEF_ENABLE_INIT; d2=n
   307	      else
   308	        d1=n;d2=$DEF_ENABLE_XINETD
   309	      fi
   310	      dual_service_query $tmp choice "$XINETD_ENABLED" "$XINETD_DISABLED" \
   311	                                     "$INIT_ENABLED" "$INIT_DISABLED" \
   312	                                     "$d1" "$d2"
   313	
   314	      case $choice in
   315	          both) list_add new_init_enab $tmp
   316	                list_add new_xinetd_enab $tmp
   317	                ;;
   318	          init) list_add new_init_enab $tmp
   319	                list_add new_xinetd_disab $tmp
   320	                ;;
   321	        xinetd) list_add new_init_disab $tmp
   322	                list_add new_xinetd_enab $tmp
   323	                ;;
   324	       neither) list_add new_init_disab $tmp
   325	                list_add new_xinetd_disab $tmp
   326	                ;;
   327	      esac
   328	    elif [[ $choice == init ]] ; then
   329	      list_add new_init_inst $tmp
   330	      list_add new_xinetd_ninst $tmp
   331	      if service_query $tmp "Enable init script $tmp?" "$INIT_ENABLED" \
   332	                            "$INIT_DISABLED" "$DEF_ENABLE_INIT" \
   333	                             new_init_enab new_init_disab; then
   334	        init_prepare_install "$tmp" "$INIT_PROVIDES" new_init_provides
   335	      fi
   336	    elif [[ $choice == xinetd ]] ; then
   337	      list_add new_init_ninst $tmp
   338	      list_add new_xinetd_inst $tmp
   339	      service_query $tmp "Enable xinetd script $tmp?" "$XINETD_ENABLED" \
   340	                         "$XINETD_DISABLED" "$DEF_ENABLE_XINETD" \
   341	                         new_xinetd_enab new_xinetd_disab
   342	    else
   343	      list_add new_init_ninst $tmp
   344	      list_add new_xinetd_ninst $tmp
   345	    fi
   346	  done
   347	
   348	  for tmp in $INIT; do
   349	    if grep -Fq 'ESSENTIAL=yes' $SCRIPT_DIRECTORY/init.d/$tmp ; then
   350	      message "Init script $tmp is \"ESSENTIAL\" for system startup," \
   351	              "\nit is recommended that you answer yes to the following" \
   352	              "\nqueries unless you know exactly what you're doing."
   353	    elif grep -Fq 'RECOMMENDED=yes' $SCRIPT_DIRECTORY/init.d/$tmp ; then
   354	      message "Init script $tmp is \"RECOMMENDED\" for system startup," \
   355	            "\nit is recommended that you answer yes to the following queries."
   356	    fi
   357	    if service_query $tmp "Install init script $tmp?" "$INIT_INSTALLED" \
   358	                          "$INIT_NOT_INSTALLED" "$DEF_INSTALL_INIT" \
   359	                          new_init_inst new_init_ninst; then
   360	      if service_query $tmp "Enable init script $tmp?" "$INIT_ENABLED" \
   361	                            "$INIT_DISABLED" "$DEF_ENABLE_INIT" \
   362	                            new_init_enab new_init_disab; then
   363	        init_prepare_install "$tmp" "$INIT_PROVIDES" new_init_provides
   364	      fi
   365	    fi
   366	  done
   367	  for tmp in $XINETD; do
   368	    if service_query $tmp "Install xinetd script $tmp?" "$XINETD_INSTALLED" \
   369	                          "$XINETD_NOT_INSTALLED" "$DEF_INSTALL_XINETD" \
   370	                          new_xinetd_inst new_xinetd_ninst; then
   371	      service_query $tmp "Enable xinetd script $tmp?" "$XINETD_ENABLED" \
   372	                         "$XINETD_DISABLED" "$DEF_ENABLE_XINETD" \
   373	                         new_xinetd_enab new_xinetd_disab
   374	    fi
   375	  done
   376	
   377	  # removing all of these is necessary incase some init/xinetd scripts were
   378	  # originally in the spell but were later removed, besides its harmless
   379	  persistent_remove INIT_INSTALLED
   380	  persistent_remove INIT_NOT_INSTALLED
   381	  persistent_remove INIT_ENABLED
   382	  persistent_remove INIT_DISABLED
   383	  persistent_remove XINETD_INSTALLED
   384	  persistent_remove XINETD_NOT_INSTALLED
   385	  persistent_remove XINETD_ENABLED
   386	  persistent_remove XINETD_DISABLED
   387	
   388	  persistent_remove INIT_PROVIDES
   389	
   390	  if [[ $INIT ]] || [[ $BOTH ]] ; then
   391	    service_store INIT_INSTALLED "$new_init_inst"
   392	    service_store INIT_NOT_INSTALLED "$new_init_ninst"
   393	    service_store INIT_ENABLED "$new_init_enab"
   394	    service_store INIT_DISABLED "$new_init_disab"
   395	  fi
   396	
   397	  if [[ $XINETD ]] || [[ $BOTH ]] ; then
   398	    service_store XINETD_INSTALLED "$new_xinetd_inst"
   399	    service_store XINETD_NOT_INSTALLED "$new_xinetd_ninst"
   400	    service_store XINETD_ENABLED "$new_xinetd_enab"
   401	    service_store XINETD_DISABLED "$new_xinetd_disab"
   402	  fi
   403	
   404	  if [[ $new_init_provides ]] ; then
   405	    service_store INIT_PROVIDES "$new_init_provides"
   406	  fi
   407	
   408	  if [[ $XINETD_INSTALLED ]] ; then
   409	    suggest_depends xinetd "" "" "for $XINETD_INSTALLED"
   410	  fi
   411	}
   412	
   413	
   414	#---------------------------------------------------------------------
   415	## Determines what the best default answer should be then gives the
   416	## user a menu of neither, init, xinetd, or both to choose from.
   417	## This is for the case of a service being provided by either init or xinetd
   418	##
   419	## @param service name
   420	## @param return variable to put answer in
   421	## @param list to look in for a default of yes to xinetd
   422	## @param list to look in for a default of no to xinetd
   423	## @param list to look in for a default of yes to init
   424	## @param list to look in for a default of no to init
   425	## @param default for xinetd if not found in either of the xinetd lists
   426	## @param default for init if not found in either of the init lists
   427	##
   428	## @return nothing of importance, returns through a pointer
   429	## @stdout a menu sans question, the caller needs to present the question
   430	#---------------------------------------------------------------------
   431	function dual_service_query() {
   432	  local service=$1
   433	  local returnvar=$2
   434	  local XY=$3
   435	  local XN=$4
   436	  local IY=$5
   437	  local IN=$6
   438	  local xinetd_default=$7
   439	  local init_default=$8
   440	
   441	  [[ $xinetd_default == off ]] && xinetd_default=n
   442	  [[ $xinetd_default == on ]] && xinetd_default=y
   443	  [[ $init_default == off ]] && init_default=n
   444	  [[ $init_default == on ]] && init_default=y
   445	
   446	  if list_find $service $XY ; then
   447	    xinetd_default=y
   448	  elif list_find $service $XN ; then
   449	    xinetd_default=n
   450	  fi
   451	
   452	  if list_find $service $IY ; then
   453	    init_default=y
   454	  elif list_find $service $IN ; then
   455	    init_default=n
   456	  fi
   457	
   458	  if [[ $init_default == y ]] && [[ $xinetd_default == y ]] ; then
   459	    default=both
   460	  elif [[ $xinetd_default == y ]] ; then
   461	    default=xinetd
   462	  elif [[ $init_default == y ]] ; then
   463	    default=init
   464	  else
   465	    default=neither
   466	  fi
   467	  select_list $returnvar $default neither init xinetd both
   468	}
   469	
   470	
   471	#---------------------------------------------------------------------
   472	## Determines what the best default answer should be then asks the
   473	## user given question and adds the service to one of two lists
   474	## @param service name
   475	## @param question to ask
   476	## @param list to look in for a default of yes
   477	## @param list to look in for a default of no
   478	## @param default if not found in either of the above two lists
   479	## @param store in this list if the answer is yes
   480	## @param store in this list if the answer is no
   481	## @return true if yes false if no
   482	## @stdout a query supplied by the caller
   483	#---------------------------------------------------------------------
   484	function service_query() {
   485	  local service=$1
   486	  local question=$2
   487	  local L1=$3
   488	  local L2=$4
   489	  local real_default=$5
   490	  local yes_list=$6
   491	  local no_list=$7
   492	
   493	  local default
   494	  if list_find $service $L1 ; then
   495	    default=y
   496	  elif list_find $service $L2 ; then
   497	    default=n
   498	  else
   499	    [[ $real_default == off ]] && real_default=n
   500	    [[ $real_default == on ]] && real_default=y
   501	    default=$real_default
   502	  fi
   503	
   504	  if query "$question" $default ; then
   505	    list_add $yes_list $service
   506	    true
   507	  else
   508	    list_add $no_list $service
   509	    false
   510	  fi
   511	}
   512	
   513	#---------------------------------------------------------------------
   514	## Internal wrapper around the task of adding a persistent variable
   515	## then storing something in it, or unsetting whatever used to be in it
   516	#---------------------------------------------------------------------
   517	function service_store() {
   518	  local VARNAME=$1
   519	  local list=$2
   520	  persistent_add $VARNAME
   521	  if [[ $list ]] ; then
   522	    eval $VARNAME=\"$list\"
   523	  else
   524	    unset $VARNAME
   525	  fi
   526	}
   527	
   528	
   529	#---------------------------------------------------------------------
   530	## Installs the scripts selected from query_services
   531	#---------------------------------------------------------------------
   532	function install_xinetd() {
   533	  if  [[  $XINETD_INSTALLED  ]] ; then
   534	    local install_dir=$INSTALL_ROOT/etc/xinetd.d
   535	    mkdir  -p  $install_dir
   536	    pushd "$SCRIPT_DIRECTORY/xinetd.d" >/dev/null
   537	
   538	    # install and enable
   539	    for  FILE in  $XINETD_INSTALLED; do
   540	      if ! test -e $FILE ; then
   541	        message "${PROBLEM_COLOR}Xinetd script $FILE doesnt exist," \
   542	                "but was selected, this may be a sorcery bug${DEFAULT_COLOR}"
   543	        continue
   544	      fi
   545	      if list_find $FILE $XINETD_ENABLED; then
   546	        message "Installing and enabling xinetd script $FILE to $install_dir"
   547	        install_xinetd_sub $FILE no $install_dir
   548	      elif list_find $FILE $XINETD_DISABLED; then
   549	        message "Installing and disabling xinetd script $FILE to $install_dir"
   550	        install_xinetd_sub $FILE yes $install_dir
   551	      else
   552	        message "${PROBLEM_COLOR}Xinetd script $FILE is in installed list" \
   553	                "but wasnt enabled or disabled, this may be a sorcery bug" \
   554	                "${DEFAULT_COLOR}"
   555	      fi
   556	    done
   557	    popd >/dev/null
   558	  fi
   559	}
   560	
   561	#---------------------------------------------------------------------
   562	## Does the dirty work involved in installing an xinetd script
   563	## this includes setting the disabled field appropriately and
   564	## not trampling on pre-existing files by default
   565	#---------------------------------------------------------------------
   566	function install_xinetd_sub() {
   567	  local file=$1
   568	  local bfile
   569	  smgl_basename "$1" bfile
   570	  local state=$2
   571	  local install_dir=$3
   572	  local tmp_file=$TMP_DIR/$bfile
   573	  local inst_file=$install_dir/$bfile
   574	  install -g root -o root $file $tmp_file
   575	
   576	  set_xinetd_state $tmp_file $state
   577	
   578	  # FIXME use install_config_file?
   579	  if test -e $inst_file &&
   580	     ! grep -v disable $inst_file|diff - $file &>/dev/null ; then
   581	    message "${QUERY_COLOR}$inst_file differs from the default $file," \
   582	            "what would you like to do?${DEFAULT_COLOR}"
   583	    select_list choice "ignore" "ignore" "overwrite" "overwrite/backup"
   584	    case $choice in
   585	      "overwrite/backup")
   586	        local backup=$inst_file.$(date +'%Y%m%d%H%M')
   587	        mv $inst_file $backup
   588	        # disable the backup
   589	        set_xinetd_state $backup yes
   590	        cp $tmp_file $inst_file ;;
   591	      overwrite) cp $tmp_file $inst_file ;;
   592	    esac
   593	  else
   594	    cp $tmp_file $inst_file
   595	  fi
   596	}
   597	
   598	#---------------------------------------------------------------------
   599	## Handles the logic of enabling or disabling of an xinetd script
   600	#---------------------------------------------------------------------
   601	function set_xinetd_state() {
   602	  local file=$1
   603	  local state=$2
   604	  if grep -q "\s*disable" $file ; then
   605	    sedit "s/disable\s*=.*/disable = $state/" $file
   606	  else
   607	    sedit "s/}/disable = $state\n}/" $file
   608	  fi
   609	}
   610	
   611	
   612	#---------------------------------------------------------------------
   613	## Copies any init.d files from the SCRIPT_DIRECTORY to the /etc/init.d.
   614	## Hopefully saving the old one if it exists and only setting the
   615	## executable bit if the user specified that the init.d script should be
   616	## started at bootup.
   617	#---------------------------------------------------------------------
   618	function install_initd() {
   619	  if  [[  $INIT_INSTALLED  ]] ; then
   620	    local install_dir=$INSTALL_ROOT/etc/init.d
   621	    mkdir  -p  $install_dir
   622	    pushd "$SCRIPT_DIRECTORY/init.d" >/dev/null
   623	
   624	    # install and enable
   625	    for  FILE in  $INIT_INSTALLED; do
   626	      message "${QUERY_COLOR}installing $FILE${DEFAULT_COLOR}"
   627	      if ! test -e $FILE ; then
   628	        message "${PROBLEM_COLOR}Init script $FILE doesnt exist," \
   629	                "but was selected, this may be a sorcery bug${DEFAULT_COLOR}"
   630	        continue
   631	      fi
   632	      if list_find $FILE $INIT_ENABLED; then
   633	        init_install enabled $FILE
   634	      elif list_find $FILE $INIT_DISABLED; then
   635	        init_install disabled $FILE
   636	      else
   637	        message "${PROBLEM_COLOR}Init script $FILE is in installed list" \
   638	                "but wasnt enabled or disabled, this may be a sorcery bug" \
   639	                "${DEFAULT_COLOR}"
   640	      fi
   641	    done
   642	    popd >/dev/null
   643	  fi
   644	}
   645	
   646	
   647	#---------------------------------------------------------------------
   648	## Gets the cast lock for us and ensures that we've waited for all
   649	## solo/non-solo casts to complete
   650	#---------------------------------------------------------------------
   651	function acquire_cast_lock() {
   652	  # locking - blocks normal spells if a solo cast is running,
   653	  # solo casts if any cast is running
   654	  message "${MESSAGE_COLOR}Waiting for any${DEFAULT_COLOR}${FILE_COLOR}" \
   655	          "Solo${DEFAULT_COLOR} ${MESSAGE_COLOR}casts to complete..." \
   656	          "${DEFAULT_COLOR}"
   657	  lock_resources "solo" "cast"
   658	  if test -f $SOLO && grep -q "^$SPELL$" $SOLO ||
   659	     [ -f $SCRIPT_DIRECTORY/SOLO ]
   660	  then #SOLO spell
   661	    message -n "${MESSAGE_COLOR}Waiting for${DEFAULT_COLOR}" \
   662	               "${SPELL_COLOR}all other${DEFAULT_COLOR} ${MESSAGE_COLOR}spells to" \
   663	               "complete...${DEFAULT_COLOR}"
   664	    excllock_resources "cast" "$SPELL"
   665	  else
   666	    message -n "${MESSAGE_COLOR}Waiting for any other casts of" \
   667	               "${DEFAULT_COLOR}${SPELL_COLOR}$SPELL${DEFAULT_COLOR}" \
   668	               "${MESSAGE_COLOR}to complete...${DEFAULT_COLOR}"
   669	    lock_resources "cast" "$SPELL"
   670	    unlock_resources "solo" "cast"
   671	  fi
   672	  message " done."
   673	}
   674	
   675	#---------------------------------------------------------------------
   676	## Takes the compile log and stuffs it into
   677	## our compile log directory.
   678	#---------------------------------------------------------------------
   679	function create_compile_log()  {
   680	  local tmp_log=$C_LOG.2
   681	
   682	  message  "${MESSAGE_COLOR}Creating compile log"                  \
   683	           "${FILE_COLOR}$COMPILE_LOGS/$SPELL-$VERSION$EXTENSION"  \
   684	           "${DEFAULT_COLOR}"
   685	  if [[ "$STORE_CONF_LOG" == on ]] && test -e $SOURCE_DIRECTORY/config.log; then
   686	    echo "---config.log---" >> $C_LOG
   687	    cat $SOURCE_DIRECTORY/config.log >> $C_LOG
   688	  fi
   689	
   690	  # remove any nplicated lines (happens due to all the redirection we do)
   691	  uniq $C_LOG > $tmp_log
   692	  mv $tmp_log $C_LOG
   693	
   694	  # install the compile log
   695	  if [  -z  "$EXTENSION"  ];  then
   696	    cp  $C_LOG  $COMPILE_LOGS/$SPELL-$VERSION
   697	  else
   698	    $COMPRESSBIN -c $C_LOG > "$COMPILE_LOGS/$SPELL-$VERSION$EXTENSION"
   699	  fi
   700	
   701	  # install the castfs log
   702	  if [[ $STAGED_INSTALL == on ]] ; then
   703	    message  "${MESSAGE_COLOR}Creating castfs debug log"                \
   704	             "${FILE_COLOR}$COMPILE_LOGS/$SPELL-$VERSION.castfs.dbglog$EXTENSION"  \
   705	             "${DEFAULT_COLOR}"
   706	    if [ -z "$EXTENSION" ]
   707	    then
   708	      cp $CASTFS_DBGLOG $COMPILE_LOGS/$SPELL-$VERSION.castfs.dbglog
   709	    else
   710	      $COMPRESSBIN -c $CASTFS_DBGLOG > "$COMPILE_LOGS/$SPELL-$VERSION.castfs.dbglog$EXTENSION"
   711	    fi
   712	    rm -f $CASTFS_DBGLOG
   713	  fi
   714	}
   715	
   716	
   717	#---------------------------------------------------------------------
   718	## Prompts the user to view the compile log
   719	## and deletes the temporary files too
   720	#---------------------------------------------------------------------
   721	function view_compile_log()  {
   722	
   723	    debug "libcast" "In view_compile_log, C_LOG=$C_LOG"
   724	    report $C_LOG  "Compile log"
   725	}
   726	
   727	#---------------------------------------------------------------------
   728	## Report that something got installed, and possibly display the report
   729	## Pawns the work off to <@function var.lib.sorcery.modules.libsorcery,report>
   730	## @Globals INST_LOG
   731	#---------------------------------------------------------------------
   732	function report_install()  {
   733	
   734	  debug "libcast" "In report_install, INST_LOG=$INST_LOG"
   735	  report  $INST_LOG  "Install log"
   736	
   737	}
   738	
   739	#---------------------------------------------------------------------
   740	## @TODO This function is dumb. It should be fixed.
   741	## @param download log file name
   742	#---------------------------------------------------------------------
   743	function show_download_progress()  {
   744	  [[ $SCREEN_NAME ]] && return
   745	  local download_log=$1
   746	
   747	  if [[ -e $download_log ]] && [[ -z $SILENT ]]; then
   748	    local line_count
   749	    line_count_old=${line_count_old:-0}
   750	
   751	    line_count=$(wc -l < $download_log)
   752	
   753	    if [[ $line_count != $line_count_old ]]; then
   754	      let line_count_old++
   755	      sed -n ${line_count_old},${line_count}p $download_log
   756	      line_count_old=$line_count
   757	    fi
   758	  fi
   759	}
   760	
   761	#---------------------------------------------------------------------
   762	## Shows download progress. Waits for the download to start, and shows
   763	## the progress until the download is done.
   764	## Pawn most of the display out to <@function show_download_progress>
   765	## @TODO fix the old style ad-hoc IPC
   766	## @param Spell to show the download progress for
   767	#---------------------------------------------------------------------
   768	function show_downloading()  {
   769	
   770	  local SPELL=$1
   771	  local download_log=$(get_spell_dl_log $SPELL)
   772	  local line_count_old
   773	  debug "cast" "Started show_downloading() on $SPELL from $download_log"
   774	
   775	  # poke around waiting for downloading to start
   776	  while ! [[ -e $download_log ]]
   777	  do
   778	    sleep 1
   779	  done
   780	
   781	  # isn't this out of band ipc great?
   782	  until [  -f "${download_log}.done"  ] ;  do
   783	    show_download_progress $download_log
   784	    sleep 1
   785	  done
   786	
   787	  show_download_progress $download_log
   788	  debug "libcast" "Out of show_downloading"
   789	}
   790	
   791	#---------------------------------------------------------------------
   792	## Gets the filename of the download log file
   793	## @param Spell
   794	## @Stdout file name
   795	#---------------------------------------------------------------------
   796	function get_spell_dl_log() {
   797	  echo "$TMP_DIR/download.$1"
   798	}
   799	
   800	#---------------------------------------------------------------------
   801	## @License
   802	##
   803	## This software is free software; you can redistribute it and/or modify
   804	## it under the terms of the GNU General Public License as published by
   805	## the Free Software Foundation; either version 2 of the License, or
   806	## (at your option) any later version.
   807	##
   808	## This software is distributed in the hope that it will be useful,
   809	## but WITHOUT ANY WARRANTY; without even the implied warranty of
   810	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   811	## GNU General Public License for more details.
   812	##
   813	## You should have received a copy of the GNU General Public License
   814	## along with this software; if not, write to the Free Software
   815	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   816	##
   817	#---------------------------------------------------------------------