Merge lp:~mdavidsaver/epics-base/epicsconf into lp:~epics-core/epics-base/3.14
- epicsconf
- Merge into 3.14
Status: | Rejected |
---|---|
Rejected by: | Andrew Johnson |
Proposed branch: | lp:~mdavidsaver/epics-base/epicsconf |
Merge into: | lp:~epics-core/epics-base/3.14 |
Diff against target: |
517 lines (+278/-22) 12 files modified
epics.conf (+72/-0) src/libCom/Makefile (+7/-0) src/libCom/env/envDefs.h (+1/-0) src/libCom/env/fileLoad.cpp (+128/-0) src/libCom/iocsh/iocsh.cpp (+14/-7) src/libCom/iocsh/iocsh.h (+1/-0) src/libCom/iocsh/libComRegister.c (+20/-0) src/libCom/macLib/macCore.c (+8/-15) src/libCom/macLib/macLib.h (+6/-0) src/libCom/osi/os/Darwin/osdEnv.c (+7/-0) src/libCom/osi/os/default/osdEnv.c (+7/-0) src/libCom/osi/os/vxWorks/osdEnv.c (+7/-0) |
To merge this branch: | bzr merge lp:~mdavidsaver/epics-base/epicsconf |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Disapprove | ||
Ralph Lange | Pending | ||
EPICS Core Developers | Pending | ||
Review via email: mp+23106@code.launchpad.net |
Commit message
Allow some setting currently set as environment variables to be given in a config file. This is intended for CA clients as a way to specify EPICS_CA_ADDR_LIST system-wide (i.e. /etc/epics.conf). Follows the usual order of precedence with individual environment variables first to preserve the current behavior.
Description of the change
Allow some setting currently set as environment variables to be given in a config file. This is intended for CA clients as a way to specify EPICS_CA_ADDR_LIST system-wide (i.e. /etc/epics.conf). Follows the usual order of precedence with individual environment variables first to preserve the current behavior.
Revision one is limited in scope. It effects only those environment variables defined in 'src/libCom/
A sample config file is included with all options commented out.
Initially added only for linux. Adding for other systems is as simple as linking in one additional object.
Ralph Lange (ralph-lange) wrote : | # |
I don't think this is intended for target systems at all - it's a client-only issue.
Which would be an answer to the vxWorks/
mdavidsaver (mdavidsaver) wrote : | # |
> Firstly, please convince me why this is necessary? A package can set
> environment variables on most on Linux distributions by adding files to
> /etc/profile.d and users can override them in ~/.login ~/.cshrc or ~/.profile
> as they wish.
Which shell (sh, csh)? Environment variables are a poor way to do configuration.
> IOC startup scripts may contain epicsEnvSet commands. Why do
> we need yet another way to set environment variables?
For IOCs you don't. This is for EDM, ALH, channel archiver, and my python scripts. Client applications which run on something other then vxworks or rtems.
The intent is to allow libca to be configured in the way that almost all other applications/
>
> If we do provide this facility, people are going to want to use it on all IOC
> architectures, so implementing it on just one OS is not a good idea. I accept
> that it was designed for Linux, but I know that someone like Ernest Williams
> is going to want to use it on vxWorks or RTEMS if we don't provide it in the
> initial release.
I don't see any reason to use it work on an embedded system. There it gives no benefit over epicsEnvSet and IOC configuration would require yet another file.
> The current code is not portable to vxWorks. The setenv() routine is not
> available there, use epicsEnvSet() or putenv() instead.
Ah, I will do this.
> We also have problems using C++ STL containers on vxWorks. No other code in
> the IOC uses them because STL containers create and destroy objects a lot,
> which used to cause major memory fragmentation in the vxWorks memory
> allocator; not sure if it still does, although that shouldn't be a problem
> with this code. However since the IOC hasn't needed it before and memory is
> precious on embedded systems, most sites don't build the STL support package
> into their vxWorks OS images, and for a minor change this will cause major
> pain. I got lots of very ugly "undefined symbol" errors for internal STL
> routines when I tried to load the fileLoad.o file on one of my boards here.
> Note also that as written the vxWorks linker does not include this file in the
> executable it generates, since no symbols reference it; that's why I had to
> explicitly load the fileLoad.o object by hand.
So maybe this should be host only...
>
> The list of files to load should not be hard-coded in the source to
> fileLoad.cpp.
Configuration files don't work unless people know where they are. Uniformity is important. It should follow the conventions of the host OS. Currently fileLoad just has the *nix set. A set of paths for Windows is also needed.
> Define a new parameter called EPICS_CONFIG_PATH which is set in
> base/configure/
> value probably needs to be architecture-
> have a mechanism to set default values from an arch-specific file, so
> bldEnvData.pl needs to be changed to handle that and some architecture-
> specific files added.
#ifdef I_don_t_
> How to specify multiple files in one parameter? Use OSI_PATH_
> from osiFileName.h so the value looks like t...
Andrew Johnson (anj) wrote : | # |
The Art of Unix Programming talks about application configuration here:
http://
In particular, http://
* A value varies across several contexts that share dotfiles,
* A value varies too often for dotfiles, but doesn't change on every startup
Both of those definitely apply to Channel Access client programs, so I don't see myself as being the only person to disagree with your blanket statement "Environment variables are a poor way to do configuration."
I agree that it is not necessary to implement this feature for IOCs, but as written all Linux IOCs /will/ attempt to read those files while IOCs on other architectures would not; this will cause user confusion, so at minimum all workstation architectures would need to support this (at the APS we have soft IOCs that we can run on Linux, Darwin or Solaris as needed). Unlike the access security and dbStatic subsystems we don't have separate versions of libCom for Host vs. IOC programs, so we're stuck with only being able to distinguish by target architecture.
I think we should implement this for all architectures, but make the list of files to read be configurable from a file in base/configure/, and since we already have a mechanism that does some of the work we should modify that to implement the solution. Here's how I think this should work:
1. Modify base/src/
2. Add a new enviroment parameter named something like EPICS_CONFIG_PATH or EPICS_RC_FILES that lists the config files to be read. You don't have to allow the environment variable to override the compiled-in value if you don't want to, although I don't see the point of preventing an override if a user has some need to do that (I personally hope to never need to set LD_PRELOAD, but I like that it's there if I do). The default value for this parameter will be given in an architecture-
3. The file parser should be integrated into base/src/
Doing it this way any environment variables will still override but can be distinguished from the values read from the files. File settings don't pollute the environment variables, nor do we permit users to add other settings to the files which are not EPICS pa...
- 12046. By mdavidsaver
-
IOCsh: create a version of iocsh() which can be quiet
- 12047. By mdavidsaver
-
env: add epicsEnvSetIfUnset
- 12048. By mdavidsaver
-
macLib: expose use environment flag
- 12049. By mdavidsaver
-
use iocsh to parse config file
Use macLib to expand strings w/ environment variables
Use Base build path is search path ($(EPICS_BASE)/epics. conf)
Add search path for win32
Exclude from builds for RTEMS/vxWorks targets - 12050. By mdavidsaver
-
update config file syntax
mdavidsaver (mdavidsaver) wrote : | # |
First the changes, then the questions
Removes the file parser and replaces it with iocsh(). Creates a modified version (iocsh2()) which has an additional option to control output to console. The default when invoked through fileLoad is silence.
Adds the command epicsEnvSetIfUnset to the ioc shell. Behaves like epicsEnvSet if the variable named has not previously been set. If it has then it is not modified.
The file list remains "static". However, it is defined in terms of some macLib style macros. macLib is made to use environment variables when expanding these macros. Additions made for windows.
mdavidsaver (mdavidsaver) wrote : | # |
> The Art of Unix Programming talks about application configuration here:
> http://
> In particular, http://
> environment variables are useful when:
> * A value varies across several contexts that share dotfiles,
An example? Most of these parameters are system wide. The only ones I see which don't follow this rule are the PORT options. In that case I would suggest creating an alternate config file and using EPICS_SYS_
> * A value varies too often for dotfiles, but doesn't change on every startup
The examples I see in this category are IOC specific and shouldn't be set it any shared config file.
If you look in TAUp a little way down in the "When to Use Environment Variables" section you will see the following.
"There is one traditional Unix design pattern that we do not recommend for new programs. Sometimes, user-set environment variables are used as a lightweight substitute for expressing a program preference in a run-control file."
This is more or less exactly how I would describe the problem with EPICS and related client programs. Base understands 26 environment variables. And if you consider clients like EDM (34) this number goes up rapidly.
> Both of those definitely apply to Channel Access client programs, so I don't
> see myself as being the only person to disagree with your blanket statement
> "Environment variables are a poor way to do configuration."
So perhaps I should say: 60 environment variables are a poor way to do configuration.
> I agree that it is not necessary to implement this feature for IOCs, but as
> written all Linux IOCs /will/ attempt to read those files while IOCs on other
> architectures would not; this will cause user confusion, so at minimum all
> workstation architectures would need to support this (at the APS we have soft
> IOCs that we can run on Linux, Darwin or Solaris as needed). Unlike the
> access security and dbStatic subsystems we don't have separate versions of
> libCom for Host vs. IOC programs, so we're stuck with only being able to
> distinguish by target architecture.
Maybe we should have two versions of libca: libcaIoc which excludes fileLoad and other "client only" bits. and libca which excludes and "IOC only" bits.
I am also thinking about how to do a runtime test to find out if the process is an IOC.
>
> I think we should implement this for all architectures, but make the list of
> files to read be configurable from a file in base/configure/, and since we
> already have a mechanism that does some of the work we should modify that to
> implement the solution.
Honestly, before I embarked on this I would make the search path fully configurable at runtime.
> Here's how I think this should work:
> [...]
>
> Doing it this way any environment variables will still override but can be
> distinguished from the values read from the files. File settings don't
> pollute the environment variables, nor do we permit users to add other
> settings to the files which are not EPICS parameters. The epicsPrtEnvParams()
> routine displays the current parameters while e...
Andrew Johnson (anj) wrote : | # |
I don't believe a iocsh new command would be necessary, one can currently use
epicsEnvSet VAR "$(VAR=new value)"
to set VAR to "new value" only if it is not currently set.
The idea of using iocsh to parse the config file(s) is ingenious. However this solution is starting to feel rather kludgey (the config file syntax gets ugly), and it doesn't take into account that iocsh doesn't always have the same commands registered. If I create a stand-alone sequence program and ask it to bring up an iocsh, it doesn't currently know epicsEnvSet or any of the other libCom commands:
octo% bin/linux-
SEQ Version 2.0.12: Wed Apr 28 10:54:19 2010
Spawning state program "sncExample", thread 0x8f5bc20: "sncExample"
epics> help
Type `help command_name' to get more information about a particular command.
# ClockTime_Report exit help
iocshCmd seq seqChanShow seqQueueShow seqShow
seqStop seqcar
epics>
A sequence program is a stand-alone CA client so would read the config files but would not be able to understand the commands in them. To fix that we'd have to change how we register the libCom commands with the IOC shell, thus the changes needed get bigger and more invasive.
I really don't like the architecture-
I don't believe your stringification of the EPICS_BASE macro will work on Windows, where a back-slash is used for the directory separator. I had major difficulties with this in src/softIoc until I used Perl to create the epicsInstallDir.h file. If you need to know the value of $(INSTALL_DIR) we should move the creation of the epicsInstallDir.h file into libCom. Where does $(PWD) get its value from anyway? INSTALL_DIR != TOP at some sites.
Why do you want to break macLib's encapsulation? A MAC_HANDLE is supposed to be opaque to its customers; admittedly the method is not documented in the appDevGuide but macEnv.c shows how to create a handle with FLAG_USE_
There are a number of Code Smells in this branch currently. I'm not saying Base isn't already smelly, but new code should make things better if possible, and never worse.
Now replies to some of Michael's comments:
> > environment variables are useful when:
> > * A value varies across several contexts that share dotfiles,
>
> An example? Most of these parameters are system wide. The only ones I see
> which don't follow this rule are the PORT options. In that case I would
> suggest creating an alternate config file and using EPICS_SYS_
>
> > * A value varies too often for dotfiles, but doesn't change on every
> > startup
>
> The examples I see in this category are IOC specific and shou...
Unmerged revisions
- 12050. By mdavidsaver
-
update config file syntax
- 12049. By mdavidsaver
-
use iocsh to parse config file
Use macLib to expand strings w/ environment variables
Use Base build path is search path ($(EPICS_BASE)/epics. conf)
Add search path for win32
Exclude from builds for RTEMS/vxWorks targets - 12048. By mdavidsaver
-
macLib: expose use environment flag
- 12047. By mdavidsaver
-
env: add epicsEnvSetIfUnset
- 12046. By mdavidsaver
-
IOCsh: create a version of iocsh() which can be quiet
- 12045. By mdavidsaver
-
set env. config from a file
On startup read key/value pairs from a set list
of files and use these to set any unset Base
environment variables.While this will work for softiocs it is really
intended for CA clientsFiles will include lines like
EPICS_CA_ADDR_LIST = "localhost 192.168.1.1"
allows comments
handles ~/ correctly
Preview Diff
1 | === added file 'epics.conf' |
2 | --- epics.conf 1970-01-01 00:00:00 +0000 |
3 | +++ epics.conf 2010-04-26 19:21:32 +0000 |
4 | @@ -0,0 +1,72 @@ |
5 | + |
6 | +## The following parameters apply to all Channel Access |
7 | +## clients (including IOCs). |
8 | + |
9 | +# The list of interfaces and IPs the CA clients should |
10 | +# use when attempting to connect before using the |
11 | +# automatic list. |
12 | +# |
13 | +# A space seperated list of IP addresses |
14 | +# (XXX.XXX.XXX.XXX) and network addresses |
15 | +# (YYY.YYY.YYY.YYY:PP). Hostname may be used. |
16 | +# |
17 | +# ie EPICS_CA_ADDR_LIST="localhost myioc.local 192.168.1.0:24" |
18 | +# |
19 | +#epicsEnvSetIfUnset("EPICS_CA_ADDR_LIST","") |
20 | + |
21 | +# Include all local interfaces (including localhost) |
22 | +# in the connection list. |
23 | +#epicsEnvSetIfUnset("EPICS_CA_AUTO_ADDR_LIST","YES") |
24 | + |
25 | +# The maximum array size which can be handled by |
26 | +# a client. |
27 | +#epicsEnvSetIfUnset("EPICS_CA_MAX_ARRAY_BYTES","16384") |
28 | + |
29 | +# Timeout in seconds before a server is declared to |
30 | +# be unreachable and the client will start the reconnection |
31 | +# process. |
32 | +#epicsEnvSetIfUnset("EPICS_CA_CONN_TMO","30.0") |
33 | + |
34 | +#epicsEnvSetIfUnset("EPICS_CA_BEACON_PERIOD","15.0") |
35 | +#epicsEnvSetIfUnset("EPICS_CA_MAX_SEARCH_PERIOD","300") |
36 | + |
37 | +# The port on which clients (repeater) and servers |
38 | +# operate. |
39 | +#epicsEnvSetIfUnset("EPICS_CA_REPEATER_PORT","5065") |
40 | +#epicsEnvSetIfUnset("EPICS_CA_SERVER_PORT","5064") |
41 | + |
42 | +## These parameters apply only to IOCs |
43 | + |
44 | +# Name/IP for NTP server for IOCs |
45 | +#epicsEnvSetIfUnset("EPICS_TS_NTP_INET","") |
46 | + |
47 | +# IOC shell prompt |
48 | +#epicsEnvSetIfUnset("IOCSH_PS1","epics> ") |
49 | + |
50 | +# IOC shell history buffer size |
51 | +#epicsEnvSetIfUnset("IOCSH_HISTSIZE","50") |
52 | + |
53 | +#epicsEnvSetIfUnset("EPICS_IOC_LOG_PORT","7004") |
54 | +#epicsEnvSetIfUnset("EPICS_IOC_LOG_INET","") |
55 | +#epicsEnvSetIfUnset("EPICS_IOC_LOG_FILE_LIMIT","1000000") |
56 | +#epicsEnvSetIfUnset("EPICS_IOC_LOG_FILE_NAME","") |
57 | +#epicsEnvSetIfUnset("EPICS_IOC_LOG_FILE_COMMAND","") |
58 | + |
59 | +## The following apply to the portable channel |
60 | +## access server, but NOT to IOCs. |
61 | + |
62 | +#epicsEnvSetIfUnset("EPICS_CAS_INTF_ADDR_LIST","") |
63 | +#epicsEnvSetIfUnset("EPICS_CAS_IGNORE_ADDR_LIST","") |
64 | +#epicsEnvSetIfUnset("EPICS_CAS_AUTO_BEACON_ADDR_LIST","") |
65 | +#epicsEnvSetIfUnset("EPICS_CAS_BEACON_ADDR_LIST","") |
66 | +#epicsEnvSetIfUnset("EPICS_CAS_SERVER_PORT","") |
67 | +#epicsEnvSetIfUnset("EPICS_CAS_BEACON_PERIOD","") |
68 | +#epicsEnvSetIfUnset("EPICS_CAS_BEACON_PORT","") |
69 | + |
70 | +## The remaining parameters do not have any effect |
71 | +## on EPICS Base, but may be used by some other |
72 | +## applications. |
73 | + |
74 | +#epicsEnvSetIfUnset("EPICS_TIMEZONE","CUS::360:031402:110702") |
75 | +#epicsEnvSetIfUnset("EPICS_CMD_PROTO_PORT","") |
76 | +#epicsEnvSetIfUnset("EPICS_AR_PORT","7002") |
77 | |
78 | === modified file 'src/libCom/Makefile' |
79 | --- src/libCom/Makefile 2009-04-02 21:15:26 +0000 |
80 | +++ src/libCom/Makefile 2010-04-26 19:21:32 +0000 |
81 | @@ -75,6 +75,13 @@ |
82 | INC += envDefs.h |
83 | SRCS += envSubr.c |
84 | SRCS += envData.c |
85 | +SRCS += fileLoad.cpp |
86 | + |
87 | +ifeq ($(GNU)$(OS_CLASS),NOWIN32) |
88 | +fileLoad_CPPFLAGS += "/DEPICS_BASE:$(PWD)\" |
89 | +else |
90 | +fileLoad_CPPFLAGS += -DEPICS_BASE="$(PWD)/" |
91 | +endif |
92 | |
93 | SRC_DIRS += $(LIBCOM)/error |
94 | INC += epicsPrint.h |
95 | |
96 | === modified file 'src/libCom/env/envDefs.h' |
97 | --- src/libCom/env/envDefs.h 2009-06-05 19:56:33 +0000 |
98 | +++ src/libCom/env/envDefs.h 2010-04-26 19:21:32 +0000 |
99 | @@ -89,6 +89,7 @@ |
100 | (const ENV_PARAM *pEnv, unsigned short defaultPort); |
101 | epicsShareFunc long epicsShareAPI epicsPrtEnvParams(void); |
102 | epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value); |
103 | +epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value); |
104 | epicsShareFunc void epicsShareAPI epicsEnvShow (const char *name); |
105 | |
106 | #ifdef __cplusplus |
107 | |
108 | === added file 'src/libCom/env/fileLoad.cpp' |
109 | --- src/libCom/env/fileLoad.cpp 1970-01-01 00:00:00 +0000 |
110 | +++ src/libCom/env/fileLoad.cpp 2010-04-26 19:21:32 +0000 |
111 | @@ -0,0 +1,128 @@ |
112 | +/* Michael Davidsaver <mdavidsaver@bnl.gov> |
113 | + * Brookhaven National Lab |
114 | + * April 2010 |
115 | + */ |
116 | + |
117 | +/* Configuration file loader for CA clients and |
118 | + * software IOCs. Configuration in this case |
119 | + * is an IOCshell script with a reduced set of |
120 | + * commends (libCom only). The most common |
121 | + * use will be "epicsEnvSetIfUnset(name,value)" |
122 | + * |
123 | + * This isn't really useful of IOCs since it is |
124 | + * exactly equivalent to |
125 | + * |
126 | + * < /some/place/epics.conf |
127 | + * < /some/other/place/epics.conf |
128 | + * |
129 | + * only the paths are hardcoded. However, |
130 | + * the lack of a CA client-only library |
131 | + * means that it can't be excluded from |
132 | + * softiocs. |
133 | + */ |
134 | +#if !defined(vxWorks) && !defined(__rtems__) |
135 | + |
136 | +#include <cstdio> |
137 | + |
138 | +#include "epicsStdlib.h" |
139 | +#include "envDefs.h" |
140 | +#include "macLib.h" |
141 | +#include "iocsh.h" |
142 | +#include "libComRegister.h" |
143 | + |
144 | +#define STRINGIFY2(X) #X |
145 | +#define STRINGIFY(X) STRINGIFY2(X) |
146 | + |
147 | +// List of files to load |
148 | +static const char* const sources[]= |
149 | +{ |
150 | + "${EPICS_CONFIG}" // remember that macLib is recursive |
151 | + ,"epics.conf" |
152 | +#if defined(__unix) || defined(__unix__) |
153 | + ,"${HOME}/.epics.conf" |
154 | +#elif defined(_WIN32) |
155 | + ,"${USERPROFILE}\epics.conf" |
156 | + /* C:\Documents and Settings\username\epics.conf on XP |
157 | + * C:\Users\username\epics.conf on Vista and WIN7 |
158 | + */ |
159 | +#endif |
160 | + ,"${EPICS_SYS_CONFIG}" |
161 | +#if defined(EPICS_BASE) |
162 | + ,STRINGIFY(EPICS_BASE) "epics.conf" |
163 | +#endif |
164 | +#if defined(__unix) || defined(__unix__) |
165 | + ,"/etc/epics.conf" |
166 | +#elif defined(_WIN32) |
167 | + ,"${ALLUSERSPROFILE}\epics.conf" |
168 | + /* C:\Documents and Settings\All Users\epics.conf on XP |
169 | + * C:\ProgramData\epics.conf on Vista and WIN7 |
170 | + */ |
171 | +#endif |
172 | + ,0 |
173 | +}; |
174 | + |
175 | +static char *envpairs[]={ NULL, NULL}; |
176 | + |
177 | +static void load() |
178 | +{ |
179 | + MAC_HANDLE *vars=0; |
180 | + int verb=0; |
181 | + unsigned long maxstr=256; |
182 | + long len; |
183 | + char *out; |
184 | + |
185 | + if (getenv("EPICS_VERBOSE")) |
186 | + verb=1; |
187 | + |
188 | + out=(char*)malloc(maxstr); |
189 | + if (!out |
190 | + || macCreateHandle(&vars, envpairs) |
191 | +#if defined(EPICS_BASE) |
192 | + || macPutValue(vars, "EPICS_BASE", STRINGIFY(EPICS_BASE))<0 |
193 | +#endif |
194 | + ) |
195 | + { |
196 | + fprintf(stderr, "out of memory while loading config environment"); |
197 | + } |
198 | + vars->flags |= MAC_FLAG_USE_ENVIRONMENT; |
199 | + if (!verb) |
200 | + vars->flags |= MAC_FLAG_SUPPRESS_WARNINGS; |
201 | + |
202 | + // A redudent call to ensure that all needed |
203 | + // IOC shell commands are available |
204 | + libComRegister(); |
205 | + |
206 | + // Populate from files |
207 | + for(size_t i=0; sources[i]; i++) { |
208 | + len=macExpandString(vars, sources[i], out, maxstr); |
209 | + if (len<0) { |
210 | + if (verb) fprintf(stderr, "Error expanding %s\n",sources[i]); |
211 | + continue; |
212 | + } else if(len==0) { |
213 | + if (verb) fprintf(stderr, "Expanding %s yields a null string\n",sources[i]); |
214 | + continue; |
215 | + } |
216 | + |
217 | + if (verb) fprintf(stderr, "Loading config from %s (%s)\n", sources[i], out); |
218 | + iocsh2(out, verb); |
219 | + } |
220 | + |
221 | + free(out); |
222 | + macDeleteHandle(vars); |
223 | + |
224 | +} |
225 | + |
226 | +class EpicsFileLoader { |
227 | +public: |
228 | + EpicsFileLoader() { |
229 | + load(); |
230 | + } |
231 | +}; |
232 | + |
233 | +#if !defined(__GNUC__) || !(__GNUC__<2 || (__GNUC__==2 && __GNUC_MINOR__<=95)) |
234 | +namespace { EpicsFileLoader epicsFileLoader; } |
235 | +#else |
236 | +EpicsFileLoader epicsFileLoader; |
237 | +#endif |
238 | + |
239 | +#endif // !defined(vxWorks) && !defined(__rtems__) |
240 | |
241 | === modified file 'src/libCom/iocsh/iocsh.cpp' |
242 | --- src/libCom/iocsh/iocsh.cpp 2008-07-29 21:11:56 +0000 |
243 | +++ src/libCom/iocsh/iocsh.cpp 2010-04-26 19:21:32 +0000 |
244 | @@ -457,7 +457,7 @@ |
245 | * The body of the command interpreter |
246 | */ |
247 | static int |
248 | -iocshBody (const char *pathname, const char *commandLine) |
249 | +iocshBody (const char *pathname, const char *commandLine, int verbose) |
250 | { |
251 | FILE *fp = NULL; |
252 | const char *filename = NULL; |
253 | @@ -493,7 +493,8 @@ |
254 | else { |
255 | fp = fopen (pathname, "r"); |
256 | if (fp == NULL) { |
257 | - fprintf (stderr, "Can't open %s: %s\n", pathname, strerror (errno)); |
258 | + if (verbose) |
259 | + fprintf (stderr, "Can't open %s: %s\n", pathname, strerror (errno)); |
260 | return -1; |
261 | } |
262 | if ((filename = strrchr (pathname, '/')) == NULL) |
263 | @@ -549,7 +550,7 @@ |
264 | * them if they came from a script. |
265 | */ |
266 | if (*raw == '#') { |
267 | - if ((prompt == NULL) && (commandLine == NULL)) |
268 | + if ((prompt == NULL) && (commandLine == NULL) && verbose) |
269 | puts(raw); |
270 | continue; |
271 | } |
272 | @@ -564,7 +565,7 @@ |
273 | /* |
274 | * Echo commands read from scripts |
275 | */ |
276 | - if ((prompt == NULL) && *line && (commandLine == NULL)) |
277 | + if ((prompt == NULL) && *line && (commandLine == NULL) && verbose) |
278 | puts(line); |
279 | |
280 | /* |
281 | @@ -704,7 +705,7 @@ |
282 | if (openRedirect(filename, lineno, redirects) < 0) |
283 | continue; |
284 | startRedirect(filename, lineno, redirects); |
285 | - iocshBody(commandFile, NULL); |
286 | + iocshBody(commandFile, NULL, verbose); |
287 | stopRedirect(filename, lineno, redirects); |
288 | continue; |
289 | } |
290 | @@ -798,7 +799,13 @@ |
291 | int epicsShareAPI |
292 | iocsh (const char *pathname) |
293 | { |
294 | - return iocshBody(pathname, NULL); |
295 | + return iocshBody(pathname, NULL, 1); |
296 | +} |
297 | + |
298 | +int epicsShareAPI |
299 | +iocsh2 (const char *pathname, int verbose) |
300 | +{ |
301 | + return iocshBody(pathname, NULL, verbose); |
302 | } |
303 | |
304 | int epicsShareAPI |
305 | @@ -806,7 +813,7 @@ |
306 | { |
307 | if (cmd == NULL) |
308 | return 0; |
309 | - return iocshBody(NULL, cmd); |
310 | + return iocshBody(NULL, cmd, 1); |
311 | } |
312 | |
313 | /* |
314 | |
315 | === modified file 'src/libCom/iocsh/iocsh.h' |
316 | --- src/libCom/iocsh/iocsh.h 2007-03-13 17:54:23 +0000 |
317 | +++ src/libCom/iocsh/iocsh.h 2010-04-26 19:21:32 +0000 |
318 | @@ -69,6 +69,7 @@ |
319 | epicsShareFunc void epicsShareAPI iocshFree(void); |
320 | |
321 | epicsShareFunc int epicsShareAPI iocsh(const char *pathname); |
322 | +epicsShareFunc int epicsShareAPI iocsh2(const char *pathname, int verbose); |
323 | epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd); |
324 | |
325 | /* 'weak' link to pdbbase */ |
326 | |
327 | === modified file 'src/libCom/iocsh/libComRegister.c' |
328 | --- src/libCom/iocsh/libComRegister.c 2009-02-24 20:10:57 +0000 |
329 | +++ src/libCom/iocsh/libComRegister.c 2010-04-26 19:21:32 +0000 |
330 | @@ -96,6 +96,25 @@ |
331 | epicsEnvSet (name, value); |
332 | } |
333 | |
334 | +/* epicsEnvSetIfUnset */ |
335 | +/* reuse definition of epicsEnvSet */ |
336 | +static const iocshFuncDef epicsEnvSetIfUnsetFuncDef = {"epicsEnvSetIfUnset",2,epicsEnvSetArgs}; |
337 | +static void epicsEnvSetIfUnsetCallFunc(const iocshArgBuf *args) |
338 | +{ |
339 | + char *name = args[0].sval; |
340 | + char *value = args[1].sval; |
341 | + |
342 | + if (name == NULL) { |
343 | + printf ("Missing environment variable name argument.\n"); |
344 | + return; |
345 | + } |
346 | + if (value == NULL) { |
347 | + printf ("Missing environment variable value argument.\n"); |
348 | + return; |
349 | + } |
350 | + epicsEnvSetIfUnset (name, value); |
351 | +} |
352 | + |
353 | /* epicsParamShow */ |
354 | static const iocshFuncDef epicsParamShowFuncDef = {"epicsParamShow",0,NULL}; |
355 | static void epicsParamShowCallFunc(const iocshArgBuf *args) |
356 | @@ -343,6 +362,7 @@ |
357 | iocshRegister(&pwdFuncDef, pwdCallFunc); |
358 | |
359 | iocshRegister(&epicsEnvSetFuncDef, epicsEnvSetCallFunc); |
360 | + iocshRegister(&epicsEnvSetIfUnsetFuncDef, epicsEnvSetIfUnsetCallFunc); |
361 | iocshRegister(&epicsParamShowFuncDef, epicsParamShowCallFunc); |
362 | iocshRegister(&epicsPrtEnvParamsFuncDef, epicsPrtEnvParamsCallFunc); |
363 | iocshRegister(&epicsEnvShowFuncDef, epicsEnvShowCallFunc); |
364 | |
365 | === modified file 'src/libCom/macLib/macCore.c' |
366 | --- src/libCom/macLib/macCore.c 2008-03-31 19:30:17 +0000 |
367 | +++ src/libCom/macLib/macCore.c 2010-04-26 19:21:32 +0000 |
368 | @@ -84,13 +84,6 @@ |
369 | */ |
370 | #define MAC_MAGIC 0xbadcafe /* ...sells sub-standard coffee? */ |
371 | |
372 | -/* |
373 | - * Flag bits |
374 | - */ |
375 | -#define FLAG_SUPPRESS_WARNINGS 0x1 |
376 | -#define FLAG_USE_ENVIRONMENT 0x80 |
377 | - |
378 | - |
379 | /*** Library routines ***/ |
380 | |
381 | /* |
382 | @@ -130,7 +123,7 @@ |
383 | |
384 | /* use environment variables if so specified */ |
385 | if (pairs && pairs[0] && !strcmp(pairs[0],"") && pairs[1] && !strcmp(pairs[1],"environ") && !pairs[3]) { |
386 | - handle->flags |= FLAG_USE_ENVIRONMENT; |
387 | + handle->flags |= MAC_FLAG_USE_ENVIRONMENT; |
388 | } |
389 | else { |
390 | /* if supplied, load macro definitions */ |
391 | @@ -159,8 +152,8 @@ |
392 | ) |
393 | { |
394 | if ( handle && handle->magic == MAC_MAGIC ) { |
395 | - handle->flags = (handle->flags & ~FLAG_SUPPRESS_WARNINGS) | |
396 | - (suppress ? FLAG_SUPPRESS_WARNINGS : 0); |
397 | + handle->flags = (handle->flags & ~MAC_FLAG_SUPPRESS_WARNINGS) | |
398 | + (suppress ? MAC_FLAG_SUPPRESS_WARNINGS : 0); |
399 | } |
400 | } |
401 | |
402 | @@ -577,7 +570,7 @@ |
403 | break; |
404 | } |
405 | if ( (special == FALSE) && (entry == NULL) && |
406 | - (handle->flags & FLAG_USE_ENVIRONMENT) ) { |
407 | + (handle->flags & MAC_FLAG_USE_ENVIRONMENT) ) { |
408 | char *value = getenv(name); |
409 | if (value) { |
410 | entry = create( handle, name, FALSE ); |
411 | @@ -794,7 +787,7 @@ |
412 | if ( *r == '=' ) { |
413 | MAC_ENTRY dflt; |
414 | int flags = handle->flags; |
415 | - handle->flags |= FLAG_SUPPRESS_WARNINGS; |
416 | + handle->flags |= MAC_FLAG_SUPPRESS_WARNINGS; |
417 | |
418 | /* store its location in case we need it */ |
419 | defval = ++r; |
420 | @@ -812,7 +805,7 @@ |
421 | if ( *r == ',' ) { |
422 | MAC_ENTRY subs; |
423 | int flags = handle->flags; |
424 | - handle->flags |= FLAG_SUPPRESS_WARNINGS; |
425 | + handle->flags |= MAC_FLAG_SUPPRESS_WARNINGS; |
426 | |
427 | subs.type = "scoped macro"; |
428 | subs.error = FALSE; |
429 | @@ -872,7 +865,7 @@ |
430 | /* reference is recursive */ |
431 | entry->error = TRUE; |
432 | errval = ",recursive)"; |
433 | - if ( (handle->flags & FLAG_SUPPRESS_WARNINGS) == 0 ) { |
434 | + if ( (handle->flags & MAC_FLAG_SUPPRESS_WARNINGS) == 0 ) { |
435 | errlogPrintf( "macLib: %s %s is recursive (expanding %s %s)\n", |
436 | entry->type, entry->name, |
437 | refentry->type, refentry->name ); |
438 | @@ -886,7 +879,7 @@ |
439 | } |
440 | entry->error = TRUE; |
441 | errval = ",undefined)"; |
442 | - if ( (handle->flags & FLAG_SUPPRESS_WARNINGS) == 0 ) { |
443 | + if ( (handle->flags & MAC_FLAG_SUPPRESS_WARNINGS) == 0 ) { |
444 | errlogPrintf( "macLib: macro %s is undefined (expanding %s %s)\n", |
445 | refname, entry->type, entry->name ); |
446 | } |
447 | |
448 | === modified file 'src/libCom/macLib/macLib.h' |
449 | --- src/libCom/macLib/macLib.h 2008-03-31 19:30:17 +0000 |
450 | +++ src/libCom/macLib/macLib.h 2010-04-26 19:21:32 +0000 |
451 | @@ -45,6 +45,12 @@ |
452 | } MAC_HANDLE; |
453 | |
454 | /* |
455 | + * Flag bits |
456 | + */ |
457 | +#define MAC_FLAG_SUPPRESS_WARNINGS 0x1 |
458 | +#define MAC_FLAG_USE_ENVIRONMENT 0x80 |
459 | + |
460 | +/* |
461 | * Function prototypes (core library) |
462 | */ |
463 | epicsShareFunc long /* 0 = OK; <0 = ERROR */ |
464 | |
465 | === modified file 'src/libCom/osi/os/Darwin/osdEnv.c' |
466 | --- src/libCom/osi/os/Darwin/osdEnv.c 2009-02-23 18:11:40 +0000 |
467 | +++ src/libCom/osi/os/Darwin/osdEnv.c 2010-04-26 19:21:32 +0000 |
468 | @@ -62,6 +62,13 @@ |
469 | } |
470 | } |
471 | |
472 | +epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value) |
473 | +{ |
474 | + if (getenv(name)) |
475 | + return; |
476 | + epicsEnvSet (name, value); |
477 | +} |
478 | + |
479 | /* |
480 | * Show the value of the specified, or all, environment variables |
481 | */ |
482 | |
483 | === modified file 'src/libCom/osi/os/default/osdEnv.c' |
484 | --- src/libCom/osi/os/default/osdEnv.c 2004-08-27 16:04:26 +0000 |
485 | +++ src/libCom/osi/os/default/osdEnv.c 2010-04-26 19:21:32 +0000 |
486 | @@ -55,6 +55,13 @@ |
487 | } |
488 | } |
489 | |
490 | +epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value) |
491 | +{ |
492 | + if (getenv(name)) |
493 | + return; |
494 | + epicsEnvSet (name, value); |
495 | +} |
496 | + |
497 | /* |
498 | * Show the value of the specified, or all, environment variables |
499 | */ |
500 | |
501 | === modified file 'src/libCom/osi/os/vxWorks/osdEnv.c' |
502 | --- src/libCom/osi/os/vxWorks/osdEnv.c 2004-08-27 16:04:26 +0000 |
503 | +++ src/libCom/osi/os/vxWorks/osdEnv.c 2010-04-26 19:21:32 +0000 |
504 | @@ -54,6 +54,13 @@ |
505 | } |
506 | } |
507 | |
508 | +epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value) |
509 | +{ |
510 | + if (getenv(name)) |
511 | + return; |
512 | + epicsEnvSet (name, value); |
513 | +} |
514 | + |
515 | /* |
516 | * Show the value of the specified, or all, environment variables |
517 | */ |
Firstly, please convince me why this is necessary? A package can set environment variables on most on Linux distributions by adding files to /etc/profile.d and users can override them in ~/.login ~/.cshrc or ~/.profile as they wish. IOC startup scripts may contain epicsEnvSet commands. Why do we need yet another way to set environment variables?
If we do provide this facility, people are going to want to use it on all IOC architectures, so implementing it on just one OS is not a good idea. I accept that it was designed for Linux, but I know that someone like Ernest Williams is going to want to use it on vxWorks or RTEMS if we don't provide it in the initial release.
The current code is not portable to vxWorks. The setenv() routine is not available there, use epicsEnvSet() or putenv() instead.
We also have problems using C++ STL containers on vxWorks. No other code in the IOC uses them because STL containers create and destroy objects a lot, which used to cause major memory fragmentation in the vxWorks memory allocator; not sure if it still does, although that shouldn't be a problem with this code. However since the IOC hasn't needed it before and memory is precious on embedded systems, most sites don't build the STL support package into their vxWorks OS images, and for a minor change this will cause major pain. I got lots of very ugly "undefined symbol" errors for internal STL routines when I tried to load the fileLoad.o file on one of my boards here. Note also that as written the vxWorks linker does not include this file in the executable it generates, since no symbols reference it; that's why I had to explicitly load the fileLoad.o object by hand.
The list of files to load should not be hard-coded in the source to fileLoad.cpp. Define a new parameter called EPICS_CONFIG_PATH which is set in base/configure/ CONFIG_ ENV and read using an envGetConfigPar am*() routine. Its value probably needs to be architecture- specific though and we don't currently have a mechanism to set default values from an arch-specific file, so bldEnvData.pl needs to be changed to handle that and some architecture- specific files added.
How to specify multiple files in one parameter? Use OSI_PATH_ LIST_SEPARATOR from osiFileName.h so the value looks like that of a regular ...PATH environment variable except it points to files, not directories.