source: src-qt4/pc-installgui/installer.cpp

Last change on this file was db8d936, checked in by Kris Moore <kris@…>, 5 weeks ago

Add icon for Emergency shell to installer GUI. Allows users
to access some of our shell utils, such as disk-mounting, and eventually
other tools

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