rpm
5.2.1
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio.h> 00009 #include <rpmiotypes.h> 00010 #include <rpmlog.h> 00011 #include "rpmbuild.h" 00012 #include "debug.h" 00013 00014 #define mySKIPSPACE(s) { while (*(s) && isspace(*(s))) (s)++; } 00015 #define mySKIPNONSPACE(s) { while (*(s) && !isspace(*(s))) (s)++; } 00016 00017 void addChangelogEntry(Header h, time_t time, const char *name, const char *text) 00018 { 00019 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00020 rpmuint32_t mytime = (rpmuint32_t)time; /* XXX convert to rpmuint32_t for header */ 00021 int xx; 00022 00023 he->tag = RPMTAG_CHANGELOGTIME; 00024 he->t = RPM_UINT32_TYPE; 00025 he->p.ui32p = &mytime; 00026 he->c = 1; 00027 he->append = 1; 00028 xx = headerPut(h, he, 0); 00029 he->append = 0; 00030 00031 he->tag = RPMTAG_CHANGELOGNAME; 00032 he->t = RPM_STRING_ARRAY_TYPE; 00033 he->p.argv = &name; 00034 he->c = 1; 00035 he->append = 1; 00036 xx = headerPut(h, he, 0); 00037 he->append = 0; 00038 00039 he->tag = RPMTAG_CHANGELOGTEXT; 00040 he->t = RPM_STRING_ARRAY_TYPE; 00041 he->p.argv = &text; 00042 he->c = 1; 00043 he->append = 1; 00044 xx = headerPut(h, he, 0); 00045 he->append = 0; 00046 } 00047 00054 static int dateToTimet(const char * datestr, /*@out@*/ time_t * secs) 00055 /*@modifies *secs @*/ 00056 { 00057 struct tm time; 00058 time_t timezone_offset; 00059 char * p, * pe, * q, ** idx; 00060 char * date = strcpy(alloca(strlen(datestr) + 1), datestr); 00061 /*@observer@*/ static char * days[] = 00062 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; 00063 /*@observer@*/ static char * months[] = 00064 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 00065 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; 00066 /*@observer@*/ static char lengths[] = 00067 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 00068 00069 memset(&time, 0, sizeof(time)); 00070 00071 pe = date; 00072 00073 /* day of week */ 00074 p = pe; mySKIPSPACE(p); 00075 if (*p == '\0') return -1; 00076 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00077 for (idx = days; *idx && strcmp(*idx, p); idx++) 00078 {}; 00079 if (*idx == NULL) return -1; 00080 00081 /* month */ 00082 p = pe; mySKIPSPACE(p); 00083 if (*p == '\0') return -1; 00084 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00085 for (idx = months; *idx && strcmp(*idx, p); idx++) 00086 {}; 00087 if (*idx == NULL) return -1; 00088 time.tm_mon = idx - months; 00089 00090 /* day */ 00091 p = pe; mySKIPSPACE(p); 00092 if (*p == '\0') return -1; 00093 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00094 00095 /* make this noon so the day is always right (as we make this UTC) */ 00096 time.tm_hour = 12; 00097 00098 time.tm_mday = strtol(p, &q, 10); 00099 if (!(q && *q == '\0')) return -1; 00100 if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1; 00101 00102 /* year */ 00103 p = pe; mySKIPSPACE(p); 00104 if (*p == '\0') return -1; 00105 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00106 time.tm_year = strtol(p, &q, 10); 00107 if (!(q && *q == '\0')) return -1; 00108 if (time.tm_year < 1990 || time.tm_year >= 3000) return -1; 00109 time.tm_year -= 1900; 00110 00111 *secs = mktime(&time); 00112 if (*secs == -1) return -1; 00113 00114 /* determine timezone offset */ 00115 /*@-nullpass@*/ /* gmtime(3) unlikely to return NULL soon. */ 00116 timezone_offset = mktime(gmtime(secs)) - *secs; 00117 /*@=nullpass@*/ 00118 00119 /* adjust to UTC */ 00120 *secs += timezone_offset; 00121 00122 return 0; 00123 } 00124 00125 /*@-redecl@*/ 00126 extern time_t get_date(const char * p, void * now); /* XXX expedient lies */ 00127 /*@=redecl@*/ 00128 00135 static rpmRC addChangelog(Header h, rpmiob iob) 00136 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00137 /*@modifies h, rpmGlobalMacroContext, internalState @*/ 00138 { 00139 char * s = rpmiobStr(iob); 00140 char * se; 00141 char *date, *name, *text; 00142 int i; 00143 time_t time; 00144 time_t lastTime = 0; 00145 int nentries = 0; 00146 static time_t last = 0; 00147 static int oneshot = 0; 00148 00149 /* Determine changelog truncation criteria. */ 00150 if (!oneshot++) { 00151 char * t = rpmExpand("%{?_changelog_truncate}", NULL); 00152 char *te = NULL; 00153 if (t && *t) { 00154 long res = strtol(t, &te, 0); 00155 if (res >= 0 && *te == '\0') { 00156 last = res; /* truncate to no. of entries. */ 00157 } else { 00158 /*@-moduncon@*/ 00159 res = (long)get_date (t, NULL); 00160 /*@=moduncon@*/ 00161 /* XXX malformed date string silently ignored. */ 00162 if (res > 0) { 00163 last = res; /* truncate to date. */ 00164 } 00165 } 00166 } 00167 t = _free(t); 00168 } 00169 00170 /* skip space */ 00171 mySKIPSPACE(s); 00172 00173 while (*s != '\0') { 00174 if (*s != '*') { 00175 rpmlog(RPMLOG_ERR, 00176 _("%%changelog entries must start with *\n")); 00177 return RPMRC_FAIL; 00178 } 00179 00180 /* find end of line */ 00181 date = s; 00182 while(*s && *s != '\n') s++; 00183 if (! *s) { 00184 rpmlog(RPMLOG_ERR, _("incomplete %%changelog entry\n")); 00185 return RPMRC_FAIL; 00186 } 00187 /*@-modobserver@*/ 00188 *s = '\0'; 00189 /*@=modobserver@*/ 00190 text = s + 1; 00191 00192 /* 4 fields of date */ 00193 date++; 00194 s = date; 00195 for (i = 0; i < 4; i++) { 00196 mySKIPSPACE(s); 00197 mySKIPNONSPACE(s); 00198 } 00199 mySKIPSPACE(date); 00200 if (dateToTimet(date, &time)) { 00201 rpmlog(RPMLOG_ERR, _("bad date in %%changelog: %s\n"), date); 00202 return RPMRC_FAIL; 00203 } 00204 if (lastTime && lastTime < time) { 00205 rpmlog(RPMLOG_ERR, 00206 _("%%changelog not in descending chronological order\n")); 00207 return RPMRC_FAIL; 00208 } 00209 lastTime = time; 00210 00211 /* skip space to the name */ 00212 mySKIPSPACE(s); 00213 if (! *s) { 00214 rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n")); 00215 return RPMRC_FAIL; 00216 } 00217 00218 /* name */ 00219 name = s; 00220 while (*s != '\0') s++; 00221 while (s > name && isspace(*s)) 00222 *s-- = '\0'; 00223 00224 if (s == name) { 00225 rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n")); 00226 return RPMRC_FAIL; 00227 } 00228 00229 /* text */ 00230 mySKIPSPACE(text); 00231 if (! *text) { 00232 rpmlog(RPMLOG_ERR, _("no description in %%changelog\n")); 00233 return RPMRC_FAIL; 00234 } 00235 00236 /* find the next leading '*' (or eos) */ 00237 s = text; 00238 do { 00239 s++; 00240 } while (*s && (*(s-1) != '\n' || *s != '*')); 00241 se = s; 00242 s--; 00243 00244 /* backup to end of description */ 00245 while ((s > text) && xisspace(*s)) 00246 *s-- = '\0'; 00247 00248 /* Add entry if not truncated. */ 00249 nentries++; 00250 00251 if (last <= 0 00252 || (last < 1000 && nentries < (int)last) 00253 || (last > 1000 && time >= last)) 00254 addChangelogEntry(h, time, name, text); 00255 00256 s = se; 00257 00258 } 00259 00260 return 0; 00261 } 00262 00263 int parseChangelog(Spec spec) 00264 { 00265 rpmParseState nextPart; 00266 rpmiob iob = rpmiobNew(0); 00267 rpmRC rc; 00268 00269 /* There are no options to %changelog */ 00270 if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) { 00271 iob = rpmiobFree(iob); 00272 return PART_NONE; 00273 } 00274 if (rc != RPMRC_OK) 00275 return rc; 00276 00277 while ((nextPart = isPart(spec)) == PART_NONE) { 00278 const char * line; 00279 line = xstrdup(spec->line); 00280 line = xstrtolocale(line); 00281 iob = rpmiobAppend(iob, spec->line, 0); 00282 line = _free(line); 00283 if ((rc = readLine(spec, STRIP_COMMENTS | STRIP_NOEXPAND)) > 0) { 00284 nextPart = PART_NONE; 00285 break; 00286 } 00287 if (rc != RPMRC_OK) 00288 return rc; 00289 } 00290 00291 rc = addChangelog(spec->packages->header, iob); 00292 iob = rpmiobFree(iob); 00293 00294 return (rc != RPMRC_OK ? rc : (rpmRC)nextPart); 00295 }