source: src-qt4/pc-installgui/installer.cpp @ 8ac9a7f

9.2-releasereleng/10.0releng/10.0.1
Last change on this file since 8ac9a7f was 8ac9a7f, checked in by Kris Moore <kris@…>, 8 months ago

Fix the top progress bar during system/package installation.

It will now show a correct progress status, along with the currently
installing meta-pkg

  • Property mode set to 100644
File size: 55.5 KB
Line 
1#include <QCloseEvent>
2#include <QDir>
3#include <QProcess>
4#include <QTimer>
5#include <QTranslator>
6#include <QInputDialog>
7#include <QGraphicsPixmapItem>
8
9#include "backend.h"
10#include "installer.h"
11#include "helpText.h"
12
13Installer::Installer(QWidget *parent) : QMainWindow(parent)
14{
15    setupUi(this);
16    translator = new QTranslator();
17    haveWarnedSpace=false;
18    force4K = false;
19
20    connect(abortButton, SIGNAL(clicked()), this, SLOT(slotAbort()));
21    connect(backButton, SIGNAL(clicked()), this, SLOT(slotBack()));
22    connect(nextButton, SIGNAL(clicked()), this, SLOT(slotNext()));
23
24    connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
25    connect(pushTouchKeyboard, SIGNAL(clicked()), this, SLOT(slotPushVirtKeyboard()));
26    connect(pushChangeKeyLayout, SIGNAL(clicked()), this, SLOT(slotPushKeyLayout()));
27    connect(pushHardware, SIGNAL(clicked()), this, SLOT(slotCheckHardware()));
28    connect(pushNetwork, SIGNAL(clicked()), this, SLOT(slotStartNetworkManager()));
29    connect(pushLoadConfig, SIGNAL(clicked()), this, SLOT(slotLoadConfigUSB()));
30    connect(pushSaveConfig, SIGNAL(clicked()), this, SLOT(slotSaveConfigUSB()));
31    connect(pushSaveConfig2, SIGNAL(clicked()), this, SLOT(slotSaveConfigUSB()));
32
33    abortButton->setText(tr("&Cancel"));
34    backButton->setText(tr("&Back"));
35    nextButton->setText(tr("&Next"));
36
37    // Init the MBR to yes
38    loadMBR = true;
39    // Init the GPT to no
40    loadGPT = false;
41
42    // No optional components by default
43    fSRC=false;
44    fPORTS=false;
45
46    // Load the keyboard info
47    keyModels = Scripts::Backend::keyModels();
48    keyLayouts = Scripts::Backend::keyLayouts();
49
50    // Set the arch name
51    setArch();
52
53    // Start on the first screen
54    installStackWidget->setCurrentIndex(0);
55    backButton->setVisible(false);
56}
57
58Installer::~Installer()
59{
60    //delete ui;
61}
62
63bool Installer::isInstalled()
64{
65    return false;
66}
67
68void Installer::setArch()
69{
70   QProcess m;
71   m.start(QString("uname"), QStringList() << "-m");
72   while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
73      m.waitForFinished(200);
74      QCoreApplication::processEvents();
75   }
76
77   // Get output
78   Arch = m.readLine().simplified();
79   qDebug() << Arch;
80}
81
82void Installer::slotCheckHardware()
83{
84  pcHardware = new dialogCheckHardware();
85  pcHardware->programInit();
86  pcHardware->setWindowModality(Qt::ApplicationModal);
87  pcHardware->show();
88  pcHardware->raise();
89}
90
91void Installer::slotPushKeyLayout()
92{
93  wKey = new widgetKeyboard();
94  wKey->programInit(keyModels, keyLayouts);
95  wKey->setWindowModality(Qt::ApplicationModal);
96  wKey->show();
97  wKey->raise();
98}
99
100void Installer::initInstall()
101{
102    // load languages
103    comboLanguage->clear();
104    languages = Scripts::Backend::languages();
105    for (int i=0; i < languages.count(); ++i) {
106        QString languageStr = languages.at(i);
107        QString language = languageStr.split("-").at(0);
108        comboLanguage->addItem(language.trimmed());
109    }
110    connect(comboLanguage, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotChangeLanguage()));
111
112    // Load any package scheme data
113    listDeskPkgs = Scripts::Backend::getPackageData(availDesktopPackageData, QString());
114    listServerPkgs = Scripts::Backend::getPackageData(availServerPackageData, QString("trueos"));
115
116    // Do check for available meta-pkgs on boot media
117    if ( QFile::exists("/tmp/no-meta-pkgs") )
118        hasPkgsOnMedia = false;
119    else
120        hasPkgsOnMedia = true;
121
122    qDebug() << "Package Media:" << availDesktopPackageData << hasPkgsOnMedia;
123
124    // See if this media has a freebsd release on it
125    if ( QFile::exists("/tmp/no-fbsd-release") ) {
126        hasFreeBSDOnMedia = false;
127    } else {
128        hasFreeBSDOnMedia = true;
129    }
130       
131    // Do check for install pkgs on boot media
132    if ( QFile::exists("/tmp/no-install-pkgs") ) {
133        hasInstallOnMedia = false;
134    } else {
135        hasInstallOnMedia = true;
136    }
137
138    // Set the key toggle
139    toggleKeyLayout = true;
140
141    // Is this a LIVE disk?
142    if ( QFile::exists("/usr/pcbsd-live") )
143        isLiveMode = true;
144    else
145        isLiveMode = false;
146
147    // Get available memory
148    systemMemory = Scripts::Backend::systemMemory();
149
150    // Load up the keyboard information
151    //connectKeyboardSlots();
152
153    // Connect the disk slots
154    connect(pushDiskCustomize,SIGNAL(clicked()), this, SLOT(slotDiskCustomizeClicked()));
155
156    // Load the disks
157    loadDiskInfo();
158   
159    // Init the desktop wheel
160    initDesktopSelector();
161}
162
163void Installer::loadDiskInfo()
164{
165   sysDisks = Scripts::Backend::hardDrives();
166   if ( sysDisks.empty() ) {
167      QMessageBox::critical(this, tr("PC-BSD Installer"),
168                                tr("Unable to detect any disk drives! The install will now exit."),
169                                QMessageBox::Ok,
170                                QMessageBox::Ok);
171      exit(1);
172   }
173
174   // For now use the first disk we find
175   if ( ! autoGenPartitionLayout(sysDisks.at(0).at(1), true) )
176   {
177      QMessageBox::critical(this, tr("PC-BSD Installer"),
178        tr("Unable to suggest a partition for the detected disk."),
179        QMessageBox::Ok,
180        QMessageBox::Ok);
181   }
182
183   textEditDiskSummary->clear();
184   QStringList summary = getDiskSummary();
185   for ( int i=0; i < summary.count(); ++i)
186     textEditDiskSummary->append(summary.at(i));
187
188   textEditDiskSummary->moveCursor(QTextCursor::Start);
189
190}
191
192// Function which will auto-generate a partition layout based upon the target disk / slice
193bool Installer::autoGenPartitionLayout(QString target, bool isDisk)
194{
195  QString targetType, tmp;
196  int targetLoc, totalSize = 0, mntsize, swapsize;
197  QString targetDisk, targetSlice, tmpPass, fsType;
198  bool ok;
199  ok = false;
200
201  // Clear out the original disk layout
202  sysFinalDiskLayout.clear();
203  QStringList fileSystem;
204  qDebug() << "Generating disk layout";
205
206
207  if ( isDisk ) {
208    targetType = "DRIVE";
209    targetSlice = "ALL";
210    targetDisk = target;
211    targetLoc = 1;
212  } else {
213    targetType = "SLICE";
214    targetDisk = target;
215    targetDisk.truncate(targetDisk.size() -2);
216    targetSlice = target;
217    targetSlice = targetSlice.remove(0, targetSlice.size() -2);
218    targetLoc = 2;
219  }
220 
221  // Lets get the size for this disk / partition
222  for (int i=0; i < sysDisks.count(); ++i) {
223      // Make sure to only add the slices to the listDiskSlices
224      if ( sysDisks.at(i).at(0) == targetType && target == sysDisks.at(i).at(targetLoc))
225        totalSize = sysDisks.at(i).at(targetLoc + 1).toInt(&ok);
226  }
227
228  // Give us a small buffer for rounding errors
229  totalSize = totalSize - 10;
230
231  // Setup some swap space
232  if ( totalSize > 30000 ) {
233    // 2GB if over 30GB of disk space, 512MB otherwise
234    swapsize = 2048;
235  } else {
236    swapsize = 512;
237  }
238  totalSize = totalSize - swapsize;
239
240  // We got a valid size for this disk / slice, lets generate the layout now
241  if( !ok )
242    return false;
243
244
245  // If on amd64 lets use ZFS, it rox
246  if ( Arch == "amd64" ) {
247    // Add the main zfs pool with standard partitions
248    fsType= "ZFS";
249    fileSystem << targetDisk << targetSlice << "/,/tmp(compress=lzjb),/usr(canmount=off),/usr/home,/usr/jails,/usr/obj(compress=lzjb),/usr/pbi,/usr/ports(compress=gzip),/usr/ports/distfiles(compress=off),/usr/src(compress=gzip),/var(canmount=off),/var/audit(compress=lzjb),/var/log(compress=gzip),/var/tmp(compress=lzjb)" << fsType << tmp.setNum(totalSize) << "" << "";
250    sysFinalDiskLayout << fileSystem;
251    fileSystem.clear();
252   
253    // Now add swap space
254    fileSystem << targetDisk << targetSlice << "SWAP" << "SWAP" << tmp.setNum(swapsize) << "" << "";
255    sysFinalDiskLayout << fileSystem;
256    fileSystem.clear();
257
258    //qDebug() << "Auto-Gen FS:" <<  fileSystem;
259    return true;
260  }
261
262  // Looks like not on amd64, fallback to UFS+SUJ and print a nice
263  // warning for the user explaining they *really* want to be on amd64
264  QMessageBox::warning(this, tr("PC-BSD Installer"),
265      tr("Detected that you are running the 32bit version. If your system is 64bit capable (most systems made after 2005), you really should be running the 64bit version"),
266      QMessageBox::Ok,
267      QMessageBox::Ok);
268
269  // Start the UFS layout now
270  mntsize = 2000;
271  fsType="UFS+SUJ";
272
273  fileSystem << targetDisk << targetSlice << "/" << fsType << tmp.setNum(mntsize) << "" << "";
274  totalSize = totalSize - mntsize;
275  //qDebug() << "Auto-Gen FS:" <<  fileSystem;
276  sysFinalDiskLayout << fileSystem;
277  fileSystem.clear();
278   
279
280  fileSystem << targetDisk << targetSlice << "SWAP" << "SWAP" << tmp.setNum(swapsize) << "" << "";
281  totalSize = totalSize - mntsize;
282  //qDebug() << "Auto-Gen FS:" <<  fileSystem;
283  sysFinalDiskLayout << fileSystem;
284  fileSystem.clear();
285
286  // If less than 3GB, skip /var and leave on /
287  if ( totalSize > 3000 ) {
288    // Figure out the default size for /var if we are on FreeBSD / PC-BSD
289    mntsize = 2048;
290    fileSystem << targetDisk << targetSlice << "/var" << fsType << tmp.setNum(mntsize) << "" << "";
291    totalSize = totalSize - mntsize;
292    //qDebug() << "Auto-Gen FS:" <<  fileSystem;
293    sysFinalDiskLayout << fileSystem;
294    fileSystem.clear();
295  }
296
297  // Now use the rest of the disk / slice for /usr
298  fileSystem << targetDisk << targetSlice << "/usr" << fsType << tmp.setNum(totalSize) << "" << "";
299  //qDebug() << "Auto-Gen FS:" <<  fileSystem;
300  sysFinalDiskLayout << fileSystem;
301  fileSystem.clear();
302
303  return true; 
304 
305}
306
307// Function which returns the pc-sysinstall cfg data
308QStringList Installer::getDiskSummary()
309{
310  QList<QStringList> copyList;
311  QStringList summaryList;
312  QString tmp, workingDisk, workingSlice, tmpSlice, XtraTmp, startPart, sliceSize;
313  int disk = 0;
314
315  // Copy over the list to a new variable we can mangle without modifying the original
316  copyList = sysFinalDiskLayout;
317
318  if ( copyList.at(0).at(0) == "MANUAL" )
319  {
320    summaryList << "";
321    summaryList << tr("Installing to file-system mounted at /mnt");
322    return summaryList;
323  }
324
325  // Start our summary
326  summaryList << "";
327  summaryList << "<b>" + tr("The disk will be setup with the following configuration:") + "</b>";
328
329  while ( ! copyList.empty() )
330  {
331    workingDisk = copyList.at(0).at(0);
332    workingSlice = copyList.at(0).at(1);
333    tmpSlice = workingSlice;
334
335    // Check if this is an install to "Unused Space"
336    for (int z=0; z < sysDisks.count(); ++z)
337      if ( sysDisks.at(z).at(0) == "SLICE" \
338        && sysDisks.at(z).at(2) == workingDisk + workingSlice \
339        && sysDisks.at(z).at(4) == "Unused Space" )
340          tmpSlice = "free";
341
342    // Check for any mirror for this device
343    for (int i=0; i < copyList.count(); ++i) {
344       if ( copyList.at(i).at(2).indexOf("MIRROR(" + workingDisk + ")") != -1 )
345       {
346         summaryList << tr("Disk:") + copyList.at(i).at(0) + " " + tr("Mirroring:") + workingDisk;
347         copyList.removeAt(i);
348         break;
349       }
350    }
351
352
353
354    // If after doing the mirror, our list is empty, break out
355    if ( copyList.empty() )
356      break;
357   
358    // If there is a dedicated /boot partition, need to list that first, see what is found
359    for (int i=0; i < copyList.count(); ++i) {
360      QStringList mounts = copyList.at(i).at(2).split(",");
361      for (int z = 0; z < mounts.size(); ++z) {
362        if ( copyList.at(i).at(0) == workingDisk \
363          && copyList.at(i).at(1) == workingSlice \
364          && mounts.at(z) == "/boot" )
365                startPart="/boot";
366      }
367    }
368
369    // If no dedicated /boot partition, then lets list "/" first
370    if(startPart.isEmpty())
371        startPart="/";
372
373    // Start by looking for the root partition
374    for (int i=0; i < copyList.count(); ++i) {
375      QStringList mounts = copyList.at(i).at(2).split(",");
376      for (int z = 0; z < mounts.size(); ++z) {
377        if ( copyList.at(i).at(0) == workingDisk \
378          && copyList.at(i).at(1) == workingSlice \
379          && (mounts.at(z) == startPart || mounts.at(z).contains(startPart + "(") ) ) {
380
381          // Check if we have any extra arguments to throw on the end
382          XtraTmp="";
383          if ( ! copyList.at(i).at(5).isEmpty() )
384            XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
385
386          // Write the user summary
387          summaryList << "";
388          summaryList << tr("Partition:") + " " + workingDisk + "(" + workingSlice + "):";
389          summaryList << tr("FileSystem:") + " " + copyList.at(i).at(3);
390          summaryList << tr("Size:") + " " + copyList.at(i).at(4) + "MB ";
391          if ( copyList.at(i).at(3) == "ZFS" ) {
392            QStringList zDS = copyList.at(i).at(2).split(",");
393            QString zTMP;
394            for (int ds = 0; ds < zDS.size(); ++ds) {
395              //if ( zDS.at(ds) != "/" )
396               // zDS.replace(ds, "/" + zDS.at(ds));
397              if ( zDS.at(ds).indexOf("(") != -1 ) {
398                zTMP = zDS.at(ds);
399                zTMP.replace("(", " (");
400                zDS.replace(ds, zTMP );
401              }
402            } 
403            if ( radioRestore->isChecked())
404               summaryList << tr("ZFS Datasets:") + " " + tr("The original ZFS layout will be restored");
405            else
406               summaryList << tr("ZFS Datasets:<br>") + " " + zDS.join("<br>");
407          } else {
408            summaryList << tr("Mount:") + " " + copyList.at(i).at(2);
409          }
410          if ( ! XtraTmp.isEmpty() ) {
411            summaryList << tr("Options:") + " " + copyList.at(i).at(5);
412          }
413
414          // Done with this item, remove it now
415          copyList.removeAt(i);
416          break;
417        }
418      }
419    }
420
421
422    // Now look for SWAP
423    for (int i=0; i < copyList.count(); ++i) {
424      if ( copyList.at(i).at(0) == workingDisk \
425        && copyList.at(i).at(1) == workingSlice \
426        && copyList.at(i).at(2) == "SWAP" ) {
427
428        // Write the user summary
429        summaryList << "";
430        summaryList << tr("Partition:") + " " + workingDisk + "(" + workingSlice + "):";
431        summaryList << tr("FileSystem:") + " " + copyList.at(i).at(3);
432        summaryList << tr("Size:") + " " + copyList.at(i).at(4) + "MB ";
433
434        // Done with this item, remove it now
435        copyList.removeAt(i);
436        break;
437      }
438    }
439
440 
441    // Now look for any other partitions
442    int count = copyList.count();
443    for (int i=0; i < count; ++i) {
444      if ( copyList.at(i).at(0) == workingDisk \
445        && copyList.at(i).at(1) == workingSlice ) {
446
447        // Check if we have any extra arguments to throw on the end
448        XtraTmp="";
449        if ( ! copyList.at(i).at(5).isEmpty() )
450          XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
451
452        // If we are working on the last partition, set the size to 0 to use remaining disk
453        if ( i == (count - 1) ) 
454                sliceSize = "0";
455        else
456                sliceSize=copyList.at(i).at(4);
457
458        // Write the user summary
459        summaryList << "";
460        summaryList << tr("Partition:") + " " + workingDisk + "(" + workingSlice + "):";
461
462        summaryList << tr("FileSystem:") + " " + copyList.at(i).at(3);
463
464        summaryList << tr("Size:") + " " + copyList.at(i).at(4) + "MB ";
465        if ( copyList.at(i).at(3) != "ZFS" )
466          summaryList << tr("Mount:") + " " + copyList.at(i).at(2);
467        if ( ! XtraTmp.isEmpty() ) {
468          summaryList << tr("Options:") + " " + copyList.at(i).at(5);
469        }
470
471        // Done with this item, remove it now
472        copyList.removeAt(i);
473        i--;
474        count--;
475      }
476    }
477
478    // Increment our disk counter
479    disk++;
480  }
481
482  return summaryList;
483}
484
485void Installer::slotDiskCustomizeClicked()
486{
487  wDisk = new wizardDisk();
488  wDisk->programInit();
489  wDisk->setWindowModality(Qt::ApplicationModal);
490  if ( radioRestore->isChecked() )
491    wDisk->setRestoreMode();
492  connect(wDisk, SIGNAL(saved(QList<QStringList>, bool, bool, QString, bool)), this, SLOT(slotSaveDiskChanges(QList<QStringList>, bool, bool, QString, bool)));
493  wDisk->show();
494  wDisk->raise();
495}
496
497void Installer::slotDesktopCustomizeClicked()
498{
499  desks = new desktopSelection();
500  if ( radioDesktop->isChecked() )
501     desks->programInit(listDeskPkgs,selectedPkgs);
502  else
503     desks->programInit(listServerPkgs,selectedPkgs);
504  desks->setWindowModality(Qt::ApplicationModal);
505  customPkgsSet = true;
506  connect(desks, SIGNAL(saved(QStringList)), this, SLOT(slotSaveMetaChanges(QStringList)));
507  desks->show();
508  desks->raise();
509}
510
511void Installer::slotSaveMetaChanges(QStringList sPkgs)
512{
513  selectedPkgs = sPkgs;
514
515  if ( radioDesktop->isChecked() )
516     groupDeskSummary->setTitle(tr("PC-BSD Package Selection"));
517  else
518     groupDeskSummary->setTitle(tr("TrueOS Package Selection"));
519
520  textDeskSummary->setText(tr("The following meta-pkgs will be installed:") + "<br>" + selectedPkgs.join("<br>"));
521}
522
523void Installer::slotSaveDiskChanges(QList<QStringList> newSysDisks, bool MBR, bool GPT, QString zName, bool zForce )
524{
525
526  zpoolName = zName; 
527  force4K = zForce;
528
529  // Save the new disk layout
530  loadMBR = MBR;
531  loadGPT = GPT;
532  sysFinalDiskLayout = newSysDisks;
533  textEditDiskSummary->clear();
534  QStringList summary = getDiskSummary();
535  for ( int i=0; i < summary.count(); ++i)
536    textEditDiskSummary->append(summary.at(i));
537               
538  textEditDiskSummary->moveCursor(QTextCursor::Start);
539 
540  // Regenerate the config
541  startConfigGen();
542}
543
544void Installer::slotChangedMetaPkgSelection()
545{
546
547  selectedPkgs.clear();
548  if ( radioRestore->isChecked() )
549  {
550     pushDeskCustomize->setEnabled(false);
551     textDeskSummary->setText(tr("Performing a restore from a Life-Preserver backup. Click next to start the restore wizard."));
552     return;
553  }
554
555  pushDeskCustomize->setEnabled(true);
556
557  // Set the default desktop meta-pkgs based upon the selection
558  if ( radioDesktop->isChecked() )
559  {
560      selectedPkgs << "KDE" << "KDE-Accessibility" << "KDE-Artwork" << "KDE-Graphics" << "KDE-Multimedia" << "KDE-Network" << "KDE-PIM";
561
562      // Include i18n stuff?
563      if ( comboLanguage->currentIndex() != 0 ) 
564         selectedPkgs << "KDE-L10N";
565
566      // Check if we are using NVIDIA driver and include it automatically
567      QFile file("/etc/X11/xorg.conf");
568      if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
569         
570        QTextStream in(&file);
571        while (!in.atEnd()) {
572           QString line = in.readLine();
573           if ( line.indexOf("nvidia") != -1 ) {
574             selectedPkgs << "NVIDIA";
575             break;
576           }
577        }     
578        file.close();
579      } // Done with NVIDIA check
580
581      // Are we on VirtualBox or VMware?
582      QFile filev("/var/log/Xorg.0.log");
583      if (filev.open(QIODevice::ReadOnly | QIODevice::Text)) {
584         
585        QTextStream inv(&filev);
586        while (!inv.atEnd()) {
587           QString line = inv.readLine();
588           if ( line.indexOf("VirtualBox") != -1 ) {
589             selectedPkgs << "VirtualBoxGuest";
590             break;
591           }
592           if ( line.indexOf("VMware") != -1 ) {
593             selectedPkgs << "VMwareGuest";
594             break;
595           }
596        }     
597        filev.close();
598      } // End of VM checks
599  }
600
601  slotSaveMetaChanges(selectedPkgs);
602  qDebug() << selectedPkgs;
603
604}
605
606void Installer::initDesktopSelector()
607{
608    // Using default pkg sets for now
609    customPkgsSet = false;
610    connect(pushDeskCustomize,SIGNAL(clicked()), this, SLOT(slotDesktopCustomizeClicked()));
611    connect(radioDesktop,SIGNAL(clicked()), this, SLOT(slotChangedMetaPkgSelection()));
612    connect(radioServer,SIGNAL(clicked()), this, SLOT(slotChangedMetaPkgSelection()));
613    connect(radioRestore,SIGNAL(clicked()), this, SLOT(slotChangedMetaPkgSelection()));
614    slotChangedMetaPkgSelection();
615}
616
617void Installer::proceed(bool forward)
618{
619    int count = installStackWidget->count() - 1;
620    int index = installStackWidget->currentIndex();
621
622    index = forward ?
623            (index == count ? count : index + 1) :
624            (index == 0 ? 0 : index - 1);
625
626    if ( index > 0 && index != 4)
627      backButton->setVisible(true);
628    else
629      backButton->setVisible(false);
630
631    installStackWidget->setCurrentIndex(index);
632}
633
634// Slot which is called when the Finish button is clicked
635void Installer::slotFinished()
636{
637  qApp->quit();
638}
639
640void Installer::slotSaveFBSDSettings(QString rootPW, QString name, QString userName, QString userPW, QString shell, QString hostname, bool ssh, bool src, bool ports, QStringList netSettings)
641{
642  fRootPW = rootPW;
643  fName = name;
644  fUserName = userName;
645  fUserPW = userPW;
646  fShell = shell;
647  fHost = hostname;
648  fSSH = ssh;
649  fSRC = src;
650  fPORTS = ports;
651  fNetSettings = netSettings;
652  installStackWidget->setCurrentIndex(installStackWidget->currentIndex() + 1);
653
654  // Generate the pc-sysinstall config
655  startConfigGen();
656}
657
658void Installer::slotNext()
659{
660   QString tmp;
661
662   // Update package selection in case user changed language, etc
663   if ( installStackWidget->currentIndex() == 0 && hasPkgsOnMedia && !customPkgsSet) {
664     slotChangedMetaPkgSelection();
665   }
666
667   // If no pkgs on media
668   if ( installStackWidget->currentIndex() == 0 && ! hasPkgsOnMedia) {
669     installStackWidget->setCurrentIndex(2);
670     return;
671   }
672
673   // Start the Restore wizard
674   if ( radioRestore->isChecked() && installStackWidget->currentIndex() == 1 ) { 
675     wRestore = new wizardRestore();
676     wRestore->setWindowModality(Qt::ApplicationModal);
677     wRestore->programInit();
678     connect(wRestore, SIGNAL(saved(QStringList)), this, SLOT(slotSaveRestoreSettings(QStringList)));
679     wRestore->show();
680     wRestore->raise();
681     return ;
682   }
683
684   // Start the TrueOS wizard
685   if ( radioServer->isChecked() && installStackWidget->currentIndex() == 1 ) { 
686     bool tOS;
687     tOS = true;
688
689     wFBSD = new wizardFreeBSD();
690     wFBSD->setWindowModality(Qt::ApplicationModal);
691     wFBSD->programInit(tOS);
692     connect(wFBSD, SIGNAL(saved(QString, QString, QString, QString, QString, QString, bool, bool, bool, QStringList)), this, SLOT(slotSaveFBSDSettings(QString, QString, QString, QString, QString, QString, bool, bool, bool, QStringList)));
693     wFBSD->show();
694     wFBSD->raise();
695     return ;
696   }
697
698   // Create the pc-sysinstall config
699   if ( installStackWidget->currentIndex() == 1 )
700     startConfigGen();
701
702   // If the chosen disk is too small or partition is invalid, don't continue
703   if ( installStackWidget->currentIndex() == 2 && ! checkDiskRequirements())
704      return;
705
706   if ( installStackWidget->currentIndex() == 2 )
707   {
708      startConfigGen();
709      QString msg;
710
711      if (radioRestore->isChecked() )
712        msg=tr("Start the restore now?");
713      else
714        msg=tr("Start the installation now?");
715
716      int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
717                                msg,
718                                QMessageBox::No | QMessageBox::Yes,
719                                QMessageBox::No);
720      switch (ret) {
721      case QMessageBox::Yes:
722          startInstall();
723          break;
724      case QMessageBox::No: // :)
725          return;
726          break;
727      }
728   }
729
730   proceed(true);
731}
732
733void Installer::slotBack()
734{
735   // If no pkgs on media
736   if ( installStackWidget->currentIndex() == 2 && ! hasPkgsOnMedia) {
737        installStackWidget->setCurrentIndex(0);
738        return;
739   }
740
741   proceed(false);
742}
743
744void Installer::slotAbort()
745{
746   close();
747}
748
749void Installer::slotChangeLanguage()
750{
751    if ( comboLanguage->currentIndex() == -1 )
752      return;
753
754    // Figure out the language code
755    QString langCode = languages.at(comboLanguage->currentIndex());
756   
757    // Grab the language code
758    langCode.truncate(langCode.lastIndexOf(")"));
759    langCode.remove(0, langCode.lastIndexOf("(") + 1); 
760
761    // Check what directory our app is in
762    QString appDir;
763    if ( QFile::exists("/usr/local/bin/pc-sysinstaller") )
764      appDir = "/usr/local/share/pcbsd";
765    else
766      appDir = QCoreApplication::applicationDirPath();
767
768    //QTranslator *translator = new QTranslator();
769    qDebug() << "Remove the translator";
770    if ( ! translator->isEmpty() )
771      QCoreApplication::removeTranslator(translator);
772
773    if (translator->load( QString("SysInstaller_") + langCode, appDir + "/i18n/" )) {
774      qDebug() << "Load new Translator" << langCode;
775      QCoreApplication::installTranslator(translator);
776      this->retranslateUi(this);
777    }
778}
779
780void Installer::changeLang(QString code)
781{
782   // Change the language in the combobox with the current running one
783   comboLanguage->disconnect();
784
785   for (int i=0; i < languages.count(); ++i) {
786      if ( languages.at(i).indexOf("(" + code + ")" ) != -1 ) {
787        comboLanguage->setCurrentIndex(i); 
788      }
789   }
790
791   connect(comboLanguage, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotChangeLanguage()));
792}
793
794QStringList Installer::getGlobalCfgSettings()
795{
796
797  QStringList tmpList;
798  QString tmp, upDrive;
799
800  tmpList << "# Auto-Generated pc-sysinstall configuration";
801  tmpList << "installInteractive=no";
802
803  // Are we doing a restore?
804  if ( radioRestore->isChecked() )
805  {
806    tmpList << "installMode=zfsrestore";
807    tmpList << "";
808    tmpList << "sshHost=" + restOpts.at(0);
809    tmpList << "sshUser=" + restOpts.at(1);
810    tmpList << "sshPort=" + restOpts.at(2);
811    if ( ! restOpts.at(3).isEmpty() )
812      tmpList << "sshKey=" + restOpts.at(3);
813    tmpList << "zfsProps=" + restOpts.at(4);
814    tmp = restOpts.at(4);
815    tmp.replace(".lp-props-", "");
816    tmp.replace("#", "/");
817    tmpList << "zfsRemoteDataset=" + tmp;
818
819    // Using a custom zpool name?
820    if ( ! zpoolName.isEmpty() )
821      tmpList << "zpoolName=" + zpoolName;
822
823    // Are we force enabling ZFS 4K block sizes?
824    if ( force4K )
825      tmpList << "zfsForce4k=YES";
826
827    tmpList << "";
828    return tmpList;
829  } // End of restore options
830
831
832  if ( sysFinalDiskLayout.at(0).at(0) == "MANUAL" )
833  {
834    tmpList << "installMode=extract";
835    tmpList << "installLocation=/mnt";
836  } else {
837    // Doing a fresh install
838    tmpList << "installMode=fresh";
839  }
840 
841  QString distFiles;
842  distFiles="base doc games kernel";
843  if ( Arch == "amd64" )
844     distFiles+=" lib32";
845
846  // System type we are installing
847  if ( radioDesktop->isChecked() )
848    tmpList << "installType=PCBSD";
849  else
850    tmpList << "installType=FreeBSD";
851
852  tmpList << "packageType=dist";
853
854  // Set the distFiles being used
855  tmpList << "distFiles=" + distFiles;
856  tmpList << "";
857
858  // If we have a custom hostname, add it to the config
859  if ( ! fHost.isEmpty() )
860    tmpList << "hostname=" + fHost;
861
862  // Using a custom zpool name?
863  if ( ! zpoolName.isEmpty() )
864    tmpList << "zpoolName=" + zpoolName;
865
866  // Are we force enabling ZFS 4K block sizes?
867  if ( force4K )
868    tmpList << "zfsForce4k=YES";
869 
870  // Networking setup
871  if ( radioDesktop->isChecked() ) {
872    // PC-BSD network setup
873    tmpList << "netSaveDev=AUTO-DHCP-SLAAC";
874  } else {
875    // FreeBSD network setup
876    if ( fNetSettings.at(0) == "AUTO-DHCP" )
877      tmpList << "netSaveDev=AUTO-DHCP";
878    else if ( fNetSettings.at(0) == "AUTO-DHCP-SLAAC" ) {
879      tmpList << "netSaveDev=AUTO-DHCP-SLAAC";
880      // We cannot rely on SLAAC to provide DNS for example.  The same is true
881      // for DHCP but the worls seems to have forgotten...
882      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
883      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
884      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
885    } else if ( fNetSettings.at(0) == "IPv6-SLAAC" ) {
886       tmpList << "netSaveDev=IPv6-SLAAC";
887      // We cannot rely on SLAAC to provide DNS for example.  The same is true
888      // for DHCP but the worls seems to have forgotten...
889      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
890      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
891      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
892    } 
893    else
894    {
895      tmp = fNetSettings.at(0);
896      if ( tmp.indexOf(":") > 0 )
897        tmp.truncate(tmp.indexOf(":"));
898      tmpList << "netSaveDev=" + tmp;
899      tmpList << "netSaveIP_" + tmp + "=" + fNetSettings.at(1); 
900      tmpList << "netSaveMask_" + tmp + "=" + fNetSettings.at(2);
901      tmpList << "netSaveNameServer=" + fNetSettings.at(3);
902      tmpList << "netSaveDefaultRouter=" + fNetSettings.at(4);
903      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
904      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
905      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
906    }
907  }
908
909
910  // Doing install from /dist directory
911  tmpList << "installMedium=local"; 
912  tmpList << "localPath=/dist";
913
914  if ( comboLanguage->currentIndex() != 0 ) {
915    QString lang = languages.at(comboLanguage->currentIndex());
916    // Grab the language code
917    lang.truncate(lang.lastIndexOf(")"));
918    lang.remove(0, lang.lastIndexOf("(") + 1);
919    tmpList << "";
920    tmpList << "localizeLang=" + lang;
921  }
922
923  // Setup custom keyboard layouts
924  /* KPM
925  tmpList << "";
926  tmpList << "# Keyboard Layout Options";
927  tmp = comboBoxKeyboardModel->currentText();
928  tmp.truncate(tmp.indexOf(")"));
929  tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
930  tmpList << "localizeKeyModel=" + tmp;
931
932  tmp = listKbLayouts->currentItem()->text();
933  tmp.truncate(tmp.indexOf(")"));
934  tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
935  tmpList << "localizeKeyLayout=" + tmp;
936
937  tmp = listKbVariants->currentItem()->text();
938  if ( tmp != "<none>" ) {
939    tmp.truncate(tmp.indexOf(")"));
940    tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
941    tmpList << "localizeKeyVariant=" + tmp;
942  }
943  */
944
945  tmpList << " ";
946
947  return tmpList;
948}
949
950void Installer::startConfigGen()
951{
952
953  if ( ! haveWarnedSpace )
954     checkSpaceWarning();
955
956  QStringList cfgList;
957
958  // Generate the config file now
959  cfgList+=getGlobalCfgSettings();
960
961  cfgList+=getDiskCfgSettings();
962 
963  // We can skip these options if doing a restore
964  if ( ! radioRestore->isChecked() ) {
965
966    cfgList+=getComponentCfgSettings();
967
968    // Save the install config script to disk
969    cfgList << "runExtCommand=/root/save-config.sh";
970
971    cfgList+= "";
972
973    // If doing install from package disk
974    if ( hasPkgsOnMedia )
975      cfgList+=getDeskPkgCfg();
976
977    cfgList+= "";
978
979    if ( radioDesktop->isChecked() ) {
980      // Doing PC-BSD Install
981
982      QString lang;
983      if ( comboLanguage->currentIndex() != 0 )
984        lang = languages.at(comboLanguage->currentIndex()).section("(",1,1).section(")",0,0);
985      else
986        lang="en_US";
987
988      // Setup the desktop
989      cfgList << "runCommand=sh /usr/local/share/pcbsd/scripts/sys-init.sh desktop " + lang;
990
991      // Setup for a fresh system first boot
992      cfgList << "# Touch flags to enable PC-BSD setup at first boot";
993      cfgList << "runCommand=touch /var/.runxsetup";
994      cfgList << "runCommand=touch /var/.pcbsd-firstboot";
995      cfgList << "runCommand=touch /var/.pcbsd-firstgui";
996
997    } else {
998      // Doing TrueOS Install
999      cfgList+=getUsersCfgSettings();
1000
1001      // Enable SSH?
1002      if ( fSSH )
1003        cfgList << "runCommand=echo 'sshd_enable=\"YES\"' >>/etc/rc.conf";
1004
1005      // Setup the TrueOS server
1006      cfgList << "runCommand=sh /usr/local/share/pcbsd/scripts/sys-init.sh server";
1007
1008    } 
1009
1010    // Run newaliases to fix mail errors
1011    cfgList << "runCommand=newaliases";
1012
1013  } // End of restore check
1014
1015  // Now write out the cfgList to file
1016  QFile cfgfile( PCSYSINSTALLCFG );
1017  if ( cfgfile.open( QIODevice::WriteOnly ) ) {
1018    QTextStream stream( &cfgfile );
1019    for ( int i=0; i < cfgList.count(); ++i) {
1020      stream <<  cfgList.at(i) << "\n";
1021    }
1022    cfgfile.close();
1023  }
1024}
1025
1026void Installer::slotHelp()
1027{
1028        pcHelp = new dialogHelp();
1029        switch (installStackWidget->currentIndex()) {
1030        case 0:
1031                pcHelp->dialogInit(HELPTEXT0);
1032                break;
1033        case 1:
1034                pcHelp->dialogInit(HELPTEXT1);
1035                break;
1036        case 2:
1037                pcHelp->dialogInit(HELPTEXT2);
1038                break;
1039        case 3:
1040                pcHelp->dialogInit(HELPTEXT3);
1041                break;
1042        default:
1043                pcHelp->dialogInit("No help text...");
1044                break;
1045        }
1046        pcHelp->show();
1047}
1048
1049// Function which returns the pc-sysinstall cfg data
1050QStringList Installer::getDiskCfgSettings()
1051{
1052  QStringList tmpList;
1053  QList<QStringList> copyList;
1054  QString tmp, workingDisk, workingSlice, tmpSlice, XtraTmp, startPart, sliceSize;
1055  int disk = 0;
1056
1057  // Copy over the list to a new variable we can mangle without modifying the original
1058  copyList = sysFinalDiskLayout;
1059
1060  // Doing manual extraction
1061  if ( copyList.at(0).at(0) == "MANUAL" )
1062    return QStringList();
1063
1064  while ( ! copyList.empty() )
1065  {
1066    workingDisk = copyList.at(0).at(0);
1067    workingSlice = copyList.at(0).at(1);
1068    tmpSlice = workingSlice;
1069    tmpList << "# Disk Setup for " + workingDisk ;
1070
1071    // Check if this is an install to "Unused Space"
1072    for (int z=0; z < sysDisks.count(); ++z)
1073      if ( sysDisks.at(z).at(0) == "SLICE" \
1074        && sysDisks.at(z).at(2) == workingDisk + workingSlice \
1075        && sysDisks.at(z).at(4) == "Unused Space" )
1076          tmpSlice = "free";
1077
1078    tmpList << "disk" + tmp.setNum(disk) + "=" + workingDisk;
1079    tmpList << "partition=" + tmpSlice;
1080
1081    // Are we loading a boot-loader?
1082    if ( loadMBR )
1083      tmpList << "bootManager=GRUB";
1084    else
1085      tmpList << "bootManager=none";
1086
1087    // Set the GPT/MBR options
1088    if ( loadGPT ) 
1089      tmpList << "partscheme=GPT";
1090    else
1091      tmpList << "partscheme=MBR";
1092
1093    tmpList << "commitDiskPart";
1094    tmpList << "";
1095
1096    // If after doing the mirror, our list is empty, break out
1097    if ( copyList.empty() )
1098      break;
1099   
1100    // Now print the partition section for this slice
1101    tmpList << "# Partition Setup for " + workingDisk + "(" + workingSlice + ")";
1102    tmpList << "# All sizes are expressed in MB";
1103    tmpList << "# Avail FS Types, UFS, UFS+S, UFS+SUJ, UFS+J, ZFS, SWAP";
1104    tmpList << "# UFS.eli, UFS+S.eli, UFS+SUJ, UFS+J.eli, ZFS.eli, SWAP.eli";
1105
1106    // If there is a dedicated /boot partition, need to list that first, see what is found
1107    for (int i=0; i < copyList.count(); ++i) {
1108      QStringList mounts = copyList.at(i).at(2).split(",");
1109      for (int z = 0; z < mounts.size(); ++z) {
1110        if ( copyList.at(i).at(0) == workingDisk \
1111          && copyList.at(i).at(1) == workingSlice \
1112          && mounts.at(z) == "/boot" )
1113                startPart="/boot";
1114      }
1115    }
1116
1117    // If no dedicated /boot partition, then lets list "/" first
1118    if(startPart.isEmpty())
1119        startPart="/";
1120
1121    // Start by looking for the root partition
1122    for (int i=0; i < copyList.count(); ++i) {
1123      QStringList mounts = copyList.at(i).at(2).split(",");
1124      for (int z = 0; z < mounts.size(); ++z) {
1125        if ( copyList.at(i).at(0) == workingDisk \
1126          && copyList.at(i).at(1) == workingSlice \
1127          && mounts.at(z) == startPart ) {
1128
1129          // Check if we have any extra arguments to throw on the end
1130          XtraTmp="";
1131          if ( ! copyList.at(i).at(5).isEmpty() )
1132            XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
1133
1134          // Write out the partition line
1135          tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1136                   + copyList.at(i).at(3) + " " + copyList.at(i).at(4) \
1137                   + " " + copyList.at(i).at(2) + XtraTmp;
1138
1139          // Check if we have an encryption passphrase to use
1140          if ( ! copyList.at(i).at(6).isEmpty() )
1141            tmpList << "encpass=" + copyList.at(i).at(6);
1142
1143          // Done with this item, remove it now
1144          copyList.removeAt(i);
1145          break;
1146        }
1147      }
1148    }
1149
1150    // Now look for SWAP
1151    for (int i=0; i < copyList.count(); ++i) {
1152      if ( copyList.at(i).at(0) == workingDisk \
1153        && copyList.at(i).at(1) == workingSlice \
1154        && copyList.at(i).at(2) == "SWAP" ) {
1155
1156        // Write the partition line
1157        tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1158                 + copyList.at(i).at(3) + " " + copyList.at(i).at(4) \
1159                 + " none";
1160
1161        // Done with this item, remove it now
1162        copyList.removeAt(i);
1163        break;
1164      }
1165    }
1166 
1167    // Now look for any other partitions
1168    int count = copyList.count();
1169    for (int i=0; i < count; ++i) {
1170      if ( copyList.at(i).at(0) == workingDisk \
1171        && copyList.at(i).at(1) == workingSlice ) {
1172
1173        // Check if we have any extra arguments to throw on the end
1174        XtraTmp="";
1175        if ( ! copyList.at(i).at(5).isEmpty() )
1176          XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
1177
1178        // If we are working on the last partition, set the size to 0 to use remaining disk
1179        if ( i == (count - 1) ) 
1180                sliceSize = "0";
1181        else
1182                sliceSize=copyList.at(i).at(4);
1183
1184        // Write the partition line
1185        tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1186                 + copyList.at(i).at(3) + " " + sliceSize \
1187                 + " " + copyList.at(i).at(2) + XtraTmp;
1188
1189        // Check if we have an encryption passphrase to use
1190        if ( ! copyList.at(i).at(6).isEmpty() )
1191          tmpList << "encpass=" + copyList.at(i).at(6);
1192
1193        // Done with this item, remove it now
1194        copyList.removeAt(i);
1195        i--;
1196        count--;
1197      }
1198    }
1199
1200
1201    // Close out this partition section
1202    tmpList << "commitDiskLabel";
1203    tmpList << "";
1204
1205    // Increment our disk counter
1206    disk++;
1207  }
1208
1209  return tmpList;
1210}
1211
1212// Slot which checks any disk requirements before procceding to the next page
1213bool Installer::checkDiskRequirements()
1214{
1215  // For now just return true, the wizard should handle making sure
1216  // the user doesn't shoot themselves in the foot during disk setup
1217  return true;
1218}
1219
1220// Function which begins the backend install, and connects slots to monitor it
1221void Installer::startInstall()
1222{
1223
1224  // Update the UI elements if doing a restore
1225  if ( radioRestore->isChecked() )
1226  {
1227      labelFinished->setText(tr("Your system is now restored!\nClick Finish to reboot. After rebooting you may eject the install media."));
1228      groupInstall->setTitle(tr("System Restore"));
1229      labelInstallHeader->setText(tr("Your system is now being restored, this may take a while depending upon the size of your backup and network conditions."));
1230  }
1231
1232  QString cfgFile;
1233  if (customCfgFile.isEmpty() )
1234    cfgFile = PCSYSINSTALLCFG;
1235  else
1236    cfgFile = customCfgFile;
1237
1238  // Disable the back / next buttons until we are finished
1239  nextButton->setEnabled(false);
1240  backButton->setEnabled(false);
1241  progressBarInstall->setValue(0); 
1242  installFoundCounter = false;
1243  installFoundMetaCounter = false;
1244  installFoundFetchOutput = false;
1245  inZFSSend = false;
1246
1247  // Setup some defaults for the secondary progress bar
1248  progressBarInstall2->setValue(0); 
1249  progressBarInstall2->setHidden(true); 
1250  labelInstallStatus2->setText("");
1251  labelInstallStatus2->setHidden(true);
1252
1253  // Kill any hald instances, which causes failures to install when it
1254  // tries to mount our new partitions
1255  QProcess::execute("killall", QStringList() << "hald");
1256
1257  // Start our process to begin the install
1258  QString PCSYSINSTALL;
1259  if ( QFile::exists("/root/pc-sysinstall/pc-sysinstall") ) 
1260     PCSYSINSTALL = "/root/pc-sysinstall/pc-sysinstall";
1261  else 
1262     PCSYSINSTALL = "/usr/local/sbin/pc-sysinstall";
1263
1264  QString program = PCSYSINSTALL;
1265  QStringList arguments;
1266  arguments << "-c" << cfgFile;
1267
1268  installProc = new QProcess();
1269  installProc->setProcessChannelMode(QProcess::MergedChannels);
1270  connect(installProc,SIGNAL(finished( int, QProcess::ExitStatus)),this,SLOT(slotInstallProcFinished( int, QProcess::ExitStatus)));
1271  connect(installProc,SIGNAL(readyRead()),this,SLOT(slotReadInstallerOutput()));
1272  installProc->start(program, arguments);
1273
1274}
1275
1276// Function run when the install failed to prompt user for course of action
1277void Installer::installFailed()
1278{
1279   QString sysLog;
1280   labelInstallStatus->setText(tr("Failed!"));
1281
1282   QMessageBox msgBox;
1283   msgBox.setWindowTitle(tr("PC-BSD Installer"));
1284   msgBox.setIcon(QMessageBox::Critical);
1285   msgBox.setText(tr("The installer has encountered an error and has been halted."));
1286   msgBox.setInformativeText(tr("Do you want to generate an error report?"));
1287   msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1288   msgBox.setDefaultButton(QMessageBox::Yes);
1289
1290   // If we have a log, show it in the detailed view button
1291   if ( QFile::exists("/tmp/.pc-sysinstall/pc-sysinstall.log") )
1292   {
1293     QFile logFile("/tmp/.pc-sysinstall/pc-sysinstall.log");
1294     if (logFile.open(QIODevice::ReadOnly | QIODevice::Text))
1295         while (!logFile.atEnd())
1296           sysLog = sysLog + logFile.readLine() + "\n";
1297     msgBox.setDetailedText(sysLog);
1298   }
1299   int ret = msgBox.exec();
1300
1301   switch (ret) {
1302   case QMessageBox::Yes:
1303       // Generate the error report
1304       Scripts::Backend::createErrorReport();
1305       break;
1306   case QMessageBox::No: // :)
1307       break;
1308   }
1309
1310   QMessageBox msgBox2;
1311   msgBox2.setWindowTitle(tr("PC-BSD Installer"));
1312   msgBox2.setIcon(QMessageBox::Critical);
1313   msgBox2.setText(tr("Restart the system now?") );
1314   msgBox2.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1315   msgBox2.setDefaultButton(QMessageBox::Yes);
1316   msgBox2.setDetailedText(sysLog);
1317
1318   ret = msgBox2.exec();
1319
1320   switch (ret) {
1321   case QMessageBox::Yes:
1322       close();
1323       break;
1324   case QMessageBox::No: // :)
1325       break;
1326   }
1327
1328}
1329
1330// Slot which is called when the installation has finished
1331void Installer::slotInstallProcFinished( int exitCode, QProcess::ExitStatus status)
1332{
1333  QString tmp;
1334  if ( status != QProcess::NormalExit || exitCode != 0 )
1335  {
1336     installFailed();
1337  } else {
1338    // Move to the final page, and show a finish button
1339    proceed(true);
1340    nextButton->setEnabled(true);
1341    nextButton->setText(tr("&Finish"));
1342    nextButton->disconnect();
1343    connect(nextButton, SIGNAL(clicked()), this, SLOT(slotFinished()));
1344    backButton->setEnabled(false);
1345    abortButton->setEnabled(false);
1346  }
1347}
1348
1349// Slot which reads the output of the installer
1350void Installer::slotReadInstallerOutput()
1351{
1352  QString tmp, line;
1353  int range;
1354  bool ok;
1355
1356
1357  while ( installProc->canReadLine() )
1358  {
1359     tmp = installProc->readLine();
1360     tmp.truncate(75);
1361     //qDebug() << tmp;
1362
1363     // If doing a restore we can do all parsing right here
1364     if ( radioRestore->isChecked() ) {
1365       line = tmp;
1366
1367       if ( tmp.contains("total estimated size"))
1368       { 
1369          repTotalK = line.section(" ",-1).simplified();
1370          double totSize = displayToDoubleK(repTotalK);
1371          progressBarInstall->setRange(0, totSize + 1024);
1372          inZFSSend = true;
1373          continue;
1374       } 
1375       if ( tmp.contains("Moving datasets to"))
1376          inZFSSend=false;
1377
1378       if( line.contains("send from ") )
1379         continue;
1380       if( line.contains("TIME ") )
1381         continue;
1382
1383       labelInstallStatus->setText(tmp);
1384
1385       if ( ! inZFSSend )
1386          continue;
1387
1388       // We got here, lets parse the ZFS send message
1389       parseStatusMessage(tmp);
1390
1391       continue;
1392     } // End of restore parsing
1393
1394     // Parse fetch output
1395     if ( installFoundFetchOutput ) {
1396       if ( tmp.indexOf("SIZE: ") != -1 ) {
1397
1398          // Get the total range first
1399          line = tmp;
1400          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1401          tmp.truncate(tmp.indexOf(" ")); 
1402          range = tmp.toInt(&ok);
1403          if ( ok )
1404             progressBarInstall->setRange(0, range + 1);
1405
1406          // Now get the current progress
1407          tmp = line;
1408          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1409          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1410          range = tmp.toInt(&ok);
1411          if ( ok )
1412             progressBarInstall->setValue(range);
1413           
1414          continue;
1415        } else {
1416          installFoundFetchOutput = false;
1417          break;
1418        }
1419     } 
1420
1421     // Unknown point in install
1422     if ( ! installFoundCounter && ! installFoundMetaCounter ) {
1423
1424        // Check if we've found fetch output to update the progress bar with
1425        if ( tmp.indexOf("FETCH: ") != -1 ) {
1426          installFoundFetchOutput = true;
1427          break;
1428        }
1429
1430        if ( tmp.indexOf("INSTALLCOUNT: ") != -1 ) {
1431          tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1432          range = tmp.toInt(&ok);
1433          if ( ok ) {
1434             range = range + 50;
1435             progressBarInstall->setRange(0, range + 1); 
1436             installFoundCounter = true;
1437             if ( availDesktopPackageData )
1438                labelInstallStatus->setText(tr("Extracting system...")); 
1439             else
1440                labelInstallStatus->setText(tr("Installing system... This may take a while...")); 
1441          }
1442
1443          break;
1444
1445        } 
1446
1447        // Check if we are on the meta-pkg installation
1448        if ( tmp.indexOf("Packages to install: ") != -1 ) {
1449          tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1450          range = tmp.toInt(&ok);
1451          if ( ok ) {
1452             progressBarInstall->setRange(0, range + 1); 
1453             progressBarInstall->setValue(0); 
1454             progressBarInstall2->setRange(0, 0); 
1455             labelInstallStatus2->setHidden(false);
1456             progressBarInstall2->setHidden(false); 
1457             installFoundMetaCounter = true;
1458             installFoundCounter = false;
1459             labelInstallStatus->setText(tr("Installing packages... This may take a while...")); 
1460             continue;
1461          }
1462
1463        } 
1464
1465        labelInstallStatus->setText(tmp);
1466        continue; 
1467     } 
1468
1469     // Doing file-extraction still
1470     if ( installFoundCounter ) {
1471
1472       // Doing dist-files, may have multiple images to extract
1473       if ( tmp.indexOf("INSTALLCOUNT: ") != -1 ) {
1474         tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1475         range = tmp.toInt(&ok);
1476         if ( ok ) {
1477            progressBarInstall->setRange(0, range + 1); 
1478            installFoundCounter = true;
1479            if ( availDesktopPackageData )
1480              labelInstallStatus->setText(tr("Extracting system...")); 
1481            else
1482              labelInstallStatus->setText(tr("Installing system... This may take a while...")); 
1483         }
1484         break;
1485       } 
1486
1487
1488       // Increment the progress
1489       progressBarInstall->setValue(progressBarInstall->value() + 1); 
1490
1491       // We've reached the end of this counted section
1492       if ( tmp.indexOf("Extraction Finished") != -1 ) {
1493         installFoundCounter = false;
1494         progressBarInstall->setRange(0, 0); 
1495       }
1496
1497       continue;
1498     }
1499
1500     // Doing meta-pkgs
1501     if ( installFoundMetaCounter ) {
1502        // Check if we are on the next meta-pkg
1503        if ( tmp.indexOf("Installing package: ") != -1 ) {
1504           progressBarInstall->setValue(progressBarInstall->value() + 1); 
1505           labelInstallStatus->setText(tr("Installing meta-package: %1").arg(tmp.section(":", 1, 5))); 
1506           continue;
1507        }
1508
1509        if ( tmp.indexOf("Package installation complete!") != -1 ) {
1510           installFoundMetaCounter = false;
1511           progressBarInstall->setRange(0, 0); 
1512           progressBarInstall2->setHidden(true);
1513           labelInstallStatus2->setHidden(true);
1514           continue;
1515        }
1516
1517        // If we are installing a package, show details to user
1518        if ( tmp.indexOf("Installing") == 0 )
1519          labelInstallStatus2->setText(tmp.section("...", 0, 0));
1520     }
1521
1522  } // end of while loop
1523}
1524
1525// Return list of components to install
1526QStringList Installer::getComponentCfgSettings()
1527{
1528  QStringList componentList, com;
1529  if ( fSRC )
1530    com << "src";
1531  if ( fPORTS )
1532    com << "ports";
1533
1534  if ( ! com.isEmpty() ) {
1535    componentList << "";
1536    componentList << "# Optional Components";
1537    componentList << "installComponents=" + com.join(",");
1538  }
1539
1540  return componentList;
1541}
1542
1543// Start xvkbd
1544void Installer::slotPushVirtKeyboard()
1545{
1546   system("killall -9 xvkbd; xvkbd -compact &");
1547}
1548
1549// Return the configuration for desktop packages
1550QStringList Installer::getDeskPkgCfg()
1551{
1552   QStringList cfgList, pkgList;
1553   QString line;
1554
1555   QList<QStringList> curList;
1556
1557   if ( radioDesktop->isChecked() ) {
1558     curList = listDeskPkgs;
1559     pkgList << "pcbsd-base";
1560   } else {
1561     curList = listServerPkgs;
1562     pkgList << "trueos-base";
1563   }
1564
1565   // Loop though list of pkgs, see what to install
1566   for ( int d=0; d < curList.count(); ++d) {
1567     for ( int i=0; i < selectedPkgs.count(); ++i)
1568        // Is the package selected or the base-system?
1569        if ( curList.at(d).at(0) == selectedPkgs.at(i) || curList.at(d).at(0) == "base-system" ) {
1570
1571           // Yay! Lets get a list of packages to install
1572           QFile mFile;
1573           mFile.setFileName(curList.at(d).at(6));
1574           if ( ! mFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
1575              qDebug() << "Invalid meta-pkg list:" << curList.at(d).at(6);
1576              break;
1577           }
1578 
1579           // Read in the meta pkg list
1580           QTextStream in(&mFile);
1581           while ( !in.atEnd() ) {
1582             line = in.readLine().simplified();
1583             if ( line.isEmpty() )
1584                 continue; 
1585             
1586             pkgList << line.section(":", 0,0);
1587           }
1588           mFile.close();
1589           break;
1590        }
1591   }
1592
1593   cfgList << "installPackages=" + pkgList.join(" ");
1594   return cfgList;
1595}
1596
1597// Return list of users in cfg format
1598QStringList Installer::getUsersCfgSettings()
1599{
1600   QStringList userList;
1601 
1602   userList << "";
1603   userList << "# Root Password";
1604   userList << "rootPass=" + fRootPW;
1605
1606   userList << "";
1607   userList << "# Users";
1608   userList << "userName=" + fUserName;
1609   userList << "userComment=" + fName;
1610   userList << "userPass=" + fUserPW;
1611   userList << "userShell=" + fShell;
1612   userList << "userHome=/home/" + fUserName;
1613   userList << "userGroups=wheel,operator,vboxusers";
1614   userList << "commitUser";
1615   userList << "";
1616 
1617   return userList;
1618}
1619
1620void Installer::closeEvent(QCloseEvent *event)
1621{
1622    int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1623                                tr("Are you sure you want to abort this installation?"),
1624                                QMessageBox::No | QMessageBox::Yes,
1625                                QMessageBox::No);
1626    switch (ret) {
1627    case QMessageBox::Yes:
1628        //exit the installer :(
1629        break;
1630    case QMessageBox::No: // :)
1631        event->ignore();
1632        break;
1633    }
1634}
1635
1636void Installer::checkSpaceWarning()
1637{
1638  int totalSize = -1;
1639  int targetSize;
1640  int targetLoc;
1641  bool ok;
1642  QString workingDisk = sysFinalDiskLayout.at(0).at(0);
1643  QString workingSlice = sysFinalDiskLayout.at(0).at(1);
1644  QString targetType;
1645  QString target;
1646  //qDebug() << "Disk layout:" << workingDisk << workingSlice;
1647
1648  if ( workingSlice == "ALL" ) {
1649    targetType = "DRIVE";
1650    target = workingDisk;
1651    targetLoc = 1;
1652  } else {
1653    targetType = "SLICE";
1654    target = workingDisk + workingSlice;
1655    targetLoc = 2;
1656  }
1657 
1658  // Lets get the size for this disk / partition
1659  for (int i=0; i < sysDisks.count(); ++i) {
1660      // Make sure to only add the slices to the listDiskSlices
1661      if ( sysDisks.at(i).at(0) == targetType && target == sysDisks.at(i).at(targetLoc))
1662        totalSize = sysDisks.at(i).at(targetLoc + 1).toInt(&ok);
1663  }
1664
1665  //qDebug() << totalSize;
1666
1667  if ( radioServer->isChecked() )
1668     targetSize=20000;
1669  else
1670     targetSize=50000;
1671
1672  int tGB = targetSize / 1000;
1673
1674  qDebug() << totalSize << targetSize;
1675
1676  // Lets print a nice handy warning for users with possible
1677  // low disk space issues
1678  if ( totalSize < targetSize ) {
1679  QMessageBox::warning(this, tr("PC-BSD Installer"),
1680      QString(tr("The selected disk / partition is less than recommended %1GB. The installation may fail...")).arg(tGB),
1681      QMessageBox::Ok,
1682      QMessageBox::Ok);
1683      haveWarnedSpace = true;     
1684  }
1685
1686  return;
1687}
1688
1689void Installer::slotSaveConfigUSB()
1690{
1691  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1692           tr("This will save your installation configuration to a MSDOSFS/FAT32 formatted USB stick. Continue?"),
1693           QMessageBox::No | QMessageBox::Yes,
1694           QMessageBox::No);
1695  switch (ret) {
1696  case QMessageBox::Yes:
1697      break;
1698  case QMessageBox::No: // :)
1699      return;
1700      break;
1701  }
1702
1703  // Prompt to insert USB stick
1704  QMessageBox::information(this, tr("PC-BSD Installer"),
1705          tr("Please insert a USB stick now, and click OK to continue."),
1706          QMessageBox::Ok,
1707          QMessageBox::Ok);
1708
1709  // While USB is settling, this is a good time to ask for the config nickname
1710  bool ok;
1711  QString cfgName = QInputDialog::getText(this, tr("PC-BSD Installer"),
1712                 tr("Please enter the nickname you want to save this configuration as."), 
1713                 QLineEdit::Normal,
1714                 QString("default"), &ok);
1715  if (!ok || cfgName.isEmpty())
1716     return;
1717
1718  // Now lets try to save the media
1719  qDebug() << "Running: /root/save-to-usb.sh" << cfgName;
1720  QProcess m;
1721  m.start(QString("/root/save-to-usb.sh"), QStringList() << cfgName);
1722  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1723     m.waitForFinished(200);
1724     QCoreApplication::processEvents();
1725  }
1726
1727  if ( m.exitCode() != 0 ) {
1728     QMessageBox::critical(this, tr("PC-BSD Installer"),
1729          tr("Failed saving config to USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1730          QMessageBox::Ok,
1731          QMessageBox::Ok);
1732
1733  } else {
1734     QMessageBox::information(this, tr("PC-BSD Installer"),
1735          tr("Configuration saved! You may now safely remove the USB media."),
1736          QMessageBox::Ok,
1737          QMessageBox::Ok);
1738  }
1739 
1740}
1741
1742void Installer::slotLoadConfigUSB()
1743{
1744  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1745           tr("This will load a installation configuration file your MSDOSFS/FAT32 formatted USB stick. Continue?"),
1746           QMessageBox::No | QMessageBox::Yes,
1747           QMessageBox::No);
1748  switch (ret) {
1749  case QMessageBox::Yes:
1750      break;
1751  case QMessageBox::No: // :)
1752      return;
1753      break;
1754  }
1755
1756  // Prompt to insert USB stick
1757  QMessageBox::information(this, tr("PC-BSD Installer"),
1758          tr("Please insert the USB stick now, and click OK to continue."),
1759          QMessageBox::Ok,
1760          QMessageBox::Ok);
1761
1762  // Now lets try to load the config files
1763  qDebug() << "Running: /root/get-from-usb.sh";
1764  QProcess m;
1765  m.start(QString("/root/get-from-usb.sh"), QStringList());
1766  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1767     m.waitForFinished(200);
1768     QCoreApplication::processEvents();
1769  }
1770
1771  if ( m.exitCode() != 0 ) {
1772     QMessageBox::critical(this, tr("PC-BSD Installer"),
1773          tr("Failed loading saved config file from the USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1774          QMessageBox::Ok,
1775          QMessageBox::Ok);
1776     return;
1777
1778  } else {
1779     QMessageBox::information(this, tr("PC-BSD Installer"),
1780          tr("Configuration loaded! You may now safely remove the USB media."),
1781          QMessageBox::Ok,
1782          QMessageBox::Ok);
1783  }
1784
1785 
1786  // Yay! Now lets prompt the user as to which config to use
1787  QDir cDir;
1788  cDir.setPath("/tmp/pc-sys");
1789  QStringList cfgs = cDir.entryList(QDir::Files);
1790
1791  bool ok;
1792  QString cfgFile = QInputDialog::getItem(this, tr("PC-BSD Installer"),
1793                                       tr("Config File:"), cfgs, 0, false, &ok);
1794  if (!ok || cfgFile.isEmpty())
1795    return;
1796 
1797  ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1798           tr("Start the install using this config file?") + "\n" + cfgFile,
1799           QMessageBox::No | QMessageBox::Yes,
1800           QMessageBox::No);
1801  switch (ret) {
1802  case QMessageBox::Yes:
1803      break;
1804  case QMessageBox::No: // :)
1805      return;
1806      break;
1807  }
1808
1809  // Time to start the installation with our custom config file
1810  qDebug() << cfgFile;
1811  customCfgFile = "/tmp/pc-sys/" + cfgFile;
1812  installStackWidget->setCurrentIndex(3);
1813  startInstall();
1814}
1815
1816void Installer::slotStartNetworkManager() 
1817{
1818  system("/usr/local/bin/pc-netmanager -installer &");
1819}
1820
1821void Installer::slotSaveRestoreSettings(QStringList Opts)
1822{
1823  restOpts = Opts;
1824
1825  textEditDiskSummary->clear();
1826  QStringList summary = getDiskSummary();
1827  for ( int i=0; i < summary.count(); ++i)
1828    textEditDiskSummary->append(summary.at(i));
1829               
1830  textEditDiskSummary->moveCursor(QTextCursor::Start);
1831 
1832  startConfigGen();
1833  installStackWidget->setCurrentIndex(installStackWidget->currentIndex() + 1);
1834}
1835
1836void Installer::parseStatusMessage(QString stat){
1837  //qDebug() << "msg:" << stat;
1838  QString dispTotal;
1839
1840  //Divide up the status message into sections
1841  stat.replace("\t"," ");
1842  QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
1843
1844  //Now Setup the tooltip
1845  if(!repTotalK.isEmpty()){
1846    double c = displayToDoubleK(cSize);
1847    progressBarInstall->setValue(c);
1848    dispTotal = repTotalK;
1849  } else {
1850    dispTotal = "??";
1851  }
1852
1853  //Format the tooltip String
1854  QString status = cSize+"/"+dispTotal;
1855
1856  QString txt = QString(tr("Restoring system: %1")).arg(status);
1857  labelInstallStatus->setText(txt);
1858
1859}
1860
1861double Installer::displayToDoubleK(QString displayNumber){
1862  QStringList labels;
1863    labels << "K" << "M" << "G" << "T" << "P" << "E";
1864  QString clab = displayNumber.right(1); //last character is the size label
1865        displayNumber.chop(1); //remove the label from the number
1866  double num = displayNumber.toDouble();
1867  //Now format the number properly
1868  bool ok = false;
1869  for(int i=0; i<labels.length(); i++){
1870    if(labels[i] == clab){ ok = true; break; }
1871    else{ num = num*1024; } //get ready for the next size
1872  }
1873  if(!ok){ num = -1; } //could not determine the size
1874  return num;
1875}
1876
Note: See TracBrowser for help on using the repository browser.