-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathiocsh
executable file
·547 lines (506 loc) · 17.3 KB
/
iocsh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
#!/bin/bash
help () {
cat <<- EOF >&2
Usage: iocsh [options] [files] [macro=value] ...
Start an EPICS iocsh and load files
Options:
-?, -h, --help Show this page and exit.
-v, --version Show version and exit.
-win, --win Run Windows softIOC via wine.
-32 Force 32 bit version (on 64 bit systems).
--nopva Do not use PVA (in EPICS 7).
--nolock Do not lock memory into RAM (in EPICS 3.15.3+).
-x[.z[.y]] Select EPICS base version x.z.y (e.g. 3.14.8, 3.15, 7).
-d, --debug Run IOC with gdb.
-dv Run IOC with valgrind.
-dp Run IOC with perf record.
-i bashscript Source bashscript before starting ioc.
-c 'cmd args' Ioc shell command.
-s 'prog m=v' Sequencer program (and arguments), run with 'seq'.
This forces an 'iocInit' before running the program.
-r module[,ver] Module (optionally with version) loaded via 'require'.
-n name Name of the IOC, used for prompt and \${IOC} variable.
Default: dirname if parent dir is "ioc" otherwise hostname.
@file More arguments are read from file.
Supported filetypes:
*.db, *.dbt, *.template loaded via 'dbLoadRecords'
*.subs, *.subst loaded via 'dbLoadTemplate'
*.dbd loaded via 'dbLoadDatabase'
*.so loaded via 'dlload' (or 'ld' before 3.14.12)
All other files are executed as startup scripts by the EPICS shell.
After a file you can specify substitutions like m1=v1 m2=v1 for that file.
If a readable file iocsh.init exists in ./, cfg/, or /etc/, it is sourced
when iocsh starts (see also -i option). Only the first one found is sourced.
This allows to set environment variables etc before EPICS starts.
In this context, the variables \${IOC}, \${BASE}, and \${EPICS_HOST_ARCH} are
already set to the ioc name, the path to the used EPICS installation and the
used architecture (which may have been modified by -32 or -win).
If the environment variable NOPVA is not empty, it works like --nopva
except if set to 0, n, no, f, false or off (case insensitive).
The environment variable LOADER can be used to run EPICS inside another
program. Internally this is used for wine, gdb, valgrind, etc.
A file EPICSVERSION or cfg/EPICSVERSION may contain a default EPICS version
like 3.14.8, 3.15, or 7 but the command line option takes precedence.
Examples:
iocsh st.cmd
iocsh my_database.template P=XY M=3
iocsh -r my_module,version -c 'initModule()'
iocsh -3.15.4 -dp st.cmd
iocsh -c 'var requireDebug 1' st.cmd
EOF
exit
}
version () {
{
echo "iocsh by Dirk Zimoch"
} >&2
exit
}
# realpath and readlink are not available on all systems, let's try what works...
rp() {
( realpath "$1" || readlink -f "$1" || readlink "$1" || (cd -P "$1" && echo $PWD) || (x=$(\ls -ld "$1") && echo ${x##* }) || echo $1 ) 2>/dev/null
}
# if EPICS_HOST_ARCH is not set guess it
if [ -z "$EPICS_HOST_ARCH" ]
then
EPICS_HOST_ARCH=$(basename $(dirname $(rp $(which caRepeater 2>/dev/null)) 2>/dev/null) 2>/dev/null)
if [ -n "$EPICS_HOST_ARCH" ]
then
echo "Guessing EPICS_HOST_ARCH=$EPICS_HOST_ARCH." >&2
else
echo "EPICS_HOST_ARCH is not set." >&2
echo "(And I cannot guess it because I cannot find caRepeater.)" >&2
exit 1
fi
fi
if read BASE < EPICSVERSION || read BASE < cfg/EPICSVERSION
then
unset EPICS_BASE
fi 2> /dev/null
# IOC name derives from hostname
# (trailing possible '\r' under cygwin)
IOC=$(hostname|tr -d '\r')
# trailing possible domain name
IOC=${IOC%%.*}
# or get IOC name from start directory following PSI convention
D=$(basename $(dirname $PWD))
if [ "${D#*_}" = "ioc" ]
then
IOC=$(basename $PWD)
fi
export IOC
while true
do
case $1 in
( -win | --win )
PATH=/opt/gfa-wine/bin:$PATH
LOADER="$LOADER wine64"
export WINEDEBUG=fixme-all,err-all
export WINEDLLOVERRIDES="mscoree,mshtml="
export WINEPREFIX=$HOME/.wine-$EPICS_HOST_ARCH
[[ $(wine64 --version) = wine-6.* ]] && stty -isig 2> /dev/null # or CTRL-C hangs up on wine 6
EPICS_HOST_ARCH=windows-x64
;;
( -32 )
EPICS_HOST_ARCH=${EPICS_HOST_ARCH%_64}
;;
( -[1-9]* )
unset EPICS_BASE
BASE=${1#-}
;;
( -nopva | --nopva )
NOPVA=1
;;
( -nolock | --nolock )
NOLOCK=1
;;
( -n | --name )
shift
IOC="$1"
;;
( -d | -dg | --debug )
LOADER="gdb --eval-command run --args $LOADER"
;;
( -dv )
LOADER="valgrind --leak-check=full $LOADER"
;;
( -dp )
LOADER="perf record $LOADER"
;;
( -h | "-?" | -help | --help )
help
;;
( -v | -ver | --ver | -version | --version )
version
;;
( * ) break
;;
esac
shift
done
# Either EPICS or EPICS_BASE should be set to the install directory
if [ -z "$EPICS_BASE" ]
then
if [ -z "$EPICS" ]
then
# look for some standard install directories
for EPICS in /usr/local/epics /opt/epics /epics
do
if [ -d "$EPICS" ]
then
break
fi
done
if [ ! -d "$EPICS" ]
then
EPICS=$(dirname $(dirname $(dirname $(dirname $(ldd $(which caRepeater) | awk '/libca/ {print $3}')))))
echo "Guessing EPICS=$EPICS"
fi
if [ ! -d "$EPICS" ]
then
echo "Cannot find EPICS installation directory." >&2
echo "Try setting EPICS environment variable." >&2
exit 1
fi
fi
if [ -z "$BASE" ]
then
# if no BASE is given, first look for plain /epics/base/ dir
EPICS_BASE=$(\ls -1vrd $EPICS/base/bin/{${EPICS_HOST_ARCH},${EPICS_HOST_ARCH%_64}} 2>/dev/null | head -n1)
fi
if [ -z "$EPICS_BASE" ]
then
# look for exact requested EPICS version
EPICS_BASE=$(\ls -1vrd $EPICS/base-$BASE/bin/{${EPICS_HOST_ARCH},${EPICS_HOST_ARCH%_64}} 2>/dev/null | head -n1)
if [ -z "$EPICS_BASE" ]
then
# find highest (requested) 3-part-numeric EPICS version that supports our architecture (or its 32 bit version)
# ignore all versions listed in ignore file
EPICS_BASE=$(eval \ls -1vrd $EPICS/base-$BASE*/bin/{${EPICS_HOST_ARCH},${EPICS_HOST_ARCH%_64}} 2>/dev/null \
$(test -f $EPICS/ignore && sed < $EPICS/ignore ':b;$!N;s/[[:space:]]/|/;tb;s/\./\\./g;s/.*/|grep -Ev \x27&\x27/g') \
| grep -E '/base-[0-9]+\.[0-9]+\.[0-9]+/' \
| head -n1)
fi
fi
if [ -z "$EPICS_BASE" ]
then
if [ -z "$(\ls -1vrd $EPICS/base-$BASE*/ 2>/dev/null)" ]
then
echo No EPICS $BASE installation found $(test -n "$EPICS" && echo -n " in $EPICS").>&2
exit 1
fi
echo No EPICS $BASE available for EPICS_HOST_ARCH=$EPICS_HOST_ARCH. >&2
test -f $EPICS/ignore && echo "(ignored: $(sed < $EPICS/ignore 's/[[:space:]]/, /g') as listed in $EPICS/ignore)"
exit 1
fi
# maybe we need to change from 64 bit to 32 bit
if [ "$EPICS_HOST_ARCH" != "${EPICS_BASE#*/bin/}" ]
then
EPICS_HOST_ARCH=${EPICS_BASE#*/bin/}
echo "No 64 bit version in ${EPICS_BASE%bin*}." >&2
echo "Switching to 32 bit version $EPICS_HOST_ARCH." >&2
fi
EPICS_BASE=$(rp ${EPICS_BASE%bin*})
fi
if [ ! -d "$EPICS_BASE" ]
then
echo "Cannot find EPICS_BASE directory." >&2
echo "Try setting EPICS_BASE environment variable to full path" >&2
exit 1
fi
LIBDIR=lib
LIBPREFIX=lib
LIBPOSTFIX=.so
EXEPOSTFIX=
case $(uname) in
( Darwin )
LIBPOSTFIX=.dylib
;;
esac
case "$EPICS_HOST_ARCH" in
( win* )
LIBDIR=bin
LIBPREFIX=
LIBPOSTFIX=.dll
EXEPOSTFIX=.exe
;;
# Some architectures have little memory
( mvl40-xscale_be | moxa42-armv6l | eldk42-ppc4xxFP )
# Safe memory by not using PVA
NOPVA=1
# Do not lock memory in RAM to save on VmRSS
NOLOCK=1
;;
esac
# Get actual EPICS BASE version, either from CONFIG_BASE_VERSION (text) file or from version string in libCom.so
# Version may have 3 or 4 digits. We make a (4*2 digit) BASECODE too for easier comparison.
# How many digits the drivers use is another question.
if [ -f "$EPICS_BASE/configure/CONFIG_BASE_VERSION" ]
then
eval $(awk -F '[ \t]*=[ \t]*' '
/^[ \t]*EPICS_VERSION[ \t]*=/ {v=$2}
/^[ \t]*EPICS_REVISION[ \t]*=/ {r=$2}
/^[ \t]*EPICS_MODIFICATION[ \t]*=/ {m=$2+0}
/^[ \t]*EPICS_PATCH_LEVEL[ \t]*=/ {p=$2+0}
END {print "BASE3="v"."r"."m";BASE4="v"."r"."m"."p";BASECODE="v*1000000+r*10000+m*100+p}
' < $EPICS_BASE/configure/CONFIG_BASE_VERSION)
elif [ -f "$EPICS_BASE/$LIBDIR/$EPICS_HOST_ARCH/${LIBPREFIX}Com$LIBPOSTFIX" ]
then
strings $EPICS_BASE/$LIBDIR/$EPICS_HOST_ARCH/${LIBPREFIX}Com$LIBPOSTFIX | grep "EPICS R[0-9]"
eval $(strings $EPICS_BASE/$LIBDIR/$EPICS_HOST_ARCH/${LIBPREFIX}Com$LIBPOSTFIX | awk -F'[.R]' '
/EPICS R[0-9]/ {print "BASE3="$2"."$3"."$4+0";BASE4="$2"."$3"."$4+0"."$5+0";BASECODE="$2*1000000+$3*10000+$4*100+$5 }')
else
echo "Cannot guess EPICS base version." >&2
exit 1;
fi
# Check how many digits of BASE we need to find the drivers
for B in $BASE $BASE4 $BASE3 ${EPICS_BASE#*/base-}
do
if [ -d "${EPICS_MODULES:=/ioc/modules}/${REQUIRE:=require}" ]
then # new module pool model
REQUIRE_LIB=$(ls -1rv $EPICS_MODULES/$REQUIRE/${REQUIRE_VERSION:-*.*.*}/R$B/lib/$EPICS_HOST_ARCH/$LIBPREFIX$REQUIRE$LIBPOSTFIX 2>/dev/null | head -n 1)
REQUIRE_DBD=${REQUIRE_LIB%/lib/*}/dbd/$REQUIRE.dbd
else # old driver pool model
REQUIRE=misc${REQUIRE_VERSION:+-}$REQUIRE_VERSION
REQUIRE_LIB=$INSTBASE/iocBoot/R$B/$EPICS_HOST_ARCH/$LIBPREFIX$REQUIRE$LIBPOSTFIX
REQUIRE_DBD=$INSTBASE/iocBoot/R$B/dbd/$REQUIRE.dbd
fi
if [ -n "$REQUIRE_LIB" ]
then
BASE=$B
break
fi
done
# Check for 64 bit versions, default to 32 bit
if [ ! -d "$EPICS_BASE/bin/${EPICS_HOST_ARCH}" -a -d "$EPICS_BASE/bin/${EPICS_HOST_ARCH%_64}" ]
then
echo "No 64 bit EPICS installation found. Defaulting to 32 bit" >&2
EPICS_HOST_ARCH=${EPICS_HOST_ARCH%_64}
fi
export EPICS_HOST_ARCH
# setup search path for require
ODIR=O.${BASE}_$EPICS_HOST_ARCH
EPICS_DRIVER_PATH=.:bin/$EPICS_HOST_ARCH:bin:snl:../snl:$ODIR:src/$ODIR:snl/$ODIR:../snl/$ODIR:${EPICS_DRIVER_PATH#:}
#Special PSI: find installation base for libs from working directory
D=$(rp $PWD)
I=${D%/iocBoot/*}
if [ "$I" != "$D" ]
then
INSTBASE=$I
fi
EPICS_DRIVER_PATH=${EPICS_DRIVER_PATH%:}:${EPICS_MODULES}:${INSTBASE:=/work}/iocBoot/R$BASE/$EPICS_HOST_ARCH
export INSTBASE
# convert for win32-x86 arch
if [ "${EPICS_HOST_ARCH#win32-}" != "$EPICS_HOST_ARCH" ]
then
EPICS_DRIVER_PATH=$(cygpath -wp $EPICS_DRIVER_PATH)
DBD=$(cygpath -wp $DBD)
fi
if [ "${EPICS_HOST_ARCH#cygwin-}" != "$EPICS_HOST_ARCH" ]
then
DBD=$(cygpath -wp $DBD)
fi
export EPICS_DRIVER_PATH
# setup search PATH (Windows needs it for libraries, but also find helper programs like msi)
PATH=$PATH:$INSTBASE/iocBoot/R$BASE/$EPICS_HOST_ARCH:$EPICS_BASE/bin/$EPICS_HOST_ARCH:$EPICS_BASE/../seq/bin/$EPICS_HOST_ARCH
export EPICS_IOCSH_HISTFILE=
# Call init script after IOC name, EPICS_HOST_ARCH and EPICS_BASE are set.
for dir in . cfg /etc
do
if [ -r "$dir/iocsh.init" ]
then
source $dir/iocsh.init
break
fi
done
loadFiles () {
while [ "$#" -gt 0 ]
do
file=$1
case $file in
( -[1-9]* | -32 | -nopva | --nopva | -win | --win | -d | -dg | --debug | -dv | -dp | -n | --name )
echo "Option $file must be used earlier" >&2
exit 1
;;
( -h | "-?" | -help | --help )
help
;;
( -v | -ver | --ver | -version | --version )
version
;;
( @* )
loadFiles $(cat ${file#@})
;;
( -i )
shift
source $1
;;
( -c )
shift
case $1 in
( seq* )
if [ "$init" != NO ]
then
echo "iocInit"
init=NO
fi
;;
( iocInit )
init=NO
;;
esac
echo $1
;;
( -s )
shift
if [ "$init" != NO ]
then
echo "iocInit"
init=NO
fi
echo "seq $1"
;;
( -r )
shift
echo "require $1"
;;
( -* )
echo "Unknown option $1" >&2
echo "Try: $(basename $0) --help" >&2
exit 1
;;
( *$LIBPOSTFIX )
if [ "$BASECODE" -ge 3141200 ]
then
echo "dlload \"$file\""
else
echo "ld \"$file\""
fi
;;
( *=* )
echo -n $file | awk -F '=' '{printf "epicsEnvSet %s '\''%s'\''\n", $1, $2}'
;;
( * )
subst=""
while [ "$#" -gt 1 ]
do
case $2 in
( *=* )
subst="$subst,$2"; shift
;;
( * )
break
;;
esac
done
subst=${subst#,}
case $file in
( *.db | *.template)
echo "dbLoadRecords '$file','$subst'"
;;
( *.subs | *.subst )
echo "dbLoadTemplate '$file','$subst'"
;;
( *.dbd )
# some dbd files must be loaded before main to take effect
echo "dbLoadDatabase '$file','$DBD','$subst'"
;;
( * )
if [ "$BASECODE" -ge 3150000 ]
then
echo "iocshLoad '$file','$subst'"
else
echo -n $subst | awk -F '=' -v 'RS=,' '{printf "epicsEnvSet %s '\''%s'\''\n", $1, $2}'
echo "< '$file'"
fi
if grep -q iocInit $file; then init=NO; fi
;;
esac
;;
esac
shift
done
}
startup=${IOCSH_TMP:-/tmp}/iocsh.startup.$$
# clean up and kill the softIoc when killed by any signal
# execute any exiting exit trap (from init scripts) as well
trap "stty sane 2> /dev/null;echo;rm -f $startup;$(trap -p EXIT | sed 's/.*\x27\(.*\)\x27.*/\1; /')kill -s SIGTERM 0" EXIT
{
echo "# date=\"$(date)\""
echo "# user=\"${USER:-$(whoami)}\""
for var in IOC PWD BASE EPICS_HOST_ARCH SHELLBOX EPICS_CA_ADDR_LIST EPICS_DRIVER_PATH PATH LD_LIBRARY_PATH
do
echo "# $var=\"${!var}\""
done
if [ "$BASECODE" -ge 3141200 ]
then
case $(tr A-Z a-z <<< "$NOPVA") in (0|n|no|f|false|off) unset NOPVA; esac
if [ -z "$NOPVA" -a -x "$EPICS_BASE/bin/$EPICS_HOST_ARCH/softIocPVA$EXEPOSTFIX" ]
then
EXE=$EPICS_BASE/bin/$EPICS_HOST_ARCH/softIocPVA$EXEPOSTFIX
ARGS="-D $EPICS_BASE/dbd/softIocPVA.dbd"
echo "dlload $EPICS_BASE/$LIBDIR/$EPICS_HOST_ARCH/${LIBPREFIX}nt$LIBPOSTFIX"
echo "dlload $EPICS_BASE/$LIBDIR/$EPICS_HOST_ARCH/${LIBPREFIX}pvDatabase$LIBPOSTFIX"
else
EXE=$EPICS_BASE/bin/$EPICS_HOST_ARCH/softIoc$EXEPOSTFIX
ARGS="-D $EPICS_BASE/dbd/softIoc.dbd"
fi
LDCMD="dlload"
else
# get rid of the compiled-in rpath because at PSI that is a link pointing to current EPICS version.
LOADER="$LOADER /lib/ld-linux.so.2"
LOADERARGS="--library-path $EPICS_BASE/$LIBDIR/$EPICS_HOST_ARCH --inhibit-rpath ''"
APP=ioc
EXE=$EPICS_EXTENSIONS/bin/$EPICS_HOST_ARCH/$APP
DBD=$EPICS_EXTENSIONS/dbd
LDCMD="ld"
echo "dbLoadDatabase \"$APP.dbd\",\"$DBD\""
echo "${APP}_registerRecordDeviceDriver(pdbbase)"
fi
# switch off memoy lock if requested (only for EPICS 3.15.3+)
if [ "$BASECODE" -ge 3150300 -a -n "$NOLOCK" ]
then
echo "var dbThreadRealtimeLock 0"
fi
# use WINE to run softIo, and convert EPICS_DRIVER_PATH to windows format
if [[ "$EXEPOSTFIX" == ".exe" ]]
then
EPICS_DRIVER_PATH_WIN=
while read -d ':' p; do
EPICS_DRIVER_PATH_WIN="$EPICS_DRIVER_PATH_WIN;${p/#\//z:/}"
done <<< "$EPICS_DRIVER_PATH:"
EPICS_DRIVER_PATH=${EPICS_DRIVER_PATH_WIN#;}
fi
if [ ! -x "$EXE" ];
then
echo "$EXE not found or not executable." >&2
exit 1
fi
if [ ! -f "$REQUIRE_LIB" ]
then
echo "Library ${REQUIRE_LIB:-$LIBPREFIX$REQUIRE$LIBPOSTFIX} not found." >&2
echo "Command 'require' is not available." >&2
else
echo "$LDCMD $REQUIRE_LIB"
echo "dbLoadDatabase $REQUIRE_DBD"
echo "${REQUIRE%-*}_registerRecordDeviceDriver"
echo "require misc ${MISC_VERSION:-ifexists}"
fi
loadFiles "$@"
if [ "$init" != NO ]
then
echo "iocInit"
fi
echo 'epicsEnvSet IOCSH_PS1,"${IOC}> "'
} > $startup
# convert startup script file name for win32-x86
if [ "${EPICS_HOST_ARCH#win32-}" != "$EPICS_HOST_ARCH" ]
then
startup=`cygpath -w $startup`
fi
echo $EXE $ARGS $startup
#enable core dumps
ulimit -c unlimited
eval "$LOADER $LOADERARGS $EXE" $ARGS "$startup" 2>&1
STATUS=$?
exit $STATUS