source: src-qt4/pc-installgui/installer.cpp @ 1bfa1e0

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

When user is installing to a MBR slice, and declines to install GRUB on MBR, we
will instead stamp it on the particular slice being used. Then the user
can manage their own MBR boot-loader to chain-load GRUB from the slice

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