source: src-qt4/pc-installgui/installer.cpp @ 01ffd8dd

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

When the user changes language, we can also set a new keyboard layout
at the same time. TODO, add more fine-grained checks for a LANG
and the relevant keyboard layout

Trac Ticket: http://trac.pcbsd.org/ticket/697

  • Property mode set to 100644
File size: 55.7 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=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) << "" << "";
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    // Change the default keyboard layout
780    if ( langCode == "en" ) {
781       Scripts::Backend::changeKbMap(langCode, "pc104", "");
782    } else {
783       // TODO - At some point, add additional tests here and set more specific layouts
784       // based upon the language selected
785       Scripts::Backend::changeKbMap(langCode, "pc105", "intl");
786    }
787   
788}
789
790QStringList Installer::getGlobalCfgSettings()
791{
792
793  QStringList tmpList;
794  QString tmp, upDrive;
795
796  tmpList << "# Auto-Generated pc-sysinstall configuration";
797  tmpList << "installInteractive=no";
798
799  // Are we doing a restore?
800  if ( radioRestore->isChecked() )
801  {
802    tmpList << "installMode=zfsrestore";
803    tmpList << "";
804    tmpList << "sshHost=" + restOpts.at(0);
805    tmpList << "sshUser=" + restOpts.at(1);
806    tmpList << "sshPort=" + restOpts.at(2);
807    if ( ! restOpts.at(3).isEmpty() )
808      tmpList << "sshKey=" + restOpts.at(3);
809    tmpList << "zfsProps=" + restOpts.at(4);
810    tmp = restOpts.at(4);
811    tmp.replace(".lp-props-", "");
812    tmp.replace("#", "/");
813    tmpList << "zfsRemoteDataset=" + tmp;
814
815    // Using a custom zpool name?
816    if ( ! zpoolName.isEmpty() )
817      tmpList << "zpoolName=" + zpoolName;
818
819    // Are we force enabling ZFS 4K block sizes?
820    if ( force4K )
821      tmpList << "zfsForce4k=YES";
822
823    tmpList << "";
824    return tmpList;
825  } // End of restore options
826
827
828  if ( sysFinalDiskLayout.at(0).at(0) == "MANUAL" )
829  {
830    tmpList << "installMode=extract";
831    tmpList << "installLocation=/mnt";
832  } else {
833    // Doing a fresh install
834    tmpList << "installMode=fresh";
835  }
836 
837  QString distFiles;
838  distFiles="base doc games kernel";
839  if ( Arch == "amd64" )
840     distFiles+=" lib32";
841
842  // System type we are installing
843  if ( radioDesktop->isChecked() )
844    tmpList << "installType=PCBSD";
845  else
846    tmpList << "installType=FreeBSD";
847
848  tmpList << "packageType=dist";
849
850  // Set the distFiles being used
851  tmpList << "distFiles=" + distFiles;
852  tmpList << "";
853
854  // If we have a custom hostname, add it to the config
855  if ( ! fHost.isEmpty() )
856    tmpList << "hostname=" + fHost;
857
858  // Using a custom zpool name?
859  if ( ! zpoolName.isEmpty() )
860    tmpList << "zpoolName=" + zpoolName;
861
862  // Are we force enabling ZFS 4K block sizes?
863  if ( force4K )
864    tmpList << "zfsForce4k=YES";
865 
866  // Networking setup
867  if ( radioDesktop->isChecked() ) {
868    // PC-BSD network setup
869    tmpList << "netSaveDev=AUTO-DHCP-SLAAC";
870  } else {
871    // FreeBSD network setup
872    if ( fNetSettings.at(0) == "AUTO-DHCP" )
873      tmpList << "netSaveDev=AUTO-DHCP";
874    else if ( fNetSettings.at(0) == "AUTO-DHCP-SLAAC" ) {
875      tmpList << "netSaveDev=AUTO-DHCP-SLAAC";
876      // We cannot rely on SLAAC to provide DNS for example.  The same is true
877      // for DHCP but the worls seems to have forgotten...
878      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
879      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
880      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
881    } else if ( fNetSettings.at(0) == "IPv6-SLAAC" ) {
882       tmpList << "netSaveDev=IPv6-SLAAC";
883      // We cannot rely on SLAAC to provide DNS for example.  The same is true
884      // for DHCP but the worls seems to have forgotten...
885      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
886      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
887      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
888    } 
889    else
890    {
891      tmp = fNetSettings.at(0);
892      if ( tmp.indexOf(":") > 0 )
893        tmp.truncate(tmp.indexOf(":"));
894      tmpList << "netSaveDev=" + tmp;
895      tmpList << "netSaveIP_" + tmp + "=" + fNetSettings.at(1); 
896      tmpList << "netSaveMask_" + tmp + "=" + fNetSettings.at(2);
897      tmpList << "netSaveNameServer=" + fNetSettings.at(3);
898      tmpList << "netSaveDefaultRouter=" + fNetSettings.at(4);
899      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
900      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
901      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
902    }
903  }
904
905
906  // Doing install from /dist directory
907  tmpList << "installMedium=local"; 
908  tmpList << "localPath=/dist";
909
910  if ( comboLanguage->currentIndex() != 0 ) {
911    QString lang = languages.at(comboLanguage->currentIndex());
912    // Grab the language code
913    lang.truncate(lang.lastIndexOf(")"));
914    lang.remove(0, lang.lastIndexOf("(") + 1);
915    tmpList << "";
916    tmpList << "localizeLang=" + lang;
917  }
918
919  // Setup custom keyboard layouts
920  /* KPM
921  tmpList << "";
922  tmpList << "# Keyboard Layout Options";
923  tmp = comboBoxKeyboardModel->currentText();
924  tmp.truncate(tmp.indexOf(")"));
925  tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
926  tmpList << "localizeKeyModel=" + tmp;
927
928  tmp = listKbLayouts->currentItem()->text();
929  tmp.truncate(tmp.indexOf(")"));
930  tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
931  tmpList << "localizeKeyLayout=" + tmp;
932
933  tmp = listKbVariants->currentItem()->text();
934  if ( tmp != "<none>" ) {
935    tmp.truncate(tmp.indexOf(")"));
936    tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
937    tmpList << "localizeKeyVariant=" + tmp;
938  }
939  */
940
941  tmpList << " ";
942
943  return tmpList;
944}
945
946void Installer::startConfigGen()
947{
948
949  if ( ! haveWarnedSpace )
950     checkSpaceWarning();
951
952  QStringList cfgList;
953
954  // Generate the config file now
955  cfgList+=getGlobalCfgSettings();
956
957  cfgList+=getDiskCfgSettings();
958 
959  // We can skip these options if doing a restore
960  if ( ! radioRestore->isChecked() ) {
961
962    cfgList+=getComponentCfgSettings();
963
964    // Save the install config script to disk
965    cfgList << "runExtCommand=/root/save-config.sh";
966
967    cfgList+= "";
968
969    // If doing install from package disk
970    if ( hasPkgsOnMedia )
971      cfgList+=getDeskPkgCfg();
972
973    cfgList+= "";
974
975    if ( radioDesktop->isChecked() ) {
976      // Doing PC-BSD Install
977
978      QString lang;
979      if ( comboLanguage->currentIndex() != 0 )
980        lang = languages.at(comboLanguage->currentIndex()).section("(",1,1).section(")",0,0);
981      else
982        lang="en_US";
983
984      // Setup the desktop
985      cfgList << "runCommand=sh /usr/local/share/pcbsd/scripts/sys-init.sh desktop " + lang;
986
987      // Setup for a fresh system first boot
988      cfgList << "# Touch flags to enable PC-BSD setup at first boot";
989      cfgList << "runCommand=touch /var/.runxsetup";
990      cfgList << "runCommand=touch /var/.pcbsd-firstboot";
991      cfgList << "runCommand=touch /var/.pcbsd-firstgui";
992
993    } else {
994      // Doing TrueOS Install
995      cfgList+=getUsersCfgSettings();
996
997      // Enable SSH?
998      if ( fSSH )
999        cfgList << "runCommand=echo 'sshd_enable=\"YES\"' >>/etc/rc.conf";
1000
1001      // Setup the TrueOS server
1002      cfgList << "runCommand=sh /usr/local/share/pcbsd/scripts/sys-init.sh server";
1003
1004    } 
1005
1006    // Run newaliases to fix mail errors
1007    cfgList << "runCommand=newaliases";
1008
1009  } // End of restore check
1010
1011  // Now write out the cfgList to file
1012  QFile cfgfile( PCSYSINSTALLCFG );
1013  if ( cfgfile.open( QIODevice::WriteOnly ) ) {
1014    QTextStream stream( &cfgfile );
1015    for ( int i=0; i < cfgList.count(); ++i) {
1016      stream <<  cfgList.at(i) << "\n";
1017    }
1018    cfgfile.close();
1019  }
1020}
1021
1022void Installer::slotHelp()
1023{
1024        pcHelp = new dialogHelp();
1025        switch (installStackWidget->currentIndex()) {
1026        case 0:
1027                pcHelp->dialogInit(HELPTEXT0);
1028                break;
1029        case 1:
1030                pcHelp->dialogInit(HELPTEXT1);
1031                break;
1032        case 2:
1033                pcHelp->dialogInit(HELPTEXT2);
1034                break;
1035        case 3:
1036                pcHelp->dialogInit(HELPTEXT3);
1037                break;
1038        default:
1039                pcHelp->dialogInit("No help text...");
1040                break;
1041        }
1042        pcHelp->show();
1043}
1044
1045// Function which returns the pc-sysinstall cfg data
1046QStringList Installer::getDiskCfgSettings()
1047{
1048  QStringList tmpList;
1049  QList<QStringList> copyList;
1050  QString tmp, workingDisk, workingSlice, tmpSlice, XtraTmp, startPart, sliceSize;
1051  int disk = 0;
1052
1053  // Copy over the list to a new variable we can mangle without modifying the original
1054  copyList = sysFinalDiskLayout;
1055
1056  // Doing manual extraction
1057  if ( copyList.at(0).at(0) == "MANUAL" )
1058    return QStringList();
1059
1060  while ( ! copyList.empty() )
1061  {
1062    workingDisk = copyList.at(0).at(0);
1063    workingSlice = copyList.at(0).at(1);
1064    tmpSlice = workingSlice;
1065    tmpList << "# Disk Setup for " + workingDisk ;
1066
1067    // Check if this is an install to "Unused Space"
1068    for (int z=0; z < sysDisks.count(); ++z)
1069      if ( sysDisks.at(z).at(0) == "SLICE" \
1070        && sysDisks.at(z).at(2) == workingDisk + workingSlice \
1071        && sysDisks.at(z).at(4) == "Unused Space" )
1072          tmpSlice = "free";
1073
1074    tmpList << "disk" + tmp.setNum(disk) + "=" + workingDisk;
1075    tmpList << "partition=" + tmpSlice;
1076
1077    // Are we loading a boot-loader?
1078    if ( loadMBR )
1079      tmpList << "bootManager=GRUB";
1080    else {
1081      // If the user declined the GRUB MBR, but we are still using a slice, install it to the slice
1082      // for chain-loading later
1083      if ( tmpSlice != "ALL" && ! loadGPT )
1084        tmpList << "bootManager=GRUB-slice";
1085      else
1086        tmpList << "bootManager=none";
1087    }
1088
1089    // Set the GPT/MBR options
1090    if ( loadGPT ) 
1091      tmpList << "partscheme=GPT";
1092    else
1093      tmpList << "partscheme=MBR";
1094
1095    tmpList << "commitDiskPart";
1096    tmpList << "";
1097
1098    // If after doing the mirror, our list is empty, break out
1099    if ( copyList.empty() )
1100      break;
1101   
1102    // Now print the partition section for this slice
1103    tmpList << "# Partition Setup for " + workingDisk + "(" + workingSlice + ")";
1104    tmpList << "# All sizes are expressed in MB";
1105    tmpList << "# Avail FS Types, UFS, UFS+S, UFS+SUJ, UFS+J, ZFS, SWAP";
1106    tmpList << "# UFS.eli, UFS+S.eli, UFS+SUJ, UFS+J.eli, ZFS.eli, SWAP.eli";
1107
1108    // If there is a dedicated /boot partition, need to list that first, see what is found
1109    for (int i=0; i < copyList.count(); ++i) {
1110      QStringList mounts = copyList.at(i).at(2).split(",");
1111      for (int z = 0; z < mounts.size(); ++z) {
1112        if ( copyList.at(i).at(0) == workingDisk \
1113          && copyList.at(i).at(1) == workingSlice \
1114          && mounts.at(z) == "/boot" )
1115                startPart="/boot";
1116      }
1117    }
1118
1119    // If no dedicated /boot partition, then lets list "/" first
1120    if(startPart.isEmpty())
1121        startPart="/";
1122
1123    // Start by looking for the root partition
1124    for (int i=0; i < copyList.count(); ++i) {
1125      QStringList mounts = copyList.at(i).at(2).split(",");
1126      for (int z = 0; z < mounts.size(); ++z) {
1127        if ( copyList.at(i).at(0) == workingDisk \
1128          && copyList.at(i).at(1) == workingSlice \
1129          && mounts.at(z) == startPart ) {
1130
1131          // Check if we have any extra arguments to throw on the end
1132          XtraTmp="";
1133          if ( ! copyList.at(i).at(5).isEmpty() )
1134            XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
1135
1136          // Write out the partition line
1137          tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1138                   + copyList.at(i).at(3) + " " + copyList.at(i).at(4) \
1139                   + " " + copyList.at(i).at(2) + XtraTmp;
1140
1141          // Check if we have an encryption passphrase to use
1142          if ( ! copyList.at(i).at(6).isEmpty() )
1143            tmpList << "encpass=" + copyList.at(i).at(6);
1144
1145          // Done with this item, remove it now
1146          copyList.removeAt(i);
1147          break;
1148        }
1149      }
1150    }
1151
1152    // Now look for SWAP
1153    for (int i=0; i < copyList.count(); ++i) {
1154      if ( copyList.at(i).at(0) == workingDisk \
1155        && copyList.at(i).at(1) == workingSlice \
1156        && copyList.at(i).at(2) == "SWAP" ) {
1157
1158        // Write the partition line
1159        tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1160                 + copyList.at(i).at(3) + " " + copyList.at(i).at(4) \
1161                 + " none";
1162
1163        // Done with this item, remove it now
1164        copyList.removeAt(i);
1165        break;
1166      }
1167    }
1168 
1169    // Now look for any other partitions
1170    int count = copyList.count();
1171    for (int i=0; i < count; ++i) {
1172      if ( copyList.at(i).at(0) == workingDisk \
1173        && copyList.at(i).at(1) == workingSlice ) {
1174
1175        // Check if we have any extra arguments to throw on the end
1176        XtraTmp="";
1177        if ( ! copyList.at(i).at(5).isEmpty() )
1178          XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
1179
1180        // If we are working on the last partition, set the size to 0 to use remaining disk
1181        if ( i == (count - 1) ) 
1182                sliceSize = "0";
1183        else
1184                sliceSize=copyList.at(i).at(4);
1185
1186        // Write the partition line
1187        tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1188                 + copyList.at(i).at(3) + " " + sliceSize \
1189                 + " " + copyList.at(i).at(2) + XtraTmp;
1190
1191        // Check if we have an encryption passphrase to use
1192        if ( ! copyList.at(i).at(6).isEmpty() )
1193          tmpList << "encpass=" + copyList.at(i).at(6);
1194
1195        // Done with this item, remove it now
1196        copyList.removeAt(i);
1197        i--;
1198        count--;
1199      }
1200    }
1201
1202
1203    // Close out this partition section
1204    tmpList << "commitDiskLabel";
1205    tmpList << "";
1206
1207    // Increment our disk counter
1208    disk++;
1209  }
1210
1211  return tmpList;
1212}
1213
1214// Slot which checks any disk requirements before procceding to the next page
1215bool Installer::checkDiskRequirements()
1216{
1217  // For now just return true, the wizard should handle making sure
1218  // the user doesn't shoot themselves in the foot during disk setup
1219  return true;
1220}
1221
1222// Function which begins the backend install, and connects slots to monitor it
1223void Installer::startInstall()
1224{
1225
1226  // Update the UI elements if doing a restore
1227  if ( radioRestore->isChecked() )
1228  {
1229      labelFinished->setText(tr("Your system is now restored!\nClick Finish to reboot. After rebooting you may eject the install media."));
1230      groupInstall->setTitle(tr("System Restore"));
1231      labelInstallHeader->setText(tr("Your system is now being restored, this may take a while depending upon the size of your backup and network conditions."));
1232  }
1233
1234  QString cfgFile;
1235  if (customCfgFile.isEmpty() )
1236    cfgFile = PCSYSINSTALLCFG;
1237  else
1238    cfgFile = customCfgFile;
1239
1240  // Disable the back / next buttons until we are finished
1241  nextButton->setEnabled(false);
1242  backButton->setEnabled(false);
1243  progressBarInstall->setValue(0); 
1244  installFoundCounter = false;
1245  installFoundMetaCounter = false;
1246  installFoundFetchOutput = false;
1247  inZFSSend = false;
1248
1249  // Setup some defaults for the secondary progress bar
1250  progressBarInstall2->setValue(0); 
1251  progressBarInstall2->setHidden(true); 
1252  labelInstallStatus2->setText("");
1253  labelInstallStatus2->setHidden(true);
1254
1255  // Kill any hald instances, which causes failures to install when it
1256  // tries to mount our new partitions
1257  QProcess::execute("killall", QStringList() << "hald");
1258
1259  // Start our process to begin the install
1260  QString PCSYSINSTALL;
1261  if ( QFile::exists("/root/pc-sysinstall/pc-sysinstall") ) 
1262     PCSYSINSTALL = "/root/pc-sysinstall/pc-sysinstall";
1263  else 
1264     PCSYSINSTALL = "/usr/local/sbin/pc-sysinstall";
1265
1266  QString program = PCSYSINSTALL;
1267  QStringList arguments;
1268  arguments << "-c" << cfgFile;
1269
1270  installProc = new QProcess();
1271  installProc->setProcessChannelMode(QProcess::MergedChannels);
1272  connect(installProc,SIGNAL(finished( int, QProcess::ExitStatus)),this,SLOT(slotInstallProcFinished( int, QProcess::ExitStatus)));
1273  connect(installProc,SIGNAL(readyRead()),this,SLOT(slotReadInstallerOutput()));
1274  installProc->start(program, arguments);
1275
1276}
1277
1278// Function run when the install failed to prompt user for course of action
1279void Installer::installFailed()
1280{
1281   QString sysLog;
1282   labelInstallStatus->setText(tr("Failed!"));
1283
1284   QMessageBox msgBox;
1285   msgBox.setWindowTitle(tr("PC-BSD Installer"));
1286   msgBox.setIcon(QMessageBox::Critical);
1287   msgBox.setText(tr("The installer has encountered an error and has been halted."));
1288   msgBox.setInformativeText(tr("Do you want to generate an error report?"));
1289   msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1290   msgBox.setDefaultButton(QMessageBox::Yes);
1291
1292   // If we have a log, show it in the detailed view button
1293   if ( QFile::exists("/tmp/.pc-sysinstall/pc-sysinstall.log") )
1294   {
1295     QFile logFile("/tmp/.pc-sysinstall/pc-sysinstall.log");
1296     if (logFile.open(QIODevice::ReadOnly | QIODevice::Text))
1297         while (!logFile.atEnd())
1298           sysLog = sysLog + logFile.readLine() + "\n";
1299     msgBox.setDetailedText(sysLog);
1300   }
1301   int ret = msgBox.exec();
1302
1303   switch (ret) {
1304   case QMessageBox::Yes:
1305       // Generate the error report
1306       Scripts::Backend::createErrorReport();
1307       break;
1308   case QMessageBox::No: // :)
1309       break;
1310   }
1311
1312   QMessageBox msgBox2;
1313   msgBox2.setWindowTitle(tr("PC-BSD Installer"));
1314   msgBox2.setIcon(QMessageBox::Critical);
1315   msgBox2.setText(tr("Restart the system now?") );
1316   msgBox2.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1317   msgBox2.setDefaultButton(QMessageBox::Yes);
1318   msgBox2.setDetailedText(sysLog);
1319
1320   ret = msgBox2.exec();
1321
1322   switch (ret) {
1323   case QMessageBox::Yes:
1324       close();
1325       break;
1326   case QMessageBox::No: // :)
1327       break;
1328   }
1329
1330}
1331
1332// Slot which is called when the installation has finished
1333void Installer::slotInstallProcFinished( int exitCode, QProcess::ExitStatus status)
1334{
1335  QString tmp;
1336  if ( status != QProcess::NormalExit || exitCode != 0 )
1337  {
1338     installFailed();
1339  } else {
1340    // Move to the final page, and show a finish button
1341    proceed(true);
1342    nextButton->setEnabled(true);
1343    nextButton->setText(tr("&Finish"));
1344    nextButton->disconnect();
1345    connect(nextButton, SIGNAL(clicked()), this, SLOT(slotFinished()));
1346    backButton->setEnabled(false);
1347    abortButton->setEnabled(false);
1348  }
1349}
1350
1351// Slot which reads the output of the installer
1352void Installer::slotReadInstallerOutput()
1353{
1354  QString tmp, line;
1355  int range;
1356  bool ok;
1357
1358
1359  while ( installProc->canReadLine() )
1360  {
1361     tmp = installProc->readLine();
1362     tmp.truncate(75);
1363     //qDebug() << tmp;
1364
1365     // If doing a restore we can do all parsing right here
1366     if ( radioRestore->isChecked() ) {
1367       line = tmp;
1368
1369       if ( tmp.contains("total estimated size"))
1370       { 
1371          repTotalK = line.section(" ",-1).simplified();
1372          double totSize = displayToDoubleK(repTotalK);
1373          progressBarInstall->setRange(0, totSize + 1024);
1374          inZFSSend = true;
1375          continue;
1376       } 
1377       if ( tmp.contains("Moving datasets to"))
1378          inZFSSend=false;
1379
1380       if( line.contains("send from ") )
1381         continue;
1382       if( line.contains("TIME ") )
1383         continue;
1384
1385       labelInstallStatus->setText(tmp);
1386
1387       if ( ! inZFSSend )
1388          continue;
1389
1390       // We got here, lets parse the ZFS send message
1391       parseStatusMessage(tmp);
1392
1393       continue;
1394     } // End of restore parsing
1395
1396     // Parse fetch output
1397     if ( installFoundFetchOutput ) {
1398       if ( tmp.indexOf("SIZE: ") != -1 ) {
1399
1400          // Get the total range first
1401          line = tmp;
1402          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1403          tmp.truncate(tmp.indexOf(" ")); 
1404          range = tmp.toInt(&ok);
1405          if ( ok )
1406             progressBarInstall->setRange(0, range + 1);
1407
1408          // Now get the current progress
1409          tmp = line;
1410          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1411          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1412          range = tmp.toInt(&ok);
1413          if ( ok )
1414             progressBarInstall->setValue(range);
1415           
1416          continue;
1417        } else {
1418          installFoundFetchOutput = false;
1419          break;
1420        }
1421     } 
1422
1423     // Unknown point in install
1424     if ( ! installFoundCounter && ! installFoundMetaCounter ) {
1425
1426        // Check if we've found fetch output to update the progress bar with
1427        if ( tmp.indexOf("FETCH: ") != -1 ) {
1428          installFoundFetchOutput = true;
1429          break;
1430        }
1431
1432        if ( tmp.indexOf("INSTALLCOUNT: ") != -1 ) {
1433          tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1434          range = tmp.toInt(&ok);
1435          if ( ok ) {
1436             range = range + 50;
1437             progressBarInstall->setRange(0, range + 1); 
1438             installFoundCounter = true;
1439             if ( availDesktopPackageData )
1440                labelInstallStatus->setText(tr("Extracting system...")); 
1441             else
1442                labelInstallStatus->setText(tr("Installing system... This may take a while...")); 
1443          }
1444
1445          break;
1446
1447        } 
1448
1449        // Check if we are on the meta-pkg installation
1450        if ( tmp.indexOf("Packages to install: ") != -1 ) {
1451          tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1452          range = tmp.toInt(&ok);
1453          if ( ok ) {
1454             progressBarInstall->setRange(0, range + 1); 
1455             progressBarInstall->setValue(0); 
1456             progressBarInstall2->setRange(0, 0); 
1457             labelInstallStatus2->setHidden(false);
1458             progressBarInstall2->setHidden(false); 
1459             installFoundMetaCounter = true;
1460             installFoundCounter = false;
1461             labelInstallStatus->setText(tr("Installing packages... This may take a while...")); 
1462             continue;
1463          }
1464
1465        } 
1466
1467        labelInstallStatus->setText(tmp);
1468        continue; 
1469     } 
1470
1471     // Doing file-extraction still
1472     if ( installFoundCounter ) {
1473
1474       // Doing dist-files, may have multiple images to extract
1475       if ( tmp.indexOf("INSTALLCOUNT: ") != -1 ) {
1476         tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1477         range = tmp.toInt(&ok);
1478         if ( ok ) {
1479            progressBarInstall->setRange(0, range + 1); 
1480            installFoundCounter = true;
1481            if ( availDesktopPackageData )
1482              labelInstallStatus->setText(tr("Extracting system...")); 
1483            else
1484              labelInstallStatus->setText(tr("Installing system... This may take a while...")); 
1485         }
1486         break;
1487       } 
1488
1489
1490       // Increment the progress
1491       progressBarInstall->setValue(progressBarInstall->value() + 1); 
1492
1493       // We've reached the end of this counted section
1494       if ( tmp.indexOf("Extraction Finished") != -1 ) {
1495         installFoundCounter = false;
1496         progressBarInstall->setRange(0, 0); 
1497       }
1498
1499       continue;
1500     }
1501
1502     // Doing meta-pkgs
1503     if ( installFoundMetaCounter ) {
1504        // Check if we are on the next meta-pkg
1505        if ( tmp.indexOf("Installing package: ") != -1 ) {
1506           progressBarInstall->setValue(progressBarInstall->value() + 1); 
1507           labelInstallStatus->setText(tr("Installing meta-package: %1").arg(tmp.section(":", 1, 5))); 
1508           continue;
1509        }
1510
1511        if ( tmp.indexOf("Package installation complete!") != -1 ) {
1512           installFoundMetaCounter = false;
1513           progressBarInstall->setRange(0, 0); 
1514           progressBarInstall2->setHidden(true);
1515           labelInstallStatus2->setHidden(true);
1516           continue;
1517        }
1518
1519        // If we are installing a package, show details to user
1520        if ( tmp.indexOf("Installing") == 0 )
1521          labelInstallStatus2->setText(tmp.section("...", 0, 0));
1522     }
1523
1524  } // end of while loop
1525}
1526
1527// Return list of components to install
1528QStringList Installer::getComponentCfgSettings()
1529{
1530  QStringList componentList, com;
1531  if ( fSRC )
1532    com << "src";
1533  if ( fPORTS )
1534    com << "ports";
1535
1536  if ( ! com.isEmpty() ) {
1537    componentList << "";
1538    componentList << "# Optional Components";
1539    componentList << "installComponents=" + com.join(",");
1540  }
1541
1542  return componentList;
1543}
1544
1545// Start xvkbd
1546void Installer::slotPushVirtKeyboard()
1547{
1548   system("killall -9 xvkbd; xvkbd -compact &");
1549}
1550
1551// Return the configuration for desktop packages
1552QStringList Installer::getDeskPkgCfg()
1553{
1554   QStringList cfgList, pkgList;
1555   QString line;
1556
1557   QList<QStringList> curList;
1558
1559   if ( radioDesktop->isChecked() ) {
1560     curList = listDeskPkgs;
1561     pkgList << "pcbsd-base";
1562   } else {
1563     curList = listServerPkgs;
1564     pkgList << "trueos-base";
1565   }
1566
1567   // Loop though list of pkgs, see what to install
1568   for ( int d=0; d < curList.count(); ++d) {
1569     for ( int i=0; i < selectedPkgs.count(); ++i)
1570        // Is the package selected or the base-system?
1571        if ( curList.at(d).at(0) == selectedPkgs.at(i) || curList.at(d).at(0) == "base-system" ) {
1572
1573           // Yay! Lets get a list of packages to install
1574           QFile mFile;
1575           mFile.setFileName(curList.at(d).at(6));
1576           if ( ! mFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
1577              qDebug() << "Invalid meta-pkg list:" << curList.at(d).at(6);
1578              break;
1579           }
1580 
1581           // Read in the meta pkg list
1582           QTextStream in(&mFile);
1583           while ( !in.atEnd() ) {
1584             line = in.readLine().simplified();
1585             if ( line.isEmpty() )
1586                 continue; 
1587             
1588             pkgList << line.section(":", 0,0);
1589           }
1590           mFile.close();
1591           break;
1592        }
1593   }
1594
1595   cfgList << "installPackages=" + pkgList.join(" ");
1596   return cfgList;
1597}
1598
1599// Return list of users in cfg format
1600QStringList Installer::getUsersCfgSettings()
1601{
1602   QStringList userList;
1603 
1604   userList << "";
1605   userList << "# Root Password";
1606   userList << "rootPass=" + fRootPW;
1607
1608   userList << "";
1609   userList << "# Users";
1610   userList << "userName=" + fUserName;
1611   userList << "userComment=" + fName;
1612   userList << "userPass=" + fUserPW;
1613   userList << "userShell=" + fShell;
1614   userList << "userHome=/home/" + fUserName;
1615   userList << "userGroups=wheel,operator,vboxusers";
1616   userList << "commitUser";
1617   userList << "";
1618 
1619   return userList;
1620}
1621
1622void Installer::closeEvent(QCloseEvent *event)
1623{
1624    int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1625                                tr("Are you sure you want to abort this installation?"),
1626                                QMessageBox::No | QMessageBox::Yes,
1627                                QMessageBox::No);
1628    switch (ret) {
1629    case QMessageBox::Yes:
1630        //exit the installer :(
1631        break;
1632    case QMessageBox::No: // :)
1633        event->ignore();
1634        break;
1635    }
1636}
1637
1638void Installer::checkSpaceWarning()
1639{
1640  int totalSize = -1;
1641  int targetSize;
1642  int targetLoc;
1643  bool ok;
1644  QString workingDisk = sysFinalDiskLayout.at(0).at(0);
1645  QString workingSlice = sysFinalDiskLayout.at(0).at(1);
1646  QString targetType;
1647  QString target;
1648  //qDebug() << "Disk layout:" << workingDisk << workingSlice;
1649
1650  if ( workingSlice == "ALL" ) {
1651    targetType = "DRIVE";
1652    target = workingDisk;
1653    targetLoc = 1;
1654  } else {
1655    targetType = "SLICE";
1656    target = workingDisk + workingSlice;
1657    targetLoc = 2;
1658  }
1659 
1660  // Lets get the size for this disk / partition
1661  for (int i=0; i < sysDisks.count(); ++i) {
1662      // Make sure to only add the slices to the listDiskSlices
1663      if ( sysDisks.at(i).at(0) == targetType && target == sysDisks.at(i).at(targetLoc))
1664        totalSize = sysDisks.at(i).at(targetLoc + 1).toInt(&ok);
1665  }
1666
1667  //qDebug() << totalSize;
1668
1669  if ( radioServer->isChecked() )
1670     targetSize=20000;
1671  else
1672     targetSize=50000;
1673
1674  int tGB = targetSize / 1000;
1675
1676  qDebug() << totalSize << targetSize;
1677
1678  // Lets print a nice handy warning for users with possible
1679  // low disk space issues
1680  if ( totalSize < targetSize ) {
1681  QMessageBox::warning(this, tr("PC-BSD Installer"),
1682      QString(tr("The selected disk / partition is less than recommended %1GB. The installation may fail...")).arg(tGB),
1683      QMessageBox::Ok,
1684      QMessageBox::Ok);
1685      haveWarnedSpace = true;     
1686  }
1687
1688  return;
1689}
1690
1691void Installer::slotSaveConfigUSB()
1692{
1693  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1694           tr("This will save your installation configuration to a MSDOSFS/FAT32 formatted USB stick. Continue?"),
1695           QMessageBox::No | QMessageBox::Yes,
1696           QMessageBox::No);
1697  switch (ret) {
1698  case QMessageBox::Yes:
1699      break;
1700  case QMessageBox::No: // :)
1701      return;
1702      break;
1703  }
1704
1705  // Prompt to insert USB stick
1706  QMessageBox::information(this, tr("PC-BSD Installer"),
1707          tr("Please insert a USB stick now, and click OK to continue."),
1708          QMessageBox::Ok,
1709          QMessageBox::Ok);
1710
1711  // While USB is settling, this is a good time to ask for the config nickname
1712  bool ok;
1713  QString cfgName = QInputDialog::getText(this, tr("PC-BSD Installer"),
1714                 tr("Please enter the nickname you want to save this configuration as."), 
1715                 QLineEdit::Normal,
1716                 QString("default"), &ok);
1717  if (!ok || cfgName.isEmpty())
1718     return;
1719
1720  // Now lets try to save the media
1721  qDebug() << "Running: /root/save-to-usb.sh" << cfgName;
1722  QProcess m;
1723  m.start(QString("/root/save-to-usb.sh"), QStringList() << cfgName);
1724  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1725     m.waitForFinished(200);
1726     QCoreApplication::processEvents();
1727  }
1728
1729  if ( m.exitCode() != 0 ) {
1730     QMessageBox::critical(this, tr("PC-BSD Installer"),
1731          tr("Failed saving config to USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1732          QMessageBox::Ok,
1733          QMessageBox::Ok);
1734
1735  } else {
1736     QMessageBox::information(this, tr("PC-BSD Installer"),
1737          tr("Configuration saved! You may now safely remove the USB media."),
1738          QMessageBox::Ok,
1739          QMessageBox::Ok);
1740  }
1741 
1742}
1743
1744void Installer::slotLoadConfigUSB()
1745{
1746  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1747           tr("This will load a installation configuration file your MSDOSFS/FAT32 formatted USB stick. Continue?"),
1748           QMessageBox::No | QMessageBox::Yes,
1749           QMessageBox::No);
1750  switch (ret) {
1751  case QMessageBox::Yes:
1752      break;
1753  case QMessageBox::No: // :)
1754      return;
1755      break;
1756  }
1757
1758  // Prompt to insert USB stick
1759  QMessageBox::information(this, tr("PC-BSD Installer"),
1760          tr("Please insert the USB stick now, and click OK to continue."),
1761          QMessageBox::Ok,
1762          QMessageBox::Ok);
1763
1764  // Now lets try to load the config files
1765  qDebug() << "Running: /root/get-from-usb.sh";
1766  QProcess m;
1767  m.start(QString("/root/get-from-usb.sh"), QStringList());
1768  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1769     m.waitForFinished(200);
1770     QCoreApplication::processEvents();
1771  }
1772
1773  if ( m.exitCode() != 0 ) {
1774     QMessageBox::critical(this, tr("PC-BSD Installer"),
1775          tr("Failed loading saved config file from the USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1776          QMessageBox::Ok,
1777          QMessageBox::Ok);
1778     return;
1779
1780  } else {
1781     QMessageBox::information(this, tr("PC-BSD Installer"),
1782          tr("Configuration loaded! You may now safely remove the USB media."),
1783          QMessageBox::Ok,
1784          QMessageBox::Ok);
1785  }
1786
1787 
1788  // Yay! Now lets prompt the user as to which config to use
1789  QDir cDir;
1790  cDir.setPath("/tmp/pc-sys");
1791  QStringList cfgs = cDir.entryList(QDir::Files);
1792
1793  bool ok;
1794  QString cfgFile = QInputDialog::getItem(this, tr("PC-BSD Installer"),
1795                                       tr("Config File:"), cfgs, 0, false, &ok);
1796  if (!ok || cfgFile.isEmpty())
1797    return;
1798 
1799  ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1800           tr("Start the install using this config file?") + "\n" + cfgFile,
1801           QMessageBox::No | QMessageBox::Yes,
1802           QMessageBox::No);
1803  switch (ret) {
1804  case QMessageBox::Yes:
1805      break;
1806  case QMessageBox::No: // :)
1807      return;
1808      break;
1809  }
1810
1811  // Time to start the installation with our custom config file
1812  qDebug() << cfgFile;
1813  customCfgFile = "/tmp/pc-sys/" + cfgFile;
1814  installStackWidget->setCurrentIndex(3);
1815  startInstall();
1816}
1817
1818void Installer::slotStartNetworkManager() 
1819{
1820  system("/usr/local/bin/pc-netmanager -installer &");
1821}
1822
1823void Installer::slotSaveRestoreSettings(QStringList Opts)
1824{
1825  restOpts = Opts;
1826
1827  textEditDiskSummary->clear();
1828  QStringList summary = getDiskSummary();
1829  for ( int i=0; i < summary.count(); ++i)
1830    textEditDiskSummary->append(summary.at(i));
1831               
1832  textEditDiskSummary->moveCursor(QTextCursor::Start);
1833 
1834  startConfigGen();
1835  installStackWidget->setCurrentIndex(installStackWidget->currentIndex() + 1);
1836}
1837
1838void Installer::parseStatusMessage(QString stat){
1839  //qDebug() << "msg:" << stat;
1840  QString dispTotal;
1841
1842  //Divide up the status message into sections
1843  stat.replace("\t"," ");
1844  QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
1845
1846  //Now Setup the tooltip
1847  if(!repTotalK.isEmpty()){
1848    double c = displayToDoubleK(cSize);
1849    progressBarInstall->setValue(c);
1850    dispTotal = repTotalK;
1851  } else {
1852    dispTotal = "??";
1853  }
1854
1855  //Format the tooltip String
1856  QString status = cSize+"/"+dispTotal;
1857
1858  QString txt = QString(tr("Restoring system: %1")).arg(status);
1859  labelInstallStatus->setText(txt);
1860
1861}
1862
1863double Installer::displayToDoubleK(QString displayNumber){
1864  QStringList labels;
1865    labels << "K" << "M" << "G" << "T" << "P" << "E";
1866  QString clab = displayNumber.right(1); //last character is the size label
1867        displayNumber.chop(1); //remove the label from the number
1868  double num = displayNumber.toDouble();
1869  //Now format the number properly
1870  bool ok = false;
1871  for(int i=0; i<labels.length(); i++){
1872    if(labels[i] == clab){ ok = true; break; }
1873    else{ num = num*1024; } //get ready for the next size
1874  }
1875  if(!ok){ num = -1; } //could not determine the size
1876  return num;
1877}
1878
Note: See TracBrowser for help on using the repository browser.