source: src-qt4/pc-installgui/installer.cpp @ 93572be

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

Welcome the new Life-Preserver restore ability to the Installer GUI

Now you can restore your entire system from a replicated life-preserver backup on a
remote machine

  • 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("Running chroot command: pkg info") != -1 ) {
1504           progressBarInstall->setValue(progressBarInstall->value() + 1); 
1505           continue;
1506        }
1507
1508        if ( tmp.indexOf("Package installation complete!") != -1 ) {
1509           installFoundMetaCounter = false;
1510           progressBarInstall->setRange(0, 0); 
1511           progressBarInstall2->setHidden(true);
1512           labelInstallStatus2->setHidden(true);
1513           continue;
1514        }
1515
1516        // If we are installing a package, show details to user
1517        if ( tmp.indexOf("Installing") == 0 )
1518          labelInstallStatus2->setText(tmp.section("...", 0, 0));
1519     }
1520
1521  } // end of while loop
1522}
1523
1524// Return list of components to install
1525QStringList Installer::getComponentCfgSettings()
1526{
1527  QStringList componentList, com;
1528  if ( fSRC )
1529    com << "src";
1530  if ( fPORTS )
1531    com << "ports";
1532
1533  if ( ! com.isEmpty() ) {
1534    componentList << "";
1535    componentList << "# Optional Components";
1536    componentList << "installComponents=" + com.join(",");
1537  }
1538
1539  return componentList;
1540}
1541
1542// Start xvkbd
1543void Installer::slotPushVirtKeyboard()
1544{
1545   system("killall -9 xvkbd; xvkbd -compact &");
1546}
1547
1548// Return the configuration for desktop packages
1549QStringList Installer::getDeskPkgCfg()
1550{
1551   QStringList cfgList, pkgList;
1552   QString line;
1553
1554   QList<QStringList> curList;
1555
1556   if ( radioDesktop->isChecked() ) {
1557     curList = listDeskPkgs;
1558     pkgList << "pcbsd-base";
1559   } else {
1560     curList = listServerPkgs;
1561     pkgList << "trueos-base";
1562   }
1563
1564   // Loop though list of pkgs, see what to install
1565   for ( int d=0; d < curList.count(); ++d) {
1566     for ( int i=0; i < selectedPkgs.count(); ++i)
1567        // Is the package selected or the base-system?
1568        if ( curList.at(d).at(0) == selectedPkgs.at(i) || curList.at(d).at(0) == "base-system" ) {
1569
1570           // Yay! Lets get a list of packages to install
1571           QFile mFile;
1572           mFile.setFileName(curList.at(d).at(6));
1573           if ( ! mFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
1574              qDebug() << "Invalid meta-pkg list:" << curList.at(d).at(6);
1575              break;
1576           }
1577 
1578           // Read in the meta pkg list
1579           QTextStream in(&mFile);
1580           while ( !in.atEnd() ) {
1581             line = in.readLine().simplified();
1582             if ( line.isEmpty() )
1583                 continue; 
1584             
1585             pkgList << line.section(":", 0,0);
1586           }
1587           mFile.close();
1588           break;
1589        }
1590   }
1591
1592   cfgList << "installPackages=" + pkgList.join(" ");
1593   return cfgList;
1594}
1595
1596// Return list of users in cfg format
1597QStringList Installer::getUsersCfgSettings()
1598{
1599   QStringList userList;
1600 
1601   userList << "";
1602   userList << "# Root Password";
1603   userList << "rootPass=" + fRootPW;
1604
1605   userList << "";
1606   userList << "# Users";
1607   userList << "userName=" + fUserName;
1608   userList << "userComment=" + fName;
1609   userList << "userPass=" + fUserPW;
1610   userList << "userShell=" + fShell;
1611   userList << "userHome=/home/" + fUserName;
1612   userList << "userGroups=wheel,operator,vboxusers";
1613   userList << "commitUser";
1614   userList << "";
1615 
1616   return userList;
1617}
1618
1619void Installer::closeEvent(QCloseEvent *event)
1620{
1621    int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1622                                tr("Are you sure you want to abort this installation?"),
1623                                QMessageBox::No | QMessageBox::Yes,
1624                                QMessageBox::No);
1625    switch (ret) {
1626    case QMessageBox::Yes:
1627        //exit the installer :(
1628        break;
1629    case QMessageBox::No: // :)
1630        event->ignore();
1631        break;
1632    }
1633}
1634
1635void Installer::checkSpaceWarning()
1636{
1637  int totalSize = -1;
1638  int targetSize;
1639  int targetLoc;
1640  bool ok;
1641  QString workingDisk = sysFinalDiskLayout.at(0).at(0);
1642  QString workingSlice = sysFinalDiskLayout.at(0).at(1);
1643  QString targetType;
1644  QString target;
1645  //qDebug() << "Disk layout:" << workingDisk << workingSlice;
1646
1647  if ( workingSlice == "ALL" ) {
1648    targetType = "DRIVE";
1649    target = workingDisk;
1650    targetLoc = 1;
1651  } else {
1652    targetType = "SLICE";
1653    target = workingDisk + workingSlice;
1654    targetLoc = 2;
1655  }
1656 
1657  // Lets get the size for this disk / partition
1658  for (int i=0; i < sysDisks.count(); ++i) {
1659      // Make sure to only add the slices to the listDiskSlices
1660      if ( sysDisks.at(i).at(0) == targetType && target == sysDisks.at(i).at(targetLoc))
1661        totalSize = sysDisks.at(i).at(targetLoc + 1).toInt(&ok);
1662  }
1663
1664  //qDebug() << totalSize;
1665
1666  if ( radioServer->isChecked() )
1667     targetSize=20000;
1668  else
1669     targetSize=50000;
1670
1671  int tGB = targetSize / 1000;
1672
1673  qDebug() << totalSize << targetSize;
1674
1675  // Lets print a nice handy warning for users with possible
1676  // low disk space issues
1677  if ( totalSize < targetSize ) {
1678  QMessageBox::warning(this, tr("PC-BSD Installer"),
1679      QString(tr("The selected disk / partition is less than recommended %1GB. The installation may fail...")).arg(tGB),
1680      QMessageBox::Ok,
1681      QMessageBox::Ok);
1682      haveWarnedSpace = true;     
1683  }
1684
1685  return;
1686}
1687
1688void Installer::slotSaveConfigUSB()
1689{
1690  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1691           tr("This will save your installation configuration to a MSDOSFS/FAT32 formatted USB stick. Continue?"),
1692           QMessageBox::No | QMessageBox::Yes,
1693           QMessageBox::No);
1694  switch (ret) {
1695  case QMessageBox::Yes:
1696      break;
1697  case QMessageBox::No: // :)
1698      return;
1699      break;
1700  }
1701
1702  // Prompt to insert USB stick
1703  QMessageBox::information(this, tr("PC-BSD Installer"),
1704          tr("Please insert a USB stick now, and click OK to continue."),
1705          QMessageBox::Ok,
1706          QMessageBox::Ok);
1707
1708  // While USB is settling, this is a good time to ask for the config nickname
1709  bool ok;
1710  QString cfgName = QInputDialog::getText(this, tr("PC-BSD Installer"),
1711                 tr("Please enter the nickname you want to save this configuration as."), 
1712                 QLineEdit::Normal,
1713                 QString("default"), &ok);
1714  if (!ok || cfgName.isEmpty())
1715     return;
1716
1717  // Now lets try to save the media
1718  qDebug() << "Running: /root/save-to-usb.sh" << cfgName;
1719  QProcess m;
1720  m.start(QString("/root/save-to-usb.sh"), QStringList() << cfgName);
1721  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1722     m.waitForFinished(200);
1723     QCoreApplication::processEvents();
1724  }
1725
1726  if ( m.exitCode() != 0 ) {
1727     QMessageBox::critical(this, tr("PC-BSD Installer"),
1728          tr("Failed saving config to USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1729          QMessageBox::Ok,
1730          QMessageBox::Ok);
1731
1732  } else {
1733     QMessageBox::information(this, tr("PC-BSD Installer"),
1734          tr("Configuration saved! You may now safely remove the USB media."),
1735          QMessageBox::Ok,
1736          QMessageBox::Ok);
1737  }
1738 
1739}
1740
1741void Installer::slotLoadConfigUSB()
1742{
1743  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1744           tr("This will load a installation configuration file your MSDOSFS/FAT32 formatted USB stick. Continue?"),
1745           QMessageBox::No | QMessageBox::Yes,
1746           QMessageBox::No);
1747  switch (ret) {
1748  case QMessageBox::Yes:
1749      break;
1750  case QMessageBox::No: // :)
1751      return;
1752      break;
1753  }
1754
1755  // Prompt to insert USB stick
1756  QMessageBox::information(this, tr("PC-BSD Installer"),
1757          tr("Please insert the USB stick now, and click OK to continue."),
1758          QMessageBox::Ok,
1759          QMessageBox::Ok);
1760
1761  // Now lets try to load the config files
1762  qDebug() << "Running: /root/get-from-usb.sh";
1763  QProcess m;
1764  m.start(QString("/root/get-from-usb.sh"), QStringList());
1765  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1766     m.waitForFinished(200);
1767     QCoreApplication::processEvents();
1768  }
1769
1770  if ( m.exitCode() != 0 ) {
1771     QMessageBox::critical(this, tr("PC-BSD Installer"),
1772          tr("Failed loading saved config file from the USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1773          QMessageBox::Ok,
1774          QMessageBox::Ok);
1775     return;
1776
1777  } else {
1778     QMessageBox::information(this, tr("PC-BSD Installer"),
1779          tr("Configuration loaded! You may now safely remove the USB media."),
1780          QMessageBox::Ok,
1781          QMessageBox::Ok);
1782  }
1783
1784 
1785  // Yay! Now lets prompt the user as to which config to use
1786  QDir cDir;
1787  cDir.setPath("/tmp/pc-sys");
1788  QStringList cfgs = cDir.entryList(QDir::Files);
1789
1790  bool ok;
1791  QString cfgFile = QInputDialog::getItem(this, tr("PC-BSD Installer"),
1792                                       tr("Config File:"), cfgs, 0, false, &ok);
1793  if (!ok || cfgFile.isEmpty())
1794    return;
1795 
1796  ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1797           tr("Start the install using this config file?") + "\n" + cfgFile,
1798           QMessageBox::No | QMessageBox::Yes,
1799           QMessageBox::No);
1800  switch (ret) {
1801  case QMessageBox::Yes:
1802      break;
1803  case QMessageBox::No: // :)
1804      return;
1805      break;
1806  }
1807
1808  // Time to start the installation with our custom config file
1809  qDebug() << cfgFile;
1810  customCfgFile = "/tmp/pc-sys/" + cfgFile;
1811  installStackWidget->setCurrentIndex(3);
1812  startInstall();
1813}
1814
1815void Installer::slotStartNetworkManager() 
1816{
1817  system("/usr/local/bin/pc-netmanager -installer &");
1818}
1819
1820void Installer::slotSaveRestoreSettings(QStringList Opts)
1821{
1822  restOpts = Opts;
1823
1824  textEditDiskSummary->clear();
1825  QStringList summary = getDiskSummary();
1826  for ( int i=0; i < summary.count(); ++i)
1827    textEditDiskSummary->append(summary.at(i));
1828               
1829  textEditDiskSummary->moveCursor(QTextCursor::Start);
1830 
1831  startConfigGen();
1832  installStackWidget->setCurrentIndex(installStackWidget->currentIndex() + 1);
1833}
1834
1835void Installer::parseStatusMessage(QString stat){
1836  //qDebug() << "msg:" << stat;
1837  QString dispTotal;
1838
1839  //Divide up the status message into sections
1840  stat.replace("\t"," ");
1841  QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
1842
1843  //Now Setup the tooltip
1844  if(!repTotalK.isEmpty()){
1845    double c = displayToDoubleK(cSize);
1846    progressBarInstall->setValue(c);
1847    dispTotal = repTotalK;
1848  } else {
1849    dispTotal = "??";
1850  }
1851
1852  //Format the tooltip String
1853  QString status = cSize+"/"+dispTotal;
1854
1855  QString txt = QString(tr("Restoring system: %1")).arg(status);
1856  labelInstallStatus->setText(txt);
1857
1858}
1859
1860double Installer::displayToDoubleK(QString displayNumber){
1861  QStringList labels;
1862    labels << "K" << "M" << "G" << "T" << "P" << "E";
1863  QString clab = displayNumber.right(1); //last character is the size label
1864        displayNumber.chop(1); //remove the label from the number
1865  double num = displayNumber.toDouble();
1866  //Now format the number properly
1867  bool ok = false;
1868  for(int i=0; i<labels.length(); i++){
1869    if(labels[i] == clab){ ok = true; break; }
1870    else{ num = num*1024; } //get ready for the next size
1871  }
1872  if(!ok){ num = -1; } //could not determine the size
1873  return num;
1874}
1875
Note: See TracBrowser for help on using the repository browser.