chiark / gitweb /
59d9308b7df80a196a00a8bedc6c91f397475544
[sw-tools] / src / sw_info.c
1 /* -*-c-*-
2  *
3  * $Id: sw_info.c,v 1.2 1999/06/18 18:58:45 mdw Exp $
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 $
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.
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
67 static 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 };
80 typedef 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
97 void 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
113 int 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
195 void 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
217 int 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
263 tidy_2:
264   rename(".sw-info.old", ".sw-info");
265 tidy_1:
266   rename(".sw-info.older", ".sw-info.old");
267 tidy_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
282 void 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
304 void 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
358 int 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
376 int 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
393 int 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) {
418       const char *sep = "";
419       fprintf(stderr, "%s: not built for ", QUIS);
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;
435     const char *sep = "";
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 -------------------------------------------------*/