summaryrefslogtreecommitdiffstats
path: root/RPM4/lib/RPM4.pm
blob: 8c826c804432f6af930d22fb028d82092c84d020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
##- Nanar <nanardon@zarb.org>
##-
##- This program is free software; you can redistribute it and/or modify
##- it under the terms of the GNU General Public License as published by
##- the Free Software Foundation; either version 2, or (at your option)
##- any later version.
##-
##- This program is distributed in the hope that it will be useful,
##- but WITHOUT ANY WARRANTY; without even the implied warranty of
##- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##- GNU General Public License for more details.
##-
##- You should have received a copy of the GNU General Public License
##- along with this program; if not, write to the Free Software
##- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# $Id$

package RPM4;

use strict;
use warnings;

use DynaLoader;
use Exporter;

use RPM4::Header;
use RPM4::Transaction;
use RPM4::Header::Dependencies;
use RPM4::Header::Files;
use RPM4::Spec;

our $VERSION = '0.36';
our @ISA = qw(DynaLoader Exporter);
our @EXPORT = qw(moduleinfo
                 readconfig querytag tagName tagValue expand rpmvercmp
                 stream2header rpm2header
                 installsrpm
                 setverbosity setlogcallback format_rpmpb
                 rpmresign dumpmacros dumprc
                 newdb parserpms);
our %EXPORT_TAGS = (
    rpmlib => [qw(getosname getarchname dumprc dumpmacros rpmvercmp setverbosity setlogcallback
                  rpmlog)],
    macros => [qw(add_macros del_macros loadmacrosfile resetmacros)],
    build => [qw(headernew)],
    rpmdb => [qw(rpmdbverify rpmdbrebuild)],
);

bootstrap RPM4;

# I18N:
sub N {
    my ($msg, @args) = @_;
    sprintf($msg, @args);
}

sub compare_evr {
    my ($ae, $av, $ar) = $_[0] =~ /^(?:([^:]*):)?([^-]*)(?:-(.*))?$/;
    my ($be, $bv, $br) = $_[1] =~ /^(?:([^:]*):)?([^-]*)(?:-(.*))?$/;

    my $rc = 0;
    if (defined($ae) && ! defined($be)) {
        return 1;
    } elsif (!defined($ae) && defined($be)) {
        return -1;
    } else {
        $rc = RPM4::rpmvercmp($ae, $be) if defined($ae) && defined($be);
        if ($rc == 0) {
            $rc = RPM4::rpmvercmp($av, $bv);
            if ($rc == 0) {
                if (defined($ar) && !defined($br)) {
                    return 1;
                } elsif (!defined($ar) && defined($br)) {
                    return -1;
                } elsif (!defined($ar) &&  !defined($br)) {
                    return 0;
                } else {
                    return RPM4::rpmvercmp($ar, $br);
                }
            } else {
                return $rc;
            }
        } else {
            return $rc;
        }
    }
}

# parse* function
# callback => function
#   (
#       header => the header (undef on error)
#       file => actual source
#   )
# files => []
# flags => ??

sub parserpms {
    my (%options) = @_;
    my $db = newdb();
    $db->vsflags($options{checkrpms} ? [ "NOSIGNATURES" ] : [ qw(NOSIGNATURES NOPAYLOAD NODIGESTS) ]);
    foreach my $rpm (@{$options{rpms} || []}) {
        my $header = $db->rpm2header($options{path} ? "$options{path}/$rpm" : $rpm);
        defined($options{callback}) and
            $options{callback}->(
                header => $header,
                dir => $options{path} ? "$options{path}/" : "",
                rpm => $rpm,
            );
    }
}

sub format_rpmpb {
    my (@msgs) = @_;
    my @ret;
    foreach my $p (@msgs) {
        $p->{pb} eq "BADARCH" and do {
            push @ret, N("package %s is intended for a different architecture", $p->{pkg});
            next;
        };
        $p->{pb} eq "BADOS" and do {
            push @ret, N("package %s is intended for a different operating system", $p->{pkg});
            next;
        };
        $p->{pb} eq "PKG_INSTALLED" and do {
            push @ret, N("package %s is allready installed", $p->{pkg});
            next;
        };
        $p->{pb} eq "BADRELOCATE" and do {
            push @ret, N("path %s in package %s is not relocatable", $p->{path}, $p->{pkg});
            next;
        };
        $p->{pb} eq "NEW_FILE_CONFLICT" and do {
            push @ret, N("file %s conflicts between attempted installs of %s and %s", $p->{file}, $p->{pkg}, $p->{pkg2});
            next;
        };
        $p->{pb} eq "FILE_CONFLICT" and do {
            push @ret, N("file %s from install of %s conflicts with file from package %s", $p->{file}, $p->{pkg}, $p->{pkg2});
            next;
        };
        $p->{pb} eq "OLDPACKAGE" and do {
            push @ret, N("package %s (which is newer than %s) is already installed", $p->{pkg2}, $p->{pkg});
            next;
        };
        $p->{pb} eq "DISKSPACE" and do {
            push @ret, N("installing package %s needs %sB on the %s filesystem", $p->{pkg},
                ($p->{size} > 1024 * 1024
                    ? ($p->{size} + 1024 * 1024 - 1) / (1024 * 1024)
                    : ($p->{size} + 1023) / 1024) . 
                ($p->{size} > 1024 * 1024 ? 'M' : 'K'),
                $p->{filesystem});
            next;
        };
        $p->{pb} eq "DISKNODES" and do {
            push @ret, N("installing package %s needs %ld inodes on the %s filesystem", $p->{pkg}, $p->{nodes}, $p->{filesystem});
            next;
        };
        $p->{pb} eq "BADPRETRANS" and do {
            push @ret, N("package %s pre-transaction syscall(s): %s failed: %s", $p->{pkg}, $p->{syscall}, $p->{error});
            next;
        };
        $p->{pb} eq "REQUIRES" and do {
            push @ret, N("%s is needed by %s%s", $p->{pkg2},
                defined($p->{installed}) ? N("(installed) ") : "",
                $p->{pkg});
            next;
        };
        $p->{pb} eq "CONFLICT" and do {
            push @ret, N("%s conflicts with %s%s", $p->{pkg2},
                defined($p->{val2}) ? N("(installed) ") : "",
                $p->{pkg});
            next;
        };
    }
    @ret;
}

##########################
# Alias for compatiblity #
##########################

sub specnew { newspec(@_) }

sub add_macro { addmacro(@_) }

sub del_macro { delmacro(@_) }

1;

__END__

=head1 NAME

RPM4 - perl module to access and manipulate RPM files

=head1 SYNOPSIS

=head1 DESCRIPTION

This module allow to use API functions from rpmlib, directly or trough
perl objects.

=head1 FUNCTIONS

=head2 readconfig($rpmrc, $target)

Force rpmlib to re-read configuration files. If defined, $rpmrc is read.
If $target is defined, rpmlib will read config for this target. $target has
the form "CPU-VENDOR-OS".

    readconfig(); # Reread default configuration
    readconfig(undef, "i386-mandrake-linux"); # Read configuration for i386

=head2 setverbosity($level)

Set the rpmlib verbosity level. $level can be an integer (0 to 7) or a
verbosity level name.

  - EMERG    (0)
  - ALERT    (1)
  - CRIT     (2)
  - ERR      (3)
  - WARNING  (4)
  - NOTICE   (5)
  - INFO     (6)
  - DEBUG    (7)

=head2 setlogcallback(sub {})

Set a perl callback code for rpm logging/output system. When the callback is
set, rpm lets your code print error/information messages. The parameter passed
to the callback is a hash with log value:
    C<locode> => the rpm log code (integer),
    C<priority> => priority of the message (0 to 7),
    C<msg> => the formated string message.

To unset the callback function, passed an undef value as code reference.
 
Ex:
  setlogcallback( sub {
    my %log = @_;
    print "$log{priority}: $log{msg}\n";
  });

=head2 setlogfile(filename)

Redirect all rpm message into this file. Data will be append to the end of the
file, the file is created if it don't already exists. The old loging file is close.

To unset (and close) a pending loging file, passed an undef value.

=head2 lastlogmsg

Return an array about latest rpm log message information:
  - rpm log code,
  - rpm priority (0 to 7),
  - string message.

=head2 rpmlog($codelevel, $msg)

Send a message trougth the rpmlib logging system.
  - $codelevel is either an integer value between 0 and 7, or a level code string,
see setverbosity(),
  - $msg is the message to send.

=head2 format_rpmpb(@pb)

Some functions return an array of rpm transaction problem
(RPM4::Db->transpb()), this function return an array of human readable
string for each problem.
 
=head2 querytag

Returns a hash containing the tags known by rpmlib. The hash has the form
C< TAGNAME => tagvalue >. Note that some tags are virtual and do not have
any tag value, and that some tags are alias to already existing tags, so
they have the same value.

=head2 tagtypevalue($tagtypename)

Return the type value of a tag type. $tagtypename can be CHAR, INT8, INT16
INT32, STRING, ARRAY_STRING or I18NSTRING. This return value is usefull with
RPM4::Header::addtag() function.

=head2 tagName($tagvalue)

Returns the tag name for a given internal value.

    tagName(1000); return "NAME".

See: L<tagValue>.

=head2 tagValue($tagname)

Returns the internal tag value for C<$tagname>.

    tagValue("NAME"); return 1000.

See: L<tagName>.

=head2 expand($string)

Evaluate macros contained in C<$string>, like C<rpm --eval>.

    expand("%_var") return "/var".

=head2 addmacro("_macro value")

Define a macro into rpmlib. The macro is defined for the whole script. Ex:
C<addmacro("_macro value")>. Note that the macro name does have the prefix
"%", to prevent rpm from evaluating it.

=head2 del_macro("_macro")

Delete a macro from rpmlib. Exactly the reverse of addmacro().

=head2 loadmacrosfile($filename)

Read a macro configuration file and load macros defined within.
Unfortunately, the function returns nothing, even when file loading failed.

To reset macros loaded from file you have to re-read the rpm config file
with L<readconfig>.

=head2 resetmacros

Reset all macros defined with add_macro() functions.

This function does not reset macros loaded with loadmacrosfile().

=head2 getosname

Returns the operating system name of current rpm configuration.
Rpmlib auto-detects the system name, but you can force rpm to use
another system name with macros or using readconfig().

=head2 getarchname

Returns the arch name of current rpm configuration.
Rpmlib auto-detects the architecture, but you can force rpm to use
another architecture with macros or by using readconfig().

=head2 buildhost

Returns the BuildHost name of the current system, ie the value rpm will use
to set BuilHost tag in built rpm.

=head2 dumprc(*FILE)

Dump rpm configuration into file handle.
Ex:
    dumprc(*STDOUT);

=head2 dumpmacros(*FILE)

Dump rpm macros into file handle.
Ex:
    dumpmacros(*STDOUT);

=head2 rpmresign($passphrase, $rpmfile)

Resign a rpm using user settings. C<$passphrase> is the key's gpg/pgp
pass phrase.

Return 0 on success.
    
=head2 rpmvercmp(version1, version2)

Compare two version and return 1 if left argument is highter, -1 if
rigth argument is highter, 0 if equal.
Ex:
    rpmvercmp("1.1mdk", "2.1mdk"); # return -1.

=head2 compare_evr(version1, version2)

COmpare two rpm version in forms [epoch:]version[-release] and return
1 if left argument is highter, -1 if rigth argument is highter, 0 if
equal.
Ex:
    compare_evr("1:1-1mdk", "2-2mdk"); # return 1
    
=head2 installsrpm($filename)

Install a source rpm and return spec file path and its cookies.
Returns undef if install is impossible.

see L<RPM4::Spec>->new() for more information about cookies.

=head2 rpmdbinit(rootdir, permissions)

Create an empty rpm database located into I<%{_dbpath}> (useally /var/lib/rpm).
If set, rootdir is the root directory of system where rpm db should be
create, if set, theses permissions will be applied to files, default is 0644.

Directory I<%{_dbpath}> should exist.

Returns 0 on success.

Ex:
    rpmdbinit(); # Create rpm database on the system
    rpmdbinit("/chroot"); # Create rpm database for system located into /chroot.

=head2 rpmdbverify($rootdir)

Verify rpm database located into I<%{_dbpath}> (useally /var/lib/rpm).
If set, $rootdir is root directory of system to check.

Returns 0 on success.

=head2 rpmdbrebuild($rootdir)

Rebuild the rpm database located into I<%{_dbpath}> (useally /var/lib/rpm).
If set, $rootdir is the root directory of system.

Returns 0 on success.

=head2 rpmlibdep()

Create a RPM4::Header::Dependencies object about rpmlib
internals provides

=head1 SEE ALSO

L<rpm(8)>,

This aims at replacing part of the functionality provided by URPM.

=cut