FOSSology  4.4.0
Open Source License Compliance by Open Source Software
snippet_scan.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-only
26 #define _GNU_SOURCE
27 #include "snippet_scan.h"
28 #include <stdio.h>
29 #include <errno.h>
30 
31 extern void logme(char *msg);
32 
33 extern char *baseTMP;
34 int Verbose = 0;
35 PGconn *db_conn = NULL;
36 extern int Agent_pk;
37 extern char ApiUrl[200];
38 extern char accToken[100];
39 
40 /***************************************************************************/
41 
42 int splitLine(char *lineToSplit, char *separator, char **fields)
43 {
44  int i = 0;
45 
46  char *token;
47 
48  char *strSplit = lineToSplit;
49  while ((token = strtok_r(strSplit, separator, &strSplit)))
50  sprintf(fields[i++], "%s", token);
51  return i;
52 }
53 
54 void extract_csv(char *out, char *in, int n, long limit, char sep)
55 {
56  char seps[3];
57  char line[2048];
58  sprintf(line, "%s", in);
59  sprintf(seps, "%c", sep);
60  char *token = strtok(line, seps);
61  // loop through the string to extract all other tokens
62  int count = 0;
63  while (token != NULL)
64  {
65  count++; // printf( " %s\n", token ); //printing each token
66  if (count == n)
67  {
68  sprintf(out, "%s", token);
69  break;
70  }
71  token = strtok(NULL, seps);
72  }
73 }
74 
80 FILE *openFileByKey(long pFileKey)
81 {
82  char sqlbuf[200];
83  PGresult *result;
84  sprintf(sqlbuf, "SELECT pfile_sha1 || '.' || pfile_md5 || '.' || pfile_size AS pfile_path FROM pfile WHERE pfile_pk = %ld;", pFileKey);
85  result = PQexec(db_conn, sqlbuf);
86  if (fo_checkPQresult(db_conn, result, sqlbuf, __FILE__, __LINE__))
87  {
88 
89  exit(-1);
90  }
91  char path[500];
92  sprintf(path, "%s", PQgetvalue(result, 0, 0));
93  return fo_RepFread("files", path);
94 }
95 
99 int getLicenseId(unsigned char *name)
100 {
101  PGresult *result;
102  char sqlbuf[500];
103  sprintf(sqlbuf, "select lr.rf_pk from license_ref lr where lr.rf_shortname like '%s';", name);
104  result = PQexec(db_conn, sqlbuf);
105 
106  if (fo_checkPQresult(db_conn, result, sqlbuf, __FILE__, __LINE__))
107  {
108  return -1;
109  }
110 
111  int num_rows = PQntuples(result);
112  int return_value = -1;
113  if (num_rows > 0)
114  {
115  const char *value = PQgetvalue(result, 0, 0);
116  if (value && *value)
117  {
118  return_value = atoi(value);
119  }
120  else
121  {
122  /* Found empty response */
123  return_value = -2;
124  }
125  }
126  else
127  {
128  /* No results found */
129  return_value = -3;
130  }
131 
132  PQclear(result);
133  return return_value;
134 }
135 
142 void dumpToFile(const char *path, unsigned char *content, long size)
143 {
144  FILE *fptr;
145  fptr = fopen(path, "w");
146 
147  if (fptr == NULL)
148  {
149  LOG_ERROR("Snippet scan: Could not create temp file")
150  }
151  else
152  {
153  fwrite(content, size, 1, fptr);
154  fclose(fptr);
155  }
156 }
157 
158 void RestoreTempFile(char *uploadFolder, long key, long realParent, char *realName)
159 {
160  char dstName[256];
161  FILE *f = openFileByKey(key); /* Open the file from the repository by its key */
162  sprintf(dstName, "%s/%ld_%ld_%s", uploadFolder, realParent, key, realName); /* Create a name for the temp file, including the temp folder */
163  if (f != NULL)
164  {
165  fseek(f, 0, SEEK_END); /* Read the file and dump the content into the temp file*/
166  int size = ftell(f);
167  unsigned char *contents = calloc(1, size);
168  memset(contents, '\0', size);
169  rewind(f);
170  size_t readSize = fread(contents, size, 1, f);
171  fo_RepFclose(f);
172  if (readSize == 0)
173  return;
174  dumpToFile(dstName, contents, size);
175  }
176 }
177 
178 /*1 inventory_id,
179  2 path,
180  3 detected_usage,
181  4 detected_component,
182  5 detected_license,
183  6 detected_version,
184  7 detected_latest,
185  8 detected_purls,
186  9 detected_url,
187  10 detected_match,
188  11 detected_lines,
189  12 detected_oss_lines,
190  13 detected_path
191 */
197 void ParseResults(char *folder)
198 {
199  PGresult *result;
200  char Cmd[100];
201  char auxSql[MAXCMD * 4];
202 
203  char detectedUsage[MAXCMD];
204  char detPurls[MAXCMD];
205  char detLicenses[MAXCMD];
206  char path[MAXCMD];
207  char detMatch[MAXCMD];
208  char detLines[MAXCMD];
209  char detPath[MAXCMD];
210  char detUrl[MAXCMD];
211 
212  sprintf(Cmd, "%s/results.csv", folder);
213  FILE *file = fopen(Cmd, "r");
214 
215  char line[MAXCMD * 10];
216  int resCount = 0;
217  if (file == NULL)
218  {
219  LOG_ERROR("Error while opening the file");
220  return;
221  }
222  while (fgets(line, sizeof(line), file))
223  {
224  if (resCount == 0)
225  {
226  resCount++;
227  continue;
228  } // Skip header
229  if (line[0] != 0 && line[0] != ' ')
230  {
231  long parent;
232  long key;
233  char srcName[MAXCMD];
234  extract_csv(path, line, 2, MAXCMD, ',');
235 
236  if (strlen(path)>0)
237  {
238  sscanf(path, "%ld_%ld_%s", &parent, &key, srcName);
239  }
240  else
241  {
242  return;
243  }
244  int lenLine = strlen(line);
245  extract_csv(detectedUsage, line, 3, lenLine, ',');
246  extract_csv(detPurls, line, 8, lenLine, ',');
247  extract_csv(detLicenses, line, 5, lenLine, ',');
248  extract_csv(detUrl, line, 9, lenLine, ',');
249 
250  extract_csv(detMatch, line, 10, lenLine, ',');
251  extract_csv(detLines, line, 12, lenLine, ',');
252  extract_csv(detPath, line, 13, lenLine, ',');
253 
254  // License store
255 
256  for (int i = 1; i < 5; i++)
257  {
258  char aux[100000];
259  if (strlen(detLicenses) > 1)
260  {
261  extract_csv(aux, detLicenses, i, strlen(detLicenses), ';');
262  if (strlen(aux)<=0)
263  break;
264  else
265  {
266 
267  int detLic = getLicenseId((unsigned char *)aux);
268  /* ... from name, get the key of license that matches short_name at license_ref*/
269  if (detLic > 0)
270  { /* If the key is valid, insert the result on DB Table */
271  sprintf(auxSql, "INSERT INTO license_file(rf_fk, agent_fk, rf_timestamp, pfile_fk) VALUES(%d,%d, now(), %ld);", detLic, Agent_pk, key);
272  result = PQexec(db_conn, auxSql);
273  }
274  else
275  {
276  // Unknown license
277  }
278  }
279  }
280  }
281 
282  // File info store
283  if (strcmp((char *)detectedUsage, "none") && (!(strcmp((char *)detectedUsage, "file")) || !(strcmp((char *)detectedUsage, "snippet"))))
284  {
285  char *auxSQL;
286  asprintf(&auxSQL, "INSERT INTO scanoss_fileinfo (pfile_fk, matchtype, lineranges, purl,filepath,url) VALUES(%ld, '%s', '%s', '%s','%s','%s');", key, detectedUsage, detLines, detPurls, detPath, detUrl); //,url,filePath);
287  result = PQexec(db_conn, auxSQL);
288  free(auxSQL);
289  if (PQntuples(result) == 0)
290  {
291  PQclear(result);
292  }
293  }
294  resCount++;
295  }
296  else
297  {
298  break;
299  }
300  }
301 }
302 
308 int ScanFolder(char *folder)
309 {
310 
311  FILE *Fin;
312  char Cmd[MAXCMD];
313  memset(Cmd, '\0', MAXCMD);
314 
315  unsigned char apiurl[400];
316  unsigned char key[110];
317 
318  if (ApiUrl[0] != '\0')
319  {
320  sprintf((char *)apiurl, "--apiurl %s", ApiUrl);
321  }
322  else
323  memset(apiurl, 0, sizeof(apiurl));
324 
325  if (accToken[0] != '\0' && accToken[0] != ' ')
326  {
327  sprintf((char *)key, "--key %s", accToken);
328  }
329  else
330  memset(key, 0, sizeof(key));
331 
332  char *user;
333  asprintf(&user, "%s", fo_config_get(sysconfig, "DIRECTORIES", "PROJECTUSER", NULL));
334 
335  sprintf(Cmd, "PYTHONPATH='/home/%s/pythondeps/' /home/%s/pythondeps/bin/scanoss-py scan %s --format=csv -o %s/results.csv %s %s", user, user, folder, folder, apiurl, key); /* Create the command to run */
336  logme(Cmd);
337  free(user);
338  Fin = popen(Cmd, "r"); /* Run the command */
339  if (!Fin)
340  {
341  LOG_ERROR("Snippet scan: failed to start scan %s", strerror(errno));
342  pclose(Fin);
343  return -1;
344  }
345  else
346  {
347  pclose(Fin);
348  }
349  return 0;
350 }
351 
352 int RebuildUpload(long upload_pk, char *tempFolder)
353 {
354 
355  char sqlbuf[1024];
356  PGresult *result;
357  int numrows;
358  int i;
359  char *uploadtree_tablename;
360 
361  if (!upload_pk) /* when upload_pk is empty */
362  {
363  LOG_ERROR("Snippet scan: Missing upload key");
364  return -1;
365  }
366 
368  if (NULL == uploadtree_tablename)
369  uploadtree_tablename = strdup("uploadtree_a");
370  /* retrieve the records to process */
371  snprintf(sqlbuf, sizeof(sqlbuf),
372  "SELECT * from uploadtree_a, upload where upload_fk = upload_pk and upload_pk = '%ld' ", upload_pk);
373  result = PQexec(db_conn, sqlbuf);
374  if (fo_checkPQresult(db_conn, result, sqlbuf, __FILE__, __LINE__))
375  {
376  LOG_ERROR("Snippet scan: Error retrieving jobs");
377  exit(-1);
378  }
379 
380  numrows = PQntuples(result);
381  long parent = 0;
382  long realParent = 0;
383  long fileMode = 0;
384  long pFileFK = 0;
385  char *realName;
386  /* for each record, get it name and real parent */
387  for (i = 0; i < numrows; i++)
388  {
389 
391  parent = atoi(PQgetvalue(result, i, 1));
392  realParent = atoi(PQgetvalue(result, i, 2));
393  fileMode = atol(PQgetvalue(result, i, 5));
394  asprintf(&realName, "%s", PQgetvalue(result, i, 8)); // 8 fileName
395  for (int j = 0; j < strlen(realName); j++)
396  {
397  if ((realName[j] >= 'A' && realName[j] <= 'Z') ||
398  (realName[j] >= 'a' && realName[j] <= 'z') ||
399  (realName[j] >= '0' && realName[j] <= '9') || realName[j] == '.')
400  ;
401  else
402  realName[j] = '_';
403  }
404  // Nothing to be done on folders entries
405  if (parent != realParent && (fileMode == ((1 << 28) | (1 << 13) | (1 << 9))))
406  {
407  }
408  else
409  {
410  // Ensure that it is a real file
411  // fileMode & ((1<<28)|(1<<13)|(1<<9)) == 0
412  if (fileMode != ((1 << 28) | (1 << 13) | (1 << 9)))
413  {
414  pFileFK = atoi(PQgetvalue(result, i, 4));
415  if (pFileFK != 0)
416  {
417  RestoreTempFile(tempFolder, pFileFK, parent, realName);
418  }
419  }
420  }
421  free(realName);
422  }
423  PQclear(result);
424 
425  return (0);
426 }
427 
428 /***********************************************
429  Usage():
430  Command line options allow you to write the agent so it works
431  stand alone, in addition to working with the scheduler.
432  This simplifies code development and testing.
433  So if you have options, have a Usage().
434  Here are some suggested options (in addition to the program
435  specific options you may already have).
436  ***********************************************/
437 void Usage(char *Name)
438 {
439  printf("Usage: %s [file|folder]\n", Name);
440  printf(" -i :: initialize the database, then exit.\n");
441  printf(" -v :: verbose (-vv = more verbose)\n");
442  printf(" -c :: Specify the directory for the system configuration.\n");
443  printf(" -C <file path/folder path> :: run from command line.\n");
444  printf(" -V :: print the version info, then exit.\n");
445 } /* Usage() */
char * uploadtree_tablename
upload.uploadtree_tablename
Definition: adj2nest.c:100
char * fo_config_get(fo_conf *conf, const char *group, const char *key, GError **error)
Gets an element based on its group name and key name. If the group or key is not found,...
Definition: fossconfig.c:336
FUNCTION char * GetUploadtreeTableName(PGconn *pgConn, int upload_pk)
Get the uploadtree table name for this upload_pk If upload_pk does not exist, return "uploadtree".
Definition: libfossagent.c:414
int fo_checkPQresult(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres SELECT.
Definition: libfossdb.c:170
int fo_RepFclose(FILE *F)
Perform an fclose.
Definition: libfossrepo.c:601
FILE * fo_RepFread(char *Type, char *Filename)
Perform an fopen for reading only.
Definition: libfossrepo.c:613
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...
fo_conf * sysconfig
void Usage(char *Name)
Say how to run this program.
Definition: snippet_scan.c:437
void dumpToFile(const char *path, unsigned char *content, long size)
Dumps the content of a file in the repository to a temporary file.
Definition: snippet_scan.c:142
PGconn * db_conn
The connection to Database.
Definition: snippet_scan.c:35
void ParseResults(char *folder)
Parse results from a temporary file and store results on database.
Definition: snippet_scan.c:197
int ScanFolder(char *folder)
Scans a Temporary folder.
Definition: snippet_scan.c:308
int Verbose
Verbose level.
Definition: snippet_scan.c:34
FILE * openFileByKey(long pFileKey)
Open a file of the repository given its primary key.
Definition: snippet_scan.c:80
int Agent_pk
agent identifier
Definition: finder.c:19
int getLicenseId(unsigned char *name)
Retrieves the license id (license_ref.rf_pk) given its short name.
Definition: snippet_scan.c:99
scanoss header
const char * upload_pk
Definition: sqlstatements.h:82