/ scripts / linuxcnc.in
linuxcnc.in
  1  #!/bin/bash
  2  ################################################################################
  3  # usage: linuxcnc [options] [<ini-file>]
  4  #
  5  # options:
  6  #     -v = verbose - prints info as it works
  7  #     -d = echos script commands to screen for debugging
  8  #
  9  # this version calls pickconfig.tcl to pick an ini file if one
 10  # is not specified on the command line
 11  #
 12  ################################################################################
 13  # Author:
 14  # License: GPL Version 2
 15  # System: Linux
 16  #    
 17  # Copyright (c) 2004-2009 All rights reserved.
 18  ################################################################################
 19  
 20  # -1. Get all rip-environment items if we are RIP
 21  if test "xyes" = "x@RUN_IN_PLACE@"; then
 22      if test "${EMC2_HOME:-}" != "@EMC2_HOME@"; then
 23          exec @EMC2_HOME@/scripts/rip-environment linuxcnc "$@"
 24      fi
 25  fi
 26  
 27  ################################################################################
 28  # 0. Values that come from configure
 29  ################################################################################
 30  prefix=@prefix@
 31  exec_prefix=@exec_prefix@
 32  
 33  PIDOF="@PIDOF@ -x"
 34  PS=@PS@
 35  AWK=@AWK@
 36  GREP=@GREP@
 37  IPCS=@IPCS@
 38  KILL=@KILL@
 39  
 40  LINUXCNC_HOME=@EMC2_HOME@; export LINUXCNC_HOME
 41  
 42  LINUXCNC_BIN_DIR=@EMC2_BIN_DIR@
 43  LINUXCNC_TCL_DIR=@EMC2_TCL_DIR@
 44  LINUXCNC_HELP_DIR=@EMC2_HELP_DIR@
 45  LINUXCNC_RTLIB_DIR=@EMC2_RTLIB_DIR@
 46  LINUXCNC_CONFIG_PATH="@LINUXCNC_CONFIG_PATH@"
 47  LINUXCNC_NCFILES_DIR=@EMC2_NCFILES_DIR@
 48  LINUXCNC_LANG_DIR=@EMC2_LANG_DIR@
 49  REALTIME=@REALTIME@
 50  LINUXCNC_IMAGEDIR=@EMC2_IMAGE_DIR@
 51  LINUXCNC_TCL_LIB_DIR=@EMC2_TCL_LIB_DIR@
 52  HALLIB_DIR=@HALLIB_DIR@; export HALLIB_DIR
 53  HALLIB_PATH=.:$HALLIB_DIR; export HALLIB_PATH
 54  
 55  # put ~.local/bin in PATH if missing. See:
 56  # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=839155
 57  if [ -d $HOME/.local/bin ]; then
 58      if [[ "$PATH" != *".local/bin"* ]]; then
 59          PATH=$HOME/.local/bin:$PATH
 60      fi
 61  fi
 62  
 63  #put the LINUXCNC_BIN_DIR in PATH
 64  PATH=$LINUXCNC_BIN_DIR:$PATH
 65  #ditto scripts if not RIP
 66  [ -d $LINUXCNC_HOME/scripts ] && PATH=$LINUXCNC_HOME/scripts:$PATH
 67  
 68  if test "xyes" = "x@RUN_IN_PLACE@"; then
 69  	if [ -z "$LD_LIBRARY_PATH" ]; then
 70  	    LD_LIBRARY_PATH=$LINUXCNC_HOME/lib
 71  	else
 72  	    LD_LIBRARY_PATH=$LINUXCNC_HOME/lib:"$LD_LIBRARY_PATH"
 73  	fi
 74  	export LD_LIBRARY_PATH
 75  fi
 76  
 77  if [ -z "$PYTHONPATH" ]; then
 78      PYTHONPATH=$LINUXCNC_HOME/lib/python
 79  else
 80      PYTHONPATH=$LINUXCNC_HOME/lib/python:"$PYTHONPATH"
 81  fi
 82  export PYTHONPATH
 83  
 84  
 85  MODULE_EXT=@MODEXT@ # module extension, used when insmod'ing
 86  
 87  DEBUG_FILE=$(mktemp /tmp/linuxcnc.debug.XXXXXX)
 88  PRINT_FILE=$(mktemp /tmp/linuxcnc.print.XXXXXX)
 89  
 90  program_available () {
 91      type -path "$1" > /dev/null 2>&1
 92  }
 93  
 94  usage () {
 95  	P=${0##*/}
 96  	cat <<EOF
 97  $P: Run LINUXCNC
 98  
 99  Usage:
100  	$P [-d] [-v]
101  		Choose the configuration file graphically
102  
103  	$P [-k] [-d] [-v] path/to/your.ini
104  		Name the configuration file using its path
105  
106  	$P [-k] [-d] [-v] -l
107  		Use the previous configuration file
108  
109  	-d: Turn on "debug" mode
110  	-v: Turn on "verbose" mode
111          -k: Continue in the presence of errors in .hal files
112  EOF
113  
114  }
115  
116  ################################################################################
117  # 1.1. strip and process command line options
118  ################################################################################
119  while getopts "dvlhkr" opt
120  do
121  	case "$opt" in
122  	d)
123  		# enable echoing of script and command output
124  		if tty -s; then
125  		    DEBUG_FILE=/dev/fd/2
126  		    echo "Debug mode on" >$DEBUG_FILE
127  		fi
128  		set -x;;
129  	v)
130  		# enable printing of verbose messages
131  		if tty -s; then
132  		    PRINT_FILE=/dev/fd/1
133  		    echo "Verbose mode on" >$PRINT_FILE
134  		fi;;
135          r)
136                  RUNTESTS=yes
137                  ;;
138  	l)
139  		USE_LAST_INIFILE=1;;
140          k)      DASHK=-k;;
141  	h)
142  		usage
143  		exit 0;;
144  	*)
145  		usage
146  		exit 1
147  	esac
148  done
149  shift $(($OPTIND-1))
150  
151  case "@KERNEL_VERS@" in
152  "") ;;
153  *)
154      if [ `uname -r` != "@KERNEL_VERS@" ]; then
155          if tty -s; then
156              echo "LinuxCNC requires the real-time kernel @KERNEL_VERS@ to run."
157              echo "Before running LinuxCNC, reboot and choose this kernel at the boot menu."
158          else
159              @WISH@ <<EOF
160                  wm wi .
161                  tk_messageBox -type ok \
162                      -title LinuxCNC -icon error -title "Realtime Kernel Required" \
163                      -message {LinuxCNC requires the real-time kernel @KERNEL_VERS@ to run.  Before running LinuxCNC, reboot and choose this kernel at the boot menu.}
164                  exit
165  EOF
166          fi
167          exit
168      fi
169  esac
170  
171  if [ -z $RUNTESTS ]; then
172  if ! tty -s; then
173      exec 2>> $DEBUG_FILE
174      exec >> $PRINT_FILE
175  fi
176  fi
177  
178  function ErrorCheck () {
179      result=$?
180      if [ ! -z "$DISPLAY" ]; then
181          echo "catch {send -async popimage destroy .}; destroy ." | @WISH@
182      fi
183  
184      if [ $result -ne 0 ]; then
185          if tty -s || [ -z "$DISPLAY" ] ; then
186              if [ -f $DEBUG_FILE ]; then
187                  cp $DEBUG_FILE $HOME/linuxcnc_debug.txt
188              else
189                  echo "(debug information was sent to stderr)" \
190                      > $HOME/linuxcnc_debug.txt
191              fi
192  
193              if [ -f $PRINT_FILE ]; then
194                  cp $PRINT_FILE $HOME/linuxcnc_print.txt
195              else
196                  echo "(print information was sent to stdout)" \
197                      > $HOME/linuxcnc_print.txt
198              fi
199  
200              echo "\
201  LinuxCNC terminated with an error.  You can find more information in the log:
202      $HOME/linuxcnc_debug.txt
203  and
204      $HOME/linuxcnc_print.txt
205  as well as in the output of the shell command 'dmesg' and in the terminal"
206          else
207              @WISH@ $LINUXCNC_TCL_DIR/show_errors.tcl $DEBUG_FILE $PRINT_FILE
208          fi
209      fi
210      rm -f $DEBUG_FILE $PRINT_FILE 2>/dev/null
211      exit $result
212  }
213  
214  trap ErrorCheck EXIT
215  
216  ################################################################################
217  # 1.3. INIFILE                           find inifile to use                   #
218  ################################################################################
219  
220  if [ ! -z "$1" ]; then
221      case "$1" in
222        -)  USE_LAST_INIFILE=1;;
223        /*) INIFILE="$1" ;;
224        *)  INIFILE="`pwd`/$1";;
225      esac
226      shift
227  fi
228  EXTRA_ARGS="$@"
229  
230  # 1.3.1. Determine if we have run-in place or installed system
231  RUN_IN_PLACE=@RUN_IN_PLACE@
232  echo RUN_IN_PLACE=$RUN_IN_PLACE >>$PRINT_FILE
233  
234  LINUXCNCVERSION="@EMC2VERSION@"; export LINUXCNCVERSION
235  
236  # common from here..
237  INIVAR=inivar
238  HALCMD="halcmd $DASHK"
239  PICKCONFIG="@WISH@ $LINUXCNC_TCL_DIR/bin/pickconfig.tcl"
240  LINUXCNC_EMCSH=@WISH@
241  
242  echo LINUXCNC_DIR=$LINUXCNC_DIR >>$PRINT_FILE
243  echo LINUXCNC_BIN_DIR=$LINUXCNC_BIN_DIR >>$PRINT_FILE
244  echo LINUXCNC_TCL_DIR=$LINUXCNC_TCL_DIR >>$PRINT_FILE
245  echo LINUXCNC_SCRIPT_DIR=$LINUXCNC_SCRIPT_DIR >>$PRINT_FILE
246  echo LINUXCNC_RTLIB_DIR=$LINUXCNC_RTLIB_DIR >>$PRINT_FILE
247  echo LINUXCNC_CONFIG_DIR=$LINUXCNC_CONFIG_DIR >>$PRINT_FILE
248  echo LINUXCNC_LANG_DIR=$LINUXCNC_LANG_DIR >>$PRINT_FILE
249  echo INIVAR=$INIVAR >>$PRINT_FILE
250  echo HALCMD=$HALCMD >>$PRINT_FILE
251  echo LINUXCNC_EMCSH=$LINUXCNC_EMCSH >>$PRINT_FILE
252  
253  #export some common directories, used by some of the GUI's
254  export LINUXCNC_TCL_DIR
255  export LINUXCNC_EMCSH
256  export LINUXCNC_HELP_DIR
257  export LINUXCNC_LANG_DIR
258  export REALTIME
259  export HALCMD
260  export LINUXCNC_NCFILES_DIR
261  
262  [ -z $RUNTESTS ] && echo "LINUXCNC - $LINUXCNCVERSION" 
263  
264  # was an inifile specified on the command line?
265  if [ ! -z "$USE_LAST_INIFILE" ]; then
266      INIFILE=$($INIVAR -ini ~/.linuxcncrc -var LAST_CONFIG -sec PICKCONFIG 2>>$DEBUG_FILE)
267      echo "Using previous inifile: $INIFILE" >> $PRINT_FILE
268  fi
269  
270  if [ ! -n "$INIFILE" ] ; then
271      # nothing specified, get from the user
272      # it returns either a path, or nothing at all
273      INIFILE=$($PICKCONFIG)
274      # if name is xxxx.demo, then:
275      #    execute xxxx.demo in background and exit
276      if [ "${INIFILE%%.demo}".demo = "${INIFILE}" ] ; then
277        "${INIFILE}" &
278        exit 0
279      fi
280  fi
281  
282  if [ ! -n "$INIFILE" ] ; then
283      # still nothing specified, exit
284      exit 0
285  fi
286  
287  function handle_includes () {
288    hdr="# handle_includes():"
289    inifile="$1"
290    cd "$(dirname $inifile)" ;# for the function() subprocess only
291    $GREP "^#INCLUDE" "$inifile" >/dev/null
292    status=$?
293    if [ $status -ne 0 ] ; then
294      echo "$inifile" ;# just use the input
295      return 0 ;# ok
296    fi
297    outfile="$(dirname $inifile)/$(basename $inifile).expanded"
298    >|"$outfile"
299    echo "#*** $outfile" >>"$outfile"
300    echo "#*** Created: $(date)" >>"$outfile"
301    echo "#*** Autogenerated file with expanded #INCLUDEs" >>"$outfile"
302    echo "" >>"$outfile"
303    line=0
304    while read a b ; do
305      line=$((line + 1))
306      if [ "$a" = "#INCLUDE" ] ; then
307         if [ "X$b" = "X" ] ; then
308            msg="$hdr <$line> found #INCLUDE with no filename" >>"$outfile"
309            echo "$msg" >&2
310            echo "$msg" >>"$outfile"
311         else
312            # expand file name
313            breal=$(eval echo "$b")
314            # -r: readable
315            if  [ -r "$breal" ] ; then
316              echo "" >>"$outfile"
317              echo "#*** Begin #INCLUDE file: $breal" >>"$outfile"
318              cat "$breal" >>"$outfile"
319              echo "#*** End   #INCLUDE file: $breal" >>"$outfile"
320            else
321              msg="$hdr <$line> CANNOT READ $breal"
322              echo "$msg" >&2
323              echo "$msg" >>"$outfile"
324            fi
325         fi
326      else
327         echo "$a $b" >> "$outfile"
328      fi
329    done <"$inifile"
330    echo "$outfile" ;# use the expanded file
331    return 0 ;# ok
332  }
333  
334  function split_app_items () {
335    app_name=$1
336    shift
337    app_args=$*
338  }
339  
340  function run_applications () {
341      NUM=1
342      APPFILE=`$INIVAR -tildeexpand -ini "$INIFILE" -var APP -sec APPLICATIONS -num $NUM 2> /dev/null`
343      if [ -z "$APPFILE" ] ; then return ; fi
344      DEFAULT_APPLICATION_DELAY=0
345      GetFromIni DELAY APPLICATIONS
346      DELAY=${retval:-$DEFAULT_APPLICATION_DELAY}
347      while [ -n "$APPFILE" ] ; do
348         split_app_items $APPFILE # --> app_name app_args
349         # try all explicit specifications before trying PATH
350         case "$app_name" in
351           /*) # absolute pathname
352               exe_name=$app_name;;
353         \./*) # name relative to inifile directory
354               exe_name="$(pwd)/$app_name";;
355            *) # try local first then PATH
356               exe_name=$(pwd)/$app_name
357               if [ ! -x $exe_name ] ; then
358                 exe_name=$(which $app_name)
359               fi
360         esac
361         if [ ! -f "$exe_name" ] ; then
362            echo "APP: Cannot find executable file for: <$app_name>"
363         else
364            if [ ! -x "$exe_name" ] ; then
365               echo "APP: File not executable: <$exe_name>"
366            else
367               echo "APP: $app_name found: <$exe_name>"
368               (sleep $DELAY; eval $exe_name $app_args) &
369            fi
370         fi
371         NUM=$(($NUM+1))
372         APPFILE=`$INIVAR -tildeexpand -ini "$INIFILE" -var APP -sec APPLICATIONS -num $NUM 2> /dev/null`
373      done
374  }
375  
376  INIFILE="$(handle_includes "$INIFILE")"
377  
378  # delete directories from path, save name only
379  INI_NAME="${INIFILE##*/}"
380  INI_DIR="${INIFILE%/*}"
381  CONFIG_DIR="${INIFILE%/*}"
382  export CONFIG_DIR
383  export PATH=$CONFIG_DIR/bin:$PATH
384  
385  [ -z $RUNTESTS ] && echo "Machine configuration directory is '$INI_DIR'"
386  echo "Machine configuration file is '$INI_NAME'"
387  
388  # make sure ini file exists (the tcl script just did this, so we could 
389  # eliminate this test, but it does no harm)
390  
391  if [ ! -f "$INIFILE" ] ; then
392      echo "Could not find ini file '$INIFILE'"
393      trap '' EXIT
394      exit -1
395  fi
396  echo INIFILE="$INIFILE" >>$PRINT_FILE
397  
398  ################################################################################
399  # 2.  extract info from the ini file that we will need later
400  ################################################################################
401  retval=
402  
403  # 2.1. define helper function
404  function GetFromIniQuiet {
405      #$1 var name   $2 - section name
406      name=$1
407      retval=`$INIVAR -ini "$INIFILE" -var $1 -sec $2 2> /dev/null`
408      if [ ! -n "$1" ] ; then
409  	exit -1
410      fi
411      echo "$name=$retval" >>$PRINT_FILE
412  }
413  
414  function GetFromIni {
415      #$1 var name   $2 - section name
416      name=$1
417      retval=`$INIVAR -ini "$INIFILE" -var $1 -sec $2 2>>$DEBUG_FILE`
418      if [ ! -n "$1" ] ; then
419  	echo "Can't find variable $1 in section [$2] of file $INIFILE."
420  	exit -1
421      fi
422      echo "$name=$retval" >>$PRINT_FILE
423  }
424  
425  # Usage:
426  #  GetFromIniEx VAR1 SEC1 [VAR2 SEC2...VARn SECn] [default]
427  function GetFromIniEx {
428      original_var="[$2]$1"
429      while [ $# -ge 2 ]; do
430  	if retval=`$INIVAR -ini "$INIFILE" -var "$1" -sec "$2" 2>/dev/null`; then return; fi
431  	shift 2
432      done
433      if [ $# -eq 0 ]; then
434  	echo "Can't find $original_var in $INIFILE."
435  	exit -1
436      fi
437      retval="$1"
438  }
439  
440  # 2.1.5 check version
441  GetFromIni VERSION EMC
442  if [ "$retval" != "1.1" ]; then
443      if [ -z "$DISPLAY" ]; then
444          echo "ini file [EMC]VERSION indicates update is needed, but the update GUI can't run without an X display"
445          exit 1
446      fi
447      update_ini -d "$INIFILE"
448      exitval=$?
449      case "$exitval" in
450      0) ;;
451      42) echo "update_ini cancelled by user" ; exit 0;;
452      *) echo "update script failed in an unexpected way."; exit $exitval ;;
453      esac
454  fi
455  
456  @TCLSH@ $HALLIB_DIR/check_config.tcl "$INIFILE"
457  exitval=$?
458  case "$exitval" in
459    0) ;;
460    1) echo "check_config validation failed"; exit $exitval ;;
461    *) echo "check_config validation failed in an unexpected way."; exit $exitval ;;
462  esac
463  # 2.2. get param file
464  
465  GetFromIni PARAMETER_FILE RS274NGC 
466  RS274NGC_PARAMFILE=$retval
467  
468  # 2.3. get mot information
469  GetFromIniEx MOT MOT EMCMOT EMCMOT motmod
470  EMCMOT=$retval$MODULE_EXT # add module extension
471  
472  # 2.4. get io information
473  GetFromIniEx IO IO EMCIO EMCIO io
474  EMCIO=$retval
475  
476  # 2.5. get task information
477  GetFromIni TASK TASK
478  EMCTASK=$retval
479  
480  if [ "$EMCTASK" = emctask ]; then EMCTASK=linuxcnctask; fi
481  
482  # 2.6. we hardcode the server name, change if needed
483  # linuxcncsvr now holds/creates all the NML channels,
484  # so it needs to start by default, as the first process
485  EMCSERVER=linuxcncsvr
486  
487  # 2.7. get halui information
488  GetFromIniQuiet HALUI HAL
489  HALUI=$retval
490  
491  # 2.8. get display information
492  GetFromIni DISPLAY DISPLAY
493  EMCDISPLAY=`(set -- $retval ; echo $1 )`
494  EMCDISPLAYARGS=`(set -- $retval ; shift ; echo $* )`
495  
496  case $EMCDISPLAY in
497      tkemc) EMCDISPLAY=tklinuxcnc ;;
498  esac
499  
500  # 2.9. get NML config information
501  GetFromIniEx NML_FILE LINUXCNC NML_FILE EMC @DEFAULT_NMLFILE@
502  NMLFILE=$retval
503  export NMLFILE
504  
505  # 2.10. INI information that may be needed by other apps in process tree
506  GetFromIni COORDINATES TRAJ
507  TRAJ_COORDINATES=$retval
508  export TRAJ_COORDINATES
509  
510  GetFromIni KINEMATICS KINS
511  KINS_KINEMATICS=$retval
512  export KINS_KINEMATICS
513  
514  ################################################################################
515  # 3. Done gathering information, define a few functions
516  # Execution resumes after function definitions...
517  ################################################################################
518  
519  KILL_TASK=
520  KILL_TIMEOUT=20
521  
522  ################################################################################
523  # 3.1. Kills a list of tasks with timeout
524  # if it doesn't work, kill -9 is used
525  ################################################################################
526  function KillTaskWithTimeout() {
527      if [ ! -n "$KILL_PIDS" ] ; then
528  	KILL_PIDS=`$PIDOF $KILL_TASK`
529      fi
530      if [ ! -n "$KILL_PIDS" ] ; then
531  	echo "Could not find pid(s) for task $KILL_TASK"
532  	return -1
533      fi
534      local NPROCS
535      for KILL_PID in $KILL_PIDS ; do
536          if $PS -o comm= $KILL_PID | $GREP -q '<defunct>'; then
537              echo "Skipping defunct task $KILL_TASK, PID=$KILL_PID" >>$PRINT_FILE
538              continue
539          fi
540  	# first a "gentle" kill with signal TERM
541  	$KILL $KILL_PID
542  	WAIT=$KILL_TIMEOUT
543  	# wait and see if it dissappears
544  	while [ $WAIT -gt 1 ] ; do
545  	    # see if it's still alive
546              NPROCS=$($PS -o comm= $KILL_PID | $GREP -v '<defunct>' | wc -l)
547              if [ $NPROCS -gt 0 ]; then
548  		WAIT=$(($WAIT-1))
549  		sleep .1
550  	    else
551  		WAIT=0
552  	    fi
553  	done
554  	if [ $WAIT -gt 0 ] ; then
555  	    # gentle didn't work, get serious
556  	    echo "Timeout, trying kill -9" >>$PRINT_FILE
557  	    $KILL -9 $KILL_PID
558  	    WAIT=$KILL_TIMEOUT
559  	    # wait and see if it dissappears
560  	    while [ $WAIT -gt 1 ] ; do
561  		# see if it's still alive
562                  NPROCS=$($PS -o comm= $KILL_PID | $GREP -v '<defunct>' | wc -l)
563                  if [ $NPROCS -gt 0 ]; then
564  		    WAIT=$(($WAIT-1))
565  		    sleep .1
566  		else
567  		    WAIT=0
568  		fi
569  	    done
570  	fi
571  	if [ $WAIT -gt 0 ] ; then
572  	    echo "Could not kill task $KILL_TASK, PID=$KILL_PID"
573  	fi
574      done
575      KILL_PIDS=
576      KILL_TASK=
577  }
578  
579  
580  ################################################################################
581  # 3.2. define the cleanup function
582  #
583  # this cleanup function doesn't know or care what was actually
584  # loaded - it simply kills _any_ processes in its list of
585  # components
586  ################################################################################
587  function Cleanup() {
588  
589      echo "Shutting down and cleaning up LinuxCNC..."
590      # Kill displays first - that should cause an orderly
591      #   shutdown of the rest of linuxcnc
592      for KILL_TASK in linuxcncpanel iosh linuxcncsh linuxcncrsh linuxcnctop mdi debuglevel gmoccapy gscreen; do
593  	if $PIDOF $KILL_TASK >>$DEBUG_FILE ; then
594  	    KillTaskWithTimeout
595  	fi
596      done
597  
598      if program_available axis-remote ; then
599  	if [ ! -z "$DISPLAY" ]; then
600  	    axis-remote --ping && axis-remote --quit
601  	fi
602      fi
603  
604      if [ "$1" = "other" ]; then
605          echo -n "Waiting for other session to finish exiting..."
606  	WAIT=$KILL_TIMEOUT
607  	while [ $WAIT -gt 1 ]; do
608              if ! [ -f $LOCKFILE ]; then
609                  echo " Ok"
610                  return 0
611              fi
612              WAIT=$(($WAIT-1))
613              sleep .1
614          done
615          echo "lockfile still not removed"
616      fi
617  
618      SHUTDOWN=`$INIVAR -ini "$INIFILE" -var SHUTDOWN -sec HAL 2> /dev/null`
619      if [ -n "$SHUTDOWN" ]; then
620  	echo "Running HAL shutdown script"
621  	$HALCMD -f $SHUTDOWN
622      fi
623  
624      # now kill all the other user space components
625      for KILL_TASK in linuxcncsvr milltask; do
626  	if $PIDOF $KILL_TASK >>$DEBUG_FILE ; then
627  	    KillTaskWithTimeout
628  	fi
629      done
630  
631      echo "Stopping realtime threads" >> $DEBUG_FILE
632      $HALCMD stop
633      echo "Unloading hal components" >> $DEBUG_FILE
634      $HALCMD unload all
635  
636      for i in `seq 10`; do
637          # (the one component is the halcmd itself)
638          if [ `$HALCMD list comp | wc -w` = 1 ]; then break; fi
639          sleep .2
640      done
641  
642      echo "Removing HAL_LIB, RTAPI, and Real Time OS modules" >>$PRINT_FILE
643      $REALTIME stop
644  
645      echo "Removing NML shared memory segments" >> $PRINT_FILE
646      while read b x t x x x x x x m x; do
647          case $b$t in
648              BSHMEM) ipcrm -M $m 2>/dev/null;;
649          esac
650      done < $NMLFILE
651  
652  
653      # remove lock file
654      if [ -f $LOCKFILE ] ; then
655  	rm $LOCKFILE
656      fi
657  }
658  
659  
660  
661  ################################################################################
662  # 4. done with function definitions, execution resumes here
663  ################################################################################
664  
665  # Name of lock file to check for that signifies that LinuxCNC is up,
666  # to prevent multiple copies of controller
667  LOCKFILE=/tmp/linuxcnc.lock
668  
669  # Check for lock file
670  if [ -f $LOCKFILE ]; then
671    if tty -s; then
672      echo -n "LinuxCNC is still running.  Restart it? [Y/n] "
673      read input; [ -z $input ] && input=y
674    else
675      input=$(@WISH@ <<EOF
676  wm wi .
677  puts [tk_messageBox -title LinuxCNC -message "LinuxCNC is still running.  Restart it?" -type yesno]
678  exit
679  EOF
680  )
681    fi
682    case $input in
683      y|Y|yes)
684        echo Cleaning up old LinuxCNC...
685        Cleanup other
686      ;;
687      *)
688        echo Not starting new LinuxCNC
689        exit 0
690      ;;
691    esac
692  fi
693  echo Starting LinuxCNC...
694  
695  # trap ^C so that it's called if user interrupts script
696  trap 'Cleanup ; exit 0' SIGINT SIGTERM
697  
698  # go to the dir where the ini file is
699  # either configs/<specific-config> when run-in-place, or
700  # /usr/local/share/linuxcnc/configs/<specific-config> (wherever it was installed)
701  cd "$INI_DIR"
702  
703  # Create the lock file
704  touch $LOCKFILE
705  
706  ################################################################################
707  # 4.1. pop up intro graphic
708  ################################################################################
709  img=`$INIVAR -ini "$INIFILE" -var INTRO_GRAPHIC -sec DISPLAY 2>>$DEBUG_FILE`
710  imgtime=`$INIVAR -ini "$INIFILE" -var INTRO_TIME -sec DISPLAY 2>>$DEBUG_FILE`
711  if [ "$imgtime" = "" ] ; then
712    imgtime=5
713  fi
714  if [ "$img" != "" ] ; then
715    if [ -e "$img" ]; then
716      true
717    elif [ -e "$INI_DIR/$img" ]; then
718      img="$INI_DIR/$img"
719    elif [ -e "$LINUXCNC_IMAGEDIR/$img" ]; then
720      img="$LINUXCNC_IMAGEDIR/$img"
721    else
722      img=
723    fi
724  fi
725  if [ "$img" != "" ] ; then
726      if [ -x $LINUXCNC_TCL_DIR/bin/popimage ] ; then
727          $LINUXCNC_TCL_DIR/bin/popimage $img $imgtime &
728      fi
729  fi
730   
731  ################################################################################
732  # 4.2. Now we can finally start loading LinuxCNC
733  ################################################################################
734  
735  # 4.3.1. Run linuxcncserver in background, always (it owns/creates the NML buffers)
736  echo "Starting LinuxCNC server program: $EMCSERVER" >>$PRINT_FILE
737  if ! program_available $EMCSERVER; then
738      echo "Can't execute server program $EMCSERVER"
739      Cleanup
740      exit 1
741  fi
742  export INI_FILE_NAME="$INIFILE"
743  $EMCSERVER -ini "$INIFILE"
744  
745  # 4.3.2. Start REALTIME
746  echo "Loading Real Time OS, RTAPI, and HAL_LIB modules" >>$PRINT_FILE
747  if ! $REALTIME start ; then
748      echo "Realtime system did not load"
749      Cleanup
750      exit -1
751  fi
752  
753  # 4.3.3. export the location of the HAL realtime modules so that
754  # "halcmd loadrt" can find them
755  export HAL_RTMOD_DIR=$LINUXCNC_RTLIB_DIR
756  
757  # 4.3.4. Run io in background if so defined in INI
758  if [ "$EMCIO" != "" ] ; then
759          echo "Starting LinuxCNC IO program: $EMCIO" >>$PRINT_FILE
760          if ! program_available $EMCIO ; then
761                  echo "Can't execute IO program $EMCIO"
762                  Cleanup
763          exit 1
764          fi
765          $HALCMD loadusr -Wn iocontrol $EMCIO -ini "$INIFILE"
766  else
767          echo "Skipping LinuxCNC IO program >>$PRINT_FILE"
768  fi
769  
770  # 4.3.5. Run halui in background, if necessary
771  if [ -n "$HALUI" ] ; then
772      echo "Starting HAL User Interface program: $HALUI" >>$PRINT_FILE
773      if ! program_available $HALUI ; then
774  	echo "Can't execute halui program $HALUI"
775  	Cleanup
776  	exit 1
777      fi
778      $HALCMD loadusr -Wn halui $HALUI -ini "$INIFILE"
779  fi
780  
781  # 4.3.6. execute HALCMD config files (if any)
782  
783  TWOPASS=`$INIVAR -ini "$INIFILE" -var TWOPASS -sec HAL -num 1 2> /dev/null`
784  if [ -n "$TWOPASS" ] ; then
785    # 4.3.6.1. if [HAL]TWOPASS is defined, handle all [HAL]HALFILE entries here:
786    CFGFILE=@EMC2_TCL_LIB_DIR@/twopass.tcl
787    export PRINT_FILE # twopass can append to PRINT_FILE
788    if ! haltcl -i "$INIFILE" $CFGFILE && [ "$DASHK" = "" ]; then
789        Cleanup
790        exit -1
791    fi
792  else
793      # 4.3.6.2. conventional execution of  HALCMD config files
794      # get first config file name from ini file
795      NUM=1
796      CFGFILE=`$INIVAR -tildeexpand -ini "$INIFILE" -var HALFILE -sec HAL -num $NUM 2> /dev/null`
797      while [ -n "$CFGFILE" ] ; do
798          IFS='\ ' read CFGFILE CFGFILE_ARGS <<< "$CFGFILE" # separate args
799          foundmsg=""
800          saveIFS=$IFS; IFS=: # colon (:) path separator for HALLIB_PATH
801          explicit_file_in_hallib=${CFGFILE#LIB:} # strip leading 'LIB:'
802          if [ -z "$explicit_file_in_hallib" ] ; then
803             echo "ILLFORMED LIB:file:<$CFGFILE>"
804          fi
805          if [ "$explicit_file_in_hallib" !=  "$CFGFILE" ] ; then
806            foundfile="$HALLIB_DIR/$explicit_file_in_hallib"
807            if [ ! -r $foundfile ] ; then
808                echo "CANNOT READ LIB:file:$foundfile"
809            fi
810            foundmsg="Found file(LIB): $foundfile"
811          else
812            if [ "${CFGFILE:0:1}" = "/" ] ; then
813              foundfile=$CFGFILE ;# absolute path specified
814              foundmsg="Found file(ABS): $foundfile"
815            else 
816              for pathdir in $HALLIB_PATH ; do
817                foundfile=$pathdir/$CFGFILE
818                if [ -r $foundfile ] ; then
819                  # use first file found in HALLIB_PATH
820                  if [ "${pathdir:0:1}" = "." ] ; then
821                    foundmsg="Found file(REL): $foundfile"
822                  else
823                    foundmsg="Found file(lib): $foundfile"
824                  fi
825                  break
826                fi
827              done
828            fi
829          fi
830          [ -d $foundfile ] && foundmsg=""
831          IFS=$saveIFS
832          if [ -z "$foundmsg" ] ; then
833            echo "CANNOT FIND FILE FOR:$CFGFILE"
834            Cleanup
835            exit -1
836          fi
837          echo "$foundmsg"
838          CFGFILE="$foundfile"
839          case $CFGFILE in
840          *.tcl)
841              if ! haltcl -i "$INIFILE" $CFGFILE $CFGFILE_ARGS \
842                 && [ "$DASHK" = "" ]; then
843                  Cleanup
844                  exit -1
845              fi
846          ;;
847          *)
848              if ! $HALCMD -i "$INIFILE" -f $CFGFILE && [ "$DASHK" = "" ]; then
849                  Cleanup
850                  exit -1
851              fi
852          esac
853          # get next config file name from ini file
854          NUM=$(($NUM+1))
855          CFGFILE=`$INIVAR -tildeexpand -ini "$INIFILE" -var HALFILE -sec HAL -num $NUM 2> /dev/null`
856      done
857  fi
858  
859  # 4.3.7. Run task in background
860  echo "Starting TASK program: $EMCTASK" >>$PRINT_FILE
861  if ! program_available $EMCTASK ; then
862      echo "Can't execute TASK program $EMCTASK"
863      Cleanup
864      exit 1
865  fi
866  
867  halcmd loadusr -Wn inihal $EMCTASK -ini "$INIFILE" &
868  
869  # 4.3.8. execute discrete HAL commands from ini file (if any)
870  # get first command from ini file
871  NUM=1
872  HALCOMMAND=`$INIVAR -ini "$INIFILE" -var HALCMD -sec HAL -num $NUM 2> /dev/null`
873  while [ -n "$HALCOMMAND" ] ; do
874      if [ -n "$HALCOMMAND" ] ; then
875  	echo "Running HAL command: $HALCOMMAND" >>$PRINT_FILE
876  	if ! $HALCMD $HALCOMMAND && [ "$DASHK" = "" ]; then
877  	    echo "ini file HAL command $HALCOMMAND failed."
878  	    Cleanup
879  	    exit -1
880  	fi
881      fi
882      # get next command from ini file
883      NUM=$(($NUM+1))
884      HALCOMMAND=`$INIVAR -ini "$INIFILE" -var HALCMD -sec HAL -num $NUM 2> /dev/null`
885  done
886  
887  # 4.3.9. start the realtime stuff ticking
888  $HALCMD start
889  
890  # 4.3.10. run other applications
891  run_applications
892  
893  # 4.3.11. Run display in foreground
894  echo "Starting DISPLAY program: $EMCDISPLAY" >>$PRINT_FILE
895  result=0
896  case $EMCDISPLAY in
897    tklinuxcnc)
898      # tklinuxcnc is in the tcl directory, not the bin directory
899      if [ ! -x $LINUXCNC_TCL_DIR/$EMCDISPLAY.tcl ] ; then
900  	echo "Can't execute DISPLAY program $LINUXCNC_TCL_DIR/$EMCDISPLAY.tcl $EMCDISPLAYARGS"
901  	Cleanup
902  	exit 1
903      fi
904      $LINUXCNC_TCL_DIR/$EMCDISPLAY.tcl -ini "$INIFILE" $EMCDISPLAYARGS
905      result=$?
906    ;;
907    dummy)
908      # dummy display just waits for <ENTER>
909      echo "DUMMY DISPLAY MODULE, press <ENTER> to continue."
910      read foo;
911    ;;
912    linuxcncrsh)
913      $EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS -- -ini "$INIFILE"
914    ;;
915    *)
916      # all other displays are assumed to be commands on the PATH
917      if ! program_available $EMCDISPLAY; then
918          echo "Can't execute DISPLAY program $EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS"
919          Cleanup
920          exit 1
921      fi
922      $EMCDISPLAY -ini "$INIFILE" $EMCDISPLAYARGS $EXTRA_ARGS
923      result=$?
924    ;;
925  esac
926  
927  # the display won't return until you shut it down,
928  # so when you get here it's time to clean up
929  Cleanup
930  
931  exit $result