summaryrefslogtreecommitdiff
path: root/build/vspec.c
blob: cc3f35510965b138570c81f29a5556076c01066d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/* Routine to "verify" a parsed spec file */

/***************

Here's what we do

. check for duplicate fields
. make sure a certain set of fields are present
. in subpackages, make sure a certain set of fields are present
. in subpackages, make sure certain fields are *not* present

. check for duplicate sources/patch numbers
. do some checking on the field values for legit characters

****************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "header.h"
#include "spec.h"
#include "specP.h"
#include "messages.h"
#include "rpmlib.h"
#include "stringbuf.h"
#include "misc.h"

#define EMPTY(s) ((!(s)) || (!(*(s))))
#define OOPS(s) {fprintf(stderr, "verifySpec: %s\n", s); res = 1;}
#define MUST 1

struct packageFieldsRec {
    int tag;
    int present;
    int shouldBePresent;
};

struct fieldNamesRec {
    int tag;
    char *name;
};

static int checkHeaderTags(Header inh, struct packageFieldsRec *pfr);
static char *tagName(int tag);

/* This is a list of tags related to the "main" package. */
/* Only list those that must or must not be present.     */

static struct packageFieldsRec packageFields[] = {
    { RPMTAG_NAME,            0, MUST },
    { RPMTAG_VERSION,         0, MUST },
    { RPMTAG_RELEASE,         0, MUST },
/*    { RPMTAG_SUMMARY,         0, MUST }, */
    { RPMTAG_DESCRIPTION,     0, MUST },
    { RPMTAG_COPYRIGHT,       0, MUST },
/*    { RPMTAG_PACKAGER,        0, MUST }, */
    { RPMTAG_GROUP,           0, MUST },
    { 0, 0, 0 },
};

/* This is a list of tags related to "sub" packages. */
/* Only list those that must or must not be present. */

static struct packageFieldsRec subpackageFields[] = {
    { RPMTAG_NAME,            0, MUST },  /* This is inserted automaticaly */
    { RPMTAG_SUMMARY,         0, MUST },
    { RPMTAG_DESCRIPTION,     0, MUST },
    { RPMTAG_GROUP,           0, MUST },
    { RPMTAG_NAME,            0, 0 },
/*    { RPMTAG_COPYRIGHT,       0, 0 }, */
    { RPMTAG_PACKAGER,        0, 0 },
    { RPMTAG_BUILDROOT,       0, 0 },
    { 0, 0, 0 },
};

static struct packageFieldsRec *findTag(int tag, struct packageFieldsRec *pfr)
{
    struct packageFieldsRec *p = pfr;

    while (p->tag) {
	if (p->tag == tag)
	    return p;
	p++;
    }

    return NULL;
}

static char *tagName(int tag)
{
    int i = 0;
    static char nameBuf[1024];
    char *s;

    strcpy(nameBuf, "(unknown)");
    while (i < rpmTagTableSize) {
	if (tag == rpmTagTable[i].val) {
	    strcpy(nameBuf, rpmTagTable[i].name + 7);
	    s = nameBuf+1;
	    while (*s) {
		*s = tolower(*s);
		s++;
	    }
	}
	i++;
    }

    return nameBuf;
}

static int checkHeaderTags(Header inh, struct packageFieldsRec *pfr)
{
    Header h;
    HeaderIterator headerIter;
    int res = 0;
    int_32 tag, lastTag, type, c;
    void *ptr;
    struct packageFieldsRec *p;

    /* Sort the index, so it'll be easy to catch dups */
    h = headerCopy(inh);
    headerSort(h);

    headerIter = headerInitIterator(h);
    lastTag = 0;
    while (headerNextIterator(headerIter, &tag, &type, &ptr, &c)) {
	if (tag == lastTag) {
	    rpmError(RPMERR_BADSPEC, "Duplicate fields for     : %s",
		  tagName(tag));
	    res = 1;
	}
	p = findTag(tag, pfr);
	if (p) 
	    p->present = 1;
	lastTag = tag;
    }
    headerFreeIterator(headerIter);
    headerFree(h);

    p = pfr;
    while (p->tag) {
	if (p->shouldBePresent != p->present) {
	    rpmError(RPMERR_BADSPEC, "Field must%s be present%s: %s",
		  p->present ? " NOT" : "", p->present ? "" : "    ",
		  tagName(p->tag));
	    res = 1;
	}
	p->present = 0;  /* hack to clear it for next time :-) */
	p++;
    }
    
    return res;
}

int verifySpec(Spec s)
{
    int res = 0;
    struct PackageRec *pr;
    struct packageFieldsRec *fields;
    char name[1024];
    char *val;
    
    if (EMPTY(s->name)) {
	OOPS("No Name field");
    }

    /* Check each package/subpackage */
    pr = s->packages;
    fields = packageFields;
    while (pr) {
	if (! pr->subname) {
	    if (pr->newname) {
		strcpy(name, pr->newname);
	    } else {
		strcpy(name, s->name);
	    }
	} else {
	    sprintf(name, "%s-%s", s->name, pr->subname);
	}
	printf("* Package: %s\n", name);

	if (checkHeaderTags(pr->header, fields)) {
	    res = 1;
	}

	val = NULL;
	headerGetEntry(pr->header, RPMTAG_VERSION, NULL, (void *) &val, NULL);
	if (val && strchr(val, '-')) {
	    rpmError(RPMERR_BADSPEC, "Illegal '-' char in version: %s\n", val);
	    res = 1;
	}
	val = NULL;
	headerGetEntry(pr->header, RPMTAG_RELEASE, NULL, (void *) &val, NULL);
	if (val && strchr(val, '-')) {
	    rpmError(RPMERR_BADSPEC, "Illegal '-' char in release: %s\n", val);
	    res = 1;
	}
	
	pr = pr->next;
	fields = subpackageFields;
    }
    
    return res;
}