1 /***************************************************************
2 Copyright (C) 2010-2013 Hewlett-Packard Development Company, L.P.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 version 2 as published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17 ***************************************************************/
18
19 /**
20 * \file leaf.c
21 * Handle leaf buckets
22 */
23 #include "buckets.h"
24
25 extern int debug;
26 extern int DEB_SOURCE;
27 extern int DEB_BINARY;
28
29
30 /**
31 * \brief Determine which bucket(s) a leaf node is in and write results
32 *
33 * \param pgConn postgresql connection
34 * \param bucketDefArray Bucket Definitions
35 * \param puploadtree uploadtree record
36 * \param ppackage package record
37 * \param agent_pk Id of agent handling the job
38 * \param hasPrules Not used
39 *
40 * \return 0=success, else error
41 */
processLeaf(PGconn * pgConn,pbucketdef_t bucketDefArray,puploadtree_t puploadtree,ppackage_t ppackage,int agent_pk,int hasPrules)42 FUNCTION int processLeaf(PGconn *pgConn, pbucketdef_t bucketDefArray,
43 puploadtree_t puploadtree, ppackage_t ppackage,
44 int agent_pk, int hasPrules)
45 {
46 int rv = 0;
47 int *bucketList;
48
49 bucketList = getLeafBuckets(pgConn, bucketDefArray, puploadtree, ppackage, hasPrules);
50 if (bucketList)
51 {
52 if (debug)
53 {
54 printf(" buckets for pfile %d:",puploadtree->pfile_fk);
55 for (rv=0;bucketList[rv];rv++) printf("%d ",bucketList[rv]);
56 printf("\n");
57 }
58 rv = writeBuckets(pgConn, puploadtree->pfile_fk, puploadtree->uploadtree_pk,
59 bucketList, agent_pk,
60 bucketDefArray->nomos_agent_pk, bucketDefArray->bucketpool_pk);
61 }
62 else
63 rv = -1;
64
65 free(bucketList);
66 return rv;
67 }
68
69
70 /**
71 * \brief Determine what buckets the pfile is in
72 *
73 * \param pgConn postgresql connection
74 * \param bucketDefArray Bucket definition to work on
75 * \param puploadtree Upload tree to work on
76 * \param hasPrules Not used
77 *
78 * \return array of bucket_pk's, or 0 if error
79 */
getLeafBuckets(PGconn * pgConn,pbucketdef_t in_bucketDefArray,puploadtree_t puploadtree,ppackage_t ppackage,int hasPrules)80 FUNCTION int *getLeafBuckets(PGconn *pgConn, pbucketdef_t in_bucketDefArray,
81 puploadtree_t puploadtree, ppackage_t ppackage,
82 int hasPrules)
83 {
84 char *fcnName = "getLeafBuckets";
85 int *bucket_pk_list = 0;
86 int *bucket_pk_list_start;
87 char filepath[512];
88 char sql[1024];
89 PGresult *result;
90 PGresult *resultmime;
91 int mimetype;
92 int numLics, licNumb;
93 int numBucketDefs = 0;
94 int match = 0; // bucket match
95 int foundmatch, foundmatch2;
96 int *pmatch_array;
97 int **ppmatch_array;
98 int *pfile_rfpks;
99 int rv;
100 int isPkg = 0;
101 int envnum;
102 pbucketdef_t bucketDefArray;
103 regex_file_t *regex_row;
104 char *argv[2];
105 char *envp[11];
106 char envbuf[4096];
107 char pkgtype=0;
108 pid_t pid;
109
110 if (debug) printf("debug: %s pfile: %d\n", fcnName, puploadtree->pfile_fk);
111 /*** count how many elements are in in_bucketDefArray ***/
112 for (bucketDefArray = in_bucketDefArray; bucketDefArray->bucket_pk; bucketDefArray++)
113 numBucketDefs++;
114
115 /* allocate return array to hold max number of bucket_pk's + 1 for null terminator */
116 bucket_pk_list_start = calloc(numBucketDefs+1, sizeof(int));
117 if (bucket_pk_list_start == 0)
118 {
119 printf("FATAL: out of memory allocating int array of %d elements\n", numBucketDefs+1);
120 return 0;
121 }
122 bucket_pk_list = bucket_pk_list_start;
123
124 /*** select all the licenses for uploadtree_pk and children and agent_pk ***/
125 bucketDefArray = in_bucketDefArray;
126 // snprintf(sql, sizeof(sql),
127 // "select rf_shortname, rf_pk from license_file, license_ref where agent_fk=%d and pfile_fk=%d and rf_fk=rf_pk",
128 // bucketDefArray->nomos_agent_pk, puploadtree->pfile_fk);
129 snprintf(sql, sizeof(sql),
130 "SELECT distinct(rf_shortname) as rf_shortname, rf_pk \
131 from license_ref,license_file,\
132 (SELECT distinct(pfile_fk) as PF from uploadtree \
133 where upload_fk=%d \
134 and uploadtree.lft BETWEEN %d and %d) as SS \
135 where PF=pfile_fk and agent_fk=%d and rf_fk=rf_pk",
136 puploadtree->upload_fk, puploadtree->lft, puploadtree->rgt,
137 bucketDefArray->nomos_agent_pk);
138
139 result = PQexec(pgConn, sql);
140 if (fo_checkPQresult(pgConn, result, sql, fcnName, __LINE__)) return 0;
141 numLics = PQntuples(result);
142
143 /* make int array of rf_pk's for this pfile */
144 pfile_rfpks = calloc(numLics+1, sizeof(int));
145 if (pfile_rfpks == 0)
146 {
147 printf("FATAL: out of memory allocating int array of %d rf_pk elements\n", numLics+1);
148 return 0;
149 }
150 for (licNumb=0; licNumb < numLics; licNumb++)
151 pfile_rfpks[licNumb] = atoi(PQgetvalue(result, licNumb, 1));
152
153
154 #ifdef BOBG
155 printf("bobg: fileName: %s\n", puploadtree->ufile_name);
156 #endif
157 isPkg = (ppackage->pkgname[0]) ? 1 : 0;
158 /* loop through all the bucket defs in this pool */
159 for (bucketDefArray = in_bucketDefArray; bucketDefArray->bucket_pk; bucketDefArray++)
160 {
161 /* if this def is restricted to package (applies_to='p'),
162 then skip if this is not a package.
163 NOTE DEPENDENCY ON PKG ANALYSIS!
164 */
165 if (bucketDefArray->applies_to == 'p')
166 {
167 if (!isPkg) continue;
168 }
169 else
170 {
171 /* If this is a container, see if any of its children are in
172 this bucket. If so, then the container is in this bucket.
173 */
174 if ((!isPkg) && (IsContainer(puploadtree->ufile_mode)))
175 {
176 rv = childInBucket(pgConn, bucketDefArray, puploadtree);
177 if (rv == 1)
178 {
179 *bucket_pk_list = bucketDefArray->bucket_pk;
180 bucket_pk_list++;
181 match++;
182 }
183 else if (rv == -1) return 0; //error
184 continue;
185 }
186 }
187
188 #ifdef BOBG
189 printf("bobg: check bucket_pk: %d\n", bucketDefArray->bucket_pk);
190 #endif
191 switch (bucketDefArray->bucket_type)
192 {
193 /*** 1 MATCH_EVERY ***/
194 case 1:
195 ppmatch_array = bucketDefArray->match_every;
196 if (!ppmatch_array) break;
197 while (*ppmatch_array)
198 {
199 /* is match_array contained in pfile_rfpks? */
200 if (arrayAinB(*ppmatch_array, pfile_rfpks))
201 {
202 *bucket_pk_list = bucketDefArray->bucket_pk;
203 bucket_pk_list++;
204 match++;
205 break;
206 }
207 ++ppmatch_array;
208 }
209 break;
210
211 /*** 2 MATCH_ONLY ***/
212 case 2:
213 if (numLics == 0) break;
214 foundmatch = 1;
215 /* loop through pfile licenses to see if they are all found in the match_only list */
216 for (licNumb=0; licNumb < numLics; licNumb++)
217 {
218 /* if rf_pk doesn't match any value in match_only,
219 then pfile is not in this bucket */
220 pmatch_array = bucketDefArray->match_only;
221 while (*pmatch_array)
222 {
223 if (pfile_rfpks[licNumb] == *pmatch_array) break;
224 pmatch_array++;
225 }
226 if (!*pmatch_array)
227 {
228 /* no match, so pfile is not in this bucket */
229 foundmatch = 0;
230 break; /* break out of for loop */
231 }
232 }
233 if (foundmatch)
234 {
235 *bucket_pk_list = bucketDefArray->bucket_pk;
236 bucket_pk_list++;
237 match++;
238 }
239 break;
240
241 /*** 3 REGEX ***/
242 case 3: /* does this regex match any license names for this pfile */
243 if (matchAnyLic(result, numLics, &bucketDefArray->compRegex))
244 {
245 /* regex matched! */
246 *bucket_pk_list = bucketDefArray->bucket_pk;
247 bucket_pk_list++;
248 match++;
249 }
250 break;
251
252 /*** 4 EXEC ***/
253 case 4:
254 /* file to exec bucketDefArray->dataFilename
255 * Exec'd file returns 0 on true (file is in bucket).
256 * When a file is exec'd it can expect the following
257 * environment variables:
258 * FILENAME: name of file being checked
259 * LICENSES: pipe seperated list of licenses for this file.
260 * PKGVERS: Package version from pkg header
261 * VENDOR: Vendor from pkg header
262 * PKGNAME: simple package name (e.g. "cup", "mozilla-mail", ...)
263 of file being checked. Only applies to packages.
264 * SRCPKGNAME: Source package name
265 * UPLOADTREE_PK: uploadtree_pk
266 * PFILE_PK: pfile_pk
267 * PKGTYPE: 's' if source, 'b' if binary package, '' if not a package
268 */
269 /* put together complete file path to file */
270 snprintf(filepath, sizeof(filepath), "%s/bucketpools/%d/%s",
271 PROJECTSTATEDIR, bucketDefArray->bucketpool_pk, bucketDefArray->dataFilename);
272 if ((pid = fork()) < 0)
273 {
274 printf("FATAL: fork failure, %s\n", strerror(errno));
275 }
276 else
277 if (pid == 0) /* in child */
278 {
279 /* use TMPDIR for working directory
280 */
281 if ((rv = chdir("/tmp")))
282 {
283 printf("FATAL: exec bucket couldn't cd to /tmp\n");
284 exit(1);
285 }
286
287 /* set up environment variables */
288 envnum = 0;
289 argv[0] = strdup(bucketDefArray->dataFilename);
290 argv[1] = 0;
291 sprintf(envbuf, "FILENAME=%s", puploadtree->ufile_name);
292 envp[envnum++] = strdup(envbuf);
293 /* create pipe seperated list of licenses */
294 strcpy(envbuf, "LICENSES=");
295 for (licNumb=0; licNumb < numLics; licNumb++)
296 {
297 if (envbuf[9]) strcat(envbuf, "|");
298 strcat(envbuf, PQgetvalue(result, licNumb, 0));
299 }
300 envp[envnum++] = strdup(envbuf);
301 sprintf(envbuf, "PKGVERS=%s", ppackage->pkgvers);
302 envp[envnum++] = strdup(envbuf);
303 sprintf(envbuf, "VENDOR=%s", ppackage->vendor);
304 envp[envnum++] =strdup(envbuf);
305 sprintf(envbuf, "PKGNAME=%s", ppackage->pkgname);
306 envp[envnum++] =strdup(envbuf);
307 sprintf(envbuf, "SRCPKGNAME=%s", ppackage->srcpkgname);
308 envp[envnum++] =strdup(envbuf);
309 sprintf(envbuf, "UPLOADTREE_PK=%d", puploadtree->uploadtree_pk);
310 envp[envnum++] =strdup(envbuf);
311 sprintf(envbuf, "PFILE_PK=%d", puploadtree->pfile_fk);
312 envp[envnum++] =strdup(envbuf);
313
314 /* Only figure out PKGTYPE if this is a pkg
315 For Debian packages, check mimetype:
316 application/x-debian-package -- binary
317 application/x-debian-source -- source
318 For RPM's,
319 if srcpkgname is not null,
320 then this is a binary package
321 else this is a source package
322 */
323 pkgtype = 0;
324 if (isPkg)
325 {
326 if ((strstr(ppackage->srcpkgname,"none")==0)
327 || (ppackage->srcpkgname[0]==0)) pkgtype='b';
328 else
329 {
330 snprintf(sql, sizeof(sql),
331 "select pfile_mimetypefk from pfile where pfile_pk=%d",
332 puploadtree->pfile_fk);
333 resultmime = PQexec(pgConn, sql);
334 if (fo_checkPQresult(pgConn, resultmime, sql, fcnName, __LINE__)) return 0;
335 mimetype = *(PQgetvalue(resultmime, 0, 0));
336 PQclear(resultmime);
337 if (mimetype == DEB_SOURCE) pkgtype = 's';
338 else if (mimetype == DEB_BINARY) pkgtype = 'b';
339 else pkgtype = 's';
340 }
341 }
342 sprintf(envbuf, "PKGTYPE=%c", pkgtype);
343 envp[envnum++] =strdup(envbuf);
344
345 envp[envnum++] = 0;
346 execve(filepath, argv, envp);
347 printf("FATAL: buckets execve (%s) failed, %s\n", filepath, strerror(errno));
348 exit(1);
349 }
350
351 /* wait for exit */
352 if (waitpid(pid, &rv, 0) < 0)
353 {
354 printf("FATAL: waitpid, %s\n", strerror(errno));
355 return 0;
356 }
357 if (WIFSIGNALED(rv))
358 {
359 printf("FATAL: child %d died from signal %d", pid, WTERMSIG(rv));
360 return 0;
361 }
362 else
363 if (WIFSTOPPED(rv))
364 {
365 printf("FATAL: child %d stopped, signal %d", pid, WSTOPSIG(rv));
366 return 0;
367 }
368 else
369 if (WIFEXITED(rv))
370 {
371 if (WEXITSTATUS(rv) == 0)
372 {
373 *bucket_pk_list = bucketDefArray->bucket_pk;
374 bucket_pk_list++;
375 match++;
376 }
377 }
378 break;
379
380 /*** 5 REGEX-FILE ***/
381 /* File format is:
382 {filetype1} {regex1} {op} {filetype2} {regex2}
383 filetype == 1 is filename
384 filetype == 2 is license
385 op to end of line is optional.
386 e.g. filename COPYRIGHT and license BSD.*clause
387 */
388 case 5:
389 regex_row = bucketDefArray->regex_row;
390 foundmatch = 0;
391 foundmatch2 = 0;
392 /* loop through each regex_row */
393 while (regex_row->ftype1)
394 {
395 /* switches do not have a default since values have already been validated
396 see init.c
397 */
398 switch (regex_row->ftype1)
399 {
400 case 1: // check regex against filename
401 foundmatch = !regexec(®ex_row->compRegex1, puploadtree->ufile_name, 0, 0, 0);
402 break;
403 case 2: // check regex against licenses
404 foundmatch = matchAnyLic(result, numLics, ®ex_row->compRegex1);
405 break;
406 }
407
408 /* no sense in evaluating last half if first have is a match and
409 op is an OR
410 */
411 if ((regex_row->op == 2) || !foundmatch)
412 if (regex_row->op)
413 {
414 switch (regex_row->ftype2)
415 {
416 case 1: // check regex against filename
417 foundmatch2 = !regexec(®ex_row->compRegex2, puploadtree->ufile_name, 0, 0, 0);
418 break;
419 case 2: // check regex against licenses
420 foundmatch2 = matchAnyLic(result, numLics, ®ex_row->compRegex2);
421 break;
422 }
423 }
424
425 switch (regex_row->op)
426 {
427 case 1: // AND
428 foundmatch = (foundmatch && foundmatch2) ? 1 : 0;
429 break;
430 case 2: // OR
431 foundmatch = (foundmatch || foundmatch2) ? 1 : 0;
432 break;
433 case 3: // Not
434 foundmatch = (foundmatch && !foundmatch2) ? 1 : 0;
435 break;
436 }
437
438 if (foundmatch)
439 {
440 *bucket_pk_list = bucketDefArray->bucket_pk;
441 bucket_pk_list++;
442 match++;
443 }
444 regex_row++;
445 }
446 break;
447
448 /*** 99 DEFAULT bucket. aka not in any other bucket ***/
449 case 99:
450 if (!match)
451 {
452 *bucket_pk_list = bucketDefArray->bucket_pk;
453 bucket_pk_list++;
454 match++;
455 }
456 break;
457
458 /*** UNKNOWN BUCKET TYPE ***/
459 default:
460 printf("FATAL: Unknown bucket type %d, exiting...\n",
461 bucketDefArray->bucket_type);
462 exit(-1);
463 }
464 #ifdef BOBG
465 printf("bobg match: %d\n", match);
466 #endif
467 if (match && bucketDefArray->stopon == 'Y') break;
468 }
469
470 #ifdef BOBG
471 printf("bobg exit GetLeafBuckets()\n");
472 #endif
473 free(pfile_rfpks);
474 PQclear(result);
475 return bucket_pk_list_start;
476 }
477