~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to build/files.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** \ingroup rpmbuild
 
2
 * \file build/files.c
 
3
 *  The post-build, pre-packaging file tree walk to assemble the package
 
4
 *  manifest.
 
5
 */
 
6
 
 
7
#include "system.h"
 
8
 
 
9
#define MYALLPERMS      07777
 
10
 
 
11
#include <regex.h>
 
12
#include <signal.h>     /* getOutputFrom() */
 
13
 
 
14
#include <rpmio_internal.h>
 
15
#include <rpmbuild.h>
 
16
#include <rpmmacro.h>
 
17
 
 
18
#include "buildio.h"
 
19
 
 
20
#include "myftw.h"
 
21
#include "md5.h"
 
22
#include "debug.h"
 
23
 
 
24
/*@access Header @*/
 
25
/*@access TFI_t @*/
 
26
/*@access FD_t @*/
 
27
/*@access StringBuf @*/         /* compared with NULL */
 
28
 
 
29
#define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
 
30
#define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
 
31
 
 
32
#define MAXDOCDIR 1024
 
33
 
 
34
/*@-redecl@*/
 
35
extern int _noDirTokens;
 
36
/*@=redecl@*/
 
37
 
 
38
/**
 
39
 */
 
40
typedef enum specdFlags_e {
 
41
    SPECD_DEFFILEMODE   = (1 << 0),
 
42
    SPECD_DEFDIRMODE    = (1 << 1),
 
43
    SPECD_DEFUID        = (1 << 2),
 
44
    SPECD_DEFGID        = (1 << 3),
 
45
    SPECD_DEFVERIFY     = (1 << 4),
 
46
 
 
47
    SPECD_FILEMODE      = (1 << 8),
 
48
    SPECD_DIRMODE       = (1 << 9),
 
49
    SPECD_UID           = (1 << 10),
 
50
    SPECD_GID           = (1 << 11),
 
51
    SPECD_VERIFY        = (1 << 12)
 
52
} specdFlags;
 
53
 
 
54
/**
 
55
 */
 
56
typedef struct FileListRec_s {
 
57
    struct stat fl_st;
 
58
#define fl_dev  fl_st.st_dev
 
59
#define fl_ino  fl_st.st_ino
 
60
#define fl_mode fl_st.st_mode
 
61
#define fl_nlink fl_st.st_nlink
 
62
#define fl_uid  fl_st.st_uid
 
63
#define fl_gid  fl_st.st_gid
 
64
#define fl_rdev fl_st.st_rdev
 
65
#define fl_size fl_st.st_size
 
66
#define fl_mtime fl_st.st_mtime
 
67
 
 
68
/*@only@*/ const char * diskURL;        /* get file from here       */
 
69
/*@only@*/ const char * fileURL;        /* filename in cpio archive */
 
70
/*@observer@*/ const char * uname;
 
71
/*@observer@*/ const char * gname;
 
72
    int         flags;
 
73
    specdFlags  specdFlags;     /* which attributes have been explicitly specified. */
 
74
    int         verifyFlags;
 
75
/*@only@*/ const char *langs;   /* XXX locales separated with | */
 
76
} * FileListRec;
 
77
 
 
78
/**
 
79
 */
 
80
typedef struct AttrRec_s {
 
81
    const char * ar_fmodestr;
 
82
    const char * ar_dmodestr;
 
83
    const char * ar_user;
 
84
    const char * ar_group;
 
85
    mode_t      ar_fmode;
 
86
    mode_t      ar_dmode;
 
87
} * AttrRec;
 
88
 
 
89
/**
 
90
 */
 
91
static int multiLib = 0;        /* MULTILIB */
 
92
 
 
93
/**
 
94
 * Package file tree walk data.
 
95
 */
 
96
typedef struct FileList_s {
 
97
/*@only@*/ const char * buildRootURL;
 
98
/*@only@*/ const char * prefix;
 
99
 
 
100
    int fileCount;
 
101
    int totalFileSize;
 
102
    int processingFailed;
 
103
 
 
104
    int passedSpecialDoc;
 
105
    int isSpecialDoc;
 
106
 
 
107
    int noGlob;
 
108
    unsigned devtype;
 
109
    unsigned devmajor;
 
110
    int devminor;
 
111
    
 
112
    int isDir;
 
113
    int inFtw;
 
114
    int currentFlags;
 
115
    specdFlags currentSpecdFlags;
 
116
    int currentVerifyFlags;
 
117
    struct AttrRec_s cur_ar;
 
118
    struct AttrRec_s def_ar;
 
119
    specdFlags defSpecdFlags;
 
120
    int defVerifyFlags;
 
121
    int nLangs;
 
122
/*@only@*/ /*@null@*/ const char ** currentLangs;
 
123
 
 
124
    /* Hard coded limit of MAXDOCDIR docdirs.         */
 
125
    /* If you break it you are doing something wrong. */
 
126
    const char * docDirs[MAXDOCDIR];
 
127
    int docDirCount;
 
128
    
 
129
/*@only@*/ FileListRec fileList;
 
130
    int fileListRecsAlloced;
 
131
    int fileListRecsUsed;
 
132
} * FileList;
 
133
 
 
134
/**
 
135
 */
 
136
static void nullAttrRec(/*@out@*/ AttrRec ar)   /*@modifies ar @*/
 
137
{
 
138
    ar->ar_fmodestr = NULL;
 
139
    ar->ar_dmodestr = NULL;
 
140
    ar->ar_user = NULL;
 
141
    ar->ar_group = NULL;
 
142
    ar->ar_fmode = 0;
 
143
    ar->ar_dmode = 0;
 
144
}
 
145
 
 
146
/**
 
147
 */
 
148
static void freeAttrRec(AttrRec ar)     /*@modifies ar @*/
 
149
{
 
150
    ar->ar_fmodestr = _free(ar->ar_fmodestr);
 
151
    ar->ar_dmodestr = _free(ar->ar_dmodestr);
 
152
    ar->ar_user = _free(ar->ar_user);
 
153
    ar->ar_group = _free(ar->ar_group);
 
154
    /* XXX doesn't free ar (yet) */
 
155
    /*@-nullstate@*/
 
156
    return;
 
157
    /*@=nullstate@*/
 
158
}
 
159
 
 
160
/**
 
161
 */
 
162
static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
 
163
        /*@modifies nar @*/
 
164
{
 
165
    if (oar == nar)
 
166
        return;
 
167
    freeAttrRec(nar);
 
168
    nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
 
169
    nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
 
170
    nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
 
171
    nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
 
172
    nar->ar_fmode = oar->ar_fmode;
 
173
    nar->ar_dmode = oar->ar_dmode;
 
174
}
 
175
 
 
176
#if 0
 
177
/**
 
178
 */
 
179
static void dumpAttrRec(const char * msg, AttrRec ar)
 
180
        /*@modifies fileSystem @*/
 
181
{
 
182
    if (msg)
 
183
        fprintf(stderr, "%s:\t", msg);
 
184
    fprintf(stderr, "(%s, %s, %s, %s)\n",
 
185
        ar->ar_fmodestr,
 
186
        ar->ar_user,
 
187
        ar->ar_group,
 
188
        ar->ar_dmodestr);
 
189
}
 
190
#endif
 
191
 
 
192
/* strtokWithQuotes() modified from glibc strtok() */
 
193
/* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
 
194
   This file is part of the GNU C Library.
 
195
 
 
196
   The GNU C Library is free software; you can redistribute it and/or
 
197
   modify it under the terms of the GNU Library General Public License as
 
198
   published by the Free Software Foundation; either version 2 of the
 
199
   License, or (at your option) any later version.
 
200
 
 
201
   The GNU C Library is distributed in the hope that it will be useful,
 
202
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
203
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
204
   Library General Public License for more details.
 
205
 
 
206
   You should have received a copy of the GNU Library General Public
 
207
   License along with the GNU C Library; see the file COPYING.LIB.  If
 
208
   not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
209
   Boston, MA 02111-1307, USA.  */
 
210
 
 
211
/**
 
212
 */
 
213
static char *strtokWithQuotes(char *s, char *delim)
 
214
{
 
215
    static char *olds = NULL;
 
216
    char *token;
 
217
 
 
218
    if (s == NULL) {
 
219
        s = olds;
 
220
    }
 
221
 
 
222
    /* Skip leading delimiters */
 
223
    s += strspn(s, delim);
 
224
    if (*s == '\0') {
 
225
        return NULL;
 
226
    }
 
227
 
 
228
    /* Find the end of the token.  */
 
229
    token = s;
 
230
    if (*token == '"') {
 
231
        token++;
 
232
        /* Find next " char */
 
233
        s = strchr(token, '"');
 
234
    } else {
 
235
        s = strpbrk(token, delim);
 
236
    }
 
237
 
 
238
    /* Terminate it */
 
239
    if (s == NULL) {
 
240
        /* This token finishes the string */
 
241
        olds = strchr(token, '\0');
 
242
    } else {
 
243
        /* Terminate the token and make olds point past it */
 
244
        *s = '\0';
 
245
        olds = s+1;
 
246
    }
 
247
 
 
248
    return token;
 
249
}
 
250
 
 
251
/**
 
252
 */
 
253
static void timeCheck(int tc, Header h) /*@modifies internalState @*/
 
254
{
 
255
    HGE_t hge = (HGE_t)headerGetEntryMinMemory;
 
256
    HFD_t hfd = headerFreeData;
 
257
    int * mtime;
 
258
    const char ** files;
 
259
    rpmTagType fnt;
 
260
    int count, x;
 
261
    time_t currentTime = time(NULL);
 
262
 
 
263
    (void) hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
 
264
    (void) hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
 
265
    
 
266
    for (x = 0; x < count; x++) {
 
267
        if ((currentTime - mtime[x]) > tc)
 
268
            rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
 
269
    }
 
270
    files = hfd(files, fnt);
 
271
}
 
272
 
 
273
/**
 
274
 */
 
275
typedef struct VFA {
 
276
/*@observer@*/ /*@null@*/ const char * attribute;
 
277
    int flag;
 
278
} VFA_t;
 
279
 
 
280
/**
 
281
 */
 
282
/*@-exportlocal -exportheadervar@*/
 
283
VFA_t verifyAttrs[] = {
 
284
    { "md5",    RPMVERIFY_MD5 },
 
285
    { "size",   RPMVERIFY_FILESIZE },
 
286
    { "link",   RPMVERIFY_LINKTO },
 
287
    { "user",   RPMVERIFY_USER },
 
288
    { "group",  RPMVERIFY_GROUP },
 
289
    { "mtime",  RPMVERIFY_MTIME },
 
290
    { "mode",   RPMVERIFY_MODE },
 
291
    { "rdev",   RPMVERIFY_RDEV },
 
292
    { NULL, 0 }
 
293
};
 
294
/*@=exportlocal =exportheadervar@*/
 
295
 
 
296
/**
 
297
 * @param fl            package file tree walk data
 
298
 */
 
299
static int parseForVerify(char * buf, FileList fl)
 
300
        /*@modifies buf, fl->processingFailed,
 
301
                fl->currentVerifyFlags, fl->defVerifyFlags,
 
302
                fl->currentSpecdFlags, fl->defSpecdFlags @*/
 
303
{
 
304
    char *p, *pe, *q;
 
305
    const char *name;
 
306
    int *resultVerify;
 
307
    int negated;
 
308
    int verifyFlags;
 
309
    specdFlags * specdFlags;
 
310
 
 
311
    if ((p = strstr(buf, (name = "%verify"))) != NULL) {
 
312
        resultVerify = &(fl->currentVerifyFlags);
 
313
        specdFlags = &fl->currentSpecdFlags;
 
314
    } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
 
315
        resultVerify = &(fl->defVerifyFlags);
 
316
        specdFlags = &fl->defSpecdFlags;
 
317
    } else
 
318
        return 0;
 
319
 
 
320
    for (pe = p; (pe-p) < strlen(name); pe++)
 
321
        *pe = ' ';
 
322
 
 
323
    SKIPSPACE(pe);
 
324
 
 
325
    if (*pe != '(') {
 
326
        rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
 
327
        fl->processingFailed = 1;
 
328
        return RPMERR_BADSPEC;
 
329
    }
 
330
 
 
331
    /* Bracket %*verify args */
 
332
    *pe++ = ' ';
 
333
    for (p = pe; *pe && *pe != ')'; pe++)
 
334
        {};
 
335
 
 
336
    if (*pe == '\0') {
 
337
        rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
 
338
        fl->processingFailed = 1;
 
339
        return RPMERR_BADSPEC;
 
340
    }
 
341
 
 
342
    /* Localize. Erase parsed string */
 
343
    q = alloca((pe-p) + 1);
 
344
    strncpy(q, p, pe-p);
 
345
    q[pe-p] = '\0';
 
346
    while (p <= pe)
 
347
        *p++ = ' ';
 
348
 
 
349
    negated = 0;
 
350
    verifyFlags = RPMVERIFY_NONE;
 
351
 
 
352
    for (p = q; *p != '\0'; p = pe) {
 
353
        SKIPWHITE(p);
 
354
        if (*p == '\0')
 
355
            break;
 
356
        pe = p;
 
357
        SKIPNONWHITE(pe);
 
358
        if (*pe != '\0')
 
359
            *pe++ = '\0';
 
360
 
 
361
        {   VFA_t *vfa;
 
362
            for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
 
363
                if (strcmp(p, vfa->attribute))
 
364
                    continue;
 
365
                verifyFlags |= vfa->flag;
 
366
                /*@innerbreak@*/ break;
 
367
            }
 
368
            if (vfa->attribute)
 
369
                continue;
 
370
        }
 
371
 
 
372
        if (!strcmp(p, "not")) {
 
373
            negated ^= 1;
 
374
        } else {
 
375
            rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
 
376
            fl->processingFailed = 1;
 
377
            return RPMERR_BADSPEC;
 
378
        }
 
379
    }
 
380
 
 
381
    *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
 
382
    *specdFlags |= SPECD_VERIFY;
 
383
 
 
384
    return 0;
 
385
}
 
386
 
 
387
#define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
 
388
 
 
389
/**
 
390
 * Parse %dev from file manifest.
 
391
 * @param fl            package file tree walk data
 
392
 */
 
393
static int parseForDev(char * buf, FileList fl)
 
394
        /*@modifies buf, fl->processingFailed,
 
395
                fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
 
396
{
 
397
    const char * name;
 
398
    const char * errstr = NULL;
 
399
    char *p, *pe, *q;
 
400
    int rc = RPMERR_BADSPEC;    /* assume error */
 
401
 
 
402
    if ((p = strstr(buf, (name = "%dev"))) == NULL)
 
403
        return 0;
 
404
 
 
405
    for (pe = p; (pe-p) < strlen(name); pe++)
 
406
        *pe = ' ';
 
407
    SKIPSPACE(pe);
 
408
 
 
409
    if (*pe != '(') {
 
410
        errstr = "'('";
 
411
        goto exit;
 
412
    }
 
413
 
 
414
    /* Bracket %dev args */
 
415
    *pe++ = ' ';
 
416
    for (p = pe; *pe && *pe != ')'; pe++)
 
417
        {};
 
418
    if (*pe != ')') {
 
419
        errstr = "')'";
 
420
        goto exit;
 
421
    }
 
422
 
 
423
    /* Localize. Erase parsed string */
 
424
    q = alloca((pe-p) + 1);
 
425
    strncpy(q, p, pe-p);
 
426
    q[pe-p] = '\0';
 
427
    while (p <= pe)
 
428
        *p++ = ' ';
 
429
 
 
430
    p = q; SKIPWHITE(p);
 
431
    pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
432
    if (*p == 'b')
 
433
        fl->devtype = 'b';
 
434
    else if (*p == 'c')
 
435
        fl->devtype = 'c';
 
436
    else {
 
437
        errstr = "devtype";
 
438
        goto exit;
 
439
    }
 
440
 
 
441
    p = pe; SKIPWHITE(p);
 
442
    pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
443
    for (pe = p; *pe && xisdigit(*pe); pe++)
 
444
        {} ;
 
445
    if (*pe == '\0') {
 
446
        fl->devmajor = atoi(p);
 
447
        /*@-unsignedcompare @*/ /* LCL: ge is ok */
 
448
        if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
 
449
            errstr = "devmajor";
 
450
            goto exit;
 
451
        }
 
452
        /*@=unsignedcompare @*/
 
453
        pe++;
 
454
    } else {
 
455
        errstr = "devmajor";
 
456
        goto exit;
 
457
    }
 
458
 
 
459
    p = pe; SKIPWHITE(p);
 
460
    pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
461
    for (pe = p; *pe && xisdigit(*pe); pe++)
 
462
        {} ;
 
463
    if (*pe == '\0') {
 
464
        fl->devminor = atoi(p);
 
465
        if (!(fl->devminor >= 0 && fl->devminor < 256)) {
 
466
            errstr = "devminor";
 
467
            goto exit;
 
468
        }
 
469
        pe++;
 
470
    } else {
 
471
        errstr = "devminor";
 
472
        goto exit;
 
473
    }
 
474
 
 
475
    fl->noGlob = 1;
 
476
 
 
477
    rc = 0;
 
478
 
 
479
exit:
 
480
    if (rc) {
 
481
        rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
 
482
        fl->processingFailed = 1;
 
483
    }
 
484
    return rc;
 
485
}
 
486
 
 
487
/**
 
488
 * Parse %attr and %defattr from file manifest.
 
489
 * @param fl            package file tree walk data
 
490
 */
 
491
static int parseForAttr(char * buf, FileList fl)
 
492
        /*@modifies buf, fl->processingFailed,
 
493
                fl->cur_ar, fl->def_ar,
 
494
                fl->currentSpecdFlags, fl->defSpecdFlags @*/
 
495
{
 
496
    const char *name;
 
497
    char *p, *pe, *q;
 
498
    int x;
 
499
    struct AttrRec_s arbuf;
 
500
    AttrRec ar = &arbuf, ret_ar;
 
501
    specdFlags * specdFlags;
 
502
 
 
503
    if ((p = strstr(buf, (name = "%attr"))) != NULL) {
 
504
        ret_ar = &(fl->cur_ar);
 
505
        specdFlags = &fl->currentSpecdFlags;
 
506
    } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
 
507
        ret_ar = &(fl->def_ar);
 
508
        specdFlags = &fl->defSpecdFlags;
 
509
    } else
 
510
        return 0;
 
511
 
 
512
    for (pe = p; (pe-p) < strlen(name); pe++)
 
513
        *pe = ' ';
 
514
 
 
515
    SKIPSPACE(pe);
 
516
 
 
517
    if (*pe != '(') {
 
518
        rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
 
519
        fl->processingFailed = 1;
 
520
        return RPMERR_BADSPEC;
 
521
    }
 
522
 
 
523
    /* Bracket %*attr args */
 
524
    *pe++ = ' ';
 
525
    for (p = pe; *pe && *pe != ')'; pe++)
 
526
        {};
 
527
 
 
528
    if (ret_ar == &(fl->def_ar)) {      /* %defattr */
 
529
        q = pe;
 
530
        q++;
 
531
        SKIPSPACE(q);
 
532
        if (*q != '\0') {
 
533
            rpmError(RPMERR_BADSPEC,
 
534
                     _("Non-white space follows %s(): %s\n"), name, q);
 
535
            fl->processingFailed = 1;
 
536
            return RPMERR_BADSPEC;
 
537
        }
 
538
    }
 
539
 
 
540
    /* Localize. Erase parsed string */
 
541
    q = alloca((pe-p) + 1);
 
542
    strncpy(q, p, pe-p);
 
543
    q[pe-p] = '\0';
 
544
    while (p <= pe)
 
545
        *p++ = ' ';
 
546
 
 
547
    nullAttrRec(ar);
 
548
 
 
549
    p = q; SKIPWHITE(p);
 
550
    if (*p != '\0') {
 
551
        pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
552
        ar->ar_fmodestr = p;
 
553
        p = pe; SKIPWHITE(p);
 
554
    }
 
555
    if (*p != '\0') {
 
556
        pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
557
        ar->ar_user = p;
 
558
        p = pe; SKIPWHITE(p);
 
559
    }
 
560
    if (*p != '\0') {
 
561
        pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
562
        ar->ar_group = p;
 
563
        p = pe; SKIPWHITE(p);
 
564
    }
 
565
    if (*p != '\0' && ret_ar == &(fl->def_ar)) {        /* %defattr */
 
566
        pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
 
567
        ar->ar_dmodestr = p;
 
568
        p = pe; SKIPWHITE(p);
 
569
    }
 
570
 
 
571
    if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
 
572
        rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
 
573
        fl->processingFailed = 1;
 
574
        return RPMERR_BADSPEC;
 
575
    }
 
576
 
 
577
    /* Do a quick test on the mode argument and adjust for "-" */
 
578
    if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
 
579
        unsigned int ui;
 
580
        x = sscanf(ar->ar_fmodestr, "%o", &ui);
 
581
        if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
 
582
            rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
 
583
            fl->processingFailed = 1;
 
584
            return RPMERR_BADSPEC;
 
585
        }
 
586
        ar->ar_fmode = ui;
 
587
    } else
 
588
        ar->ar_fmodestr = NULL;
 
589
 
 
590
    if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
 
591
        unsigned int ui;
 
592
        x = sscanf(ar->ar_dmodestr, "%o", &ui);
 
593
        if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
 
594
            rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
 
595
            fl->processingFailed = 1;
 
596
            return RPMERR_BADSPEC;
 
597
        }
 
598
        ar->ar_dmode = ui;
 
599
    } else
 
600
        ar->ar_dmodestr = NULL;
 
601
 
 
602
    if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
 
603
        ar->ar_user = NULL;
 
604
 
 
605
    if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
 
606
        ar->ar_group = NULL;
 
607
 
 
608
    dupAttrRec(ar, ret_ar);
 
609
 
 
610
    /* XXX fix all this */
 
611
    *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
 
612
    
 
613
    return 0;
 
614
}
 
615
 
 
616
/**
 
617
 * @param fl            package file tree walk data
 
618
 */
 
619
static int parseForConfig(char * buf, FileList fl)
 
620
        /*@modifies buf, fl->processingFailed,
 
621
                fl->currentFlags @*/
 
622
{
 
623
    char *p, *pe, *q;
 
624
    const char *name;
 
625
 
 
626
    if ((p = strstr(buf, (name = "%config"))) == NULL)
 
627
        return 0;
 
628
 
 
629
    fl->currentFlags = RPMFILE_CONFIG;
 
630
 
 
631
    for (pe = p; (pe-p) < strlen(name); pe++)
 
632
        *pe = ' ';
 
633
    SKIPSPACE(pe);
 
634
    if (*pe != '(')
 
635
        return 0;
 
636
 
 
637
    /* Bracket %config args */
 
638
    *pe++ = ' ';
 
639
    for (p = pe; *pe && *pe != ')'; pe++)
 
640
        {};
 
641
 
 
642
    if (*pe == '\0') {
 
643
        rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
 
644
        fl->processingFailed = 1;
 
645
        return RPMERR_BADSPEC;
 
646
    }
 
647
 
 
648
    /* Localize. Erase parsed string */
 
649
    q = alloca((pe-p) + 1);
 
650
    strncpy(q, p, pe-p);
 
651
    q[pe-p] = '\0';
 
652
    while (p <= pe)
 
653
        *p++ = ' ';
 
654
 
 
655
    for (p = q; *p != '\0'; p = pe) {
 
656
        SKIPWHITE(p);
 
657
        if (*p == '\0')
 
658
            break;
 
659
        pe = p;
 
660
        SKIPNONWHITE(pe);
 
661
        if (*pe != '\0')
 
662
            *pe++ = '\0';
 
663
        if (!strcmp(p, "missingok")) {
 
664
            fl->currentFlags |= RPMFILE_MISSINGOK;
 
665
        } else if (!strcmp(p, "noreplace")) {
 
666
            fl->currentFlags |= RPMFILE_NOREPLACE;
 
667
        } else {
 
668
            rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
 
669
            fl->processingFailed = 1;
 
670
            return RPMERR_BADSPEC;
 
671
        }
 
672
    }
 
673
 
 
674
    return 0;
 
675
}
 
676
 
 
677
/**
 
678
 */
 
679
static int langCmp(const void * ap, const void * bp)    /*@*/
 
680
{
 
681
    return strcmp(*(const char **)ap, *(const char **)bp);
 
682
}
 
683
 
 
684
/**
 
685
 * @param fl            package file tree walk data
 
686
 */
 
687
static int parseForLang(char * buf, FileList fl)
 
688
        /*@modifies buf, fl->processingFailed,
 
689
                fl->currentLangs, fl->nLangs @*/
 
690
{
 
691
    char *p, *pe, *q;
 
692
    const char *name;
 
693
 
 
694
  while ((p = strstr(buf, (name = "%lang"))) != NULL) {
 
695
 
 
696
    for (pe = p; (pe-p) < strlen(name); pe++)
 
697
        *pe = ' ';
 
698
    SKIPSPACE(pe);
 
699
 
 
700
    if (*pe != '(') {
 
701
        rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
 
702
        fl->processingFailed = 1;
 
703
        return RPMERR_BADSPEC;
 
704
    }
 
705
 
 
706
    /* Bracket %lang args */
 
707
    *pe++ = ' ';
 
708
    for (pe = p; *pe && *pe != ')'; pe++)
 
709
        {};
 
710
 
 
711
    if (*pe == '\0') {
 
712
        rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
 
713
        fl->processingFailed = 1;
 
714
        return RPMERR_BADSPEC;
 
715
    }
 
716
 
 
717
    /* Localize. Erase parsed string */
 
718
    q = alloca((pe-p) + 1);
 
719
    strncpy(q, p, pe-p);
 
720
    q[pe-p] = '\0';
 
721
    while (p <= pe)
 
722
        *p++ = ' ';
 
723
 
 
724
    /* Parse multiple arguments from %lang */
 
725
    for (p = q; *p != '\0'; p = pe) {
 
726
        char *newp;
 
727
        size_t np;
 
728
        int i;
 
729
 
 
730
        SKIPWHITE(p);
 
731
        pe = p;
 
732
        SKIPNONWHITE(pe);
 
733
 
 
734
        np = pe - p;
 
735
        
 
736
        /* Sanity check on locale lengths */
 
737
        if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
 
738
            rpmError(RPMERR_BADSPEC,
 
739
                _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
 
740
                (int)np, p, q);
 
741
            fl->processingFailed = 1;
 
742
            return RPMERR_BADSPEC;
 
743
        }
 
744
 
 
745
        /* Check for duplicate locales */
 
746
        if (fl->currentLangs != NULL)
 
747
        for (i = 0; i < fl->nLangs; i++) {
 
748
            if (strncmp(fl->currentLangs[i], p, np))
 
749
                continue;
 
750
            rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
 
751
                (int)np, p, q);
 
752
            fl->processingFailed = 1;
 
753
            return RPMERR_BADSPEC;
 
754
        }
 
755
 
 
756
        /* Add new locale */
 
757
        fl->currentLangs = xrealloc(fl->currentLangs,
 
758
                                (fl->nLangs + 1) * sizeof(*fl->currentLangs));
 
759
        newp = xmalloc( np+1 );
 
760
        strncpy(newp, p, np);
 
761
        newp[np] = '\0';
 
762
        fl->currentLangs[fl->nLangs++] = newp;
 
763
        if (*pe == ',') pe++;   /* skip , if present */
 
764
    }
 
765
  }
 
766
 
 
767
    /* Insure that locales are sorted. */
 
768
    if (fl->currentLangs)
 
769
        qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
 
770
 
 
771
    return 0;
 
772
}
 
773
 
 
774
/**
 
775
 */
 
776
static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
 
777
        /*@modifies *lang @*/
 
778
{
 
779
    static int initialized = 0;
 
780
    static int hasRegex = 0;
 
781
    static regex_t compiledPatt;
 
782
    static char buf[BUFSIZ];
 
783
    int x;
 
784
    regmatch_t matches[2];
 
785
    const char *s;
 
786
 
 
787
    if (! initialized) {
 
788
        const char *patt = rpmExpand("%{_langpatt}", NULL);
 
789
        int rc = 0;
 
790
        if (!(patt && *patt != '%'))
 
791
            rc = 1;
 
792
        else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
 
793
            rc = -1;
 
794
        patt = _free(patt);
 
795
        if (rc)
 
796
            return rc;
 
797
        hasRegex = 1;
 
798
        initialized = 1;
 
799
    }
 
800
    
 
801
    memset(matches, 0, sizeof(matches));
 
802
    if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
 
803
        return 1;
 
804
 
 
805
    /* Got match */
 
806
    s = fileName + matches[1].rm_eo - 1;
 
807
    x = matches[1].rm_eo - matches[1].rm_so;
 
808
    buf[x] = '\0';
 
809
    while (x) {
 
810
        buf[--x] = *s--;
 
811
    }
 
812
    if (lang)
 
813
        *lang = buf;
 
814
    return 0;
 
815
}
 
816
 
 
817
/**
 
818
 */
 
819
static int parseForRegexMultiLib(const char *fileName)  /*@*/
 
820
{
 
821
    static int initialized = 0;
 
822
    static int hasRegex = 0;
 
823
    static regex_t compiledPatt;
 
824
 
 
825
    if (! initialized) {
 
826
        const char *patt;
 
827
        int rc = 0;
 
828
 
 
829
        initialized = 1;
 
830
        patt = rpmExpand("%{_multilibpatt}", NULL);
 
831
        if (!(patt && *patt != '%'))
 
832
            rc = 1;
 
833
        else if (regcomp(&compiledPatt, patt, REG_EXTENDED | REG_NOSUB))
 
834
            rc = -1;
 
835
        patt = _free(patt);
 
836
        if (rc)
 
837
            return rc;
 
838
        hasRegex = 1;
 
839
    }
 
840
 
 
841
    if (! hasRegex || regexec(&compiledPatt, fileName, 0, NULL, 0))
 
842
        return 1;
 
843
 
 
844
    return 0;
 
845
}
 
846
 
 
847
/**
 
848
 */
 
849
/*@-exportlocal -exportheadervar@*/
 
850
VFA_t virtualFileAttributes[] = {
 
851
        { "%dir",       0 },    /* XXX why not RPMFILE_DIR? */
 
852
        { "%doc",       RPMFILE_DOC },
 
853
        { "%ghost",     RPMFILE_GHOST },
 
854
        { "%exclude",   RPMFILE_EXCLUDE },
 
855
        { "%readme",    RPMFILE_README },
 
856
        { "%license",   RPMFILE_LICENSE },
 
857
        { "%multilib",  0 },
 
858
 
 
859
#if WHY_NOT
 
860
        { "%spec",      RPMFILE_SPEC },
 
861
        { "%config",    RPMFILE_CONFIG },
 
862
        { "%donotuse",  RPMFILE_DONOTUSE },     /* XXX WTFO? */
 
863
        { "%missingok", RPMFILE_CONFIG|RPMFILE_MISSINGOK },
 
864
        { "%noreplace", RPMFILE_CONFIG|RPMFILE_NOREPLACE },
 
865
#endif
 
866
 
 
867
        { NULL, 0 }
 
868
};
 
869
/*@=exportlocal =exportheadervar@*/
 
870
 
 
871
/**
 
872
 * @param fl            package file tree walk data
 
873
 */
 
874
static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
 
875
                          FileList fl, /*@out@*/ const char ** fileName)
 
876
        /*@modifies buf, fl->processingFailed, *fileName,
 
877
                fl->currentFlags,
 
878
                fl->docDirs, fl->docDirCount, fl->isDir,
 
879
                fl->passedSpecialDoc, fl->isSpecialDoc,
 
880
                pkg->specialDoc @*/
 
881
{
 
882
    char *s, *t;
 
883
    int res, specialDoc = 0;
 
884
    char specialDocBuf[BUFSIZ];
 
885
 
 
886
    specialDocBuf[0] = '\0';
 
887
    *fileName = NULL;
 
888
    res = 0;
 
889
 
 
890
    t = buf;
 
891
    while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
 
892
        t = NULL;
 
893
        if (!strcmp(s, "%docdir")) {
 
894
            s = strtokWithQuotes(NULL, " \t\n");
 
895
            if (fl->docDirCount == MAXDOCDIR) {
 
896
                rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
 
897
                fl->processingFailed = 1;
 
898
                res = 1;
 
899
            }
 
900
            fl->docDirs[fl->docDirCount++] = xstrdup(s);
 
901
            if (strtokWithQuotes(NULL, " \t\n")) {
 
902
                rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
 
903
                fl->processingFailed = 1;
 
904
                res = 1;
 
905
            }
 
906
            break;
 
907
        }
 
908
 
 
909
    /* Set flags for virtual file attributes */
 
910
    {   VFA_t *vfa;
 
911
        for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
 
912
            if (strcmp(s, vfa->attribute))
 
913
                continue;
 
914
            if (!vfa->flag) {
 
915
                if (!strcmp(s, "%dir"))
 
916
                    fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
 
917
                else if (!strcmp(s, "%multilib"))
 
918
                    fl->currentFlags |= multiLib;
 
919
            } else
 
920
                fl->currentFlags |= vfa->flag;
 
921
            /*@innerbreak@*/ break;
 
922
        }
 
923
        /* if we got an attribute, continue with next token */
 
924
        if (vfa->attribute != NULL)
 
925
            continue;
 
926
    }
 
927
 
 
928
        if (*fileName) {
 
929
            /* We already got a file -- error */
 
930
            rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
 
931
                *fileName);
 
932
            fl->processingFailed = 1;
 
933
            res = 1;
 
934
        }
 
935
 
 
936
        if (*s != '/') {
 
937
            if (fl->currentFlags & RPMFILE_DOC) {
 
938
                specialDoc = 1;
 
939
                strcat(specialDocBuf, " ");
 
940
                strcat(specialDocBuf, s);
 
941
            } else {
 
942
                /* not in %doc, does not begin with / -- error */
 
943
                rpmError(RPMERR_BADSPEC,
 
944
                    _("File must begin with \"/\": %s\n"), s);
 
945
                fl->processingFailed = 1;
 
946
                res = 1;
 
947
            }
 
948
        } else {
 
949
            *fileName = s;
 
950
        }
 
951
    }
 
952
 
 
953
    if (specialDoc) {
 
954
        if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
 
955
            rpmError(RPMERR_BADSPEC,
 
956
                     _("Can't mix special %%doc with other forms: %s\n"),
 
957
                     (*fileName ? *fileName : ""));
 
958
            fl->processingFailed = 1;
 
959
            res = 1;
 
960
        } else {
 
961
        /* XXX WATCHOUT: buf is an arg */
 
962
            {   const char *ddir, *n, *v;
 
963
 
 
964
                (void) headerNVR(pkg->header, &n, &v, NULL);
 
965
 
 
966
                ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
 
967
                strcpy(buf, ddir);
 
968
                ddir = _free(ddir);
 
969
            }
 
970
 
 
971
        /* XXX FIXME: this is easy to do as macro expansion */
 
972
 
 
973
            if (! fl->passedSpecialDoc) {
 
974
                pkg->specialDoc = newStringBuf();
 
975
                appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
 
976
                appendLineStringBuf(pkg->specialDoc, buf);
 
977
                appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
 
978
                appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
 
979
                appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
 
980
 
 
981
                /*@-temptrans@*/
 
982
                *fileName = buf;
 
983
                /*@=temptrans@*/
 
984
                fl->passedSpecialDoc = 1;
 
985
                fl->isSpecialDoc = 1;
 
986
            }
 
987
 
 
988
            appendStringBuf(pkg->specialDoc, "cp -pr ");
 
989
            appendStringBuf(pkg->specialDoc, specialDocBuf);
 
990
            appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
 
991
        }
 
992
    }
 
993
 
 
994
    return res;
 
995
}
 
996
 
 
997
/**
 
998
 */
 
999
static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
 
1000
{
 
1001
    const char *a = ((FileListRec)ap)->fileURL;
 
1002
    const char *b = ((FileListRec)bp)->fileURL;
 
1003
    return strcmp(a, b);
 
1004
}
 
1005
 
 
1006
/**
 
1007
 * @param fl            package file tree walk data
 
1008
 */
 
1009
static int isDoc(FileList fl, const char * fileName)    /*@*/
 
1010
{
 
1011
    int x = fl->docDirCount;
 
1012
 
 
1013
    while (x--) {
 
1014
        if (strstr(fileName, fl->docDirs[x]) == fileName)
 
1015
            return 1;
 
1016
    }
 
1017
    return 0;
 
1018
}
 
1019
 
 
1020
/**
 
1021
 * Verify that file attributes scope over hardlinks correctly.
 
1022
 * @todo only %lang for now, finish other attributes later.
 
1023
 * @param fl            package file tree walk data
 
1024
 */
 
1025
static void checkHardLinks(FileList fl)
 
1026
        /*@modifies fl->fileList->flags, fl->fileList->langs @*/
 
1027
{
 
1028
    char nlangs[BUFSIZ];
 
1029
    FileListRec ilp, jlp;
 
1030
    int i, j;
 
1031
 
 
1032
    nlangs[0] = '\0';
 
1033
    for (i = 0;  i < fl->fileListRecsUsed; i++) {
 
1034
        char *te;
 
1035
 
 
1036
        ilp = fl->fileList + i;
 
1037
        if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
 
1038
            continue;
 
1039
        if (ilp->flags & RPMFILE_SPECFILE)
 
1040
            continue;
 
1041
 
 
1042
        te = nlangs;
 
1043
        *te = '\0';
 
1044
        for (j = i + 1; j < fl->fileListRecsUsed; j++) {
 
1045
            jlp = fl->fileList + j;
 
1046
            if (!S_ISREG(jlp->fl_mode))
 
1047
                continue;
 
1048
            if (ilp->fl_nlink != jlp->fl_nlink)
 
1049
                continue;
 
1050
            if (ilp->fl_ino != jlp->fl_ino)
 
1051
                continue;
 
1052
            if (ilp->fl_dev != jlp->fl_dev)
 
1053
                continue;
 
1054
            if (!strcmp(ilp->langs, jlp->langs)) {
 
1055
                jlp->flags |= RPMFILE_SPECFILE;
 
1056
                continue;
 
1057
            }
 
1058
            if (te == nlangs)
 
1059
                te = stpcpy(te, ilp->langs);
 
1060
            *te++ = '|';
 
1061
            te = stpcpy(te, jlp->langs);
 
1062
        }
 
1063
 
 
1064
        /* Are locales distributed over hard links correctly? */
 
1065
        if (te == nlangs)
 
1066
            continue;
 
1067
 
 
1068
        ilp->langs = _free(ilp->langs);
 
1069
        ilp->langs = xstrdup(nlangs);
 
1070
        for (j = i + 1; j < fl->fileListRecsUsed; j++) {
 
1071
            jlp = fl->fileList + j;
 
1072
            if (!S_ISREG(jlp->fl_mode))
 
1073
                continue;
 
1074
            if (ilp->fl_nlink != jlp->fl_nlink)
 
1075
                continue;
 
1076
            if (ilp->fl_ino != jlp->fl_ino)
 
1077
                continue;
 
1078
            if (ilp->fl_dev != jlp->fl_dev)
 
1079
                continue;
 
1080
            jlp->flags |= RPMFILE_SPECFILE;
 
1081
            jlp->langs = _free(jlp->langs);
 
1082
            jlp->langs = xstrdup(nlangs);
 
1083
        }
 
1084
    }
 
1085
 
 
1086
    for (i = 0;  i < fl->fileListRecsUsed; i++) {
 
1087
        ilp = fl->fileList + i;
 
1088
        ilp->flags &= ~RPMFILE_SPECFILE;
 
1089
    }
 
1090
}
 
1091
 
 
1092
/**
 
1093
 * @todo Should directories have %doc/%config attributes? (#14531)
 
1094
 * @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead.
 
1095
 * @param fl            package file tree walk data
 
1096
 */
 
1097
static void genCpioListAndHeader(/*@partial@*/ FileList fl,
 
1098
                TFI_t * cpioList, Header h, int isSrc)
 
1099
        /*@modifies h, *cpioList, fl->processingFailed, fl->fileList @*/
 
1100
{
 
1101
    int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
 
1102
    uint_32 multiLibMask = 0;
 
1103
    int apathlen = 0;
 
1104
    int dpathlen = 0;
 
1105
    int skipLen = 0;
 
1106
    FileListRec flp;
 
1107
    char buf[BUFSIZ];
 
1108
    int i;
 
1109
    
 
1110
    /* Sort the big list */
 
1111
    qsort(fl->fileList, fl->fileListRecsUsed,
 
1112
          sizeof(*(fl->fileList)), compareFileListRecs);
 
1113
    
 
1114
    /* Generate the header. */
 
1115
    if (! isSrc) {
 
1116
        skipLen = 1;
 
1117
        if (fl->prefix)
 
1118
            skipLen += strlen(fl->prefix);
 
1119
    }
 
1120
 
 
1121
    for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
 
1122
        char *s;
 
1123
 
 
1124
        /* Merge duplicate entries. */
 
1125
        while (i < (fl->fileListRecsUsed - 1) &&
 
1126
            !strcmp(flp->fileURL, flp[1].fileURL)) {
 
1127
 
 
1128
            /* Two entries for the same file found, merge the entries. */
 
1129
 
 
1130
            rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
 
1131
                flp->fileURL);
 
1132
 
 
1133
            /* file flags */
 
1134
            flp[1].flags |= flp->flags; 
 
1135
   
 
1136
            /* file mode */
 
1137
            if (S_ISDIR(flp->fl_mode)) {
 
1138
                if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
 
1139
                    (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
 
1140
                        flp[1].fl_mode = flp->fl_mode;
 
1141
            } else {
 
1142
                if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
 
1143
                    (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
 
1144
                        flp[1].fl_mode = flp->fl_mode;
 
1145
            }
 
1146
 
 
1147
            /* uid */
 
1148
            if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
 
1149
                (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
 
1150
            {
 
1151
                flp[1].fl_uid = flp->fl_uid;
 
1152
                flp[1].uname = flp->uname;
 
1153
            }
 
1154
 
 
1155
            /* gid */
 
1156
            if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
 
1157
                (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
 
1158
            {
 
1159
                flp[1].fl_gid = flp->fl_gid;
 
1160
                flp[1].gname = flp->gname;
 
1161
            }
 
1162
 
 
1163
            /* verify flags */
 
1164
            if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
 
1165
                (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
 
1166
                    flp[1].verifyFlags = flp->verifyFlags;
 
1167
 
 
1168
            /* XXX to-do: language */
 
1169
 
 
1170
            flp++; i++;
 
1171
        }
 
1172
 
 
1173
        /* Skip files that were marked with %exclude. */
 
1174
        if (flp->flags & RPMFILE_EXCLUDE) continue;
 
1175
 
 
1176
        /* Omit '/' and/or URL prefix, leave room for "./" prefix */
 
1177
        apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
 
1178
 
 
1179
        /* Leave room for both dirname and basename NUL's */
 
1180
        dpathlen += (strlen(flp->diskURL) + 2);
 
1181
 
 
1182
        if (flp->flags & RPMFILE_MULTILIB_MASK)
 
1183
            multiLibMask |=
 
1184
                (1u << ((flp->flags & RPMFILE_MULTILIB_MASK))
 
1185
                      >> RPMFILE_MULTILIB_SHIFT);
 
1186
 
 
1187
        /*
 
1188
         * Make the header, the OLDFILENAMES will get converted to a 
 
1189
         * compressed file list write before we write the actual package to
 
1190
         * disk.
 
1191
         */
 
1192
        (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
 
1193
                               &(flp->fileURL), 1);
 
1194
 
 
1195
      if (sizeof(flp->fl_size) != sizeof(uint_32)) {
 
1196
        uint_32 psize = (uint_32)flp->fl_size;
 
1197
        (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
 
1198
                               &(psize), 1);
 
1199
      } else {
 
1200
        (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
 
1201
                               &(flp->fl_size), 1);
 
1202
      }
 
1203
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
 
1204
                               &(flp->uname), 1);
 
1205
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
 
1206
                               &(flp->gname), 1);
 
1207
      if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
 
1208
        uint_32 mtime = (uint_32)flp->fl_mtime;
 
1209
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
 
1210
                               &(mtime), 1);
 
1211
      } else {
 
1212
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
 
1213
                               &(flp->fl_mtime), 1);
 
1214
      }
 
1215
      if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
 
1216
        uint_16 pmode = (uint_16)flp->fl_mode;
 
1217
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
 
1218
                               &(pmode), 1);
 
1219
      } else {
 
1220
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
 
1221
                               &(flp->fl_mode), 1);
 
1222
      }
 
1223
      if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
 
1224
        uint_16 prdev = (uint_16)flp->fl_rdev;
 
1225
        (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
 
1226
                               &(prdev), 1);
 
1227
      } else {
 
1228
        (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
 
1229
                               &(flp->fl_rdev), 1);
 
1230
      }
 
1231
      if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
 
1232
        uint_32 pdevice = (uint_32)flp->fl_dev;
 
1233
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
 
1234
                               &(pdevice), 1);
 
1235
      } else {
 
1236
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
 
1237
                               &(flp->fl_dev), 1);
 
1238
      }
 
1239
 
 
1240
      if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
 
1241
        uint_32 ino = (uint_32)flp->fl_ino;
 
1242
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
 
1243
                               &(ino), 1);
 
1244
      } else {
 
1245
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
 
1246
                               &(flp->fl_ino), 1);
 
1247
      }
 
1248
 
 
1249
        (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
 
1250
                               &(flp->langs),  1);
 
1251
        
 
1252
        /* We used to add these, but they should not be needed */
 
1253
        /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
 
1254
         *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
 
1255
         * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
 
1256
         *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
 
1257
         */
 
1258
        
 
1259
        buf[0] = '\0';
 
1260
        if (S_ISREG(flp->fl_mode))
 
1261
            (void) mdfile(flp->diskURL, buf);
 
1262
        s = buf;
 
1263
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
 
1264
                               &s, 1);
 
1265
        
 
1266
        buf[0] = '\0';
 
1267
        if (S_ISLNK(flp->fl_mode)) {
 
1268
            buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
 
1269
            if (fl->buildRootURL) {
 
1270
                const char * buildRoot;
 
1271
                (void) urlPath(fl->buildRootURL, &buildRoot);
 
1272
 
 
1273
                if (buf[0] == '/' && strcmp(buildRoot, "/") &&
 
1274
                    !strncmp(buf, buildRoot, strlen(buildRoot))) {
 
1275
                     rpmError(RPMERR_BADSPEC,
 
1276
                                _("Symlink points to BuildRoot: %s -> %s\n"),
 
1277
                                flp->fileURL, buf);
 
1278
                    fl->processingFailed = 1;
 
1279
                }
 
1280
            }
 
1281
        }
 
1282
        s = buf;
 
1283
        (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
 
1284
                               &s, 1);
 
1285
        
 
1286
        if (flp->flags & RPMFILE_GHOST) {
 
1287
            flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
 
1288
                                RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
 
1289
        }
 
1290
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
 
1291
                               &(flp->verifyFlags), 1);
 
1292
        
 
1293
        if (!isSrc && isDoc(fl, flp->fileURL))
 
1294
            flp->flags |= RPMFILE_DOC;
 
1295
        /* XXX Should directories have %doc/%config attributes? (#14531) */
 
1296
        if (S_ISDIR(flp->fl_mode))
 
1297
            flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
 
1298
 
 
1299
        (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
 
1300
                               &(flp->flags), 1);
 
1301
 
 
1302
    }
 
1303
    (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
 
1304
                   &(fl->totalFileSize), 1);
 
1305
 
 
1306
    /* XXX This should be added always so that packages look alike.
 
1307
     * XXX However, there is logic in files.c/depends.c that checks for
 
1308
     * XXX existence (rather than value) that will need to change as well.
 
1309
     */
 
1310
    if (multiLibMask)
 
1311
        (void) headerAddEntry(h, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
 
1312
                       &multiLibMask, 1);
 
1313
 
 
1314
    if (_addDotSlash)
 
1315
        (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
 
1316
 
 
1317
    /* Choose how filenames are represented. */
 
1318
    if (_noDirTokens)
 
1319
        expandFilelist(h);
 
1320
    else {
 
1321
        compressFilelist(h);
 
1322
        /* Binary packages with dirNames cannot be installed by legacy rpm. */
 
1323
        (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
 
1324
    }
 
1325
 
 
1326
  { TFI_t fi = xcalloc(sizeof(*fi), 1);
 
1327
    char * a, * d;
 
1328
 
 
1329
    fi->type = TR_ADDED;
 
1330
    loadFi(h, fi);
 
1331
    fi->dnl = _free(fi->dnl);
 
1332
    fi->bnl = _free(fi->bnl);
 
1333
 
 
1334
    fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
 
1335
    d = (char *)(fi->dnl + fi->fc);
 
1336
    *d = '\0';
 
1337
 
 
1338
    fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
 
1339
    fi->dil = (int *)(fi->bnl + fi->fc);
 
1340
 
 
1341
    fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
 
1342
    a = (char *)(fi->apath + fi->fc);
 
1343
    *a = '\0';
 
1344
 
 
1345
    fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
 
1346
    fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
 
1347
    fi->astriplen = 0;
 
1348
    if (fl->buildRootURL)
 
1349
        fi->astriplen = strlen(fl->buildRootURL);
 
1350
    fi->striplen = 0;
 
1351
    fi->fuser = NULL;
 
1352
    fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
 
1353
    fi->fgroup = NULL;
 
1354
    fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
 
1355
 
 
1356
    /* Make the cpio list */
 
1357
    for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
 
1358
        char * b;
 
1359
 
 
1360
        /* Skip (possible) duplicate file entries, use last entry info. */
 
1361
        while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
 
1362
                !strcmp(flp->fileURL, flp[1].fileURL))
 
1363
            flp++;
 
1364
 
 
1365
        /* Create disk directory and base name. */
 
1366
        fi->dil[i] = i;
 
1367
        fi->dnl[fi->dil[i]] = d;
 
1368
        d = stpcpy(d, flp->diskURL);
 
1369
 
 
1370
        /* Make room for the dirName NUL, find start of baseName. */
 
1371
        for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
 
1372
            b[1] = b[0];
 
1373
        b++;            /* dirname's end in '/' */
 
1374
        *b++ = '\0';    /* terminate dirname, b points to basename */
 
1375
        fi->bnl[i] = b;
 
1376
        d += 2;         /* skip both dirname and basename NUL's */
 
1377
 
 
1378
        /* Create archive path, normally adding "./" */
 
1379
        /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
 
1380
        fi->apath[i] = a;
 
1381
        /*@=dependenttrans@*/
 
1382
        if (_addDotSlash) a = stpcpy(a, "./");
 
1383
        a = stpcpy(a, (flp->fileURL + skipLen));
 
1384
        a++;            /* skip apath NUL */
 
1385
 
 
1386
        if (flp->flags & RPMFILE_GHOST) {
 
1387
            fi->actions[i] = FA_SKIP;
 
1388
            continue;
 
1389
        }
 
1390
        fi->actions[i] = FA_COPYOUT;
 
1391
        fi->fuids[i] = getUidS(flp->uname);
 
1392
        fi->fgids[i] = getGidS(flp->gname);
 
1393
        if (fi->fuids[i] == (uid_t)-1) fi->fuids[i] = 0;
 
1394
        if (fi->fgids[i] == (gid_t)-1) fi->fgids[i] = 0;
 
1395
        fi->fmapflags[i] = CPIO_MAP_PATH |
 
1396
                CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
 
1397
        if (isSrc)
 
1398
            fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
 
1399
        if (flp->flags & RPMFILE_MULTILIB_MASK)
 
1400
            fi->fmapflags[i] |= CPIO_MULTILIB;
 
1401
 
 
1402
    }
 
1403
    if (cpioList)
 
1404
        *cpioList = fi;
 
1405
    else
 
1406
        fi = _free(fi);
 
1407
  }
 
1408
}
 
1409
 
 
1410
/**
 
1411
 */
 
1412
static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
 
1413
                        int count)
 
1414
        /*@*/
 
1415
{
 
1416
    while (count--) {
 
1417
        fileList[count].diskURL = _free(fileList[count].diskURL);
 
1418
        fileList[count].fileURL = _free(fileList[count].fileURL);
 
1419
        fileList[count].langs = _free(fileList[count].langs);
 
1420
    }
 
1421
    fileList = _free(fileList);
 
1422
    return NULL;
 
1423
}
 
1424
 
 
1425
/**
 
1426
 * @param fl            package file tree walk data
 
1427
 */
 
1428
static int addFile(FileList fl, const char * diskURL, struct stat * statp)
 
1429
        /*@modifies *statp, fl->processingFailed,
 
1430
                fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
 
1431
                fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir @*/
 
1432
{
 
1433
    const char *fileURL = diskURL;
 
1434
    struct stat statbuf;
 
1435
    mode_t fileMode;
 
1436
    uid_t fileUid;
 
1437
    gid_t fileGid;
 
1438
    const char *fileUname;
 
1439
    const char *fileGname;
 
1440
    char *lang;
 
1441
    
 
1442
    /* Path may have prepended buildRootURL, so locate the original filename. */
 
1443
    /*
 
1444
     * XXX There are 3 types of entry into addFile:
 
1445
     *
 
1446
     *  From                    diskUrl                 statp
 
1447
     *  =====================================================
 
1448
     *  processBinaryFile       path                    NULL
 
1449
     *  processBinaryFile       glob result path        NULL
 
1450
     *  myftw                   path                    stat
 
1451
     *
 
1452
     */
 
1453
    {   const char *fileName;
 
1454
        (void) urlPath(fileURL, &fileName);
 
1455
        if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
 
1456
            fileURL += strlen(fl->buildRootURL);
 
1457
    }
 
1458
 
 
1459
    /* XXX make sure '/' can be packaged also */
 
1460
    if (*fileURL == '\0')
 
1461
        fileURL = "/";
 
1462
 
 
1463
    /* If we are using a prefix, validate the file */
 
1464
    if (!fl->inFtw && fl->prefix) {
 
1465
        const char *prefixTest;
 
1466
        const char *prefixPtr = fl->prefix;
 
1467
 
 
1468
        (void) urlPath(fileURL, &prefixTest);
 
1469
        while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
 
1470
            prefixPtr++;
 
1471
            prefixTest++;
 
1472
        }
 
1473
        if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
 
1474
            rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
 
1475
                     fl->prefix, fileURL);
 
1476
            fl->processingFailed = 1;
 
1477
            return RPMERR_BADSPEC;
 
1478
        }
 
1479
    }
 
1480
 
 
1481
    if (statp == NULL) {
 
1482
        statp = &statbuf;
 
1483
        memset(statp, 0, sizeof(*statp));
 
1484
        if (fl->devtype) {
 
1485
            time_t now = time(NULL);
 
1486
 
 
1487
            /* XXX hack up a stat structure for a %dev(...) directive. */
 
1488
            statp->st_nlink = 1;
 
1489
            statp->st_rdev =
 
1490
                ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
 
1491
            statp->st_dev = statp->st_rdev;
 
1492
            statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
 
1493
            statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
 
1494
            statp->st_atime = now;
 
1495
            statp->st_mtime = now;
 
1496
            statp->st_ctime = now;
 
1497
        } else if (Lstat(diskURL, statp)) {
 
1498
            rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
 
1499
            fl->processingFailed = 1;
 
1500
            return RPMERR_BADSPEC;
 
1501
        }
 
1502
    }
 
1503
 
 
1504
    if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
 
1505
        /* We use our own ftw() call, because ftw() uses stat()    */
 
1506
        /* instead of lstat(), which causes it to follow symlinks! */
 
1507
        /* It also has better callback support.                    */
 
1508
        
 
1509
        fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
 
1510
        fl->isDir = 1;  /* Keep it from following myftw() again         */
 
1511
        (void) myftw(diskURL, 16, (myftwFunc) addFile, fl);
 
1512
        fl->isDir = 0;
 
1513
        fl->inFtw = 0;
 
1514
        return 0;
 
1515
    }
 
1516
 
 
1517
    fileMode = statp->st_mode;
 
1518
    fileUid = statp->st_uid;
 
1519
    fileGid = statp->st_gid;
 
1520
 
 
1521
    if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
 
1522
        fileMode &= S_IFMT;
 
1523
        fileMode |= fl->cur_ar.ar_dmode;
 
1524
    } else if (fl->cur_ar.ar_fmodestr != NULL) {
 
1525
        fileMode &= S_IFMT;
 
1526
        fileMode |= fl->cur_ar.ar_fmode;
 
1527
    }
 
1528
    if (fl->cur_ar.ar_user) {
 
1529
        fileUname = getUnameS(fl->cur_ar.ar_user);
 
1530
    } else {
 
1531
        fileUname = getUname(fileUid);
 
1532
    }
 
1533
    if (fl->cur_ar.ar_group) {
 
1534
        fileGname = getGnameS(fl->cur_ar.ar_group);
 
1535
    } else {
 
1536
        fileGname = getGname(fileGid);
 
1537
    }
 
1538
        
 
1539
#if 0   /* XXX this looks dumb to me */
 
1540
    if (! (fileUname && fileGname)) {
 
1541
        rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskName);
 
1542
        fl->processingFailed = 1;
 
1543
        return RPMERR_BADSPEC;
 
1544
    }
 
1545
#else
 
1546
    /* Default user/group to builder's user/group */
 
1547
    if (fileUname == NULL)
 
1548
        fileUname = getUname(getuid());
 
1549
    if (fileGname == NULL)
 
1550
        fileGname = getGname(getgid());
 
1551
#endif
 
1552
    
 
1553
    rpmMessage(RPMMESS_DEBUG, _("File %4d: %07o %s.%s\t %s\n"), fl->fileCount,
 
1554
        (unsigned)fileMode, fileUname, fileGname, fileURL);
 
1555
 
 
1556
    /* Add to the file list */
 
1557
    if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
 
1558
        fl->fileListRecsAlloced += 128;
 
1559
        fl->fileList = xrealloc(fl->fileList,
 
1560
                        fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
 
1561
    }
 
1562
            
 
1563
    {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
 
1564
        int i;
 
1565
 
 
1566
        flp->fl_st = *statp;    /* structure assignment */
 
1567
        flp->fl_mode = fileMode;
 
1568
        flp->fl_uid = fileUid;
 
1569
        flp->fl_gid = fileGid;
 
1570
 
 
1571
        flp->fileURL = xstrdup(fileURL);
 
1572
        flp->diskURL = xstrdup(diskURL);
 
1573
        flp->uname = fileUname;
 
1574
        flp->gname = fileGname;
 
1575
 
 
1576
        if (fl->currentLangs && fl->nLangs > 0) {
 
1577
            char * ncl;
 
1578
            size_t nl = 0;
 
1579
            
 
1580
            for (i = 0; i < fl->nLangs; i++)
 
1581
                nl += strlen(fl->currentLangs[i]) + 1;
 
1582
 
 
1583
            flp->langs = ncl = xmalloc(nl);
 
1584
            for (i = 0; i < fl->nLangs; i++) {
 
1585
                const char *ocl;
 
1586
                if (i)  *ncl++ = '|';
 
1587
                for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
 
1588
                        *ncl++ = *ocl;
 
1589
                *ncl = '\0';
 
1590
            }
 
1591
        } else if (! parseForRegexLang(fileURL, &lang)) {
 
1592
            flp->langs = xstrdup(lang);
 
1593
        } else {
 
1594
            flp->langs = xstrdup("");
 
1595
        }
 
1596
 
 
1597
        flp->flags = fl->currentFlags;
 
1598
        flp->specdFlags = fl->currentSpecdFlags;
 
1599
        flp->verifyFlags = fl->currentVerifyFlags;
 
1600
 
 
1601
        if (multiLib
 
1602
            && !(flp->flags & RPMFILE_MULTILIB_MASK)
 
1603
            && !parseForRegexMultiLib(fileURL))
 
1604
            flp->flags |= multiLib;
 
1605
 
 
1606
 
 
1607
        /* Hard links need be counted only once. */
 
1608
        if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
 
1609
            FileListRec ilp;
 
1610
            for (i = 0;  i < fl->fileListRecsUsed; i++) {
 
1611
                ilp = fl->fileList + i;
 
1612
                if (!S_ISREG(ilp->fl_mode))
 
1613
                    continue;
 
1614
                if (flp->fl_nlink != ilp->fl_nlink)
 
1615
                    continue;
 
1616
                if (flp->fl_ino != ilp->fl_ino)
 
1617
                    continue;
 
1618
                if (flp->fl_dev != ilp->fl_dev)
 
1619
                    continue;
 
1620
                break;
 
1621
            }
 
1622
        } else
 
1623
            i = fl->fileListRecsUsed;
 
1624
 
 
1625
        if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
 
1626
            fl->totalFileSize += flp->fl_size;
 
1627
    }
 
1628
 
 
1629
    fl->fileListRecsUsed++;
 
1630
    fl->fileCount++;
 
1631
 
 
1632
    return 0;
 
1633
}
 
1634
 
 
1635
/**
 
1636
 * @param fl            package file tree walk data
 
1637
 */
 
1638
static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
 
1639
                const char * fileURL)
 
1640
        /*@modifies fl->processingFailed,
 
1641
                fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
 
1642
                fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir @*/
 
1643
{
 
1644
    int doGlob;
 
1645
    const char *diskURL = NULL;
 
1646
    int rc = 0;
 
1647
    
 
1648
    doGlob = myGlobPatternP(fileURL);
 
1649
 
 
1650
    /* Check that file starts with leading "/" */
 
1651
    {   const char * fileName;
 
1652
        (void) urlPath(fileURL, &fileName);
 
1653
        if (*fileName != '/') {
 
1654
            rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
 
1655
                        fileName);
 
1656
            rc = 1;
 
1657
            goto exit;
 
1658
        }
 
1659
    }
 
1660
    
 
1661
    /* Copy file name or glob pattern removing multiple "/" chars. */
 
1662
    /*
 
1663
     * Note: rpmGetPath should guarantee a "canonical" path. That means
 
1664
     * that the following pathologies should be weeded out:
 
1665
     *          //bin//sh
 
1666
     *          //usr//bin/
 
1667
     *          /.././../usr/../bin//./sh
 
1668
     */
 
1669
    diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
 
1670
 
 
1671
    if (doGlob) {
 
1672
        const char ** argv = NULL;
 
1673
        int argc = 0;
 
1674
        int i;
 
1675
 
 
1676
        if (fl->noGlob) {
 
1677
            rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
 
1678
                        diskURL);
 
1679
            rc = 1;
 
1680
            goto exit;
 
1681
        }
 
1682
 
 
1683
        rc = rpmGlob(diskURL, &argc, &argv);
 
1684
        if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
 
1685
            for (i = 0; i < argc; i++) {
 
1686
                rc = addFile(fl, argv[i], NULL);
 
1687
                argv[i] = _free(argv[i]);
 
1688
            }
 
1689
            argv = _free(argv);
 
1690
        } else {
 
1691
            rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
 
1692
                        diskURL);
 
1693
            rc = 1;
 
1694
        }
 
1695
    } else {
 
1696
        rc = addFile(fl, diskURL, NULL);
 
1697
    }
 
1698
 
 
1699
exit:
 
1700
    diskURL = _free(diskURL);
 
1701
    if (rc)
 
1702
        fl->processingFailed = 1;
 
1703
    return rc;
 
1704
}
 
1705
 
 
1706
/**
 
1707
 */
 
1708
static int processPackageFiles(Spec spec, Package pkg,
 
1709
                               int installSpecialDoc, int test)
 
1710
        /*@modifies spec->macros,
 
1711
                pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header */
 
1712
{
 
1713
    HGE_t hge = (HGE_t)headerGetEntryMinMemory;
 
1714
    struct FileList_s fl;
 
1715
    char *s, **files, **fp;
 
1716
    const char *fileName;
 
1717
    char buf[BUFSIZ];
 
1718
    struct AttrRec_s arbuf;
 
1719
    AttrRec specialDocAttrRec = &arbuf;
 
1720
    char *specialDoc = NULL;
 
1721
 
 
1722
#ifdef MULTILIB
 
1723
    multiLib = rpmExpandNumeric("%{_multilibno}");
 
1724
    if (multiLib)
 
1725
        multiLib = RPMFILE_MULTILIB(multiLib);
 
1726
#endif /* MULTILIB */
 
1727
    
 
1728
    nullAttrRec(specialDocAttrRec);
 
1729
    pkg->cpioList = NULL;
 
1730
 
 
1731
    if (pkg->fileFile) {
 
1732
        const char *ffn;
 
1733
        FILE * f;
 
1734
        FD_t fd;
 
1735
 
 
1736
        /* XXX W2DO? urlPath might be useful here. */
 
1737
        if (*pkg->fileFile == '/') {
 
1738
            ffn = rpmGetPath(pkg->fileFile, NULL);
 
1739
        } else {
 
1740
            /* XXX FIXME: add %{_buildsubdir} */
 
1741
            ffn = rpmGetPath("%{_builddir}/",
 
1742
                (spec->buildSubdir ? spec->buildSubdir : "") ,
 
1743
                "/", pkg->fileFile, NULL);
 
1744
        }
 
1745
        fd = Fopen(ffn, "r.fpio");
 
1746
 
 
1747
        if (fd == NULL || Ferror(fd)) {
 
1748
            rpmError(RPMERR_BADFILENAME,
 
1749
                _("Could not open %%files file %s: %s\n"),
 
1750
                ffn, Fstrerror(fd));
 
1751
            return RPMERR_BADFILENAME;
 
1752
        }
 
1753
        ffn = _free(ffn);
 
1754
 
 
1755
        /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
 
1756
        if (f != NULL)
 
1757
        while (fgets(buf, sizeof(buf), f)) {
 
1758
            handleComments(buf);
 
1759
            if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
 
1760
                rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
 
1761
                return RPMERR_BADSPEC;
 
1762
            }
 
1763
            appendStringBuf(pkg->fileList, buf);
 
1764
        }
 
1765
        (void) Fclose(fd);
 
1766
    }
 
1767
    
 
1768
    /* Init the file list structure */
 
1769
    memset(&fl, 0, sizeof(fl));
 
1770
 
 
1771
    /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
 
1772
    fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
 
1773
 
 
1774
    if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
 
1775
        fl.prefix = xstrdup(fl.prefix);
 
1776
    else
 
1777
        fl.prefix = NULL;
 
1778
 
 
1779
    fl.fileCount = 0;
 
1780
    fl.totalFileSize = 0;
 
1781
    fl.processingFailed = 0;
 
1782
 
 
1783
    fl.passedSpecialDoc = 0;
 
1784
    fl.isSpecialDoc = 0;
 
1785
 
 
1786
    fl.isDir = 0;
 
1787
    fl.inFtw = 0;
 
1788
    fl.currentFlags = 0;
 
1789
    fl.currentVerifyFlags = 0;
 
1790
    
 
1791
    fl.noGlob = 0;
 
1792
    fl.devtype = 0;
 
1793
    fl.devmajor = 0;
 
1794
    fl.devminor = 0;
 
1795
 
 
1796
    nullAttrRec(&fl.cur_ar);
 
1797
    nullAttrRec(&fl.def_ar);
 
1798
 
 
1799
    fl.defVerifyFlags = RPMVERIFY_ALL;
 
1800
    fl.nLangs = 0;
 
1801
    fl.currentLangs = NULL;
 
1802
 
 
1803
    fl.currentSpecdFlags = 0;
 
1804
    fl.defSpecdFlags = 0;
 
1805
 
 
1806
    fl.docDirCount = 0;
 
1807
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
 
1808
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
 
1809
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
 
1810
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
 
1811
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
 
1812
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
 
1813
    fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
 
1814
    fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
 
1815
    fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
 
1816
    fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
 
1817
    
 
1818
    fl.fileList = NULL;
 
1819
    fl.fileListRecsAlloced = 0;
 
1820
    fl.fileListRecsUsed = 0;
 
1821
 
 
1822
    s = getStringBuf(pkg->fileList);
 
1823
    files = splitString(s, strlen(s), '\n');
 
1824
 
 
1825
    for (fp = files; *fp != NULL; fp++) {
 
1826
        s = *fp;
 
1827
        SKIPSPACE(s);
 
1828
        if (*s == '\0')
 
1829
            continue;
 
1830
        fileName = NULL;
 
1831
        /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
 
1832
        strcpy(buf, s);
 
1833
        /*@=nullpass@*/
 
1834
        
 
1835
        /* Reset for a new line in %files */
 
1836
        fl.isDir = 0;
 
1837
        fl.inFtw = 0;
 
1838
        fl.currentFlags = 0;
 
1839
        /* turn explicit flags into %def'd ones (gosh this is hacky...) */
 
1840
        fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
 
1841
        fl.currentVerifyFlags = fl.defVerifyFlags;
 
1842
        fl.isSpecialDoc = 0;
 
1843
 
 
1844
        fl.noGlob = 0;
 
1845
        fl.devtype = 0;
 
1846
        fl.devmajor = 0;
 
1847
        fl.devminor = 0;
 
1848
 
 
1849
        /* XXX should reset to %deflang value */
 
1850
        if (fl.currentLangs) {
 
1851
            int i;
 
1852
            for (i = 0; i < fl.nLangs; i++)
 
1853
                /*@-unqualifiedtrans@*/
 
1854
                fl.currentLangs[i] = _free(fl.currentLangs[i]);
 
1855
                /*@=unqualifiedtrans@*/
 
1856
            fl.currentLangs = _free(fl.currentLangs);
 
1857
        }
 
1858
        fl.nLangs = 0;
 
1859
 
 
1860
        dupAttrRec(&fl.def_ar, &fl.cur_ar);
 
1861
 
 
1862
        /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
 
1863
        if (parseForVerify(buf, &fl))
 
1864
            continue;
 
1865
        if (parseForAttr(buf, &fl))
 
1866
            continue;
 
1867
        if (parseForDev(buf, &fl))
 
1868
            continue;
 
1869
        if (parseForConfig(buf, &fl))
 
1870
            continue;
 
1871
        if (parseForLang(buf, &fl))
 
1872
            continue;
 
1873
        /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
 
1874
        if (parseForSimple(spec, pkg, buf, &fl, &fileName))
 
1875
        /*@=nullstate@*/
 
1876
            continue;
 
1877
        /*@=nullpass@*/
 
1878
        if (fileName == NULL)
 
1879
            continue;
 
1880
 
 
1881
        if (fl.isSpecialDoc) {
 
1882
            /* Save this stuff for last */
 
1883
            specialDoc = _free(specialDoc);
 
1884
            specialDoc = xstrdup(fileName);
 
1885
            dupAttrRec(&fl.cur_ar, specialDocAttrRec);
 
1886
        } else {
 
1887
            /*@-nullstate@*/    /* FIX: pkg->fileFile might be NULL */
 
1888
            (void) processBinaryFile(pkg, &fl, fileName);
 
1889
            /*@=nullstate@*/
 
1890
        }
 
1891
    }
 
1892
 
 
1893
    /* Now process special doc, if there is one */
 
1894
    if (specialDoc) {
 
1895
        if (installSpecialDoc) {
 
1896
            (void) doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
 
1897
        }
 
1898
 
 
1899
        /* Reset for %doc */
 
1900
        fl.isDir = 0;
 
1901
        fl.inFtw = 0;
 
1902
        fl.currentFlags = 0;
 
1903
        fl.currentVerifyFlags = 0;
 
1904
 
 
1905
        fl.noGlob = 0;
 
1906
        fl.devtype = 0;
 
1907
        fl.devmajor = 0;
 
1908
        fl.devminor = 0;
 
1909
 
 
1910
        /* XXX should reset to %deflang value */
 
1911
        if (fl.currentLangs) {
 
1912
            int i;
 
1913
            for (i = 0; i < fl.nLangs; i++)
 
1914
                /*@-unqualifiedtrans@*/
 
1915
                fl.currentLangs[i] = _free(fl.currentLangs[i]);
 
1916
                /*@=unqualifiedtrans@*/
 
1917
            fl.currentLangs = _free(fl.currentLangs);
 
1918
        }
 
1919
        fl.nLangs = 0;
 
1920
 
 
1921
        dupAttrRec(specialDocAttrRec, &fl.cur_ar);
 
1922
        freeAttrRec(specialDocAttrRec);
 
1923
 
 
1924
        /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
 
1925
        (void) processBinaryFile(pkg, &fl, specialDoc);
 
1926
        /*@=nullstate@*/
 
1927
 
 
1928
        specialDoc = _free(specialDoc);
 
1929
    }
 
1930
    
 
1931
    freeSplitString(files);
 
1932
 
 
1933
    if (fl.processingFailed)
 
1934
        goto exit;
 
1935
 
 
1936
    /* Verify that file attributes scope over hardlinks correctly. */
 
1937
    checkHardLinks(&fl);
 
1938
 
 
1939
    genCpioListAndHeader(&fl, (TFI_t *)&pkg->cpioList, pkg->header, 0);
 
1940
 
 
1941
    if (spec->timeCheck)
 
1942
        timeCheck(spec->timeCheck, pkg->header);
 
1943
    
 
1944
exit:
 
1945
    fl.buildRootURL = _free(fl.buildRootURL);
 
1946
    fl.prefix = _free(fl.prefix);
 
1947
 
 
1948
    freeAttrRec(&fl.cur_ar);
 
1949
    freeAttrRec(&fl.def_ar);
 
1950
 
 
1951
    if (fl.currentLangs) {
 
1952
        int i;
 
1953
        for (i = 0; i < fl.nLangs; i++)
 
1954
            /*@-unqualifiedtrans@*/
 
1955
            fl.currentLangs[i] = _free(fl.currentLangs[i]);
 
1956
            /*@=unqualifiedtrans@*/
 
1957
        fl.currentLangs = _free(fl.currentLangs);
 
1958
    }
 
1959
 
 
1960
    fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
 
1961
    while (fl.docDirCount--)
 
1962
        fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
 
1963
    return fl.processingFailed;
 
1964
}
 
1965
 
 
1966
void initSourceHeader(Spec spec)
 
1967
{
 
1968
    HeaderIterator hi;
 
1969
    int_32 tag, type, count;
 
1970
    const void * ptr;
 
1971
 
 
1972
    spec->sourceHeader = headerNew();
 
1973
    /* Only specific tags are added to the source package header */
 
1974
    for (hi = headerInitIterator(spec->packages->header);
 
1975
        headerNextIterator(hi, &tag, &type, &ptr, &count);
 
1976
        ptr = headerFreeData(ptr, type))
 
1977
    {
 
1978
        switch (tag) {
 
1979
        case RPMTAG_NAME:
 
1980
        case RPMTAG_VERSION:
 
1981
        case RPMTAG_RELEASE:
 
1982
        case RPMTAG_EPOCH:
 
1983
        case RPMTAG_SUMMARY:
 
1984
        case RPMTAG_DESCRIPTION:
 
1985
        case RPMTAG_PACKAGER:
 
1986
        case RPMTAG_DISTRIBUTION:
 
1987
        case RPMTAG_DISTURL:
 
1988
        case RPMTAG_VENDOR:
 
1989
        case RPMTAG_LICENSE:
 
1990
        case RPMTAG_GROUP:
 
1991
        case RPMTAG_OS:
 
1992
        case RPMTAG_ARCH:
 
1993
        case RPMTAG_CHANGELOGTIME:
 
1994
        case RPMTAG_CHANGELOGNAME:
 
1995
        case RPMTAG_CHANGELOGTEXT:
 
1996
        case RPMTAG_URL:
 
1997
        case HEADER_I18NTABLE:
 
1998
            if (ptr)
 
1999
                (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
 
2000
            break;
 
2001
        default:
 
2002
            /* do not copy */
 
2003
            break;
 
2004
        }
 
2005
    }
 
2006
    hi = headerFreeIterator(hi);
 
2007
 
 
2008
    /* Add the build restrictions */
 
2009
    for (hi = headerInitIterator(spec->buildRestrictions);
 
2010
        headerNextIterator(hi, &tag, &type, &ptr, &count);
 
2011
        ptr = headerFreeData(ptr, type))
 
2012
    {
 
2013
        if (ptr)
 
2014
            (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
 
2015
    }
 
2016
    hi = headerFreeIterator(hi);
 
2017
 
 
2018
    if (spec->BANames && spec->BACount > 0) {
 
2019
        (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
 
2020
                       RPM_STRING_ARRAY_TYPE,
 
2021
                       spec->BANames, spec->BACount);
 
2022
    }
 
2023
}
 
2024
 
 
2025
int processSourceFiles(Spec spec)
 
2026
{
 
2027
    struct Source *srcPtr;
 
2028
    StringBuf sourceFiles;
 
2029
    int x, isSpec = 1;
 
2030
    struct FileList_s fl;
 
2031
    char *s, **files, **fp;
 
2032
    Package pkg;
 
2033
 
 
2034
    sourceFiles = newStringBuf();
 
2035
 
 
2036
    /* XXX
 
2037
     * XXX This is where the source header for noarch packages needs
 
2038
     * XXX to be initialized.
 
2039
     */
 
2040
    if (spec->sourceHeader == NULL)
 
2041
        initSourceHeader(spec);
 
2042
 
 
2043
    /* Construct the file list and source entries */
 
2044
    appendLineStringBuf(sourceFiles, spec->specFile);
 
2045
    if (spec->sourceHeader != NULL)
 
2046
    for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
 
2047
        if (srcPtr->flags & RPMBUILD_ISSOURCE) {
 
2048
            (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
 
2049
                                   RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
 
2050
            if (srcPtr->flags & RPMBUILD_ISNO) {
 
2051
                (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
 
2052
                                       RPM_INT32_TYPE, &srcPtr->num, 1);
 
2053
            }
 
2054
        }
 
2055
        if (srcPtr->flags & RPMBUILD_ISPATCH) {
 
2056
            (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
 
2057
                                   RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
 
2058
            if (srcPtr->flags & RPMBUILD_ISNO) {
 
2059
                (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
 
2060
                                       RPM_INT32_TYPE, &srcPtr->num, 1);
 
2061
            }
 
2062
        }
 
2063
 
 
2064
      { const char * sfn;
 
2065
        sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
 
2066
                "%{_sourcedir}/", srcPtr->source, NULL);
 
2067
        appendLineStringBuf(sourceFiles, sfn);
 
2068
        sfn = _free(sfn);
 
2069
      }
 
2070
    }
 
2071
 
 
2072
    for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
 
2073
        for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
 
2074
            const char * sfn;
 
2075
            sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
 
2076
                "%{_sourcedir}/", srcPtr->source, NULL);
 
2077
            appendLineStringBuf(sourceFiles, sfn);
 
2078
            sfn = _free(sfn);
 
2079
        }
 
2080
    }
 
2081
 
 
2082
    spec->sourceCpioList = NULL;
 
2083
 
 
2084
    fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
 
2085
    fl.processingFailed = 0;
 
2086
    fl.fileListRecsUsed = 0;
 
2087
    fl.totalFileSize = 0;
 
2088
    fl.prefix = NULL;
 
2089
    fl.buildRootURL = NULL;
 
2090
 
 
2091
    s = getStringBuf(sourceFiles);
 
2092
    files = splitString(s, strlen(s), '\n');
 
2093
 
 
2094
    /* The first source file is the spec file */
 
2095
    x = 0;
 
2096
    for (fp = files; *fp != NULL; fp++) {
 
2097
        const char * diskURL, *diskPath;
 
2098
        FileListRec flp;
 
2099
 
 
2100
        diskURL = *fp;
 
2101
        SKIPSPACE(diskURL);
 
2102
        if (! *diskURL)
 
2103
            continue;
 
2104
 
 
2105
        flp = &fl.fileList[x];
 
2106
 
 
2107
        flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
 
2108
        /* files with leading ! are no source files */
 
2109
        if (*diskURL == '!') {
 
2110
            flp->flags |= RPMFILE_GHOST;
 
2111
            diskURL++;
 
2112
        }
 
2113
 
 
2114
        (void) urlPath(diskURL, &diskPath);
 
2115
 
 
2116
        flp->diskURL = xstrdup(diskURL);
 
2117
        diskPath = strrchr(diskPath, '/');
 
2118
        if (diskPath)
 
2119
            diskPath++;
 
2120
        else
 
2121
            diskPath = diskURL;
 
2122
 
 
2123
        flp->fileURL = xstrdup(diskPath);
 
2124
        flp->verifyFlags = RPMVERIFY_ALL;
 
2125
 
 
2126
        if (Stat(diskURL, &flp->fl_st)) {
 
2127
            rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
 
2128
                diskURL, strerror(errno));
 
2129
            fl.processingFailed = 1;
 
2130
        }
 
2131
 
 
2132
        flp->uname = getUname(flp->fl_uid);
 
2133
        flp->gname = getGname(flp->fl_gid);
 
2134
        flp->langs = xstrdup("");
 
2135
        
 
2136
        fl.totalFileSize += flp->fl_size;
 
2137
        
 
2138
        if (! (flp->uname && flp->gname)) {
 
2139
            rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
 
2140
            fl.processingFailed = 1;
 
2141
        }
 
2142
 
 
2143
        isSpec = 0;
 
2144
        x++;
 
2145
    }
 
2146
    fl.fileListRecsUsed = x;
 
2147
    freeSplitString(files);
 
2148
 
 
2149
    if (! fl.processingFailed) {
 
2150
        if (spec->sourceHeader != NULL)
 
2151
            genCpioListAndHeader(&fl, (TFI_t *)&spec->sourceCpioList,
 
2152
                        spec->sourceHeader, 1);
 
2153
    }
 
2154
 
 
2155
    sourceFiles = freeStringBuf(sourceFiles);
 
2156
    fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
 
2157
    return fl.processingFailed;
 
2158
}
 
2159
 
 
2160
/**
 
2161
 */
 
2162
static StringBuf getOutputFrom(char * dir, char * argv[],
 
2163
                        const char * writePtr, int writeBytesLeft,
 
2164
                        int failNonZero)
 
2165
        /*@*/
 
2166
{
 
2167
    int progPID;
 
2168
    int toProg[2];
 
2169
    int fromProg[2];
 
2170
    int status;
 
2171
    void *oldhandler;
 
2172
    StringBuf readBuff;
 
2173
    int done;
 
2174
 
 
2175
    oldhandler = signal(SIGPIPE, SIG_IGN);
 
2176
 
 
2177
    toProg[0] = toProg[1] = 0;
 
2178
    (void) pipe(toProg);
 
2179
    fromProg[0] = fromProg[1] = 0;
 
2180
    (void) pipe(fromProg);
 
2181
    
 
2182
    if (!(progPID = fork())) {
 
2183
        (void) close(toProg[1]);
 
2184
        (void) close(fromProg[0]);
 
2185
        
 
2186
        (void) dup2(toProg[0], STDIN_FILENO);   /* Make stdin the in pipe */
 
2187
        (void) dup2(fromProg[1], STDOUT_FILENO); /* Make stdout the out pipe */
 
2188
 
 
2189
        (void) close(toProg[0]);
 
2190
        (void) close(fromProg[1]);
 
2191
 
 
2192
        if (dir) {
 
2193
            (void) chdir(dir);
 
2194
        }
 
2195
        
 
2196
        (void) execvp(argv[0], argv);
 
2197
        /* XXX this error message is probably not seen. */
 
2198
        rpmError(RPMERR_EXEC, _("Couldn't exec %s: %s\n"),
 
2199
                argv[0], strerror(errno));
 
2200
        _exit(RPMERR_EXEC);
 
2201
    }
 
2202
    if (progPID < 0) {
 
2203
        rpmError(RPMERR_FORK, _("Couldn't fork %s: %s\n"),
 
2204
                argv[0], strerror(errno));
 
2205
        return NULL;
 
2206
    }
 
2207
 
 
2208
    (void) close(toProg[0]);
 
2209
    (void) close(fromProg[1]);
 
2210
 
 
2211
    /* Do not block reading or writing from/to prog. */
 
2212
    (void) fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
 
2213
    (void) fcntl(toProg[1], F_SETFL, O_NONBLOCK);
 
2214
    
 
2215
    readBuff = newStringBuf();
 
2216
 
 
2217
    do {
 
2218
        fd_set ibits, obits;
 
2219
        struct timeval tv;
 
2220
        int nfd, nbw, nbr;
 
2221
        int rc;
 
2222
 
 
2223
        done = 0;
 
2224
top:
 
2225
        /* XXX the select is mainly a timer since all I/O is non-blocking */
 
2226
        FD_ZERO(&ibits);
 
2227
        FD_ZERO(&obits);
 
2228
        if (fromProg[0] >= 0) {
 
2229
            FD_SET(fromProg[0], &ibits);
 
2230
        }
 
2231
        if (toProg[1] >= 0) {
 
2232
            FD_SET(toProg[1], &obits);
 
2233
        }
 
2234
        tv.tv_sec = 1;
 
2235
        tv.tv_usec = 0;
 
2236
        nfd = ((fromProg[0] > toProg[1]) ? fromProg[0] : toProg[1]);
 
2237
        if ((rc = select(nfd, &ibits, &obits, NULL, &tv)) < 0) {
 
2238
            if (errno == EINTR)
 
2239
                goto top;
 
2240
            break;
 
2241
        }
 
2242
 
 
2243
        /* Write any data to program */
 
2244
        if (toProg[1] >= 0 && FD_ISSET(toProg[1], &obits)) {
 
2245
          if (writeBytesLeft) {
 
2246
            if ((nbw = write(toProg[1], writePtr,
 
2247
                    (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
 
2248
                if (errno != EAGAIN) {
 
2249
                    perror("getOutputFrom()");
 
2250
                    exit(EXIT_FAILURE);
 
2251
                }
 
2252
                nbw = 0;
 
2253
            }
 
2254
            writeBytesLeft -= nbw;
 
2255
            writePtr += nbw;
 
2256
          } else if (toProg[1] >= 0) {  /* close write fd */
 
2257
            (void) close(toProg[1]);
 
2258
            toProg[1] = -1;
 
2259
          }
 
2260
        }
 
2261
        
 
2262
        /* Read any data from prog */
 
2263
        {   char buf[BUFSIZ+1];
 
2264
            while ((nbr = read(fromProg[0], buf, sizeof(buf)-1)) > 0) {
 
2265
                buf[nbr] = '\0';
 
2266
                appendStringBuf(readBuff, buf);
 
2267
            }
 
2268
        }
 
2269
 
 
2270
        /* terminate on (non-blocking) EOF or error */
 
2271
        done = (nbr == 0 || (nbr < 0 && errno != EAGAIN));
 
2272
 
 
2273
    } while (!done);
 
2274
 
 
2275
    /* Clean up */
 
2276
    if (toProg[1] >= 0)
 
2277
        (void) close(toProg[1]);
 
2278
    if (fromProg[0] >= 0)
 
2279
        (void) close(fromProg[0]);
 
2280
    (void) signal(SIGPIPE, oldhandler);
 
2281
 
 
2282
    /* Collect status from prog */
 
2283
    (void)waitpid(progPID, &status, 0);
 
2284
    if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
 
2285
        rpmError(RPMERR_EXEC, _("%s failed\n"), argv[0]);
 
2286
        return NULL;
 
2287
    }
 
2288
    if (writeBytesLeft) {
 
2289
        rpmError(RPMERR_EXEC, _("failed to write all data to %s\n"), argv[0]);
 
2290
        return NULL;
 
2291
    }
 
2292
    return readBuff;
 
2293
}
 
2294
 
 
2295
/**
 
2296
 */
 
2297
typedef struct {
 
2298
/*@observer@*/ /*@null@*/ const char * msg;
 
2299
/*@observer@*/ const char * argv[4];
 
2300
    rpmTag ntag;
 
2301
    rpmTag vtag;
 
2302
    rpmTag ftag;
 
2303
    int mask;
 
2304
    int xor;
 
2305
} DepMsg_t;
 
2306
 
 
2307
/**
 
2308
 */
 
2309
/*@-exportlocal -exportheadervar@*/
 
2310
DepMsg_t depMsgs[] = {
 
2311
  { "Provides",         { "%{__find_provides}", NULL, NULL, NULL },
 
2312
        RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
 
2313
        0, -1 },
 
2314
  { "PreReq",           { NULL, NULL, NULL, NULL },
 
2315
        RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
 
2316
        RPMSENSE_PREREQ, 0 },
 
2317
  { "Requires(interp)", { NULL, "interp", NULL, NULL },
 
2318
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2319
        _notpre(RPMSENSE_INTERP), 0 },
 
2320
  { "Requires(rpmlib)", { NULL, "rpmlib", NULL, NULL },
 
2321
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2322
        _notpre(RPMSENSE_RPMLIB), 0 },
 
2323
  { "Requires(verify)", { NULL, "verify", NULL, NULL },
 
2324
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2325
        RPMSENSE_SCRIPT_VERIFY, 0 },
 
2326
  { "Requires(pre)",    { NULL, "pre", NULL, NULL },
 
2327
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2328
        _notpre(RPMSENSE_SCRIPT_PRE), 0 },
 
2329
  { "Requires(post)",   { NULL, "post", NULL, NULL },
 
2330
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2331
        _notpre(RPMSENSE_SCRIPT_POST), 0 },
 
2332
  { "Requires(preun)",  { NULL, "preun", NULL, NULL },
 
2333
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2334
        _notpre(RPMSENSE_SCRIPT_PREUN), 0 },
 
2335
  { "Requires(postun)", { NULL, "postun", NULL, NULL },
 
2336
        -1, -1, RPMTAG_REQUIREFLAGS,
 
2337
        _notpre(RPMSENSE_SCRIPT_POSTUN), 0 },
 
2338
  { "Requires",         { "%{__find_requires}", NULL, NULL, NULL },
 
2339
        -1, -1, RPMTAG_REQUIREFLAGS,    /* XXX inherit name/version arrays */
 
2340
        RPMSENSE_PREREQ, RPMSENSE_PREREQ },
 
2341
  { "Conflicts",        { "%{__find_conflicts}", NULL, NULL, NULL },
 
2342
        RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS,
 
2343
        0, -1 },
 
2344
  { "Obsoletes",        { "%{__find_obsoletes}", NULL, NULL, NULL },
 
2345
        RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS,
 
2346
        0, -1 },
 
2347
  { NULL,               { NULL, NULL, NULL, NULL },     0, 0, 0, 0, 0 }
 
2348
};
 
2349
/*@=exportlocal =exportheadervar@*/
 
2350
 
 
2351
/**
 
2352
 */
 
2353
static int generateDepends(Spec spec, Package pkg, TFI_t cpioList, int multiLib)
 
2354
        /*@modifies cpioList @*/
 
2355
{
 
2356
    TFI_t fi = cpioList;
 
2357
    StringBuf writeBuf;
 
2358
    int writeBytes;
 
2359
    StringBuf readBuf;
 
2360
    DepMsg_t *dm;
 
2361
    char *myargv[4];
 
2362
    int failnonzero = 0;
 
2363
    int rc = 0;
 
2364
    int i;
 
2365
 
 
2366
    if (!(fi && fi->fc > 0))
 
2367
        return 0;
 
2368
 
 
2369
    if (! (pkg->autoReq || pkg->autoProv))
 
2370
        return 0;
 
2371
    
 
2372
    writeBuf = newStringBuf();
 
2373
    for (i = 0, writeBytes = 0; i < fi->fc; i++) {
 
2374
 
 
2375
        if (fi->fmapflags && multiLib == 2) {
 
2376
            if (!(fi->fmapflags[i] & CPIO_MULTILIB))
 
2377
                continue;
 
2378
            fi->fmapflags[i] &= ~CPIO_MULTILIB;
 
2379
        }
 
2380
 
 
2381
        appendStringBuf(writeBuf, fi->dnl[fi->dil[i]]);
 
2382
        writeBytes += strlen(fi->dnl[fi->dil[i]]);
 
2383
        appendLineStringBuf(writeBuf, fi->bnl[i]);
 
2384
        writeBytes += strlen(fi->bnl[i]) + 1;
 
2385
    }
 
2386
 
 
2387
    for (dm = depMsgs; dm->msg != NULL; dm++) {
 
2388
        int tag, tagflags;
 
2389
 
 
2390
        tag = (dm->ftag > 0) ? dm->ftag : dm->ntag;
 
2391
        tagflags = 0;
 
2392
 
 
2393
        switch(tag) {
 
2394
        case RPMTAG_PROVIDEFLAGS:
 
2395
            if (!pkg->autoProv)
 
2396
                continue;
 
2397
            failnonzero = 1;
 
2398
            tagflags = RPMSENSE_FIND_PROVIDES;
 
2399
            break;
 
2400
        case RPMTAG_REQUIREFLAGS:
 
2401
            if (!pkg->autoReq)
 
2402
                continue;
 
2403
            failnonzero = 0;
 
2404
            tagflags = RPMSENSE_FIND_REQUIRES;
 
2405
            break;
 
2406
        default:
 
2407
            continue;
 
2408
            /*@notreached@*/ break;
 
2409
        }
 
2410
 
 
2411
        /* Get the script name to run */
 
2412
        /*@-nullderef@*/        /* FIX: double indirection. @*/
 
2413
        myargv[0] = (dm->argv[0] ? rpmExpand(dm->argv[0], NULL) : NULL);
 
2414
        /*@=nullderef@*/
 
2415
 
 
2416
        if (!(myargv[0] && *myargv[0] != '%')) {
 
2417
            myargv[0] = _free(myargv[0]);
 
2418
            continue;
 
2419
        }
 
2420
 
 
2421
        rpmMessage(RPMMESS_NORMAL, _("Finding  %s: (using %s)...\n"),
 
2422
                dm->msg, myargv[0]);
 
2423
 
 
2424
#if 0
 
2425
        if (*myargv[0] != '/') {        /* XXX FIXME: stat script here */
 
2426
            myargv[0] = _free(myargv[0]);
 
2427
            continue;
 
2428
        }
 
2429
#endif
 
2430
 
 
2431
        /* Expand rest of script arguments (if any) */
 
2432
        for (i = 1; i < 4; i++) {
 
2433
            /*@-nullderef@*/    /* FIX: double indirection. @*/
 
2434
            myargv[i] = dm->argv[i] ? rpmExpand(dm->argv[i], NULL) : NULL;
 
2435
            /*@=nullderef@*/
 
2436
        }
 
2437
 
 
2438
        readBuf = getOutputFrom(NULL, myargv,
 
2439
                        getStringBuf(writeBuf), writeBytes, failnonzero);
 
2440
 
 
2441
        /* Free expanded args */
 
2442
        for (i = 0; i < 4; i++)
 
2443
            myargv[i] = _free(myargv[i]);
 
2444
 
 
2445
        if (readBuf == NULL) {
 
2446
            rc = RPMERR_EXEC;
 
2447
            rpmError(rc, _("Failed to find %s:\n"), dm->msg);
 
2448
            break;
 
2449
        }
 
2450
 
 
2451
        /* Parse dependencies into header */
 
2452
        tagflags &= ~RPMSENSE_MULTILIB;
 
2453
        if (multiLib > 1)
 
2454
            tagflags |=  RPMSENSE_MULTILIB;
 
2455
        else
 
2456
            tagflags &= ~RPMSENSE_MULTILIB;
 
2457
        rc = parseRCPOT(spec, pkg, getStringBuf(readBuf), tag, 0, tagflags);
 
2458
        readBuf = freeStringBuf(readBuf);
 
2459
 
 
2460
        if (rc) {
 
2461
            rpmError(rc, _("Failed to find %s:\n"), dm->msg);
 
2462
            break;
 
2463
        }
 
2464
    }
 
2465
 
 
2466
    writeBuf = freeStringBuf(writeBuf);
 
2467
    return rc;
 
2468
}
 
2469
 
 
2470
/**
 
2471
 */
 
2472
static void printDepMsg(DepMsg_t * dm, int count, const char ** names,
 
2473
                const char ** versions, int *flags)
 
2474
        /*@modifies fileSystem @*/
 
2475
{
 
2476
    int hasVersions = (versions != NULL);
 
2477
    int hasFlags = (flags != NULL);
 
2478
    int bingo = 0;
 
2479
    int i;
 
2480
 
 
2481
    for (i = 0; i < count; i++, names++, versions++, flags++) {
 
2482
        if (hasFlags && !((*flags & dm->mask) ^ dm->xor))
 
2483
            continue;
 
2484
        if (bingo == 0) {
 
2485
            rpmMessage(RPMMESS_NORMAL, "%s:", (dm->msg ? dm->msg : ""));
 
2486
            bingo = 1;
 
2487
        }
 
2488
        rpmMessage(RPMMESS_NORMAL, " %s", *names);
 
2489
 
 
2490
        if (hasFlags && isDependsMULTILIB(*flags))
 
2491
            rpmMessage(RPMMESS_NORMAL, " (multilib)");
 
2492
 
 
2493
        if (hasVersions && !(*versions != NULL && **versions != '\0'))
 
2494
            continue;
 
2495
        if (!(hasFlags && (*flags && RPMSENSE_SENSEMASK)))
 
2496
            continue;
 
2497
 
 
2498
        rpmMessage(RPMMESS_NORMAL, " ");
 
2499
        if (*flags & RPMSENSE_LESS)
 
2500
            rpmMessage(RPMMESS_NORMAL, "<");
 
2501
        if (*flags & RPMSENSE_GREATER)
 
2502
            rpmMessage(RPMMESS_NORMAL, ">");
 
2503
        if (*flags & RPMSENSE_EQUAL)
 
2504
            rpmMessage(RPMMESS_NORMAL, "=");
 
2505
 
 
2506
        rpmMessage(RPMMESS_NORMAL, " %s", *versions);
 
2507
    }
 
2508
    if (bingo)
 
2509
        rpmMessage(RPMMESS_NORMAL, "\n");
 
2510
}
 
2511
 
 
2512
/**
 
2513
 */
 
2514
static void printDeps(Header h)
 
2515
        /*@modifies fileSystem @*/
 
2516
{
 
2517
    HGE_t hge = (HGE_t)headerGetEntryMinMemory;
 
2518
    HFD_t hfd = headerFreeData;
 
2519
    const char ** names = NULL;
 
2520
    rpmTagType dnt = -1;
 
2521
    const char ** versions = NULL;
 
2522
    rpmTagType dvt = -1;
 
2523
    int * flags = NULL;
 
2524
    DepMsg_t * dm;
 
2525
    int count;
 
2526
 
 
2527
    for (dm = depMsgs; dm->msg != NULL; dm++) {
 
2528
        switch (dm->ntag) {
 
2529
        case 0:
 
2530
            names = hfd(names, dnt);
 
2531
            break;
 
2532
        case -1:
 
2533
            break;
 
2534
        default:
 
2535
            names = hfd(names, dnt);
 
2536
            if (!hge(h, dm->ntag, &dnt, (void **) &names, &count))
 
2537
                continue;
 
2538
            break;
 
2539
        }
 
2540
        switch (dm->vtag) {
 
2541
        case 0:
 
2542
            versions = hfd(versions, dvt);
 
2543
            break;
 
2544
        case -1:
 
2545
            break;
 
2546
        default:
 
2547
            versions = hfd(versions, dvt);
 
2548
            (void) hge(h, dm->vtag, &dvt, (void **) &versions, NULL);
 
2549
            break;
 
2550
        }
 
2551
        switch (dm->ftag) {
 
2552
        case 0:
 
2553
            flags = NULL;
 
2554
            break;
 
2555
        case -1:
 
2556
            break;
 
2557
        default:
 
2558
            (void) hge(h, dm->ftag, NULL, (void **) &flags, NULL);
 
2559
            break;
 
2560
        }
 
2561
        printDepMsg(dm, count, names, versions, flags);
 
2562
    }
 
2563
    names = hfd(names, dnt);
 
2564
    versions = hfd(versions, dvt);
 
2565
}
 
2566
 
 
2567
int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
 
2568
{
 
2569
    Package pkg;
 
2570
    int res = 0;
 
2571
    
 
2572
    for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
 
2573
        const char *n, *v, *r;
 
2574
        int rc;
 
2575
 
 
2576
        if (pkg->fileList == NULL)
 
2577
            continue;
 
2578
 
 
2579
        (void) headerNVR(pkg->header, &n, &v, &r);
 
2580
        rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
 
2581
                   
 
2582
        if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
 
2583
            res = rc;
 
2584
 
 
2585
    /* XXX This should be added always so that packages look alike.
 
2586
     * XXX However, there is logic in files.c/depends.c that checks for
 
2587
     * XXX existence (rather than value) that will need to change as well.
 
2588
     */
 
2589
        if (headerIsEntry(pkg->header, RPMTAG_MULTILIBS)) {
 
2590
            (void) generateDepends(spec, pkg, pkg->cpioList, 1);
 
2591
            (void) generateDepends(spec, pkg, pkg->cpioList, 2);
 
2592
        } else
 
2593
            (void) generateDepends(spec, pkg, pkg->cpioList, 0);
 
2594
        printDeps(pkg->header);
 
2595
    }
 
2596
 
 
2597
    return res;
 
2598
}