FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
monkbulk.c
1 /*
2 Author: Daniele Fognini, Andreas Wuerl
3 Copyright (C) 2013-2015,2018 Siemens AG
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 version 2 as published by the Free Software Foundation.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 
19 #include <stdlib.h>
20 
21 #include "libfossology.h"
22 
23 #include "monkbulk.h"
24 #include "database.h"
25 #include "license.h"
26 #include "match.h"
27 #include "common.h"
28 #include "monk.h"
29 
30 int bulk_onAllMatches(MonkState* state, const File* file, const GArray* matches);
31 
32 MatchCallbacks bulkCallbacks = {.onAll = bulk_onAllMatches};
33 
34 int setLeftAndRight(MonkState* state) {
35  BulkArguments* bulkArguments = state->ptr;
36 
37  gchar* tableName = getUploadTreeTableName(state->dbManager, bulkArguments->uploadId);
38 
39  if (!tableName)
40  return 0;
41 
42  gchar* sql = g_strdup_printf("SELECT lft, rgt FROM %s WHERE uploadtree_pk = $1", tableName);
43  gchar* stmt = g_strdup_printf("setLeftAndRight.%s", tableName);
44 
45  if ((!sql) || (!stmt))
46  return 0;
47 
48  PGresult* leftAndRightResult = fo_dbManager_ExecPrepared(
49  fo_dbManager_PrepareStamement(
50  state->dbManager,
51  stmt,
52  sql,
53  long
54  ),
55  bulkArguments->uploadTreeId
56  );
57 
58  g_free(stmt);
59  g_free(sql);
60 
61  int result = 0;
62 
63  if (leftAndRightResult) {
64  if (PQntuples(leftAndRightResult)==1) {
65  int i = 0;
66  bulkArguments->uploadTreeLeft = atol(PQgetvalue(leftAndRightResult, 0, i++));
67  bulkArguments->uploadTreeRight = atol(PQgetvalue(leftAndRightResult, 0, i));
68 
69  result = 1;
70  }
71  PQclear(leftAndRightResult);
72  }
73  return result;
74 }
75 
76 void bulkArguments_contents_free(BulkArguments* bulkArguments);
77 
78 BulkAction** queryBulkActions(MonkState* state, long bulkId);
79 
80 int queryBulkArguments(MonkState* state, long bulkId) {
81  int result = 0;
82 
83  PGresult* bulkArgumentsResult = fo_dbManager_ExecPrepared(
84  fo_dbManager_PrepareStamement(
85  state->dbManager,
86  "queryBulkArguments",
87  "SELECT ut.upload_fk, ut.uploadtree_pk, lrb.user_fk, lrb.group_fk, lrb.rf_text "
88  "FROM license_ref_bulk lrb INNER JOIN uploadtree ut "
89  "ON ut.uploadtree_pk = lrb.uploadtree_fk "
90  "WHERE lrb_pk = $1",
91  long
92  ),
93  bulkId
94  );
95 
96  if (bulkArgumentsResult) {
97  if (PQntuples(bulkArgumentsResult)==1) {
98  BulkArguments* bulkArguments = (BulkArguments*)malloc(sizeof(BulkArguments));
99 
100  int column = 0;
101  bulkArguments->uploadId = atoi(PQgetvalue(bulkArgumentsResult, 0, column++));
102  bulkArguments->uploadTreeId = atol(PQgetvalue(bulkArgumentsResult, 0, column++));
103  bulkArguments->userId = atoi(PQgetvalue(bulkArgumentsResult, 0, column++));
104  bulkArguments->groupId = atoi(PQgetvalue(bulkArgumentsResult, 0, column++));
105  bulkArguments->refText = g_strdup(PQgetvalue(bulkArgumentsResult, 0, column++));
106  bulkArguments->bulkId = bulkId;
107  bulkArguments->actions = queryBulkActions(state, bulkId);
108  bulkArguments->jobId = fo_scheduler_jobId();
109 
110  state->ptr = bulkArguments;
111 
112  if (!setLeftAndRight(state)) {
113  printf("FATAL: could not retrieve left and right for bulk id=%ld\n", bulkId);
114  bulkArguments_contents_free(state->ptr);
115  } else {
116  result = 1;
117  }
118  } else {
119  printf("FATAL: could not retrieve arguments for bulk scan with id=%ld\n", bulkId);
120  }
121  PQclear(bulkArgumentsResult);
122  }
123  return result;
124 }
125 
126 BulkAction** queryBulkActions(MonkState* state, long bulkId) {
127 
128  PGresult* bulkActionsResult = fo_dbManager_ExecPrepared(
129  fo_dbManager_PrepareStamement(
130  state->dbManager,
131  "queryBulkActions",
132  "SELECT rf_fk, removing, comment, reportinfo, acknowledgement FROM license_set_bulk WHERE lrb_fk = $1",
133  long
134  ),
135  bulkId
136  );
137 
138  int numberOfRows = bulkActionsResult ? PQntuples(bulkActionsResult) : 0;
139  BulkAction** bulkActions = (BulkAction**)malloc((numberOfRows + 1) * sizeof(BulkAction*));
140 
141  int row;
142  for (row = 0; row < numberOfRows; row++) {
143  int column = 0;
144  BulkAction *action = (BulkAction *) malloc(sizeof(BulkAction));
145  action->licenseId = atoi(PQgetvalue(bulkActionsResult, row, column++));
146  action->removing = (strcmp(PQgetvalue(bulkActionsResult, row, column++), "t") == 0);
147  action->comment = g_strdup(PQgetvalue(bulkActionsResult, row, column++));
148  action->reportinfo = g_strdup(PQgetvalue(bulkActionsResult, row, column++));
149  action->acknowledgement = g_strdup(PQgetvalue(bulkActionsResult, row, column++));
150  bulkActions[row] = action;
151  }
152  bulkActions[row] = NULL;
153 
154  if (bulkActionsResult) {
155  PQclear(bulkActionsResult);
156  }
157 
158  return bulkActions;
159 }
160 
161 void bulkArguments_contents_free(BulkArguments* bulkArguments) {
162 
163  BulkAction **bulkActions = bulkArguments->actions;
164  for (int i=0; bulkActions[i] != NULL; i++) {
165  free(bulkActions[i]);
166  }
167  free(bulkActions);
168 
169  g_free(bulkArguments->refText);
170 
171  free(bulkArguments);
172 }
173 
174 int bulk_identification(MonkState* state) {
175  BulkArguments* bulkArguments = state->ptr;
176 
177  License license = (License){
178  .refId = bulkArguments->licenseId,
179  };
180  license.tokens = tokenize(bulkArguments->refText, DELIMITERS);
181 
182  GArray* licenseArray = g_array_new(FALSE, FALSE, sizeof (License));
183  g_array_append_val(licenseArray, license);
184 
185  Licenses* licenses = buildLicenseIndexes(licenseArray, MIN_ADJACENT_MATCHES, 0);
186 
187  PGresult* filesResult = queryFileIdsForUploadAndLimits(
188  state->dbManager,
189  bulkArguments->uploadId,
190  bulkArguments->uploadTreeLeft,
191  bulkArguments->uploadTreeRight,
192  bulkArguments->groupId
193  );
194 
195  int haveError = 1;
196  if (filesResult != NULL) {
197  int resultsCount = PQntuples(filesResult);
198  haveError = 0;
199 #ifdef MONK_MULTI_THREAD
200  #pragma omp parallel
201 #endif
202  {
203  MonkState threadLocalStateStore = *state;
204  MonkState* threadLocalState = &threadLocalStateStore;
205 
206  threadLocalState->dbManager = fo_dbManager_fork(state->dbManager);
207  if (threadLocalState->dbManager) {
208 #ifdef MONK_MULTI_THREAD
209  #pragma omp for schedule(dynamic)
210 #endif
211  for (int i = 0; i<resultsCount; i++) {
212  if (haveError)
213  continue;
214 
215  long fileId = atol(PQgetvalue(filesResult, i, 0));
216 
217  if (matchPFileWithLicenses(threadLocalState, fileId, licenses, &bulkCallbacks)) {
219  } else {
221  haveError = 1;
222  }
223  }
224  fo_dbManager_finish(threadLocalState->dbManager);
225  } else {
226  haveError = 1;
227  }
228  }
229  PQclear(filesResult);
230  }
231 
232  licenses_free(licenses);
233 
234  return !haveError;
235 }
236 
237 int main(int argc, char** argv) {
238  MonkState stateStore;
239  MonkState* state = &stateStore;
240 
241  fo_scheduler_connect_dbMan(&argc, argv, &(state->dbManager));
242 
243  queryAgentId(state, AGENT_BULK_NAME, AGENT_BULK_DESC);
244 
245  state->scanMode = MODE_BULK;
246 
247  while (fo_scheduler_next() != NULL) {
248  const char* schedulerCurrent = fo_scheduler_current();
249 
250  long bulkId = atol(schedulerCurrent);
251 
252  if (bulkId == 0) continue;
253 
254  if (!queryBulkArguments(state, bulkId)) {
255  bail(state, 1);
256  }
257 
258  BulkArguments* bulkArguments = state->ptr;
259 
260  int arsId = fo_WriteARS(fo_dbManager_getWrappedConnection(state->dbManager),
261  0, bulkArguments->uploadId, state->agentId, AGENT_BULK_ARS, NULL, 0);
262 
263  if (arsId<=0)
264  bail(state, 2);
265 
266  if (!bulk_identification(state))
267  bail(state, 3);
268 
269  fo_WriteARS(fo_dbManager_getWrappedConnection(state->dbManager),
270  arsId, bulkArguments->uploadId, state->agentId, AGENT_BULK_ARS, NULL, 1);
271 
272  bulkArguments_contents_free(bulkArguments);
274  }
275 
276  scheduler_disconnect(state, 0);
277  return 0;
278 }
279 
280 int bulk_onAllMatches(MonkState* state, const File* file, const GArray* matches) {
281  int haveAFullMatch = 0;
282  for (guint j=0; j<matches->len; j++) {
283  Match* match = match_array_index(matches, j);
284 
285  if (match->type == MATCH_TYPE_FULL) {
286  haveAFullMatch = 1;
287  break;
288  }
289  }
290 
291  if (!haveAFullMatch)
292  return 1;
293 
294  BulkArguments* bulkArguments = state->ptr;
295 
296  if (!fo_dbManager_begin(state->dbManager))
297  return 0;
298 
299  BulkAction **actions = bulkArguments->actions;
300  for (int i = 0; actions[i] != NULL; i++) {
301  BulkAction* action = actions[i];
302 
303  PGresult* licenseDecisionIds = fo_dbManager_ExecPrepared(
304  fo_dbManager_PrepareStamement(
305  state->dbManager,
306  "saveBulkResult:decision",
307  "INSERT INTO clearing_event(uploadtree_fk, user_fk, group_fk, job_fk, type_fk, rf_fk, removed, comment, reportinfo, acknowledgement)"
308  " SELECT uploadtree_pk, $2, $3, $4, $5, $6, $7, $8, $9, $10"
309  " FROM uploadtree"
310  " WHERE upload_fk = $11 AND pfile_fk = $1 AND lft BETWEEN $12 AND $13"
311  "RETURNING clearing_event_pk",
312  long, int, int, int, int, long, int, char*, char*, char*,
313  int, long, long
314  ),
315  file->id,
316 
317  bulkArguments->userId,
318  bulkArguments->groupId,
319  bulkArguments->jobId,
320  BULK_DECISION_TYPE,
321  action->licenseId,
322  action->removing ? 1 : 0,
323  action->comment,
324  action->reportinfo,
325  action->acknowledgement,
326 
327  bulkArguments->uploadId,
328  bulkArguments->uploadTreeLeft,
329  bulkArguments->uploadTreeRight
330  );
331 
332  if (licenseDecisionIds) {
333  for (int i=0; i<PQntuples(licenseDecisionIds);i++) {
334  long licenseDecisionEventId = atol(PQgetvalue(licenseDecisionIds,i,0));
335 
336  for (guint j=0; j<matches->len; j++) {
337  Match* match = match_array_index(matches, j);
338 
339  if (match->type != MATCH_TYPE_FULL)
340  continue;
341 
342  DiffPoint* highlightTokens = match->ptr.full;
343  DiffPoint highlight = getFullHighlightFor(file->tokens, highlightTokens->start, highlightTokens->length);
344 
345  PGresult* highlightResult = fo_dbManager_ExecPrepared(
346  fo_dbManager_PrepareStamement(
347  state->dbManager,
348  "saveBulkResult:highlight",
349  "INSERT INTO highlight_bulk(clearing_event_fk, lrb_fk, start, len) VALUES($1,$2,$3,$4)",
350  long, long, size_t, size_t
351  ),
352  licenseDecisionEventId,
353  bulkArguments->bulkId,
354  highlight.start,
355  highlight.length
356  );
357 
358  if (highlightResult) {
359  PQclear(highlightResult);
360  } else {
361  fo_dbManager_rollback(state->dbManager);
362  return 0;
363  }
364  }
365  }
366  PQclear(licenseDecisionIds);
367  } else {
368  fo_dbManager_rollback(state->dbManager);
369  return 0;
370  }
371  }
372 
373 
374  return fo_dbManager_commit(state->dbManager);
375 }
Definition: monk.h:78
Definition: match.h:31
void bail(int exitval)
Disconnect with scheduler returning an error code and exit.
Definition: monk.h:55
Store the results of a regex match.
Definition: scanners.hpp:39
Definition: monk.h:72
char * getUploadTreeTableName(fo_dbManager *dbManager, int uploadId)
Get the upload tree table name for a given upload.
Definition: libfossagent.c:37
Definition: nomos.h:439
PGresult * fo_dbManager_ExecPrepared(fo_dbManager_PreparedStatement *preparedStatement,...)
Execute a prepared statement.
Definition: standalone.c:31
char * fo_scheduler_current()
Get the last read string from the scheduler.
Definition: monk.h:66
Definition: diff.h:25
The main FOSSology C library.
void fo_scheduler_connect_dbMan(int *argc, char **argv, fo_dbManager **dbManager)
Make a connection from an agent to the scheduler and create a DB manager as well. ...
int queryAgentId(PGconn *dbConn)
Get agent id, exit if agent id is incorrect.
int fo_scheduler_jobId()
Gets the id of the job that the agent is running.
char * fo_scheduler_next()
Get the next data to process from the scheduler.
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:228
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...
void matchPFileWithLicenses(CopyrightState const &state, int agentId, unsigned long pFileId, CopyrightDatabaseHandler &databaseHandler)
Get the file contents, scan for statements and save findings to database.