Various tidyings.
[sw-tools] / src / sw_info.c
CommitLineData
3315e8b3 1/* -*-c-*-
2 *
e0465a2b 3 * $Id: sw_info.c,v 1.2 1999/06/18 18:58:45 mdw Exp $
3315e8b3 4 *
5 * Maintenance of `.sw-info' files
6 *
7 * (c) 1999 EBI
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of sw-tools.
13 *
14 * sw-tools is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * sw-tools is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with sw-tools; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: sw_info.c,v $
e0465a2b 32 * Revision 1.2 1999/06/18 18:58:45 mdw
33 * Various tidyings.
34 *
35 * Revision 1.1.1.1 1999/06/02 16:53:35 mdw
36 * Initial import.
3315e8b3 37 *
38 */
39
40/*----- Header files ------------------------------------------------------*/
41
42#include "config.h"
43
44#include <ctype.h>
45#include <errno.h>
46#include <stddef.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <time.h>
51
52#include <sys/types.h>
53#include <pwd.h>
54#include <unistd.h>
55
56#include <mLib/alloc.h>
57#include <mLib/dstr.h>
58#include <mLib/lock.h>
59#include <mLib/quis.h>
60#include <mLib/report.h>
61
62#include "sw_arch.h"
63#include "sw_info.h"
64
65/*----- Static variables --------------------------------------------------*/
66
67static struct swfield {
68 char *name;
69 size_t off;
70 char *desc;
71} swfields[] = {
72 { "package", offsetof(swinfo, package), "Package" },
73 { "version", offsetof(swinfo, version), "Version" },
74 { "maintainer", offsetof(swinfo, maintainer), "Maintained by" },
75 { "date", offsetof(swinfo, date), "Last modified" },
76 { "only-arch", offsetof(swinfo, only_arch), "Only build for" },
77 { "arch", offsetof(swinfo, arch), "Successfully built" },
78 { 0, 0 }
79};
80typedef struct swfield swfield;
81
82#define SWINFO(sw, off) (*(char **)((char *)sw + off))
83
84/*----- Main code ---------------------------------------------------------*/
85
86/* --- @swinfo_clear@ --- *
87 *
88 * Arguments: @swinfo *sw@ = pointe to info block
89 *
90 * Returns: ---
91 *
92 * Use: Clears an info block so that it doesn't contain anything.
93 * This is mainly useful when building skeletons to apply using
94 * @swinfo_update@.
95 */
96
97void swinfo_clear(swinfo *sw)
98{
99 swfield *f;
100 for (f = swfields; f->name; f++)
101 SWINFO(sw, f->off) = 0;
102}
103
104/* --- @swinfo_fetch@ --- *
105 *
106 * Arguments: @swinfo *sw@ = pointer to info block to fill in
107 *
108 * Returns: Zero if OK, else nonzero.
109 *
110 * Use: Fills in the info block if it can.
111 */
112
113int swinfo_fetch(swinfo *sw)
114{
115 FILE *fp;
116 dstr d = DSTR_INIT;
117 swfield *f;
118 int line = 0;
119
120 /* --- Initialize the various fields --- */
121
122 swinfo_clear(sw);
123
124 /* --- Open the data file --- */
125
126 if ((fp = fopen(".sw-info", "r")) == 0)
127 return (-1);
128
129 /* --- Read the lines from the file --- */
130
131 for (; dstr_putline(&d, fp) != EOF; DRESET(&d)) {
132 char *p = d.buf;
133 char *key, *value;
134 line++;
135
136 /* --- Find the field name --- */
137
138 while (isspace((unsigned char)*p))
139 p++;
140 if (*p == 0 || *p == '#')
141 continue;
142
143 /* --- Find the end of the field name --- */
144
145 key = p;
146 while (*p && *p != '=' && !isspace((unsigned char)*p))
147 p++;
148
149 /* --- Skip an optional `=' sign --- */
150
151 {
152 char ch = *p;
153 if (ch)
154 *p++ = 0;
155 while (isspace((unsigned char)*p))
156 p++;
157 if (*p == '=' && ch != '=') {
158 p++;
159 while (isspace((unsigned char)*p))
160 p++;
161 }
162 }
163
164 value = p;
165
166 /* --- Look up the key in the table --- */
167
168 for (f = swfields; f->name; f++) {
169 if (strcmp(key, f->name) == 0)
170 goto found;
171 }
172 moan("unknown key `%s' at line %i in `.sw-info'", key, line);
173 continue;
174
175 /* --- Put the value in --- */
176
177 found:
178 SWINFO(sw, f->off) = xstrdup(value);
179 }
180
181 fclose(fp);
182 dstr_destroy(&d);
183 return (0);
184}
185
186/* --- @swinfo_sanity@ --- *
187 *
188 * Arguments: @swinfo *sw@ = pointer to an info block
189 *
190 * Returns: Yes, if the block is OK.
191 *
192 * Use: Objects if the information in the info block is bad.
193 */
194
195void swinfo_sanity(swinfo *sw)
196{
197 if (!sw->package)
198 die(1, "unknown package name. Try `%s setup PACKAGE VERSION'.", QUIS);
199 if (!sw->version)
200 die(1, "unknown package version. Try `%s setup PACKAGE VERSION'.",
201 QUIS);
202 if (!sw->maintainer)
203 die(1, "unknown maintainer. Try `%s setup PACKAGE VERSION'.", QUIS);
204 if (!sw->date)
205 die(1, "unknown date. Try `%s setup PACKAGE VERSION'.", QUIS);
206}
207
208/* --- @swinfo_put@ --- *
209 *
210 * Arguments: @swinfo *sw@ = pointer to an info block
211 *
212 * Returns: Zero if it worked, nonzero if not.
213 *
214 * Use: Writes an info block to the appropriate file.
215 */
216
217int swinfo_put(swinfo *sw)
218{
219 FILE *fp;
220 swfield *f;
221 int e;
222
223 /* --- Quick sanity check --- */
224
225 swinfo_sanity(sw);
226
227 /* --- Write the new data out --- */
228
229 if ((fp = fopen(".sw-info.new", "w")) == 0)
230 return (-1);
231 for (f = swfields; f->name; f++) {
232 if (!SWINFO(sw, f->off))
233 continue;
234 if (fprintf(fp, "%s = %s\n", f->name, SWINFO(sw, f->off)) == EOF) {
235 e = errno;
236 fclose(fp);
237 goto tidy_0;
238 }
239 }
240 if (fclose(fp) == EOF) {
241 e = errno;
242 goto tidy_0;
243 }
244
245 /* --- Carefully! replace the old one --- *
246 *
247 * Keep an old one around just in case, unless the renames fail because
248 * files don't exist.
249 */
250
251 remove(".sw-info.older"); /* Don't care if this fails */
252 if (rename(".sw-info.old", ".sw-info.older") && errno != ENOENT)
253 { e = errno; goto tidy_0; }
254 if (rename(".sw-info", ".sw-info.old") && errno != ENOENT)
255 { e = errno; goto tidy_1; }
256 if (rename(".sw-info.new", ".sw-info"))
257 { e = errno; goto tidy_2; }
258 remove(".sw-info.older"); /* Don't care if this fails */
259 return (0);
260
261 /* --- Tidy up if anything went tits-up --- */
262
263tidy_2:
264 rename(".sw-info.old", ".sw-info");
265tidy_1:
266 rename(".sw-info.older", ".sw-info.old");
267tidy_0:
268 remove(".sw-info.new");
269 errno = e;
270 return (-1);
271}
272
273/* --- @swinfo_destroy@ --- *
274 *
275 * Arguments: @swinfo *sw@ = pointer to info block
276 *
277 * Returns: ---
278 *
279 * Use: Destroys an info block when it's not useful any more.
280 */
281
282void swinfo_destroy(swinfo *sw)
283{
284 swfield *f;
285
286 for (f = swfields; f->name; f++) {
287 if (SWINFO(sw, f->off))
288 free(SWINFO(sw, f->off));
289 }
290}
291
292/* --- @swinfo_update@ --- *
293 *
294 * Arguments: @swinfo *sw@ = pointer to info block
295 * @swinfo *skel@ = pointer to skeleton values
296 *
297 * Returns: ---
298 *
299 * Use: Updates the fields in an information block, except for the
300 * architecture names stuff. (I'll leave that for later,
301 * because it's rather more involved.
302 */
303
304void swinfo_update(swinfo *sw, swinfo *skel)
305{
306 char ubuf[20];
307 char dbuf[20];
308 swfield *f;
309
310 /* --- Set up a default maintainer --- */
311
312 if (!skel->maintainer && !sw->maintainer) {
313 char *u = getenv("USER");
314
315 if (!u)
316 u = getenv("LOGNAME");
317 if (!u) {
318 struct passwd *pw = getpwuid(getuid());
319 if (!pw) {
320 moan("you don't seem to exist");
321 sprintf(ubuf, "uid %i", (int)getuid());
322 u = ubuf;
323 } else
324 u = pw->pw_name;
325 }
326 skel->maintainer = u;
327 }
328
329 /* --- Set up a default date --- */
330
331 {
332 time_t t = time(0);
333 struct tm *tm = localtime(&t);
334 strftime(dbuf, sizeof(dbuf), "%Y-%m-%d", tm);
335 skel->date = dbuf;
336 }
337
338 /* --- Set a default architecture list --- */
339
340 if (!skel->arch && !sw->arch)
341 skel->arch = "";
342
343 /* --- Grind through all the fields --- */
344
345 for (f = swfields; f->name; f++) {
346 if (!SWINFO(skel, f->off) || strcmp(SWINFO(skel, f->off), "-") == 0)
347 continue;
348 if (SWINFO(sw, f->off))
349 free(SWINFO(sw, f->off));
350 SWINFO(sw, f->off) = xstrdup(SWINFO(skel, f->off));
351 }
352}
353
354/*----- Subcommands -------------------------------------------------------*/
355
356/* --- @sw_setup@ --- */
357
358int sw_setup(int argc, char *argv[])
359{
360 swinfo sw, skel;
361 if (argc < 3 || argc > 4)
362 die(1, "Usage: setup PACKAGE VERSION [MAINTAINER]");
363 swinfo_fetch(&sw);
364 swinfo_clear(&skel);
365 skel.package = argv[1];
366 skel.version = argv[2];
367 if (argv[3])
368 skel.maintainer = argv[3];
369 swinfo_update(&sw, &skel);
370 swinfo_put(&sw);
371 return (0);
372}
373
374/* --- @sw_status@ --- */
375
376int sw_status(int argc, char *argv[])
377{
378 swinfo sw;
379 swfield *f;
380 if (swinfo_fetch(&sw)) {
381 die(1, "couldn't read build status: %s (try running setup)",
382 strerror(errno));
383 }
384 for (f = swfields; f->name; f++) {
385 if (SWINFO(&sw, f->off))
386 printf("%s: %s\n", f->desc, SWINFO(&sw, f->off));
387 }
388 return (0);
389}
390
391/* --- @sw_commit@ --- */
392
393int sw_commit(int argc, char *argv[])
394{
395 swinfo sw;
396
397 if (argc != 1)
398 die(1, "Usage: commit");
399 if (swinfo_fetch(&sw)) {
400 die(1, "couldn't read build status: %s (try running setup)",
401 strerror(errno));
402 }
403
404 /* --- Make sure everything has been built properly --- */
405
406 {
407 archcons *a, *aa;
408 archcons *all = arch_readtab();
409
410 if (sw.arch) {
411 for (a = aa = arch_filter(all, sw.arch, 0, 0); a; a = a->cdr)
412 a->car->flags |= archFlag_built;
413 arch_free(aa);
414 }
415
416 aa = arch_filter(all, sw.only_arch, archFlag_built, 0);
417 if (aa) {
e0465a2b 418 const char *sep = "";
419 fprintf(stderr, "%s: not built for ", QUIS);
3315e8b3 420 for (a = aa; a; a = a->cdr) {
421 fprintf(stderr, "%s%s", sep, a->car->arch);
422 sep = ", ";
423 }
424 fputc('\n', stderr);
425 exit(1);
426 }
427 arch_free(aa);
428 }
429
430 /* --- Write to the index file --- */
431
432 {
433 FILE *fp = fopen(PREFIX "/sw-index", "a");
434 swfield *f;
e0465a2b 435 const char *sep = "";
3315e8b3 436
437 if (!fp)
438 die(1, "couldn't open index file: %s", strerror(errno));
439 if (lock_file(fileno(fp), LOCK_EXCL))
440 die(1, "couldn't obtain lock on index file: %s", strerror(errno));
441
442 for (f = swfields; f->name; f++) {
443 if (SWINFO(&sw, f->off)) {
444 fprintf(fp, "%s%s = %s", sep, f->name, SWINFO(&sw, f->off));
445 sep = "; ";
446 }
447 }
448 fputc('\n', fp);
449 fclose(fp);
450 }
451
452 return (0);
453}
454
455/*----- That's all, folks -------------------------------------------------*/