~ubuntu-branches/ubuntu/precise/qapt/precise

« back to all changes in this revision

Viewing changes to .pc/kubuntu_01_dont_close_stdout.diff/src/worker/workerinstallprogress.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Thomas
  • Date: 2011-01-26 21:27:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110126212709-ffsm3rdrs3ami6d6
Tags: 1.1.0-0ubuntu2
Add kubuntu_01_dont_close_stdout.diff from upstream to fix the failure
of postinst scripts needing stdout. (LP: #680328)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright © 2010 Jonathan Thomas <echidnaman@kubuntu.org>             *
 
3
 *                                                                         *
 
4
 *   This program is free software; you can redistribute it and/or         *
 
5
 *   modify it under the terms of the GNU General Public License as        *
 
6
 *   published by the Free Software Foundation; either version 2 of        *
 
7
 *   the License or (at your option) version 3 or any later version        *
 
8
 *   accepted by the membership of KDE e.V. (or its successor approved     *
 
9
 *   by the membership of KDE e.V.), which shall act as a proxy            *
 
10
 *   defined in Section 14 of version 3 of the license.                    *
 
11
 *                                                                         *
 
12
 *   This program is distributed in the hope that it will be useful,       *
 
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
15
 *   GNU General Public License for more details.                          *
 
16
 *                                                                         *
 
17
 *   You should have received a copy of the GNU General Public License     *
 
18
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 
19
 ***************************************************************************/
 
20
 
 
21
#include "workerinstallprogress.h"
 
22
 
 
23
#include <QtCore/QStringBuilder>
 
24
#include <QtCore/QStringList>
 
25
#include <QtCore/QFile>
 
26
 
 
27
#include <apt-pkg/error.h>
 
28
 
 
29
#include <sys/statvfs.h>
 
30
#include <sys/statfs.h>
 
31
#include <sys/wait.h>
 
32
#include <sys/fcntl.h>
 
33
#include <errno.h>
 
34
 
 
35
#include <iostream>
 
36
#include <stdlib.h>
 
37
 
 
38
#include "../globals.h"
 
39
#include "worker.h"
 
40
 
 
41
using namespace std;
 
42
 
 
43
WorkerInstallProgress::WorkerInstallProgress(QAptWorker* parent)
 
44
        : QObject(parent)
 
45
        , m_worker(parent)
 
46
        , m_questionResponse(QVariantMap())
 
47
        , m_startCounting(false)
 
48
{
 
49
    setenv("DEBIAN_FRONTEND", "passthrough", 1);
 
50
    setenv("DEBCONF_PIPE", "/tmp/qapt-sock", 1);
 
51
    // TODO: apt-listchanges
 
52
    setenv("APT_LISTCHANGES_FRONTEND", "none", 1);
 
53
}
 
54
 
 
55
WorkerInstallProgress::~WorkerInstallProgress()
 
56
{
 
57
}
 
58
 
 
59
pkgPackageManager::OrderResult WorkerInstallProgress::start(pkgPackageManager *pm)
 
60
{
 
61
    pkgPackageManager::OrderResult res;
 
62
 
 
63
    res = pm->DoInstallPreFork();
 
64
    if (res == pkgPackageManager::Failed) {
 
65
        return res;
 
66
    }
 
67
 
 
68
    int readFromChildFD[2];
 
69
    int writeToChildFD[2];
 
70
 
 
71
    //Initialize both pipes
 
72
    if (pipe(readFromChildFD) < 0 || pipe(writeToChildFD) < 0) {
 
73
        return res;
 
74
    }
 
75
 
 
76
    m_child_id = fork();
 
77
    if (m_child_id == -1) {
 
78
        return res;
 
79
    } else if (m_child_id == 0) {
 
80
        close(0);
 
81
 
 
82
        if (dup(writeToChildFD[0]) != 0) {
 
83
            close(readFromChildFD[1]);
 
84
            close(writeToChildFD[0]);
 
85
            _exit(1);
 
86
        }
 
87
 
 
88
        // close Forked stdout and the read end of the pipe
 
89
        close(1);
 
90
 
 
91
        res = pm->DoInstallPostFork(readFromChildFD[1]);
 
92
 
 
93
        // dump errors into cerr (pass it to the parent process)
 
94
        _error->DumpErrors();
 
95
 
 
96
        close(readFromChildFD[0]);
 
97
        close(writeToChildFD[1]);
 
98
        close(readFromChildFD[1]);
 
99
        close(writeToChildFD[0]);
 
100
 
 
101
        _exit(res);
 
102
    }
 
103
 
 
104
    // make it nonblocking
 
105
    fcntl(readFromChildFD[0], F_SETFL, O_NONBLOCK);
 
106
 
 
107
    // Check if the child died
 
108
    int ret;
 
109
    while (waitpid(m_child_id, &ret, WNOHANG) == 0) {
 
110
        updateInterface(readFromChildFD[0], writeToChildFD[1]);
 
111
    }
 
112
 
 
113
    close(readFromChildFD[0]);
 
114
    close(readFromChildFD[1]);
 
115
    close(writeToChildFD[0]);
 
116
    close(writeToChildFD[1]);
 
117
 
 
118
    return res;
 
119
}
 
120
 
 
121
void WorkerInstallProgress::updateInterface(int fd, int writeFd)
 
122
{
 
123
    char buf[2];
 
124
    static char line[1024] = "";
 
125
 
 
126
    while (1) {
 
127
        // This algorithm should be improved (it's the same as the rpm one ;)
 
128
        int len = read(fd, buf, 1);
 
129
 
 
130
        // nothing was read
 
131
        if (len < 1) {
 
132
            break;
 
133
        }
 
134
 
 
135
        if (buf[0] == '\n') {
 
136
            const QStringList list = QString::fromUtf8(line).split(QLatin1Char(':'));
 
137
            const QString status = list.at(0);
 
138
            const QString package = list.at(1);
 
139
            QString percent = list.at(2);
 
140
            QString str = list.at(3);
 
141
 
 
142
            // If str legitimately had a ':' in it (such as a package version)
 
143
            // we need to retrieve the next string in the list.
 
144
            if (list.count() == 5) {
 
145
                str += QString(QLatin1Char(':') % list.at(4));
 
146
            }
 
147
 
 
148
            if (package.isEmpty() || status.isEmpty()) {
 
149
                continue;
 
150
            }
 
151
 
 
152
            if (status.contains(QLatin1String("pmerror"))) {
 
153
                QVariantMap args;
 
154
                args[QLatin1String("FailedItem")] = package;
 
155
                args[QLatin1String("ErrorText")] = str;
 
156
                emit commitError(QApt::CommitError, args);
 
157
            } else if (status.contains(QLatin1String("pmconffile"))) {
 
158
                // From what I understand, the original file starts after the ' character ('\'') and
 
159
                // goes to a second ' character. The new conf file starts at the next ' and goes to
 
160
                // the next '.
 
161
                QStringList strList = str.split(QLatin1Char('\''));
 
162
                QString oldFile = strList.at(1);
 
163
                QString newFile = strList.at(2);
 
164
 
 
165
                QVariantMap args;
 
166
                args[QLatin1String("OldConfFile")] = oldFile;
 
167
                args[QLatin1String("NewConfFile")] = newFile;
 
168
                //TODO: diff support
 
169
 
 
170
                QVariantMap result = askQuestion(QApt::ConfFilePrompt, args);
 
171
 
 
172
                bool replaceFile = result[QLatin1String("ReplaceFile")].toBool();
 
173
 
 
174
                if (replaceFile) {
 
175
                    ssize_t reply = write(writeFd, "Y\n", 2);
 
176
                    Q_UNUSED(reply);
 
177
                } else {
 
178
                    ssize_t reply = write(writeFd, "N\n", 2);
 
179
                    Q_UNUSED(reply);
 
180
                }
 
181
            } else {
 
182
                m_startCounting = true;
 
183
            }
 
184
 
 
185
            int percentage;
 
186
            if (percent.contains(QLatin1Char('.'))) {
 
187
                QStringList percentList = percent.split(QLatin1Char('.'));
 
188
                percentage = percentList.at(0).toInt();
 
189
            } else {
 
190
                percentage = percent.toInt();
 
191
            }
 
192
 
 
193
            emit commitProgress(str, percentage);
 
194
            // clean-up
 
195
            line[0] = 0;
 
196
        } else {
 
197
            buf[1] = 0;
 
198
            strcat(line, buf);
 
199
        }
 
200
    }
 
201
    // 30 frames per second
 
202
    usleep(1000000/30);
 
203
}
 
204
 
 
205
QVariantMap WorkerInstallProgress::askQuestion(int questionCode, const QVariantMap &args)
 
206
{
 
207
    m_questionBlock = new QEventLoop;
 
208
    connect(m_worker, SIGNAL(answerReady(const QVariantMap&)),
 
209
            this, SLOT(setAnswer(const QVariantMap&)));
 
210
 
 
211
    emit workerQuestion(questionCode, args);
 
212
    m_questionBlock->exec(); // Process blocked, waiting for answerReady signal over dbus
 
213
 
 
214
    return m_questionResponse;
 
215
}
 
216
 
 
217
void WorkerInstallProgress::setAnswer(const QVariantMap &answer)
 
218
{
 
219
    disconnect(m_worker, SIGNAL(answerReady(const QVariantMap&)),
 
220
               this, SLOT(setAnswer(const QVariantMap&)));
 
221
    m_questionResponse = answer;
 
222
    m_questionBlock->quit();
 
223
}