source: src-qt4/pc-installgui/installer.cpp @ 0e213ad

9.2-release
Last change on this file since 0e213ad was 0e213ad, checked in by Kris Moore <kris@…>, 9 months ago

Backport fix for >2TB drives

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