FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
fossinit.php
Go to the documentation of this file.
1 #!/usr/bin/php
2 <?php
3 /***********************************************************
4  Copyright (C) 2008-2015 Hewlett-Packard Development Company, L.P.
5  Copyright (C) 2014-2015,2019 Siemens AG
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License
9  version 2 as published by the Free Software Foundation.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License along
17  with this program; if not, write to the Free Software Foundation, Inc.,
18  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  ***********************************************************/
20 
24 function explainUsage()
25 {
26  global $argv;
27 
28  $usage = "Usage: " . basename($argv[0]) . " [options]
29  Update FOSSology database. This should be used immediately after an install or update. Options are:
30  -c path to fossology configuration files
31  -d {database name} default is 'fossology'
32  -f {file} update the schema with file generated by schema-export.php
33  -l update the license_ref table with fossology supplied licenses
34  -r {prefix} drop database with name starts with prefix
35  -v enable verbose preview (prints sql that would happen, but does not execute it, DB is not updated)
36  --force-decision force recalculation of SHA256 for decision tables
37  --force-pfile force recalculation of SHA256 for pfile entries
38  --force-encode force recode of copyright and sister tables
39  -h this help usage";
40  print "$usage\n";
41  exit(0);
42 }
43 
44 
54 
55 /* Note: php 5 getopt() ignores options not specified in the function call, so add
56  * dummy options in order to catch invalid options.
57  */
58 $AllPossibleOpts = "abc:d:ef:ghijklmnopqr:stuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
59 $longOpts = [
60  "force-decision",
61  "force-pfile",
62  "force-encode"
63 ];
64 
65 /* defaults */
66 $Verbose = false;
67 $DatabaseName = "fossology";
68 $UpdateLiceneseRef = false;
69 $sysconfdir = '';
70 $delDbPattern = 'the option -rfosstest will drop data bases with datname like "fosstest%"';
71 $forceDecision = false;
72 $forcePfile = false;
73 
74 /* command-line options */
75 $Options = getopt($AllPossibleOpts, $longOpts);
76 foreach($Options as $optKey => $optVal)
77 {
78  switch($optKey)
79  {
80  case 'c': /* set SYSCONFIDR */
81  $sysconfdir = $optVal;
82  break;
83  case 'd': /* optional database name */
84  $DatabaseName = $optVal;
85  break;
86  case 'f': /* schema file */
87  $SchemaFilePath = $optVal;
88  break;
89  case 'h': /* help */
90  explainUsage();
91  case 'l': /* update the license_ref table */
92  $UpdateLiceneseRef = true;
93  break;
94  case 'v': /* verbose */
95  $Verbose = true;
96  break;
97  case 'r':
98  $delDbPattern = $optVal ? "$optVal%" : "fosstest%";
99  break;
100  case "force-decision":
101  $forceDecision = true;
102  break;
103  case "force-pfile":
104  $forcePfile = true;
105  break;
106  case "force-encode":
107  putenv('FOSSENCODING=1');
108  break;
109  default:
110  echo "Invalid Option \"$optKey\".\n";
111  explainUsage();
112  }
113 }
114 
115 require_once 'fossinit-common.php';
116 
117 /* Set SYSCONFDIR and set global (for backward compatibility) */
118 $SysConf = bootstrap($sysconfdir);
119 $SysConf["DBCONF"]["dbname"] = $DatabaseName;
120 $GLOBALS["SysConf"] = array_merge($GLOBALS["SysConf"], $SysConf);
121 $projectGroup = $SysConf['DIRECTORIES']['PROJECTGROUP'] ?: 'fossy';
122 $gInfo = posix_getgrnam($projectGroup);
123 posix_setgid($gInfo['gid']);
124 $groups = `groups`;
125 if (!preg_match("/\s$projectGroup\s/",$groups) && (posix_getgid() != $gInfo['gid']))
126 {
127  print "FATAL: You must be in group '$projectGroup'.\n";
128  exit(1);
129 }
130 
131 require_once("$MODDIR/vendor/autoload.php");
132 require_once("$MODDIR/lib/php/common-db.php");
133 require_once("$MODDIR/lib/php/common-container.php");
134 require_once("$MODDIR/lib/php/common-cache.php");
135 require_once("$MODDIR/lib/php/common-sysconfig.php");
136 
137 /* Initialize global system configuration variables $SysConfig[] */
138 ConfigInit($SYSCONFDIR, $SysConf);
139 
147 if (empty($SchemaFilePath)) {
148  $SchemaFilePath = "$MODDIR/www/ui/core-schema.dat";
149 }
150 
151 if (!file_exists($SchemaFilePath))
152 {
153  print "FAILED: Schema data file ($SchemaFilePath) not found.\n";
154  exit(1);
155 }
156 
157 require_once("$MODDIR/lib/php/libschema.php");
158 $pgDriver = new Postgres($PG_CONN);
159 $libschema->setDriver($pgDriver);
160 $previousSchema = $libschema->getCurrSchema();
161 $isUpdating = array_key_exists('TABLE', $previousSchema) && array_key_exists('users', $previousSchema['TABLE']);
163 if ($dbManager->existsTable('sysconfig'))
164 {
165  $sysconfig = $dbManager->createMap('sysconfig', 'variablename', 'conf_value');
166  if(!array_key_exists('Release', $sysconfig))
167  {
168  $sysconfig['Release'] = 0;
169  }
170  print "Old release was $sysconfig[Release]\n";
171 }
172 
173 $migrateColumns = array('clearing_decision'=>array('reportinfo','clearing_pk','type_fk','comment'),
174  'license_ref_bulk'=>array('rf_fk','removing'));
175 if($isUpdating && !empty($sysconfig) && $sysconfig['Release'] == '2.6.3.1')
176 {
177  $dbManager->queryOnce('begin;
178  CREATE TABLE uploadtree_b AS (SELECT * FROM uploadtree_a);
179  DROP TABLE uploadtree_a;
180  CREATE TABLE uploadtree_a () INHERITS (uploadtree);
181  ALTER TABLE uploadtree_a ADD CONSTRAINT uploadtree_a_pkey PRIMARY KEY (uploadtree_pk);
182  INSERT INTO uploadtree_a SELECT * FROM uploadtree_b;
183  DROP TABLE uploadtree_b;
184  COMMIT;',__FILE__.'.rebuild.uploadtree_a');
185 }
186 
187 if($dbManager->existsTable("author"))
188 {
189  require_once("$LIBEXECDIR/resequence_author_table.php"); // If table exists, clean up for Schema
190 }
191 
192 // Migration script to clear tables for new constraints
193 require_once("$LIBEXECDIR/dbmigrate_3.3-3.4.php");
194 Migrate_33_34($dbManager, $Verbose);
195 
196 $FailMsg = $libschema->applySchema($SchemaFilePath, $Verbose, $DatabaseName, $migrateColumns);
197 if ($FailMsg)
198 {
199  print "ApplySchema failed: $FailMsg\n";
200  exit(1);
201 }
202 $Filename = "$MODDIR/www/ui/init.ui";
203 $flagRemoved = !file_exists($Filename);
204 if (!$flagRemoved)
205 {
206  if ($Verbose)
207  {
208  print "Removing flag '$Filename'\n";
209  }
210  if (is_writable("$MODDIR/www/ui/"))
211  {
212  $flagRemoved = unlink($Filename);
213  }
214 }
215 if (!$flagRemoved)
216 {
217  print "Failed to remove $Filename\n";
218  print "Remove this file to complete the initialization.\n";
219 }
220 else
221 {
222  print "Database schema update completed successfully.\n";
223 }
224 
225 /* initialize the license_ref table */
226 if ($UpdateLiceneseRef)
227 {
228  $row = $dbManager->getSingleRow("SELECT count(*) FROM license_ref",array(),'license_ref.count');
229  if ($row['count'] > 0) {
230  print "Update reference licenses\n";
231  initLicenseRefTable(false);
232  }
233  else if ($row['count'] == 0) {
234  insertInToLicenseRefTableUsingJson('license_ref');
235 
236  $row_max = $dbManager->getSingleRow("SELECT max(rf_pk) from license_ref",array(),'license_ref.max.rf_pk');
237  $current_license_ref_rf_pk_seq = $row_max['max'];
238  $dbManager->getSingleRow("SELECT setval('license_ref_rf_pk_seq', $current_license_ref_rf_pk_seq)",array(),
239  'set next license_ref_rf_pk_seq value');
240 
241  print "fresh install, import licenseRef.json \n";
242  }
243 }
244 
245 if (array_key_exists('r', $Options))
246 {
247  $dbManager->prepare(__METHOD__.".getDelDbNames",'SELECT datname FROM pg_database WHERE datistemplate = false and datname like $1');
248  $resDelDbNames = $dbManager->execute(__METHOD__.".getDelDbNames",array($delDbPattern));
249  $delDbNames=pg_fetch_all($resDelDbNames);
250  pg_free_result($resDelDbNames);
251  foreach ($delDbNames as $deleteDatabaseName)
252  {
253  $dbManager->queryOnce("DROP DATABASE $deleteDatabaseName[datname]");
254  }
255  if ($Verbose)
256  {
257  echo "dropped " . count($delDbNames) . " databases ";
258  }
259 }
260 
261 /* migration */
262 $currSchema = $libschema->getCurrSchema();
263 $sysconfig = $dbManager->createMap('sysconfig','variablename','conf_value');
264 global $LIBEXECDIR;
265 if($isUpdating && empty($sysconfig['Release'])) {
266  require_once("$LIBEXECDIR/dbmigrate_2.0-2.1.php"); // this is needed for all new installs from 2.0 on
267  Migrate_20_21($Verbose);
268  require_once("$LIBEXECDIR/dbmigrate_2.1-2.2.php");
269  print "Migrate data from 2.1 to 2.2 in $LIBEXECDIR\n";
270  Migrate_21_22($Verbose);
271  if($dbManager->existsTable('license_file_audit') && array_key_exists('clearing_pk', $currSchema['TABLE']['clearing_decision']))
272  {
273  require_once("$LIBEXECDIR/dbmigrate_2.5-2.6.php");
274  migrate_25_26($Verbose);
275  }
276  if(!array_key_exists('clearing_pk', $currSchema['TABLE']['clearing_decision']) && $isUpdating)
277  {
278  $timeoutSec = 20;
279  echo "Missing column clearing_decision.clearing_pk, you should update to version 2.6.2 before migration\n";
280  echo "Enter 'i' within $timeoutSec seconds to ignore this warning and run the risk of losing clearing decisions: ";
281  $handle = fopen ("php://stdin","r");
282  stream_set_blocking($handle,0);
283  for($s=0;$s<$timeoutSec;$s++)
284  {
285  sleep(1);
286  $line = fread($handle,1);
287  if ($line) {
288  break;
289  }
290  }
291  if(trim($line) != 'i')
292  {
293  echo "ABORTING!\n";
294  exit(26);
295  }
296  }
297  $sysconfig['Release'] = '2.6';
298 }
299 if (! $isUpdating) {
300  require_once ("$LIBEXECDIR/dbmigrate_2.1-2.2.php");
301  print "Creating default user\n";
302  Migrate_21_22($Verbose);
303 } else {
304  require_once ("$LIBEXECDIR/dbmigrate_3.5-3.6.php");
305  migrate_35_36($dbManager, $forceDecision);
306  updatePfileSha256($dbManager, $forcePfile);
307 }
308 
309 if(!$isUpdating || $sysconfig['Release'] == '2.6')
310 {
311  if(!$dbManager->existsTable('license_candidate'))
312  {
313  $dbManager->queryOnce("CREATE TABLE license_candidate (group_fk integer) INHERITS (license_ref)");
314  }
315  if ($isUpdating && array_key_exists('clearing_pk', $currSchema['TABLE']['clearing_decision']))
316  {
317  require_once("$LIBEXECDIR/dbmigrate_clearing-event.php");
318  $libschema->dropColumnsFromTable(array('reportinfo','clearing_pk','type_fk','comment'), 'clearing_decision');
319  }
320  $sysconfig['Release'] = '2.6.3';
321 }
322 
323 if($sysconfig['Release'] == '2.6.3')
324 {
325  require_once("$LIBEXECDIR/dbmigrate_real-parent.php");
326 }
327 
328 $expiredDbReleases = array('2.6.3', '2.6.3.1', '2.6.3.2');
329 if($isUpdating && (empty($sysconfig['Release']) || in_array($sysconfig['Release'], $expiredDbReleases)))
330 {
331  require_once("$LIBEXECDIR/fo_mapping_license.php");
332  print "Rename license (using $LIBEXECDIR) for SPDX validity\n";
334 }
335 
336 $expiredDbReleases[] = '2.6.3.3';
337 $expiredDbReleases[] = '3.0.0';
338 if($isUpdating && (empty($sysconfig['Release']) || in_array($sysconfig['Release'], $expiredDbReleases)))
339 {
340  require_once("$LIBEXECDIR/dbmigrate_bulk_license.php");
341 }
342 
343 if(in_array($sysconfig['Release'], $expiredDbReleases))
344 {
345  $sysconfig['Release'] = '3.0.1';
346 }
347 
348 // Update '3dfx' licence shortname to 'Glide'. Since shortname is used as an
349 // identifier, this is not done as part of the licenseref updates.
350 if($isUpdating && (empty($sysconfig['Release']) || $sysconfig['Release'] == '3.0.1'))
351 {
352  $dbManager->begin();
353  $row = $dbManager->getSingleRow("
354  SELECT rf1.rf_pk AS id_3dfx,
355  rf2.rf_pk AS id_glide
356  FROM license_ref rf1
357  INNER JOIN license_ref rf2 USING (rf_fullname)
358  WHERE rf1.rf_shortname='3DFX'
359  AND rf2.rf_shortname='Glide'
360  LIMIT 1", array(), 'old.3dfx.rf_pk');
361  if (!empty($row))
362  {
363  $id_3dfx = intval($row['id_3dfx']);
364  $id_glide = intval($row['id_glide']);
365  $dbManager->queryOnce("DELETE FROM license_ref WHERE rf_pk=$id_glide");
366  $dbManager->queryOnce("UPDATE license_ref SET rf_shortname='Glide' WHERE rf_pk=$id_3dfx");
367  }
368  $dbManager->commit();
369 
370  $sysconfig['Release'] = "3.0.2";
371 }
372 
373 if($isUpdating && (empty($sysconfig['Release']) || $sysconfig['Release'] == '3.0.2'))
374 {
375  require_once("$LIBEXECDIR/dbmigrate_multiple_copyright_decisions.php");
376 
377  $sysconfig['Release'] = "3.1.0";
378 }
379 
380 // fix release-version datamodel-version missmatch
381 if($isUpdating && (empty($sysconfig['Release']) || $sysconfig['Release'] == "3.1.0")) {
382  $sysconfig['Release'] = "3.3.0";
383 }
384 
385 $dbManager->begin();
386 $dbManager->getSingleRow("DELETE FROM sysconfig WHERE variablename=$1",array('Release'),$sqlLog='drop.sysconfig.release');
387 $dbManager->insertTableRow('sysconfig',
388  array('variablename'=>'Release','conf_value'=>$sysconfig['Release'],'ui_label'=>'Release','vartype'=>2,'group_name'=>'Release','description'=>''));
389 $dbManager->commit();
390 /* email/url/author data migration to other table */
391 require_once("$LIBEXECDIR/dbmigrate_copyright-author.php");
392 
393 // Migration script to move candidate licenses in obligations
394 require_once("$LIBEXECDIR/dbmigrate_3.6-3.7.php");
395 Migrate_36_37($dbManager, $Verbose);
396 
397 // Migration script for 3.7 => 3.8
398 require_once("$LIBEXECDIR/dbmigrate_3.7-3.8.php");
399 Migrate_37_38($dbManager, $MODDIR);
400 
401 /* sanity check */
402 require_once ("$LIBEXECDIR/sanity_check.php");
403 $checker = new SanityChecker($dbManager,$Verbose);
404 $errors = $checker->check();
405 
406 if($errors>0)
407 {
408  echo "ERROR: $errors sanity check".($errors>1?'s':'')." failed\n";
409 }
410 exit($errors);
411 
418 {
419  global $LIBEXECDIR;
420  global $dbManager;
421 
422  if (!is_dir($LIBEXECDIR)) {
423  print "FATAL: Directory '$LIBEXECDIR' does not exist.\n";
424  return (1);
425  }
426 
427  $dir = opendir($LIBEXECDIR);
428  if (!$dir) {
429  print "FATAL: Unable to access '$LIBEXECDIR'.\n";
430  return (1);
431  }
432  $dbManager->begin();
433  if ($tableName === 'license_ref_2') {
434  $dbManager->queryOnce("DROP TABLE IF EXISTS license_ref_2", $statment = __METHOD__.'.dropAncientBackUp');
435  $dbManager->queryOnce("CREATE TABLE license_ref_2 AS SELECT * FROM license_ref WHERE 1=2", $statment = __METHOD__.'.backUpData');
436  }
438  $keysToBeChanged = array(
439  'rf_OSIapproved' => '"rf_OSIapproved"',
440  'rf_FSFfree'=> '"rf_FSFfree"',
441  'rf_GPLv2compatible' => '"rf_GPLv2compatible"',
442  'rf_GPLv3compatible'=> '"rf_GPLv3compatible"',
443  'rf_Fedora' => '"rf_Fedora"'
444  );
445 
446  $jsonData = json_decode(file_get_contents("$LIBEXECDIR/licenseRef.json"), true);
447  $statementName = __METHOD__.'.insertInTo'.$tableName;
448  foreach($jsonData as $licenseArrayKey => $licenseArray) {
449  $keys = strtr(implode(",", array_keys($licenseArray)), $keysToBeChanged);
450  $valuePlaceHolders = "$" . join(",$",range(1, count(array_keys($licenseArray))));
451  $SQL = "INSERT INTO $tableName ( $keys ) VALUES ($valuePlaceHolders);";
452  $dbManager->prepare($statementName, $SQL);
453  $dbManager->execute($statementName, array_values($licenseArray));
454  }
455  $dbManager->commit();
456  return;
457 }
458 
467 function initLicenseRefTable($Verbose)
468 {
469  global $dbManager;
470 
471  $dbManager->queryOnce("BEGIN");
472  insertInToLicenseRefTableUsingJson('license_ref_2');
473  $dbManager->prepare(__METHOD__.".newLic", "select * from license_ref_2");
474  $result_new = $dbManager->execute(__METHOD__.".newLic");
475 
476  $dbManager->prepare(__METHOD__.'.licenseRefByShortname','SELECT * from license_ref where rf_shortname=$1');
478  while ($row = pg_fetch_assoc($result_new))
479  {
480  $rf_shortname = $row['rf_shortname'];
481  $escaped_name = pg_escape_string($rf_shortname);
482  $result_check = $dbManager->execute(__METHOD__.'.licenseRefByShortname',array($rf_shortname));
483  $count = pg_num_rows($result_check);
484 
485  $rf_text = pg_escape_string($row['rf_text']);
486  $rf_url = pg_escape_string($row['rf_url']);
487  $rf_fullname = pg_escape_string($row['rf_fullname']);
488  $rf_notes = pg_escape_string($row['rf_notes']);
489  $rf_active = $row['rf_active'];
490  $marydone = $row['marydone'];
491  $rf_text_updatable = $row['rf_text_updatable'];
492  $rf_detector_type = $row['rf_detector_type'];
493  $rf_flag = $row['rf_flag'];
494 
495  if ($count) // update when it is existing
496  {
497  $row_check = pg_fetch_assoc($result_check);
498  pg_free_result($result_check);
499  $rf_text_check = pg_escape_string($row_check['rf_text']);
500  $rf_url_check = pg_escape_string($row_check['rf_url']);
501  $rf_fullname_check = pg_escape_string($row_check['rf_fullname']);
502  $rf_notes_check = pg_escape_string($row_check['rf_notes']);
503  $rf_active_check = $row_check['rf_active'];
504  $marydone_check = $row_check['marydone'];
505  $rf_text_updatable_check = $row_check['rf_text_updatable'];
506  $rf_detector_type_check = $row_check['rf_detector_type'];
507  $rf_flag_check = $row_check['rf_flag'];
508 
509  $sql = "UPDATE license_ref set ";
510  if ($rf_flag_check == 2 && $rf_flag == 1) {
511  $sql .= " rf_text='$rf_text_check',";
512  } else {
513  if ($rf_text_check != $rf_text && !empty($rf_text) && !(stristr($rf_text, 'License by Nomos'))) $sql .= " rf_text='$rf_text', rf_flag='1',";
514  }
515  if ($rf_url_check != $rf_url && !empty($rf_url)) $sql .= " rf_url='$rf_url',";
516  if ($rf_fullname_check != $rf_fullname && !empty($rf_fullname)) $sql .= " rf_fullname ='$rf_fullname',";
517  if ($rf_notes_check != $rf_notes && !empty($rf_notes)) $sql .= " rf_notes ='$rf_notes',";
518  if ($rf_active_check != $rf_active && !empty($rf_active)) $sql .= " rf_active ='$rf_active',";
519  if ($marydone_check != $marydone && !empty($marydone)) $sql .= " marydone ='$marydone',";
520  if ($rf_text_updatable_check != $rf_text_updatable && !empty($rf_text_updatable)) $sql .= " rf_text_updatable ='$rf_text_updatable',";
521  if ($rf_detector_type_check != $rf_detector_type && !empty($rf_detector_type)) $sql .= " rf_detector_type = '$rf_detector_type',";
522  $sql = substr_replace($sql ,"",-1);
523 
524  if ($sql != "UPDATE license_ref set") { // check if have something to update
525  $sql .= " where rf_shortname = '$escaped_name'";
526  $dbManager->queryOnce($sql);
527  }
528  } else { // insert when it is new
529  pg_free_result($result_check);
530  $sql = "INSERT INTO license_ref (rf_shortname, rf_text, rf_url, rf_fullname, rf_notes, rf_active, rf_text_updatable, rf_detector_type, marydone)"
531  . "VALUES ('$escaped_name', '$rf_text', '$rf_url', '$rf_fullname', '$rf_notes', '$rf_active', '$rf_text_updatable', '$rf_detector_type', '$marydone');";
532  $dbManager->queryOnce($sql);
533  }
534  }
535  pg_free_result($result_new);
536 
537  $dbManager->queryOnce("DROP TABLE license_ref_2");
538  $dbManager->queryOnce("COMMIT");
539 
540  return (0);
541 } // initLicenseRefTable()
542 
migrate_35_36($dbManager, $force=false)
initLicenseRefTable($Verbose)
Load the license_ref table with licenses.
Definition: fossinit.php:467
Migrate_33_34($dbManager, $dryRun)
Migrate_37_38($dbManager, $MODDIR)
Migrate_36_37($dbManager, $verbose)
setDriver(Driver &$dbDriver)
Definition: DbManager.php:47
Migrate_20_21($DryRun)
Migrate to the uploadtree_a table.
explainUsage()
Print Usage statement.
Definition: fossinit.php:24
migrate_25_26($verbose)
Migrate_21_22($Verbose)
Create new groups, group_user_member, perm_upload and perm_folder records to support 2...
foreach($Options as $Option=> $OptVal) if(0==$reference_flag &&0==$nomos_flag) $PG_CONN
insertInToLicenseRefTableUsingJson($tableName)
insert into license_ref table using json file.
Definition: fossinit.php:417
bootstrap($sysconfdir="")
Bootstrap the fossology php library.
Definition: migratetest.php:93
ConfigInit($sysconfdir, &$SysConf)
Initialize the fossology system after bootstrap().
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:695
renameLicensesForSpdxValidation($verbose)
Create map of old_shortname to new_shortname for SPDX and call renameLicenses.