FOSSology  4.4.0
Open Source License Compliance by Open Source Software
OjoUtils.cc
Go to the documentation of this file.
1 /*
2  SPDX-FileCopyrightText: © 2019 Siemens AG
3 
4  SPDX-License-Identifier: GPL-2.0-only
5 */
11 #include <iostream>
12 
13 #include "OjoUtils.hpp"
14 #include "OjoAgent.hpp"
15 
16 using namespace fo;
17 
26 {
27  int agentId = queryAgentId(dbManager);
28  return OjoState(agentId, std::move(cliOptions));
29 }
30 
37 {
38  return OjoState(-1, std::move(cliOptions));
39 }
40 
47 {
48  char* COMMIT_HASH = fo_sysconfig(AGENT_NAME, "COMMIT_HASH");
49  char* VERSION = fo_sysconfig(AGENT_NAME, "VERSION");
50  char *agentRevision;
51 
52  if (!asprintf(&agentRevision, "%s.%s", VERSION, COMMIT_HASH))
53  bail(-1);
54 
55  int agentId = fo_GetAgentKey(dbManager.getConnection(), AGENT_NAME, 0,
56  agentRevision, AGENT_DESC);
57  free(agentRevision);
58 
59  if (agentId <= 0)
60  bail(1);
61 
62  return agentId;
63 }
64 
74 int writeARS(const OjoState &state, int arsId, int uploadId, int success,
76 {
77  PGconn *connection = dbManager.getConnection();
78  int agentId = state.getAgentId();
79 
80  return fo_WriteARS(connection, arsId, uploadId, agentId, AGENT_ARS, NULL,
81  success);
82 }
83 
88 void bail(int exitval)
89 {
90  fo_scheduler_disconnect(exitval);
91  exit(exitval);
92 }
93 
102 bool processUploadId(const OjoState &state, int uploadId,
103  OjosDatabaseHandler &databaseHandler, bool ignoreFilesWithMimeType)
104 {
105  vector<unsigned long> fileIds = databaseHandler.queryFileIdsForUpload(
106  uploadId, state.getAgentId(), ignoreFilesWithMimeType);
107  char const *repoArea = "files";
108 
109  bool errors = false;
110 #pragma omp parallel
111  {
112  OjosDatabaseHandler threadLocalDatabaseHandler(databaseHandler.spawn());
113 
114  size_t pFileCount = fileIds.size();
115  OjoAgent agentObj = state.getOjoAgent();
116 #pragma omp for
117  for (size_t it = 0; it < pFileCount; ++it)
118  {
119  if (errors)
120  continue;
121 
122  unsigned long pFileId = fileIds[it];
123 
124  if (pFileId == 0)
125  continue;
126 
127  char *fileName = threadLocalDatabaseHandler.getPFileNameForFileId(
128  pFileId);
129  char *filePath = NULL;
130 #pragma omp critical (repo_mk_path)
131  filePath = fo_RepMkPath(repoArea, fileName);
132 
133  if (!filePath)
134  {
135  LOG_FATAL(
136  AGENT_NAME" was unable to derive a file path for pfile %ld. Check your HOSTS configuration.",
137  pFileId);
138  errors = true;
139  }
140 
141  vector<ojomatch> identified;
142  try
143  {
144  identified = agentObj.processFile(filePath, threadLocalDatabaseHandler,
145  state.getCliOptions().getGroupId(),
146  state.getCliOptions().getUserId());
147  }
148  catch (std::runtime_error &e)
149  {
150  LOG_FATAL("Unable to read %s.", e.what());
151  continue;
152  }
153 
154  if (!storeResultInDb(identified, threadLocalDatabaseHandler,
155  state.getAgentId(), pFileId))
156  {
157  LOG_FATAL("Unable to store results in database for pfile %ld.",
158  pFileId);
159  bail(-20);
160  }
161 
163  }
164  }
165 
166  return !errors;
167 }
168 
181 bool storeResultInDb(const vector<ojomatch> &matches,
182  OjosDatabaseHandler &databaseHandle, const int agent_fk, const int pfile_fk)
183 {
184  if (!databaseHandle.begin())
185  {
186  return false;
187  }
188 
189  size_t count = 0;
190  if (matches.size() == 0)
191  {
192  OjoDatabaseEntry entry(-1, agent_fk, pfile_fk);
193  databaseHandle.insertNoResultInDatabase(entry);
194  return databaseHandle.commit();
195  }
196  for (auto m : matches)
197  {
198  OjoDatabaseEntry entry(m.license_fk, agent_fk, pfile_fk);
199 
200  if (entry.license_fk > 0)
201  {
202  ++count;
203  unsigned long int fl_pk = databaseHandle.saveLicenseToDatabase(entry);
204  if (!(fl_pk > 0) || !databaseHandle.saveHighlightToDatabase(m, fl_pk))
205  {
206  databaseHandle.rollback();
207  return false;
208  }
209  }
210  else
211  {
212  databaseHandle.insertNoResultInDatabase(entry);
213  }
214  }
215 
216  return databaseHandle.commit();
217 }
218 
228 bool parseCliOptions(int argc, char **argv, OjoCliOptions &dest,
229  std::vector<std::string> &fileNames, string &directoryToScan)
230 {
231  boost::program_options::options_description desc(
232  AGENT_NAME ": recognized options");
233  desc.add_options()
234  (
235  "help,h", "shows help"
236  )
237  (
238  "verbose,v", "increase verbosity"
239  )
240  (
241  "files",
242  boost::program_options::value<vector<string> >(),
243  "files to scan"
244  )
245  (
246  "json,J", "output JSON"
247  )
248  (
249  "ignoreFilesWithMimeType,I", "ignoreFilesWithMimeType"
250  )
251  (
252  "config,c",
253  boost::program_options::value<string>(),
254  "path to the sysconfigdir"
255  )
256  (
257  "scheduler_start",
258  "specifies, that the command was called by the scheduler"
259  )
260  (
261  "userID",
262  boost::program_options::value<int>(),
263  "the id of the user that created the job (only in combination with --scheduler_start)"
264  )
265  (
266  "groupID",
267  boost::program_options::value<int>(),
268  "the id of the group of the user that created the job (only in combination with --scheduler_start)"
269  )
270  (
271  "jobId",
272  boost::program_options::value<int>(),
273  "the id of the job (only in combination with --scheduler_start)"
274  )
275  (
276  "directory,d",
277  boost::program_options::value<string>(),
278  "directory to scan (recursive)"
279  )
280  ;
281 
282  boost::program_options::positional_options_description p;
283  p.add("files", -1);
284 
285  boost::program_options::variables_map vm;
286 
287  try
288  {
289  boost::program_options::store(
290  boost::program_options::command_line_parser(argc, argv).options(desc).positional(
291  p).run(), vm);
292 
293  if (vm.count("help") > 0)
294  {
295  cout << desc << endl;
296  exit(0);
297  }
298 
299  if (vm.count("files"))
300  {
301  fileNames = vm["files"].as<std::vector<string> >();
302  }
303 
304  unsigned long verbosity = vm.count("verbose");
305  bool json = vm.count("json") > 0 ? true : false;
306  bool ignoreFilesWithMimeType = vm.count("ignoreFilesWithMimeType") > 0 ? true : false;
307 
308  dest = OjoCliOptions(verbosity, json, ignoreFilesWithMimeType);
309 
310  if (vm.count("userID") > 0)
311  {
312  dest.setUserId(vm["userID"].as<int>());
313  }
314 
315  if (vm.count("groupID") > 0)
316  {
317  dest.setGroupId(vm["groupID"].as<int>());
318  }
319 
320  if (vm.count("directory"))
321  {
322  if (vm.count("files"))
323  {
324  cout << "cannot pass files and directory at the same time" << endl;
325  cout << desc << endl;
326  fileNames.clear();
327  return false;
328  }
329  directoryToScan = vm["directory"].as<std::string>();
330  }
331 
332  return true;
333  }
334  catch (boost::bad_any_cast&)
335  {
336  cout << "wrong parameter type" << endl;
337  cout << desc << endl;
338  return false;
339  }
340  catch (boost::program_options::error&)
341  {
342  cout << "wrong command line arguments" << endl;
343  cout << desc << endl;
344  return false;
345  }
346 }
347 
355 void appendToJson(const std::string fileName,
356  const std::pair<string, vector<ojomatch>> resultPair,
357  bool &printComma)
358 {
359  Json::Value result;
360 #if JSONCPP_VERSION_HEXA < ((1 << 24) | (4 << 16))
361  // Use FastWriter for versions below 1.4.0
362  Json::FastWriter jsonWriter;
363 #else
364  // Since version 1.4.0, FastWriter is deprecated and replaced with
365  // StreamWriterBuilder
366  Json::StreamWriterBuilder jsonWriter;
367  jsonWriter["commentStyle"] = "None";
368  jsonWriter["indentation"] = "";
369 #endif
370  if (resultPair.first.empty())
371  {
372  result["file"] = fileName;
373  result["results"] = "Unable to read file";
374  }
375  else
376  {
377  vector<ojomatch> resultList = resultPair.second;
378  Json::Value results;
379  for (auto m : resultList)
380  {
381  Json::Value j;
382  j["start"] = Json::Value::UInt(m.start);
383  j["end"] = Json::Value::UInt(m.end);
384  j["len"] = Json::Value::UInt(m.len);
385  j["license"] = m.content;
386  results.append(j);
387  }
388  result["file"] = fileName;
389  result["results"] = results;
390  }
391  // Thread-Safety: output all matches JSON at once to STDOUT
392 #pragma omp critical (jsonPrinter)
393  {
394  if (printComma)
395  {
396  cout << "," << endl;
397  }
398  else
399  {
400  printComma = true;
401  }
402  string jsonString;
403 #if JSONCPP_VERSION_HEXA < ((1 << 24) | (4 << 16))
404  // For version below 1.4.0, every writer append `\n` at end.
405  // Find and replace it.
406  jsonString = jsonWriter.write(result);
407  jsonString.replace(jsonString.find("\n"), string("\n").length(), "");
408 #else
409  // For version >= 1.4.0, \n is not appended.
410  jsonString = Json::writeString(jsonWriter, result);
411 #endif
412  cout << " " << jsonString << flush;
413  }
414 }
415 
421 void printResultToStdout(const std::string fileName,
422  const std::pair<string, vector<ojomatch>> resultPair)
423 {
424  if (resultPair.first.empty())
425  {
426  cout << fileName << " :: Unable to read file" << endl;
427  return;
428  }
429  stringstream ss;
430  ss << fileName << " ::" << endl;
431  // Output matches
432  vector<ojomatch> resultList = resultPair.second;
433  for (auto m : resultList)
434  {
435  ss << "\t[" << m.start << ':' << m.end << "]: '" << m.content << "'" << endl;
436  }
437  // Thread-Safety: output all matches (collected in ss) at once to cout
438  cout << ss.str();
439 }
void appendToJson(const std::string fileName, const std::pair< string, vector< ojomatch >> resultPair, bool &printComma)
Definition: OjoUtils.cc:355
bool parseCliOptions(int argc, char **argv, OjoCliOptions &dest, std::vector< std::string > &fileNames, string &directoryToScan)
Parse the options sent by CLI to CliOptions object.
Definition: OjoUtils.cc:228
void printResultToStdout(const std::string fileName, const std::pair< string, vector< ojomatch >> resultPair)
Definition: OjoUtils.cc:421
bool storeResultInDb(const vector< ojomatch > &matches, OjosDatabaseHandler &databaseHandle, const int agent_fk, const int pfile_fk)
Store the results from scan to DB.
Definition: OjoUtils.cc:181
OjoState getState(DbManager &dbManager, OjoCliOptions &&cliOptions)
Create a new state for the current agent based on CliOptions.
Definition: OjoUtils.cc:25
int queryAgentId(DbManager &dbManager)
Definition: OjoUtils.cc:46
int writeARS(const OjoState &state, int arsId, int uploadId, int success, DbManager &dbManager)
Definition: OjoUtils.cc:74
void bail(int exitval)
Disconnect with scheduler returning an error code and exit.
Definition: OjoUtils.cc:88
bool processUploadId(const OjoState &state, int uploadId, OjosDatabaseHandler &databaseHandler, bool ignoreFilesWithMimeType)
Definition: OjoUtils.cc:102
Store the options sent through the CLI.
Definition: OjoState.hpp:24
int getGroupId() const
Get the group running the agent.
Definition: OjoState.cc:134
int getUserId() const
Get the user running the agent.
Definition: OjoState.cc:125
Store the state of the agent.
Definition: OjoState.hpp:51
const OjoAgent & getOjoAgent() const
Definition: OjoState.cc:41
int getAgentId() const
Definition: OjoState.cc:32
const OjoCliOptions & getCliOptions() const
Get the OjoCliOptions set by user.
Definition: OjoState.cc:71
OjosDatabaseHandler spawn() const
std::vector< unsigned long > queryFileIdsForUpload(int uploadId, int agentId, bool ignoreFilesWithMimeType)
bool insertNoResultInDatabase(OjoDatabaseEntry &entry) const
Save no result to the database.
bool saveHighlightToDatabase(const ojomatch &match, const unsigned long fl_fk) const
unsigned long saveLicenseToDatabase(OjoDatabaseEntry &entry) const
Save findings to the database if agent was called by scheduler.
bool commit() const
COMMIT a transaction block in DB.
bool begin() const
BEGIN a transaction block in DB.
char * getPFileNameForFileId(unsigned long pfileId) const
Get the file name of a give pfile id.
bool rollback() const
ROLLBACK a transaction block in DB.
DB wrapper for agents.
FUNCTION int fo_WriteARS(PGconn *pgConn, int ars_pk, int upload_pk, int agent_pk, const char *tableName, const char *ars_status, int ars_success)
Write ars record.
Definition: libfossagent.c:214
FUNCTION int fo_GetAgentKey(PGconn *pgConn, const char *agent_name, long Upload_pk, const char *rev, const char *agent_desc)
Get the latest enabled agent key (agent_pk) from the database.
Definition: libfossagent.c:158
char * fo_RepMkPath(const char *Type, char *Filename)
Given a filename, construct the full path to the file.
Definition: libfossrepo.c:352
void fo_scheduler_disconnect(int retcode)
Disconnect the scheduler connection.
void fo_scheduler_heart(int i)
This function must be called by agents to let the scheduler know they are alive and how many items th...
char * fo_sysconfig(const char *sectionname, const char *variablename)
gets a system configuration variable from the configuration data.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
fo namespace holds the FOSSology library functions.
const unsigned long int license_fk