From 8674e81a42ebd44879b9893f052069eed9075574 Mon Sep 17 00:00:00 2001 From: zimoch Date: Mon, 28 Nov 2011 14:18:37 +0000 Subject: [PATCH] merged disctools and exec into this directory. Added iocsh wrapper with flexible EPICS version handling --- Makefile | 3 + README | 28 +++- disctools.c | 366 ++++++++++++++++++++++++++++++++++++++++++++++++++ disctools.dbd | 1 + exec.c | 105 +++++++++++++++ exec.dbd | 1 + iocsh | 257 +++++++++++++++++++++++++++++++++++ 7 files changed, 755 insertions(+), 6 deletions(-) create mode 100644 disctools.c create mode 100644 disctools.dbd create mode 100644 exec.c create mode 100644 exec.dbd create mode 100755 iocsh diff --git a/Makefile b/Makefile index 9e0bd0a..f859d43 100644 --- a/Makefile +++ b/Makefile @@ -7,4 +7,7 @@ SOURCES += require.c SOURCES += listRecords.c SOURCES += updateMenuConvert.c SOURCES += addScan.c +SOURCES += disctools.c +SOURCES += exec.c + SOURCES_vxWorks += bootNotify.c diff --git a/README b/README index 18076bf..d4d81ab 100644 --- a/README +++ b/README @@ -8,14 +8,30 @@ require "" [,""] load a library and its dbd file updateMenuConvert - shell function - add all breakpoint tables found on this ioc to menu convert + startup script function + add all loaded breakpoint tables found on this ioc to menu convert + to be called before iocInit +addScan rate + startup script function + create a new scan rate (seconds) and add it to menuScan + to be called before iocInit + bootNotify startup script function call a script on the boot pc and tell it a lot of boot infos -iocCheck / iocCheckInit - subroutine record function - set record to 0 if any task dies - reset record to 1 when 1 is written to A +dir / ls / ll / mkdir / rmdir / rm / mv / umask / chmod + shell functions + make disc functions available in iocsh + not needed on vxWorks + +exec / ! + execute an externel command from iocsh + shell function + not available on vxWorks + +listRecords filename fields + shell function + wrapper for dbl to get same syntax in 3.13 and 3.14 + diff --git a/disctools.c b/disctools.c new file mode 100644 index 0000000..cb246f0 --- /dev/null +++ b/disctools.c @@ -0,0 +1,366 @@ +/* +* disctools - dir etc. +* +* $Author: zimoch $ +* $ID$ +* $Date: 2011/11/28 14:18:37 $ +* +* DISCLAIMER: Use at your own risc and so on. No warranty, no refund. +*/ + +#include +#include +#ifdef UNIX +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include + +#ifdef UNIX + +/* dir, ll, ls */ +static const iocshArg dirArg0 = { "directrory", iocshArgString }; +static const iocshArg * const dirArgs[1] = { &dirArg0 }; +static const iocshFuncDef dirDef = { "dir", 1, dirArgs }; +static const iocshFuncDef llDef = { "ll", 1, dirArgs }; +static const iocshFuncDef lsDef = { "ls", 1, dirArgs }; + +static int nohidden(const struct dirent *entry) +{ + return entry->d_name[0] != '.'; +} + +static void llFunc(const iocshArgBuf *args) +{ + char* dirname = "."; + struct dirent** namelist; + struct stat filestat; + char type; + char filename[256]; + char target[256]; + struct group* group; + struct passwd* user; + struct tm time; + char timestr[20]; + int n, i, len; + + if (args[0].sval) dirname = args[0].sval; + n = scandir(dirname, &namelist, nohidden, alphasort); + if (n < 0) + { + perror(dirname); + return; + } + for (i = 0; i < n; i++) + { + sprintf(filename, "%s/%s", dirname, namelist[i]->d_name); + if (lstat(filename, &filestat)) + { + perror(namelist[i]->d_name); + continue; + } + if (S_ISREG(filestat.st_mode)) type='-'; + else if (S_ISDIR(filestat.st_mode)) type='d'; + else if (S_ISCHR(filestat.st_mode)) type='c'; + else if (S_ISBLK(filestat.st_mode)) type='b'; + else if (S_ISFIFO(filestat.st_mode)) type='p'; + else if (S_ISLNK(filestat.st_mode)) type='l'; + else if (S_ISSOCK(filestat.st_mode)) type='s'; + else type='?'; + localtime_r(&filestat.st_mtime, &time); + strftime(timestr, 20, "%b %e %Y %H:%M", &time); + printf("%c%c%c%c%c%c%c%c%c%c %4d", + type, + filestat.st_mode & S_IRUSR ? 'r' : '-', + filestat.st_mode & S_IWUSR ? 'w' : '-', + filestat.st_mode & S_ISUID ? 's' : + filestat.st_mode & S_IXUSR ? 'x' : '-', + filestat.st_mode & S_IRGRP ? 'r' : '-', + filestat.st_mode & S_IWGRP ? 'w' : '-', + filestat.st_mode & S_ISGID ? 's' : + filestat.st_mode & S_IXGRP ? 'x' : '-', + filestat.st_mode & S_IROTH ? 'r' : '-', + filestat.st_mode & S_IWOTH ? 'w' : '-', + filestat.st_mode & S_ISVTX ? 't' : + filestat.st_mode & S_IXOTH ? 'x' : '-', + filestat.st_nlink); + user=getpwuid(filestat.st_uid); + if (user) printf(" %-8s", user->pw_name); + else printf(" %-8d", filestat.st_uid); + group=getgrgid(filestat.st_gid); + if (group) printf(" %-8s", group->gr_name); + else printf(" %-8d", filestat.st_gid); + printf (" %8ld %s %s", + filestat.st_size, timestr, + namelist[i]->d_name); + if (S_ISLNK(filestat.st_mode)) + { + len = readlink(filename, target, 255); + if (len == -1) perror(filename); + else + { + target[len] = 0; + printf(" -> %s\n", target); + } + } + else + { + printf("\n"); + } + free(namelist[i]); + } + free(namelist); +} + +static void lsFunc(const iocshArgBuf *args) +{ + char* dirname = "."; + struct dirent** namelist; + int n, i, cols, rows, r, c, len, maxlen=0; + + if (args[0].sval) dirname = args[0].sval; + n = scandir(dirname, &namelist, nohidden, alphasort); + if (n < 0) + { + perror(dirname); + return; + } + for (i = 0; i < n; i++) + { + len = strlen(namelist[i]->d_name); + if (len > maxlen) maxlen = len; + } + cols=80/(maxlen+=2); + rows=(n-1)/cols+1; + for (r = 0; r < rows; r++) + { + for (c = 0; c < cols; c++) + { + i = r + c*rows; + if (i >= n) continue; + printf("%-*s", + maxlen, namelist[i]->d_name); + free(namelist[i]); + } + printf("\n"); + } + free(namelist); +} +/* mkdir */ +static const iocshArg mkdirArg0 = { "directrory", iocshArgString }; +static const iocshArg * const mkdirArgs[1] = { &mkdirArg0 }; +static const iocshFuncDef mkdirDef = { "mkdir", 1, mkdirArgs }; + +static void mkdirFunc(const iocshArgBuf *args) +{ + char* dirname; + + dirname = args[0].sval; + if (!dirname) + { + fprintf(stderr, "missing directory name\n"); + return; + } + if (mkdir(dirname, 0777)) + { + perror(dirname); + } +} + +/* rmdir */ +static const iocshArg rmdirArg0 = { "directrory", iocshArgString }; +static const iocshArg * const rmdirArgs[1] = { &rmdirArg0 }; +static const iocshFuncDef rmdirDef = { "rmdir", 1, rmdirArgs }; + +static void rmdirFunc(const iocshArgBuf *args) +{ + char* dirname; + + dirname = args[0].sval; + if (!dirname) + { + fprintf(stderr, "missing directory name\n"); + return; + } + if (rmdir(dirname)) + { + perror(dirname); + } +} + +/* rm */ +static const iocshArg rmArg0 = { "file", iocshArgString }; +static const iocshArg * const rmArgs[1] = { &rmArg0 }; +static const iocshFuncDef rmDef = { "rm", 1, rmArgs }; + +static void rmFunc(const iocshArgBuf *args) +{ + char* filename; + + filename = args[0].sval; + if (!filename) + { + fprintf(stderr, "missing file name\n"); + return; + } + if (unlink(filename)) + { + perror(filename); + } +} + +/* mv */ +static const iocshArg mvArg0 = { "oldname", iocshArgString }; +static const iocshArg mvArg1 = { "newname", iocshArgString }; +static const iocshArg * const mvArgs[2] = { &mvArg0, &mvArg1 }; +static const iocshFuncDef mvDef = { "mv", 2, mvArgs }; + +static void mvFunc(const iocshArgBuf *args) +{ + char* oldname; + char* newname; + struct stat filestat; + char filename[256]; + + oldname = args[0].sval; + newname = args[1].sval; + if (!oldname || !newname) + { + fprintf(stderr, "need 2 file names\n"); + return; + } + if (!stat(newname, &filestat) && S_ISDIR(filestat.st_mode)) + { + sprintf(filename, "%s/%s", newname, oldname); + newname = filename; + } + if (rename(oldname, newname)) + { + perror("mv"); + } +} + +/* cp, copy */ +static const iocshArg cpArg0 = { "source", iocshArgString }; +static const iocshArg cpArg1 = { "target", iocshArgString }; +static const iocshArg * const cpArgs[2] = { &cpArg0, &cpArg1 }; +static const iocshFuncDef cpDef = { "cp", 2, cpArgs }; +static const iocshFuncDef copyDef = { "copy", 2, cpArgs }; + +static void cpFunc(const iocshArgBuf *args) +{ + char buffer [256]; + char* sourcename; + char* targetname; + FILE* sourcefile; + FILE* targetfile; + size_t len; + + sourcename = args[0].sval; + targetname = args[1].sval; + if (sourcename == NULL || sourcename[0] == '\0') + sourcefile = stdin; + else if (!(sourcefile = fopen(sourcename,"r"))) + { + perror(sourcename); + return; + } + if (targetname == NULL || targetname[0] == '\0') + targetfile = stdout; + else if (!(targetfile = fopen(targetname,"w"))) + { + perror(targetname); + return; + } + while (!feof(sourcefile)) + { + len = fread(buffer, 1, 256, sourcefile); + if (ferror(sourcefile)) + { + perror(sourcename); + break; + } + fwrite(buffer, 1, len, targetfile); + if (ferror(targetfile)) + { + perror(targetname); + break; + } + } + if (sourcefile != stdin) + fclose(sourcefile); + if (targetfile != stdout) + fclose(targetfile); + else + fflush(stdout); +} + +/* umask */ +static const iocshArg umaskArg0 = { "mask", iocshArgString }; +static const iocshArg * const umaskArgs[1] = { &umaskArg0 }; +static const iocshFuncDef umaskDef = { "umask", 1, umaskArgs }; + +static void umaskFunc(const iocshArgBuf *args) +{ + mode_t mask; + if (args[0].sval == NULL) + { + mask = umask(0); + umask(mask); + printf("%03o\n", (int)mask); + return; + } + if (sscanf(args[0].sval, "%o", &mask) == 1) + { + umask(mask); + return; + } + fprintf(stderr, "mode %s not recognized\n", args[0].sval); +} + +/* chmod */ +static const iocshArg chmodArg0 = { "mode", iocshArgInt }; +static const iocshArg chmodArg1 = { "file", iocshArgString }; +static const iocshArg * const chmodArgs[2] = { &chmodArg0, &chmodArg1 }; +static const iocshFuncDef chmodDef = { "chmod", 2, chmodArgs }; + +static void chmodFunc(const iocshArgBuf *args) +{ + mode_t mode = args[0].ival; + char* path = args[1].sval; + if (chmod(path, mode) != 0) + { + perror(path); + } +} +#endif + +static void +disctoolsRegister(void) +{ + static int firstTime = 1; + if (firstTime) { +#ifdef UNIX + iocshRegister(&dirDef, llFunc); + iocshRegister(&llDef, llFunc); + iocshRegister(&lsDef, lsFunc); + iocshRegister(&mkdirDef, mkdirFunc); + iocshRegister(&rmdirDef, rmdirFunc); + iocshRegister(&rmDef, rmFunc); + iocshRegister(&mvDef, mvFunc); + iocshRegister(&cpDef, cpFunc); + iocshRegister(©Def, cpFunc); + iocshRegister(&umaskDef, umaskFunc); + iocshRegister(&chmodDef, chmodFunc); +#endif + firstTime = 0; + } +} + +epicsExportRegistrar(disctoolsRegister); diff --git a/disctools.dbd b/disctools.dbd new file mode 100644 index 0000000..fa1f094 --- /dev/null +++ b/disctools.dbd @@ -0,0 +1 @@ +registrar(disctoolsRegister) diff --git a/exec.c b/exec.c new file mode 100644 index 0000000..5356b57 --- /dev/null +++ b/exec.c @@ -0,0 +1,105 @@ +/* +* exec - execute shell commands. +* +* $Author: zimoch $ +* $ID$ +* $Date: 2011/11/28 14:18:37 $ +* +* DISCLAIMER: Use at your own risc and so on. No warranty, no refund. +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#ifdef UNIX +#include +#include +#include +#include +#include +#include +#include +#endif +#include + +#ifdef UNIX +static const iocshArg execArg0 = { "command", iocshArgString }; +static const iocshArg execArg1 = { "arguments", iocshArgArgv }; +static const iocshArg * const execArgs[2] = { &execArg0, &execArg1 }; +static const iocshFuncDef execDef = { "exec", 2, execArgs }; +static const iocshFuncDef exclDef = { "!", 2, execArgs }; /* alias */ + +static void execFunc (const iocshArgBuf *args) +{ + int i; + int status; + char commandline [256]; + char *p = commandline; + + if (args[0].sval == NULL) + { + fprintf(stderr, "missing command\n"); + return; + } + p += sprintf(p, "\"%s\"", args[0].sval); + for (i = 1; i < args[1].aval.ac; i++) + { + p += sprintf(p, " \"%s\"", args[1].aval.av[i]); + } + status = system(commandline); + if (WIFSIGNALED(status)) + { +#ifdef __USE_GNU + fprintf (stderr, "%s killed by signal %d: %s\n", + args[0].sval, WTERMSIG(status), strsignal(WTERMSIG(status))); +#else + fprintf (stderr, "%s killed by signal %d: statuscode %d\n", + args[0].sval, WTERMSIG(status), WTERMSIG(status)); + +#endif + } + if (WEXITSTATUS(status)) + { + fprintf (stderr, "exit status is %d\n", WEXITSTATUS(status)); + } +} + +/* sleep */ +static const iocshArg sleepArg0 = { "seconds", iocshArgDouble }; +static const iocshArg * const sleepArgs[1] = { &sleepArg0 }; +static const iocshFuncDef sleepDef = { "sleep", 1, sleepArgs }; + +static void sleepFunc (const iocshArgBuf *args) +{ + struct timespec sleeptime; + + sleeptime.tv_sec = (long) args[0].dval; + sleeptime.tv_nsec = (long) ((args[0].dval - (long) args[0].dval) * 1000000000); + while (nanosleep (&sleeptime, &sleeptime) == -1) + { + if (errno != EINTR) + { + perror("sleep"); + break; + } + } +} +#endif + +static void +execRegister(void) +{ + static int firstTime = 1; + if (firstTime) { +#ifdef UNIX + iocshRegister (&execDef, execFunc); + iocshRegister (&exclDef, execFunc); + iocshRegister (&sleepDef, sleepFunc); +#endif + firstTime = 0; + } +} + +epicsExportRegistrar(execRegister); diff --git a/exec.dbd b/exec.dbd new file mode 100644 index 0000000..ac1b2bd --- /dev/null +++ b/exec.dbd @@ -0,0 +1 @@ +registrar(execRegister) diff --git a/iocsh b/iocsh new file mode 100755 index 0000000..1e22985 --- /dev/null +++ b/iocsh @@ -0,0 +1,257 @@ +#!/bin/bash +SOURCE='$Source: /cvs/G/DRV/misc/iocsh,v $' +REVISION='$Revision: 1.1 $' +DATE='$Date: 2011/11/28 14:18:37 $' + +rp() { + ( realpath $1 || readlink -f $1 || readlink $1 || echo $1 ) 2>/dev/null +} + +# Either EPICS or EPICS_BASE should be set to the install directory +if [ -z "$EPICS_BASE" ] +then + if [ -z "$EPICS" ] + then + for EPICS in /epics /opt/epics /usr/local/epics + do + if [ -d $EPICS ] + then + break 2 + fi + echo "Cannot find EPICS installation directory." >&2 + exit 1 + done + fi + EPICS_BASE=$EPICS/base-3.14.12 + if [ ! -d $EPICS_BASE ] + then + EPICS_BASE=$(rp $EPICS/base) + fi +fi +if [ ! -d $EPICS_BASE ] +then + echo "Cannot find EPICS base directory." >&2 + exit 1 +fi + +# Check revision +if [ -r $EPICS_BASE/configure/CONFIG_BASE_VERSION ] +then +BASE=$(awk -F '[[:space:]]*=[[:space:]]*' ' + /^EPICS_VERSION[[:space:]]*=[[:space:]]*/ {v=$2} + /^EPICS_REVISION[[:space:]]*=[[:space:]]*/ {r=$2} + /^EPICS_MODIFICATION[[:space:]]*=[[:space:]]*/ {m=$2} + END {print v"."r"."m}' < $EPICS_BASE/configure/CONFIG_BASE_VERSION) +else +BASE=$(basename $(rp $EPICS_BASE)) +BASE=${BASE#*base-} +fi + +if [ "${BASE#3.14.}" = "$BASE" ] +then + echo "Do not find an EPICS 3.14 version" >&2 + exit 1 +fi +export BASE + +# 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 +if [ $(basename $(dirname $PWD)) = "ioc" ] +then + IOC=$(basename $PWD) +fi +export IOC + +# setup search path for require +ODIR=O.${BASE}_$EPICS_HOST_ARCH +EPICS_DRIVER_PATH=.: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 + export INSTBASE +fi + +if [ -z "$INSTBASE" ] +then + INSTBASE=/work +fi +EPICS_DRIVER_PATH=${EPICS_DRIVER_PATH%:}:$INSTBASE/iocBoot/R$BASE/$EPICS_HOST_ARCH + +# 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 + +loadFiles () { +while [ "$#" -gt 0 ] +do + file=$1 + case $file in + ( @* ) + loadFiles $(cat ${file#@}) + ;; + ( *.db | *.template) + subst="" + while [ "$#" -gt 1 ] + do + case $2 in + ( *=* ) + subst="$subst,$2"; shift + ;; + ( * ) + break + ;; + esac + done + echo "dbLoadRecords \"$file\",\"${subst#,}\"" + ;; + ( *.subs | *.subst ) + echo "dbLoadTemplate \"$file\"" + ;; + ( *.dbd ) + # some dbd files must be loaded before main to take effect + echo "dbLoadDatabase \"$file\",\"$DBD\"" + ;; + ( *.so ) + echo "ld \"$file\"" + ;; + ( -c ) + shift + echo $1 + ;; + ( -r ) + shift + echo "require $1" + ;; + ( -n ) + shift + IOC="$1" + ;; + ( -h | "-?" | -help | --help ) + { + echo "usage: iocsh [options] [files]" + echo "Start an EPICS iocsh and load files" + echo "Recognized filetypes: *.db *.dbt *.template *.subs *.subst *.dbd *.so" + echo + echo "Possible options:" + echo " -? or -h or --help : show this page and exit" + echo " -v or --version : show version and exit" + echo " -c: The next string is executed as a command by the EPICS iocsh." + echo " -r: The next string is a module, loaded via require." + echo " -n: The next string is the IOC name (used for prompt)" + echo " default: dirname if parent dir is \"ioc\" otherwise hostname" + echo + echo "Supported filetypes:" + echo "*.db, *.dbt and *.template are loaded via dbLoadRecords" + echo "After the filename, you can specify substitutions like MACRO=value." + echo + echo "*.subs and *.subst are loaded via dbLoadTemplate" + echo + echo "*.dbd is loaded via dbLoadDatabase" + echo + echo "*.so is loaded via ld" + echo + echo "If a file is @filename, more arguments are read from filename." + echo + echo "All other files are executed as startup scripts by the EPICS iocsh." + } >&2 + exit + ;; + ( -v | -ver | --ver | -version | --version ) + { + echo "iocsh by Dirk Zimoch" + echo $SOURCE + echo $REVISION + echo $DATE + } >&2 + exit + ;; + ( -* ) + { + echo "unknown option $1" + echo "try: $(basename $0) --help" + } >&2 + exit 1 + ;; + ( * ) + echo "< \"$file\"" + if grep -q iocInit $file; then init=NO; fi + ;; + esac + shift +done +} + +startup=/tmp/iocsh.startup.$$ +trap "rm -f $startup" EXIT TERM KILL +{ + +echo "#date=$(date)" +echo "#user=${USER:-$(whoami)}" +echo "#PWD=$PWD" +echo "#EPICS_CA_ADDR_LIST=$EPICS_CA_ADDR_LIST" +echo "#EPICS_DRIVER_PATH=$EPICS_DRIVER_PATH" +if [ ${BASE#3.14.} -ge 12 ] +then + EXE=$EPICS_BASE/bin/$EPICS_HOST_ARCH/softIoc + ARGS="-D $EPICS_BASE/dbd/softIoc.dbd" + # load "require" command + REQUIRE=misc + LIBPREFIX=lib + LIBPOSTFIX=.so + echo "dlload $INSTBASE/iocBoot/R$BASE/$EPICS_HOST_ARCH/${LIBPREFIX}${REQUIRE}${LIBPOSTFIX}" + echo "dbLoadDatabase $INSTBASE/iocBoot/R$BASE/dbd/${REQUIRE}.dbd" + echo "${REQUIRE%-*}_registerRecordDeviceDriver" +# STDLIBS="exec disctools" +else + APP=ioc + EXE=$EPICS_EXTENSIONS/bin/$EPICS_HOST_ARCH/$APP + DBD=$EPICS_EXTENSIONS/dbd + echo "dbLoadDatabase \"$APP.dbd\",\"$DBD\"" + echo "${APP}_registerRecordDeviceDriver(pdbbase)" +fi +for i in $STDLIBS; do echo "require $i"; done +loadFiles "$@" +if [ "$init" != NO ] +then + echo "iocInit" +fi +if [ "$SHELLBOX" ] +then + PATH=$PATH:/home/ioc/bin + echo 'dbl "","RTYP DESC" > /home/ioc/${SHELLBOX}.dbl' + echo "! dbl2odb.sh ${SHELLBOX} $(/sbin/ifconfig eth0 | awk -F '[ :]+' '/Bcast/ {print $6}') $EPICS_CA_SERVER_PORT" +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 + +if [ ${EPICS_HOST_ARCH#win32-} != $EPICS_HOST_ARCH -o ${EPICS_HOST_ARCH#cygwin-} != $EPICS_HOST_ARCH ] +then + PATH=$INSTBASE/iocBoot/R$BASE/$EPICS_HOST_ARCH:$EPIC_BASE/bin/$EPICS_HOST_ARCH:$EPICS_BASE/../seq/bin/$EPICS_HOST_ARCH:$PATH +fi + +echo $EXE $ARGS $startup +eval "$EXE" $ARGS "$startup" 2>&1 +echo