~ubuntu-branches/ubuntu/oneiric/partitionmanager/oneiric

« back to all changes in this revision

Viewing changes to src/core/libparted.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Mercatante
  • Date: 2009-01-23 17:57:36 UTC
  • Revision ID: james.westby@ubuntu.com-20090123175736-2ltrhgg3m55dokbm
Tags: upstream-1.0.0~beta1a
ImportĀ upstreamĀ versionĀ 1.0.0~beta1a

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2008 by Volker Lanz <vl@fidra.de>                       *
 
3
 *                                                                         *
 
4
 *   This program is free software; you can redistribute it and/or modify  *
 
5
 *   it under the terms of the GNU General Public License as published by  *
 
6
 *   the Free Software Foundation; either version 2 of the License, or     *
 
7
 *   (at your option) any later version.                                   *
 
8
 *                                                                         *
 
9
 *   This program is distributed in the hope that it will be useful,       *
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
12
 *   GNU General Public License for more details.                          *
 
13
 *                                                                         *
 
14
 *   You should have received a copy of the GNU General Public License     *
 
15
 *   along with this program; if not, write to the                         *
 
16
 *   Free Software Foundation, Inc.,                                       *
 
17
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
 
18
 ***************************************************************************/
 
19
 
 
20
/** @file
 
21
*/
 
22
 
 
23
#include "core/libparted.h"
 
24
#include "core/device.h"
 
25
#include "core/partition.h"
 
26
#include "core/partitiontable.h"
 
27
#include "core/operationstack.h"
 
28
 
 
29
#include "jobs/setpartflagsjob.h"
 
30
 
 
31
#include "fs/filesystem.h"
 
32
#include "fs/filesystemfactory.h"
 
33
 
 
34
#include "util/globallog.h"
 
35
 
 
36
#include <QString>
 
37
#include <QStringList>
 
38
#include <QList>
 
39
#include <QFile>
 
40
#include <QMap>
 
41
 
 
42
#include <kdebug.h>
 
43
#include <klocale.h>
 
44
 
 
45
#include <parted/parted.h>
 
46
#include <sys/statvfs.h>
 
47
#include <unistd.h>
 
48
 
 
49
/** Callback to handle exceptions from libparted
 
50
        @param e the libparted exception to handle
 
51
*/
 
52
static PedExceptionOption pedExceptionHandler(PedException* e)
 
53
{
 
54
        /** @todo These messages should end up in the Report, not in the GlobalLog. */
 
55
        log(log::error) << i18nc("@info/plain", "LibParted Exception: %1", QString::fromLocal8Bit(e->message));
 
56
        return PED_EXCEPTION_UNHANDLED;
 
57
}
 
58
 
 
59
/** Finds a device by UUID.
 
60
        @param s the UUID
 
61
        @return the device node the UUID links to
 
62
*/
 
63
static QString findUuidDevice(const QString& s)
 
64
{
 
65
        const QString filename = "/dev/disk/by-uuid/" + QString(s).remove("UUID=", Qt::CaseInsensitive);
 
66
        return QFile::exists(filename) ? QFile::symLinkTarget(filename) : "";
 
67
}
 
68
 
 
69
/** Reads mountpoints from a file.
 
70
        @param filename the name of the file to read mount points from
 
71
        @param result reference to QMap where the result will be stored
 
72
*/
 
73
static void readMountpoints(const QString& filename, QMap<QString, QStringList>& result)
 
74
{
 
75
        QFile file(filename);
 
76
        if (!file.open(QIODevice::ReadOnly))
 
77
                return;
 
78
 
 
79
        QByteArray line = file.readLine();
 
80
 
 
81
        while(!line.isEmpty())
 
82
        {
 
83
                line = line.simplified();
 
84
 
 
85
                if (!line.isEmpty() && (line[0] == '/' || line.startsWith("UUID=")))
 
86
                {
 
87
                        QList<QByteArray> split = line.split(' ');
 
88
 
 
89
                        if (split.size() >= 2)
 
90
                        {
 
91
                                QString device = split[0];
 
92
 
 
93
                                if (device.startsWith("UUID=", Qt::CaseInsensitive))
 
94
                                        device = findUuidDevice(device);
 
95
 
 
96
                                if (!device.isEmpty())
 
97
                                {
 
98
                                        QString mountPoint = split[1].replace("\\040", " ");
 
99
 
 
100
                                        if (QFile::exists(mountPoint) && result[device].indexOf(mountPoint) == -1)
 
101
                                                result[device].append(mountPoint);
 
102
                                }
 
103
                        }
 
104
                }
 
105
 
 
106
                line = file.readLine();
 
107
        }
 
108
}
 
109
 
 
110
/** Reads sectors used on a FileSystem using libparted functions.
 
111
        @param pedDisk pointer to pedDisk  where the Partition and its FileSystem are
 
112
        @param p the Partition the FileSystem is on
 
113
        @return the number of sectors used
 
114
*/
 
115
static qint64 readSectorsUsedLibParted(PedDisk* pedDisk, const Partition& p)
 
116
{
 
117
        Q_ASSERT(pedDisk);
 
118
 
 
119
        qint64 rval = -1;
 
120
 
 
121
        PedPartition* pedPartition = ped_disk_get_partition_by_sector(pedDisk, p.firstSector());
 
122
 
 
123
        if (pedPartition)
 
124
        {
 
125
                PedFileSystem* pedFileSystem = ped_file_system_open(&pedPartition->geom);
 
126
 
 
127
                if (pedFileSystem)
 
128
                {
 
129
                        if (PedConstraint* pedConstraint = ped_file_system_get_resize_constraint(pedFileSystem))
 
130
                        {
 
131
                                rval = pedConstraint->min_size;
 
132
                                ped_constraint_destroy(pedConstraint);
 
133
                        }
 
134
 
 
135
                        ped_file_system_close(pedFileSystem);
 
136
                }
 
137
        }
 
138
 
 
139
        return rval;
 
140
}
 
141
 
 
142
/** Reads the sectors used in a FileSystem and stores the result in the Partition's FileSystem object.
 
143
        @param pedDisk pointer to pedDisk  where the Partition and its FileSystem are
 
144
        @param p the Partition the FileSystem is on
 
145
        @param mountInfo map of mount points for the partition in question
 
146
*/
 
147
static void readSectorsUsed(PedDisk* pedDisk, Partition& p, QMap<QString, QStringList>& mountInfo)
 
148
{
 
149
        Q_ASSERT(pedDisk);
 
150
 
 
151
        struct statvfs sfs;
 
152
 
 
153
        if (p.isMounted() && mountInfo[p.deviceNode()].size() > 0 && statvfs(mountInfo[p.deviceNode()][0].toLatin1(), &sfs) == 0)
 
154
                p.fileSystem().setSectorsUsed((sfs.f_blocks - sfs.f_bfree) * sfs.f_bsize / p.sectorSize());
 
155
        else if (p.fileSystem().supportGetUsed() == FileSystem::SupportExternal)
 
156
                p.fileSystem().setSectorsUsed(p.fileSystem().readUsedCapacity(p.deviceNode()) / p.sectorSize());
 
157
        else if (p.fileSystem().supportGetUsed() == FileSystem::SupportLibParted)
 
158
                p.fileSystem().setSectorsUsed(readSectorsUsedLibParted(pedDisk, p));
 
159
}
 
160
 
 
161
/** Scans a Device for Partitions.
 
162
 
 
163
        This function will scan a Device for all Partitions on it, detect the FileSystem for each Partition,
 
164
        try to determine the FileSystem usage, read the FileSystem label and store it all in newly created
 
165
        objects that are in the end added to the Device's PartitionTable.
 
166
 
 
167
        @param pedDevice libparted pointer to the device
 
168
        @param d Device
 
169
        @param pedDisk libparted pointer to the disk label
 
170
        @param mountInfo map of mount points
 
171
*/
 
172
static void scanDevicePartitions(PedDevice* pedDevice, Device& d, PedDisk* pedDisk, QMap<QString, QStringList>& mountInfo)
 
173
{
 
174
        Q_ASSERT(pedDevice);
 
175
        Q_ASSERT(pedDisk);
 
176
        Q_ASSERT(d.partitionTable());
 
177
 
 
178
        PedPartition* pedPartition = NULL;
 
179
 
 
180
        while ((pedPartition = ped_disk_next_partition(pedDisk, pedPartition)))
 
181
        {
 
182
                if (pedPartition->num < 1)
 
183
                        continue;
 
184
 
 
185
                PartitionRole::Roles r = PartitionRole::None;
 
186
                FileSystem::Type type = Job::detectFileSystem(pedDevice, pedPartition);
 
187
 
 
188
                switch(pedPartition->type)
 
189
                {
 
190
                        case PED_PARTITION_NORMAL:
 
191
                                r = PartitionRole::Primary;
 
192
                                break;
 
193
 
 
194
                        case PED_PARTITION_EXTENDED:
 
195
                                r = PartitionRole::Extended;
 
196
                                type = FileSystem::Extended;
 
197
                                break;
 
198
 
 
199
                        case PED_PARTITION_LOGICAL:
 
200
                                r = PartitionRole::Logical;
 
201
                                break;
 
202
 
 
203
                        default:
 
204
                                continue;
 
205
                }
 
206
 
 
207
                // Find an extended partition this partition is in.
 
208
                PartitionNode* parent = d.partitionTable()->findPartitionBySector(pedPartition->geom.start, PartitionRole(PartitionRole::Extended));
 
209
 
 
210
                // None found, so it's a primary in the device's partition table.
 
211
                if (parent == NULL)
 
212
                        parent = d.partitionTable();
 
213
 
 
214
                const QString node = pedDisk->dev->path + QString::number(pedPartition->num);
 
215
                FileSystem* fs = FileSystemFactory::create(type, pedPartition->geom.start, pedPartition->geom.end);
 
216
 
 
217
                Partition* part = new Partition(parent, d, PartitionRole(r), fs, pedPartition->geom.start, pedPartition->geom.end,
 
218
                                pedPartition->num, SetPartFlagsJob::availableFlags(pedPartition),
 
219
                                mountInfo[node], ped_partition_is_busy(pedPartition), SetPartFlagsJob::activeFlags(pedPartition));
 
220
 
 
221
                readSectorsUsed(pedDisk, *part, mountInfo);
 
222
 
 
223
                if (fs->supportGetLabel() == FileSystem::SupportExternal)
 
224
                        fs->setLabel(fs->readLabel(part->deviceNode()));
 
225
 
 
226
                parent->append(part);
 
227
 
 
228
                PartitionTable::isSnapped(d, *part);
 
229
        }
 
230
 
 
231
        d.partitionTable()->updateUnallocated(d);
 
232
 
 
233
        ped_disk_destroy(pedDisk);
 
234
}
 
235
 
 
236
/** Destructs a LibParted object. */
 
237
LibParted::LibParted()
 
238
{
 
239
        ped_exception_set_handler(pedExceptionHandler);
 
240
}
 
241
 
 
242
/** Scans for all available Devices on this computer.
 
243
 
 
244
        This method tries to find all Devices on the computer and creates new Device instances for each of them. It then calls scanDevicePartitions() to find all Partitions and FileSystems on each Device and set those up.
 
245
 
 
246
        The method will clear the list of operations and devices currently in the OperationStack given.
 
247
 
 
248
        @param ostack the OperationStack where the devices will be created
 
249
*/
 
250
void LibParted::scanDevices(OperationStack& ostack)
 
251
{
 
252
        QMap<QString, QStringList> mountInfo;
 
253
 
 
254
        readMountpoints("/proc/mounts", mountInfo);
 
255
        readMountpoints("/etc/mtab", mountInfo);
 
256
        readMountpoints("/etc/fstab", mountInfo);
 
257
 
 
258
        ostack.clearOperations();
 
259
        ostack.clearDevices();
 
260
 
 
261
        ped_device_probe_all();
 
262
 
 
263
        PedDevice* pedDevice = ped_device_get_next(NULL);
 
264
 
 
265
        while (pedDevice)
 
266
        {
 
267
                log(log::information) << i18nc("@info/plain", "Device found: %1", pedDevice->model);
 
268
 
 
269
                Device* d = new Device(pedDevice->model, pedDevice->path, pedDevice->bios_geom.heads, pedDevice->bios_geom.sectors, pedDevice->bios_geom.cylinders, pedDevice->sector_size);
 
270
 
 
271
                PedDisk* pedDisk = ped_disk_new(pedDevice);
 
272
 
 
273
                if (pedDisk)
 
274
                {
 
275
                        d->setPartitionTable(new PartitionTable());
 
276
                        d->partitionTable()->setMaxPrimaries(ped_disk_get_max_primary_partition_count(pedDisk));
 
277
                        d->partitionTable()->setTypeName(pedDisk->type->name);
 
278
 
 
279
                        scanDevicePartitions(pedDevice, *d, pedDisk, mountInfo);
 
280
                }
 
281
 
 
282
                // add this device if either there is a valid partition table or it's not
 
283
                // read only (read only devices without partition table are CD/DVD readers, writers etc)
 
284
                if (pedDisk || !pedDevice->read_only)
 
285
                        ostack.addDevice(d);
 
286
 
 
287
                pedDevice = ped_device_get_next(pedDevice);
 
288
        }
 
289
}