dynamicCode.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "dynamicCode.H"
27 #include "dynamicCodeContext.H"
28 #include "stringOps.H"
29 #include "IFstream.H"
30 #include "OFstream.H"
31 #include "OSspecific.H"
32 #include "dictionary.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
37 (
38  Foam::debug::infoSwitch("allowSystemOperations", 0)
39 );
40 
41 
43  = "FOAM_CODE_TEMPLATES";
44 
46  = "codeTemplates/dynamicCode";
47 
48 const char* const Foam::dynamicCode::libTargetRoot =
49  "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib";
50 
51 const char* const Foam::dynamicCode::topDirName = "dynamicCode";
52 
53 
54 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
55 
57 (
58  const char* title,
59  const dictionary& dict
60 )
61 {
62  if (isAdministrator())
63  {
65  << "This code should not be executed by someone with administrator"
66  << " rights due to security reasons." << nl
67  << "(it writes a shared library which then gets loaded "
68  << "using dlopen)"
69  << exit(FatalIOError);
70  }
71 
72  if (!allowSystemOperations)
73  {
75  << "Loading a shared library using case-supplied code is not"
76  << " enabled by default" << nl
77  << "because of security issues. If you trust the code you can"
78  << " enable this" << nl
79  << "facility be adding to the InfoSwitches setting in the system"
80  << " controlDict:" << nl << nl
81  << " allowSystemOperations 1" << nl << nl
82  << "The system controlDict is either" << nl << nl
83  << " ~/.OpenFOAM/$WM_PROJECT_VERSION/controlDict" << nl << nl
84  << "or" << nl << nl
85  << " $WM_PROJECT_DIR/etc/controlDict" << nl
86  << endl
87  << exit(FatalIOError);
88  }
89 }
90 
91 
93 {
94  word libName(libPath.name(true));
95  libName.erase(0, 3); // remove leading 'lib' from name
96  return libName;
97 }
98 
99 
100 
101 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
102 
104 (
105  ISstream& is,
106  OSstream& os,
107  const HashTable<string>& mapping
108 )
109 {
110  if (!is.good())
111  {
113  << "Failed opening for reading " << is.name()
114  << exit(FatalError);
115  }
116 
117  if (!os.good())
118  {
120  << "Failed writing " << os.name()
121  << exit(FatalError);
122  }
123 
124  // Copy file while rewriting $VARS and ${VARS}
125  string line;
126  do
127  {
128  is.getLine(line);
129 
130  // expand according to mapping
131  // expanding according to env variables might cause too many
132  // surprises
133  stringOps::inplaceExpand(line, mapping);
134  os.writeQuoted(line, false) << nl;
135  }
136  while (is.good());
137 }
138 
139 
141 (
142  const UList<fileName>& templateNames,
143  DynamicList<fileName>& resolvedFiles,
144  DynamicList<fileName>& badFiles
145 )
146 {
147  // try to get template from FOAM_CODESTREAM_TEMPLATES
148  const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
149 
150  bool allOkay = true;
151  forAll(templateNames, fileI)
152  {
153  const fileName& templateName = templateNames[fileI];
154 
155  fileName file;
156  if (!templateDir.empty() && isDir(templateDir))
157  {
158  file = templateDir/templateName;
159  if (!isFile(file, false))
160  {
161  file.clear();
162  }
163  }
164 
165  // not found - fallback to ~OpenFOAM expansion
166  if (file.empty())
167  {
168  file = findEtcFile(codeTemplateDirName/templateName);
169  }
170 
171  if (file.empty())
172  {
173  badFiles.append(templateName);
174  allOkay = false;
175  }
176  else
177  {
178  resolvedFiles.append(file);
179  }
180  }
181 
182  return allOkay;
183 }
184 
185 
187 {
188  const bool hasSHA1 = filterVars_.found("SHA1sum");
189 
190  if (hasSHA1)
191  {
192  os << "/* dynamicCode:\n * SHA1 = ";
193  os.writeQuoted(filterVars_["SHA1sum"], false) << "\n */\n";
194  }
195 
196  return hasSHA1;
197 }
198 
199 
201 {
202  // Create Make/files
203  if (compileFiles_.empty())
204  {
205  return false;
206  }
207 
208  const fileName dstFile(this->codePath()/"Make/files");
209 
210  // Create dir
211  mkDir(dstFile.path());
212 
213  OFstream os(dstFile);
214  //Info<< "Writing to " << dstFile << endl;
215  if (!os.good())
216  {
218  << "Failed writing " << dstFile
219  << exit(FatalError);
220  }
221 
222  writeCommentSHA1(os);
223 
224  // Write compile files
225  forAll(compileFiles_, fileI)
226  {
227  os.writeQuoted(compileFiles_[fileI], false) << nl;
228  }
229 
230  os << nl
231  << libTargetRoot << codeName_.c_str() << nl;
232 
233  return true;
234 }
235 
236 
238 {
239  // Create Make/options
240  if (compileFiles_.empty() || makeOptions_.empty())
241  {
242  return false;
243  }
244 
245  const fileName dstFile(this->codePath()/"Make/options");
246 
247  // Create dir
248  mkDir(dstFile.path());
249 
250  OFstream os(dstFile);
251  //Info<< "Writing to " << dstFile << endl;
252  if (!os.good())
253  {
255  << "Failed writing " << dstFile
256  << exit(FatalError);
257  }
258 
259  writeCommentSHA1(os);
260  os.writeQuoted(makeOptions_, false) << nl;
261 
262  return true;
263 }
264 
265 
267 {
268  const fileName file = digestFile();
269  mkDir(file.path());
270 
271  OFstream os(file);
272  sha1.write(os, true) << nl;
273 
274  return os.good();
275 }
276 
277 
278 bool Foam::dynamicCode::writeDigest(const std::string& sha1) const
279 {
280  const fileName file = digestFile();
281  mkDir(file.path());
282 
283  OFstream os(file);
284  os << '_';
285  os.writeQuoted(sha1, false) << nl;
286 
287  return os.good();
288 }
289 
290 
291 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
292 
293 Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName)
294 :
295  codeRoot_(stringOps::expand("$FOAM_CASE")/topDirName),
296  libSubDir_(stringOps::expand("platforms/$WM_OPTIONS/lib")),
297  codeName_(codeName),
298  codeDirName_(codeDirName)
299 {
300  if (codeDirName_.empty())
301  {
303  }
304 
305  clear();
306 }
307 
308 
309 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
310 
312 {
313  return topDirName/codeDirName_;
314 }
315 
316 
318 {
319  return codeRelPath()/libSubDir_/"lib" + codeName_ + ".so";
320 }
321 
322 
324 {
325  compileFiles_.clear();
326  copyFiles_.clear();
327  createFiles_.clear();
328  filterVars_.clear();
329  filterVars_.set("typeName", codeName_);
330  filterVars_.set("SHA1sum", SHA1Digest().str());
331 
332  // provide default Make/options
333  makeOptions_ =
334  "EXE_INC = -g\n"
335  "\n\nLIB_LIBS = ";
336 }
337 
338 
340 (
341  const dynamicCodeContext& context
342 )
343 {
344  clear();
345  setFilterContext(context);
346 }
347 
348 
350 {
351  compileFiles_.append(name);
352 }
353 
354 
356 {
357  copyFiles_.append(name);
358 }
359 
360 
362 (
363  const fileName& name,
364  const string& contents
365 )
366 {
367  createFiles_.append(fileAndContent(name, contents));
368 }
369 
370 
372 (
373  const dynamicCodeContext& context
374 )
375 {
376  filterVars_.set("localCode", context.localCode());
377  filterVars_.set("code", context.code());
378  filterVars_.set("codeInclude", context.include());
379  filterVars_.set("SHA1sum", context.sha1().str());
380 }
381 
382 
384 (
385  const word& key,
386  const std::string& value
387 )
388 {
389  filterVars_.set(key, value);
390 }
391 
392 
393 void Foam::dynamicCode::setMakeOptions(const std::string& content)
394 {
395  makeOptions_ = content;
396 }
397 
398 
399 bool Foam::dynamicCode::copyOrCreateFiles(const bool verbose) const
400 {
401  if (verbose)
402  {
403  Info<< "Creating new library in " << this->libRelPath() << endl;
404  }
405 
406  const label nFiles = compileFiles_.size() + copyFiles_.size();
407 
408  DynamicList<fileName> resolvedFiles(nFiles);
409  DynamicList<fileName> badFiles(nFiles);
410 
411  // resolve template, or add to bad-files
412  resolveTemplates(compileFiles_, resolvedFiles, badFiles);
413  resolveTemplates(copyFiles_, resolvedFiles, badFiles);
414 
415  if (!badFiles.empty())
416  {
418  << "Could not find the code template(s): "
419  << badFiles << nl
420  << "Under the $" << codeTemplateEnvName
421  << " directory or via via the ~OpenFOAM/"
422  << codeTemplateDirName << " expansion"
423  << exit(FatalError);
424  }
425 
426 
427 
428  // Create dir
429  const fileName outputDir = this->codePath();
430 
431  // Create dir
432  mkDir(outputDir);
433 
434  // Copy/filter files
435  forAll(resolvedFiles, fileI)
436  {
437  const fileName& srcFile = resolvedFiles[fileI];
438  const fileName dstFile(outputDir/srcFile.name());
439 
440  IFstream is(srcFile);
441  //Info<< "Reading from " << is.name() << endl;
442  if (!is.good())
443  {
445  << "Failed opening " << srcFile
446  << exit(FatalError);
447  }
448 
449  OFstream os(dstFile);
450  //Info<< "Writing to " << dstFile.name() << endl;
451  if (!os.good())
452  {
454  << "Failed writing " << dstFile
455  << exit(FatalError);
456  }
457 
458  // Copy lines while expanding variables
459  copyAndFilter(is, os, filterVars_);
460  }
461 
462 
463  // Create files:
464  forAll(createFiles_, fileI)
465  {
466  const fileName dstFile
467  (
468  outputDir/stringOps::expand(createFiles_[fileI].first())
469  );
470 
471  mkDir(dstFile.path());
472  OFstream os(dstFile);
473  //Info<< "Writing to " << createFiles_[fileI].first() << endl;
474  if (!os.good())
475  {
477  << "Failed writing " << dstFile
478  << exit(FatalError);
479  }
480  os.writeQuoted(createFiles_[fileI].second(), false) << nl;
481  }
482 
483 
484  // Create Make/files + Make/options
485  createMakeFiles();
486  createMakeOptions();
487 
488  writeDigest(filterVars_["SHA1sum"]);
489 
490  return true;
491 }
492 
493 
495 {
496  const Foam::string wmakeCmd("wmake -s libso " + this->codePath());
497  Info<< "Invoking " << wmakeCmd << endl;
498 
499  if (Foam::system(wmakeCmd))
500  {
501  return false;
502  }
503  else
504  {
505  return true;
506  }
507 }
508 
509 
511 {
512  const fileName file = digestFile();
513 
514  if (!exists(file, false) || SHA1Digest(IFstream(file)()) != sha1)
515  {
516  return false;
517  }
518 
519  return true;
520 }
521 
522 
524 {
525  return upToDate(context.sha1());
526 }
527 
528 
529 // ************************************************************************* //
Foam::findEtcFile
fileName findEtcFile(const fileName &, bool mandatory=false)
Search for a file using findEtcFiles.
Definition: POSIX.C:404
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::dynamicCode::createMakeFiles
bool createMakeFiles() const
Copy/create Make/files prior to compilation.
Definition: dynamicCode.C:200
Foam::dynamicCode::topDirName
static const char *const topDirName
Top-level directory name for copy/compiling.
Definition: dynamicCode.H:109
Foam::dynamicCode::writeCommentSHA1
bool writeCommentSHA1(Ostream &) const
Write SHA1 value as C-comment.
Definition: dynamicCode.C:186
Foam::SHA1Digest::write
Ostream & write(Ostream &, const bool prefixed=false) const
Write (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1Digest.C:137
Foam::word
A class for handling words, derived from string.
Definition: word.H:59
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::exists
bool exists(const fileName &, const bool checkGzip=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: POSIX.C:608
Foam::dynamicCode::libPath
fileName libPath() const
Library path for specified code name.
Definition: dynamicCode.H:221
Foam::dynamicCode::copyAndFilter
static void copyAndFilter(ISstream &, OSstream &, const HashTable< string > &mapping)
Copy lines while expanding variables.
Definition: dynamicCode.C:104
Foam::dynamicCode::copyOrCreateFiles
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:399
clear
UEqn clear()
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::dynamicCode::wmakeLibso
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:494
Foam::IFstream
Input from file stream.
Definition: IFstream.H:81
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:56
Foam::dynamicCodeContext
Encapsulation of dynamic code dictionaries.
Definition: dynamicCodeContext.H:49
Foam::debug::infoSwitch
int infoSwitch(const char *name, const int defaultValue=0)
Lookup info switch or add default value.
Definition: debug.C:173
Foam::dynamicCode::createMakeOptions
bool createMakeOptions() const
Copy/create Make/options prior to compilation.
Definition: dynamicCode.C:237
Foam::dynamicCode::writeDigest
bool writeDigest(const SHA1Digest &) const
Write digest to Make/SHA1Digest.
Definition: dynamicCode.C:266
Foam::fileName::path
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:293
Foam::ISstream
Generic input stream.
Definition: ISstream.H:51
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::dynamicCodeContext::include
const string & include() const
Return the code-includes.
Definition: dynamicCodeContext.H:90
Foam::string
A class for handling character strings derived from std::string.
Definition: string.H:74
dynamicCodeContext.H
Foam::dynamicCode::setFilterContext
void setFilterContext(const dynamicCodeContext &)
Define filter variables for code, codeInclude, SHA1sum.
Definition: dynamicCode.C:372
Foam::dynamicCode::resolveTemplates
static bool resolveTemplates(const UList< fileName > &templateNames, DynamicList< fileName > &resolvedFiles, DynamicList< fileName > &badFiles)
Resolve code-templates via the codeTemplateEnvName.
Definition: dynamicCode.C:141
Foam::dynamicCode::addCopyFile
void addCopyFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:355
Foam::fileName::name
word name() const
Return file name (part beyond last /)
Definition: fileName.C:212
Foam::dynamicCode::allowSystemOperations
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:161
OFstream.H
Foam::isAdministrator
bool isAdministrator()
Is user administrator.
Definition: POSIX.C:184
Foam::dynamicCode::codeTemplateEnvName
static const word codeTemplateEnvName
Name of the code template environment variable.
Definition: dynamicCode.H:154
Foam::dynamicCode::dynamicCode
dynamicCode(const dynamicCode &)
Disallow default bitwise copy construct.
Foam::dynamicCode::addCompileFile
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:349
Foam::getEnv
string getEnv(const word &)
Return environment variable of given name.
Definition: POSIX.C:101
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::ISstream::getLine
ISstream & getLine(string &)
Raw, low-level getline into a string function.
Definition: ISstreamI.H:77
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:88
Foam::dynamicCodeContext::code
const string & code() const
Return the code.
Definition: dynamicCodeContext.H:108
Foam::dynamicCode::checkSecurity
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:57
Foam::dynamicCode::codeRelPath
fileName codeRelPath() const
Path for specified code name relative to $FOAM_CASE.
Definition: dynamicCode.C:311
dynamicCode.H
Foam::OSstream
Generic output stream.
Definition: OSstream.H:51
Foam::dynamicCode::libRelPath
fileName libRelPath() const
Library path for specified code name relative to $FOAM_CASE.
Definition: dynamicCode.C:317
IFstream.H
Foam::ISstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: ISstream.H:106
Foam::dynamicCodeContext::sha1
const SHA1Digest & sha1() const
Return SHA1 digest calculated from include, options, code.
Definition: dynamicCodeContext.H:120
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:137
Foam::isFile
bool isFile(const fileName &, const bool checkGzip=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:622
Foam::isDir
bool isDir(const fileName &)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:615
Foam::SHA1Digest
The SHA1 message digest.
Definition: SHA1Digest.H:62
Foam::dynamicCode::setFilterVariable
void setFilterVariable(const word &key, const std::string &value)
Define a filter variable.
Definition: dynamicCode.C:384
Foam::DynamicList::append
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::OFstream
Output to file stream.
Definition: OFstream.H:81
Foam::dynamicCode::reset
void reset(const dynamicCodeContext &)
Clear files and reset variables to specified context.
Definition: dynamicCode.C:340
Foam::HashTable
An STL-conforming hash table.
Definition: HashTable.H:61
Foam::dynamicCode::libraryBaseName
static word libraryBaseName(const fileName &libPath)
Return the library basename without leading 'lib' or trailing '.so'.
Definition: dynamicCode.C:92
Foam::dynamicCodeContext::localCode
const string & localCode() const
Return the local (file-scope) code.
Definition: dynamicCodeContext.H:114
Foam::dynamicCode::upToDate
bool upToDate(const dynamicCodeContext &context) const
Verify if the copied code is up-to-date, based on Make/SHA1Digest.
Definition: dynamicCode.C:523
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::dynamicCode::setMakeOptions
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:393
Foam::dynamicCode::clear
void clear()
Clear files and variables.
Definition: dynamicCode.C:323
Foam::OSstream::writeQuoted
virtual Ostream & writeQuoted(const std::string &, const bool quoted=true)
Write std::string surrounded by quotes.
Definition: OSstream.C:125
Foam::dynamicCode::codeTemplateDirName
static const fileName codeTemplateDirName
Name of the code template sub-directory.
Definition: dynamicCode.H:158
Foam::Ostream::writeQuoted
virtual Ostream & writeQuoted(const std::string &, const bool quoted=true)=0
Write std::string surrounded by quotes.
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
dictionary.H
Foam::dynamicCode::codeName_
word codeName_
Name for code.
Definition: dynamicCode.H:71
Foam::line
A line primitive.
Definition: line.H:56
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:330
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:53
Foam::Tuple2
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:47
Foam::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
Foam::mkDir
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:419
stringOps.H
Foam::stringOps::inplaceExpand
string & inplaceExpand(string &, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Inplace expand occurences of variables according to the mapping.
Definition: stringOps.C:86
Foam::system
int system(const std::string &command)
Execute the specified command.
Definition: POSIX.C:1155
Foam::name
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Foam::dynamicCode::addCreateFile
void addCreateFile(const fileName &name, const string &contents)
Add a file to create with its contents. Will not be filtered.
Definition: dynamicCode.C:362
Foam::SHA1Digest::str
std::string str(const bool prefixed=false) const
Return (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1Digest.C:112
Foam::stringOps::expand
string expand(const string &, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Expand occurences of variables according to the mapping.
Definition: stringOps.C:74
Foam::dynamicCode::codeDirName_
word codeDirName_
Name for code subdirectory.
Definition: dynamicCode.H:74
Foam::dynamicCode::libTargetRoot
static const char *const libTargetRoot
Root of the LIB target for Make/files.
Definition: dynamicCode.H:106