17 #include <epicsVersion.h>
18 #include <epicsGetopt.h>
19 #include "registryFunction.h"
20 #include "epicsThread.h"
21 #include "epicsExit.h"
22 #include "epicsStdio.h"
23 #include "epicsString.h"
24 #include "dbStaticLib.h"
25 #include "subRecord.h"
30 #include "osiFileName.h"
34 extern "C" int softIocPVA_registerRecordDeviceDriver(
struct dbBase *pdbbase);
38 # define EPICS_BASE "/"
39 # error -DEPICS_BASE required
42 #if EPICS_VERSION_INT>=VERSION_INT(7,0,2,0)
46 #define DBD_BASE "dbd" OSI_PATH_SEPARATOR "softIocPVA.dbd"
47 #define EXIT_BASE "db" OSI_PATH_SEPARATOR "softIocExit.db"
48 #define DBD_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR DBD_BASE
49 #define EXIT_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR EXIT_BASE
50 #define DBD_FILE EPICS_BASE OSI_PATH_SEPARATOR DBD_BASE
51 #define EXIT_FILE EPICS_BASE OSI_PATH_SEPARATOR EXIT_BASE
57 static void exitSubroutine(subRecord *precord) {
58 epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
61 void usage(
const char *arg0,
const std::string& base_dbd) {
62 std::cout<<
"Usage: "<<arg0<<
63 " [-D softIocPVA.dbd] [-h] [-S] [-s] [-v] [-a ascf]\n"
64 "[-m macro=value,macro2=value2] [-d file.db]\n"
65 "[-x prefix] [st.cmd]\n"
67 " -D <dbd> If used, must come first. Specify the path to the softIocPVA.dbdfile."
68 " The compile-time install location is saved in the binary as a default.\n"
70 " -h Print this mesage and exit.\n"
72 " -S Prevents an interactive shell being started.\n"
74 " -s Previously caused a shell to be started. Now accepted and ignored.\n"
76 " -v Verbose, display steps taken during startup.\n"
78 " -a <acf> Access Security configuration file. Macro substitution is\n"
81 " -G <json> DB Group definition file in JSON format.\n"
83 " -m <MAC>=<value>,... Set/replace macro definitions used by subsequent -d and\n"
86 " -d <db> Load records from file (dbLoadRecords). Macro substitution is\n"
89 " -x <prefix> Load softIocExit.db. Provides a record \"<prefix>:exit\".\n"
90 " Put 0 to exit with success, or non-zero to exit with an error.\n"
92 "Any number of -m and -d arguments can be interspersed; the macros are applied\n"
93 "to the following .db files. Each later -m option causes earlier macros to be\n"
96 "A st.cmd file is optional. If any databases were loaded the st.cmd file will\n"
97 "be run *after* iocInit. To perform iocsh commands before iocInit, all database\n"
98 "loading must be performed by the script itself, or by the user from the\n"
99 "interactive IOC shell.\n"
101 "Compiled-in path to softIocPVA.dbd is:\n"
102 "\t"<<base_dbd.c_str()<<
"\n";
105 void errIf(
int ret,
const std::string& msg)
108 throw std::runtime_error(msg);
111 bool lazy_dbd_loaded;
113 void lazy_dbd(
const std::string& dbd_file) {
114 if(lazy_dbd_loaded)
return;
115 lazy_dbd_loaded =
true;
118 std::cout<<
"dbLoadDatabase(\""<<dbd_file<<
"\")\n";
119 errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL),
120 std::string(
"Failed to load DBD file: ")+dbd_file);
123 std::cout<<
"softIocPVA_registerRecordDeviceDriver(pdbbase)\n";
124 softIocPVA_registerRecordDeviceDriver(pdbbase);
125 registryFunctionAdd(
"exit", (REGISTRYFUNCTION) exitSubroutine);
130 int main(
int argc,
char *argv[])
133 std::string dbd_file(DBD_FILE),
134 exit_file(EXIT_FILE),
137 bool interactive =
true;
138 bool loadedDb =
false;
139 bool ranScript =
false;
145 char *cprefix = epicsGetExecDir();
156 dbd_file = prefix + DBD_FILE_REL;
157 exit_file = prefix + EXIT_FILE_REL;
163 while ((opt = getopt(argc, argv,
"ha:D:d:m:Ssx:G:v")) != -1) {
166 usage(argv[0], dbd_file);
170 usage(argv[0], dbd_file);
171 std::cerr<<
"Unknown argument: -"<<char(opt)<<
"\n";
176 if (!macros.empty()) {
178 std::cout<<
"asSetSubstitutions(\""<<macros<<
"\")\n";
179 if(asSetSubstitutions(macros.c_str()))
180 throw std::bad_alloc();
183 std::cout<<
"asSetFilename(\""<<optarg<<
"\")\n";
184 if(asSetFilename(optarg))
185 throw std::bad_alloc();
188 if(lazy_dbd_loaded) {
189 throw std::runtime_error(
"-D specified too late. softIocPVA.dbd already loaded.\n");
196 std::cout<<
"dbLoadRecords(\""<<optarg<<
"\"";
198 std::cout<<
", \""<<macros<<
"\"";
201 errIf(dbLoadRecords(optarg, macros.c_str()),
202 std::string(
"Failed to load: ")+optarg);
220 errIf(dbLoadRecords(exit_file.c_str(), xmacro.c_str()),
221 std::string(
"Failed to load: ")+exit_file);
237 std::cout<<
"# Begin "<<argv[optind]<<
"\n";
238 errIf(iocsh(argv[optind]),
239 std::string(
"Error in ")+argv[optind]);
241 std::cout<<
"# End "<<argv[optind]<<
"\n";
243 epicsThreadSleep(0.2);
249 std::cout<<
"iocInit()\n";
251 epicsThreadSleep(0.2);
263 if (loadedDb || ranScript) {
264 epicsThreadExitMain();
267 usage(argv[0], dbd_file);
268 std::cerr<<
"Nothing to do!\n";
277 }
catch(std::exception& e){
278 std::cerr<<
"Error: "<<e.what()<<
"\n";