source: src-qt4/pc-installgui/installer.cpp @ 199284b

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

Remove vboxusers from users created via installer GUI

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