source: src-qt4/pc-updatecenter/syscontroller.cpp @ 2f75b29

enter/10releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1releng/10.1.1releng/10.1.2
Last change on this file since 2f75b29 was 2f75b29, checked in by yurkis <yurkis@…>, 16 months ago

Update center: Fix for freebsd update check parsing.

  • Property mode set to 100644
File size: 17.3 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2013- by Yuri Momotyuk                                   *
3*   yurkis@gmail.com                                                      *
4*                                                                         *
5*   Permission is hereby granted, free of charge, to any person obtaining *
6*   a copy of this software and associated documentation files (the       *
7*   "Software"), to deal in the Software without restriction, including   *
8*   without limitation the rights to use, copy, modify, merge, publish,   *
9*   distribute, sublicense, and/or sell copies of the Software, and to    *
10*   permit persons to whom the Software is furnished to do so, subject to *
11*   the following conditions:                                             *
12*                                                                         *
13*   The above copyright notice and this permission notice shall be        *
14*   included in all copies or substantial portions of the Software.       *
15*                                                                         *
16*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
17*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
18*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
19*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
20*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
21*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
22*   OTHER DEALINGS IN THE SOFTWARE.                                       *
23***************************************************************************/
24
25#include "syscontroller.h"
26#include "utils.h"
27#include "pcbsd-utils.h"
28#include <QDebug>
29#include <QRegExp>
30
31__string_constant PC_UPDATE_COMMAND = "pc-updatemanager";
32//_STRING_CONSTANT FBSD_UPDATE_COMMAND = "cat";
33__string_constant FBSD_UPDATE_COMMAND = "pc-fbsdupdatecheck";
34static const QStringList PC_UPDATE_ARGS(QStringList()<<"check");
35static const QStringList FBSD_UPDATE_ARGS (QStringList()<<"update");
36//static const QStringList FBSD_UPDATE_ARGS (QStringList()<<"/home/yurkis/_sysbasesys_check.txt");
37
38__string_constant NAME_TAG = "NAME:";
39__string_constant TYPE_TAG = "TYPE:";
40__string_constant TAG_TAG = "TAG:";
41__string_constant VERSION_TAG = "VERSION:";
42__string_constant DEATILS_TAG = "DETAILS:";
43__string_constant DATE_TAG = "DATE:";
44__string_constant SIZE_TAG = "SIZE:";
45__string_constant CU_END_MARKER = "To install:";
46__string_constant PATCH_TYPE = "PATCH";
47__string_constant SYSUPDATE_TYPE = "SYSUPDATE";
48__string_constant STANDALONE_TAG = "STANDALONE:";
49__string_constant REQUIRESREBOOT_TAG = "REQUIRESREBOOT:";
50
51__string_constant FILES_MODIFYED_LOCALLY = "been downloaded because the files have been modified locally:";
52__string_constant FILES_TO_DELETE = "The following files will be removed as part of updating to";
53__string_constant FILES_TO_UPDATE = "The following files will be updated as part of updating to";
54
55__string_constant NETWORKING_PROBLEM= "No mirrors remaining, giving up.";
56
57__string_constant SYS_PATCH_DOWNLOADING_WORD= "DOWNLOADING:";
58__string_constant SYS_PATCH_FETCH= "FETCH";
59__string_constant SYS_PATCH_DL_FINISHED= "DOWNLOADFINISHED:";
60__string_constant SYS_PATCH_TOTAL_STEPS= "TOTALSTEPS:";
61__string_constant SYS_PATCH_SETSTEPS= "SETSTEPS:";
62__string_constant SYS_PATCH_MSG= "MSG:";
63__string_constant SYS_PATCH_FINISHED= "INSTALLFINISHED:";
64
65__string_constant UPDATE_DESCRIPTIONS_FETCH_COMMAND = "fetch -q -o-";
66__string_constant UPDATE_DESCRIPTIONS_URL = "http://fbsd-update.pcbsd.org/updates.desc";
67__string_constant UPDATE_DESCRIPTIONS_FIELDS_SEPARATOR = ":::";
68
69__string_constant FILES_REQUIRED_REBOOT []= { "/boot/*", "/usr/lib/libc*" };
70
71const int FILES_REQUIRED_REBOOT_SIZE = sizeof(FILES_REQUIRED_REBOOT) / sizeof(char*);
72
73///////////////////////////////////////////////////////////////////////////////
74CSysController::CSysController()
75{
76    misFREEBSDCheck= false;
77
78    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
79    env.insert("PCFETCHGUI", "YES");
80    process().setProcessEnvironment(env);
81    misFBSDRebootRequired= false;
82    misRebootRequired = false;
83    mCurrCheckState = eUndefined;
84}
85
86///////////////////////////////////////////////////////////////////////////////
87bool CSysController::rebootRequired()
88{
89    return misRebootRequired && (currentState()!= eUPDATING);
90}
91
92///////////////////////////////////////////////////////////////////////////////
93QVector<CSysController::SFbsdUpdatesDescription> CSysController::updateDescriptions(QString RelName, bool isForse)
94{
95    QVector<CSysController::SFbsdUpdatesDescription> out;
96
97    if (!mvFbsdUpdateDescriptions.size() || isForse)
98    {
99        QStringList fetch_out = pcbsd::Utils::runShellCommand(QString(UPDATE_DESCRIPTIONS_FETCH_COMMAND) + " " + UPDATE_DESCRIPTIONS_URL);
100        mvFbsdUpdateDescriptions.clear();
101        for (int i=0; i<fetch_out.size(); i++)
102        {
103            SFbsdUpdatesDescription entry;
104            QStringList line_split = fetch_out[i].split(UPDATE_DESCRIPTIONS_FIELDS_SEPARATOR);
105            if (line_split.size() < 3)
106                continue;
107            entry.mRelease = line_split[0];
108            entry.mDescription = line_split[2];
109            entry.mUpdateNo = line_split[1].toInt();
110            mvFbsdUpdateDescriptions.push_back(entry);
111        }
112    }
113
114    //filter by RelName
115    for (int i=0; i<mvFbsdUpdateDescriptions.size(); i++)
116    {
117        if ((!RelName.length()) || RelName.trimmed().toUpper() == mvFbsdUpdateDescriptions[i].mRelease.trimmed().toUpper() )
118        {
119            out.push_back(mvFbsdUpdateDescriptions[i]);
120        }
121    }
122    return out;
123}
124
125///////////////////////////////////////////////////////////////////////////////
126void CSysController::updateSelected(QVector<CSysController::SSystemUpdate> selectedUpdates)
127{
128    mvUpdatesToApply= selectedUpdates;
129    mCurrentUpdate= 0;
130    launchUpdate();
131}
132
133///////////////////////////////////////////////////////////////////////////////
134void CSysController::onCheckUpdates()
135{
136    misFREEBSDCheck= false;
137    mCurrCheckState = eUndefined;
138    mvUpdates.clear();
139    mFilesLocallyModifyed.clear();
140    mFilesToRemove.clear();
141    mFilesToUpdate.clear();
142    mCurrentFbsdDescription = tr("Base system update");
143    updateDescriptions();
144}
145
146///////////////////////////////////////////////////////////////////////////////
147void CSysController::onUpdateAll()
148{
149    mvUpdatesToApply = mvUpdates;
150    mCurrentUpdate= 0;
151    launchUpdate();
152}
153
154///////////////////////////////////////////////////////////////////////////////
155void CSysController::checkShellCommand(QString &cmd, QStringList &args)
156{
157    if (misFREEBSDCheck)
158    {
159        cmd= FBSD_UPDATE_COMMAND;
160        args= FBSD_UPDATE_ARGS;
161        mCurrCheckState = eUndefined;
162    }
163    else
164    {
165        cmd= PC_UPDATE_COMMAND;
166        args= PC_UPDATE_ARGS;
167    }
168    //TODO: add sudo if regular user
169    //if ()
170}
171
172///////////////////////////////////////////////////////////////////////////////
173void CSysController::updateShellCommand(QString &cmd, QStringList &args)
174{
175    if (mCurrentUpdate>=mvUpdatesToApply.size())
176        return;
177
178    ESysUpdate currUpdateType= mvUpdatesToApply[mCurrentUpdate].mType;
179    if ((currUpdateType == ePATCH) || (currUpdateType == eSYSUPDATE))
180    {
181        cmd= PC_UPDATE_COMMAND;
182        args= QStringList()<<"install"<<mvUpdatesToApply[mCurrentUpdate].mTag;
183    }
184    else
185    {
186        cmd="freebsd-update";
187        args= QStringList()<<"install";
188    }
189
190}
191
192///////////////////////////////////////////////////////////////////////////////
193void CSysController::onReadCheckLine(QString line)
194{   
195    if (misFREEBSDCheck)
196        parseCheckFREEBSDLine(line);
197    else
198        parseCheckPCBSDLine(line);
199
200}
201
202///////////////////////////////////////////////////////////////////////////////
203void CSysController::onReadUpdateLine(QString line)
204{
205    line= line.trimmed();
206    if (mCurrentUpdate>=mvUpdatesToApply.size())
207        return;
208    ESysUpdate currUpdateType= mvUpdatesToApply[mCurrentUpdate].mType;
209    misRebootRequired |= mvUpdatesToApply[mCurrentUpdate].misRequiresReboot;
210
211    switch(currUpdateType)
212    {
213        case ePATCH:
214            parsePatchUpdateLine(line);
215            break;
216        case eSYSUPDATE:
217            parseUpgradeLine(line);
218            break;
219        case eFBSDUPDATE:
220            parseFreeBSDUpdateLine(line);
221            break;
222    }
223}
224
225///////////////////////////////////////////////////////////////////////////////
226void CSysController::onReadProcessChar(char character)
227{
228    qDebug()<<character;
229}
230
231///////////////////////////////////////////////////////////////////////////////
232void CSysController::onCheckProcessfinished(int exitCode)
233{
234    if (!misFREEBSDCheck)
235    {       
236        misFREEBSDCheck= true;
237        misFBSDRebootRequired= false;
238        launchCheck();
239    }
240    else
241    {       
242        if (mFilesToRemove.size() || mFilesToUpdate.size())
243        {
244            SSystemUpdate entry;
245            entry.mName = mCurrentFbsdDescription;
246            entry.mType= eFBSDUPDATE;
247            entry.misRequiresReboot= misFBSDRebootRequired;
248            mvUpdates.push_back(entry);
249        }
250
251        int n= mvUpdates.size();
252
253        if (n)
254        {
255
256            if (n>1)
257                reportUpdatesAvail(tr("%1 system updates avilable").arg(QString::number(n)));
258            else
259                reportUpdatesAvail(tr("System update is available"));
260            return;
261        }
262        else
263        {
264            if (!exitCode)
265            {
266                setCurrentState(eFULLY_UPDATED);
267            }
268            else
269            {
270                reportError(tr("Error while system update check process"));
271            }
272            return;
273        }
274    }
275}
276
277///////////////////////////////////////////////////////////////////////////////
278void CSysController::onUpdateProcessfinished(int exitCode)
279{
280    Q_UNUSED(exitCode);
281
282    if (currentState() != eUPDATING)
283        return;
284    mCurrentUpdate++;
285    if (mCurrentUpdate == mvUpdatesToApply.size())
286    {
287        if (misRebootRequired)
288        {
289            system("touch /tmp/.fbsdup-reboot");
290        }
291        check();
292    }
293    else
294    {
295        launchUpdate();
296    }
297}
298
299///////////////////////////////////////////////////////////////////////////////
300void CSysController::onCancel()
301{
302    process().terminate();
303    process().waitForFinished();
304    check();
305}
306
307///////////////////////////////////////////////////////////////////////////////
308void CSysController::parseCheckPCBSDLine(QString line)
309{
310    /*if (line == QString("Your system is up to date!"))
311    {
312        setCurrentState(eFULLY_UPDATED);
313    }*/   
314    static SSystemUpdate upd;
315    line= line.trimmed();
316
317#define _GET_TAG(tag, field)  if(line.indexOf(tag) == 0) {upd.field = line.replace(tag,""); return;}
318    _GET_TAG(NAME_TAG, mName);
319    _GET_TAG(TAG_TAG, mTag);
320    _GET_TAG(VERSION_TAG, mVersion);
321    _GET_TAG(DEATILS_TAG, mDetails);
322    _GET_TAG(SIZE_TAG, mSize);
323#undef _GET_TAG
324
325    if (line.indexOf(TYPE_TAG) == 0)
326    {
327        line= line.replace(TYPE_TAG, "");
328        if (line.contains(SYSUPDATE_TYPE))
329        {
330            upd.mType = eSYSUPDATE;
331        }
332        else
333        {
334            upd.mType = ePATCH;
335        }
336    }
337
338    if (line.indexOf(DATE_TAG) == 0)
339    {
340        //Example:
341        // DATE: 02-10-2013
342        // x     ^0 ^1 ^2   (m-d-y)?
343        QString y,m,d;
344        line= line.replace(DATE_TAG, "");
345        QStringList line_list = line.split("-");
346        upd.mDate= QDate(line_list[2].toInt(),
347                         line_list[0].toInt(),
348                         line_list[1].toInt());       
349        return;
350    }
351
352    if (line.indexOf(STANDALONE_TAG) == 0)
353    {
354        line= line.replace(STANDALONE_TAG, "");
355        if (line.trimmed().toLower() == "yes")
356            upd.misStandalone= true;
357    }
358
359    if (line.indexOf(REQUIRESREBOOT_TAG) == 0)
360    {
361        line= line.replace(REQUIRESREBOOT_TAG, "");
362        if (line.trimmed().toLower() == "yes")
363            upd.misRequiresReboot= true;
364    }
365
366    if (line.indexOf(CU_END_MARKER) == 0)
367    {
368        mvUpdates.push_back(upd);
369        upd = SSystemUpdate();
370        return;
371    }
372}
373
374///////////////////////////////////////////////////////////////////////////////
375void CSysController::parseCheckFREEBSDLine(QString line)
376{
377    line=line.trimmed();
378    if (!line.length())
379    {
380        return;
381    }
382
383    if (line.contains(NETWORKING_PROBLEM) && (!mvUpdates.size()))
384    {
385        reportError(tr("Error during update check. Check network connection"));
386    }
387
388    if (line.contains(FILES_MODIFYED_LOCALLY))
389    {
390        mCurrCheckState= eFilesModifyedLocally;
391        return;
392    }
393    else if (line.contains(FILES_TO_DELETE))
394    {
395        mCurrCheckState= eFilesToDelete;
396        mCurrentFbsdDescription= fbsdUpdateDescription(line);
397        return;
398    }
399    else if (line.contains(FILES_TO_UPDATE))
400    {       
401        mCurrCheckState= eFilesToUpdate;
402        mCurrentFbsdDescription= fbsdUpdateDescription(line);
403
404        return;
405    }
406
407
408    if (eFilesModifyedLocally == mCurrCheckState)
409    {
410        mFilesLocallyModifyed<<line;
411    }
412    else
413    if (eFilesToDelete == mCurrCheckState)
414    {
415        mFilesToRemove<<line;
416    }
417    else
418    if(eFilesToUpdate == mCurrCheckState)
419    {
420        mFilesToUpdate<<line;
421        // Check if reboot requuired.
422        // FILES_REQUIRED_REBOOT const array contains wildcards for files.
423        // Modification of that files requires system reboot
424        QRegExp rx;
425        rx.setPatternSyntax(QRegExp::WildcardUnix);
426        for (int i=0; i<FILES_REQUIRED_REBOOT_SIZE; i++)
427        {
428            rx.setPattern(FILES_REQUIRED_REBOOT[i]);
429            if (rx.exactMatch(line))
430            {
431                misFBSDRebootRequired= true;
432            }//if match
433        }//for all wildcard
434    }
435
436}
437
438///////////////////////////////////////////////////////////////////////////////
439void CSysController::parsePatchUpdateLine(QString line)
440{
441    SProgress progress;
442    static int total_steps = 0;
443    QString dl_speed;
444    long dl_size, dl_complete;
445
446    line= line.trimmed();
447
448    if (line.indexOf(SYS_PATCH_DOWNLOADING_WORD) == 0)
449    {
450        reportLogLine(QString("---------------------"));
451        reportLogLine(QString("Installing update ") + mvUpdatesToApply[mCurrentUpdate].mName);
452        reportLogLine(line.replace(SYS_PATCH_DOWNLOADING_WORD, "Downloading"));
453        progress.mMessage= tr("Preparing to download ") + mvUpdatesToApply[mCurrentUpdate].mName;
454        reportProgress(progress);
455        return;
456    }
457    else
458    if (line.indexOf(SYS_PATCH_FETCH) == 0)
459    {
460        return;
461    }
462    else
463    if (parseFetchOutput(line, dl_size, dl_complete, dl_speed))
464    {
465        progress.mMessage=tr("Downloading update (%1/%2 at %3)").arg(pcbsd::Utils::bytesToHumanReadable(dl_size),
466                                                                   pcbsd::Utils::bytesToHumanReadable(dl_complete),
467                                                                   dl_speed);
468        progress.mProgressMax= dl_size;
469        progress.mProgressCurr= dl_complete;
470        progress.mSubstate= eDownload;
471        progress.misCanCancel= true;
472        reportProgress(progress);
473        return;
474    }
475    else
476    if (line.indexOf(SYS_PATCH_TOTAL_STEPS) == 0)
477    {
478        line.replace(SYS_PATCH_TOTAL_STEPS, "");
479        total_steps= line.toInt();
480        return;
481    }
482    else
483    if (line.indexOf(SYS_PATCH_SETSTEPS) == 0)
484    {
485        line.replace(SYS_PATCH_SETSTEPS, "");
486        progress.mMessage= tr("Installing update ") + mvUpdatesToApply[mCurrentUpdate].mName;
487        progress.mProgressMax= total_steps;
488        progress.mProgressCurr= line.toInt();
489        progress.mSubstate= eInstall;
490        reportProgress(progress);
491        return;
492    }
493    else
494    if (line.indexOf(SYS_PATCH_MSG) == 0)
495    {
496        line.replace(SYS_PATCH_MSG, "");
497        reportLogLine(line);
498        return;
499    }
500    else
501    if (line.indexOf(SYS_PATCH_FINISHED) == 0)
502    {
503        reportLogLine(QString("Finished install: ") + mvUpdatesToApply[mCurrentUpdate].mName);
504        return;
505    }
506
507}
508
509///////////////////////////////////////////////////////////////////////////////
510void CSysController::parseUpgradeLine(QString line)
511{
512    SProgress progress;
513    progress.mMessage = tr("Installing system upgrade");
514    reportProgress(progress);
515    reportLogLine(line);
516}
517
518///////////////////////////////////////////////////////////////////////////////
519void CSysController::parseFreeBSDUpdateLine(QString line)
520{
521    SProgress progress;
522    progress.mMessage = tr("Installing system update");
523    reportProgress(progress);
524    reportLogLine(line);
525}
526
527///////////////////////////////////////////////////////////////////////////////
528QString CSysController::fbsdUpdateDescription(QString line)
529{
530    // Example line: "The following files will be updated as part of updating to 10.0-RELEASE-p3:"
531    line = line.trimmed();
532    QString release = line.right(line.length() - line.lastIndexOf(" "));
533    release = release.left(release.lastIndexOf("-")).trimmed();
534    QString patch = line.right(line.length() - line.lastIndexOf("-")).replace("-p","").replace(':',"");
535    int patch_num = patch.toInt();
536    QVector<SFbsdUpdatesDescription> descrs = updateDescriptions(release);
537
538    QString ret = tr("Base system update");
539
540    for(int i=0; i<descrs.size(); i++)
541    {
542        if (descrs[i].mUpdateNo == patch_num)
543        {
544            ret = descrs[i].mDescription;
545            break;
546        }
547    }
548    return ret;
549}
Note: See TracBrowser for help on using the repository browser.