source: src-qt4/pc-installgui/installer.cpp @ 8d3682c

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

Add the ability for the GUI installer to detect your country and try to
set the default language based upon it. This will work ONLY if the
installer was able to connect to the internet.

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