3 * $Id: sw_info.c,v 1.5 1999/06/24 16:02:12 mdw Exp $
5 * Maintenance of `.sw-info' files
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of sw-tools.
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.
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.
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.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.5 1999/06/24 16:02:12 mdw
33 * Fix call to `execl'.
35 * Revision 1.4 1999/06/24 15:57:07 mdw
36 * Stupid bug fix. Code wouldn't even compile. Tut.
38 * Revision 1.3 1999/06/24 15:51:59 mdw
39 * Add support for the `sw-precommit' script.
41 * Revision 1.2 1999/06/18 18:58:45 mdw
44 * Revision 1.1.1.1 1999/06/02 16:53:35 mdw
49 /*----- Header files ------------------------------------------------------*/
62 #include <sys/types.h>
68 extern char **environ
;
71 #include <mLib/alloc.h>
72 #include <mLib/dstr.h>
73 #include <mLib/lock.h>
74 #include <mLib/quis.h>
75 #include <mLib/report.h>
81 /*----- Static variables --------------------------------------------------*/
83 static struct swfield
{
88 { "package", offsetof(swinfo
, package
), "Package" },
89 { "version", offsetof(swinfo
, version
), "Version" },
90 { "maintainer", offsetof(swinfo
, maintainer
), "Maintained by" },
91 { "date", offsetof(swinfo
, date
), "Last modified" },
92 { "only-arch", offsetof(swinfo
, only_arch
), "Only build for" },
93 { "arch", offsetof(swinfo
, arch
), "Successfully built" },
96 typedef struct swfield swfield
;
98 #define SWINFO(sw, off) (*(char **)((char *)sw + off))
100 /*----- Main code ---------------------------------------------------------*/
102 /* --- @swinfo_clear@ --- *
104 * Arguments: @swinfo *sw@ = pointe to info block
108 * Use: Clears an info block so that it doesn't contain anything.
109 * This is mainly useful when building skeletons to apply using
113 void swinfo_clear(swinfo
*sw
)
116 for (f
= swfields
; f
->name
; f
++)
117 SWINFO(sw
, f
->off
) = 0;
120 /* --- @swinfo_fetch@ --- *
122 * Arguments: @swinfo *sw@ = pointer to info block to fill in
124 * Returns: Zero if OK, else nonzero.
126 * Use: Fills in the info block if it can.
129 int swinfo_fetch(swinfo
*sw
)
136 /* --- Initialize the various fields --- */
140 /* --- Open the data file --- */
142 if ((fp
= fopen(".sw-info", "r")) == 0)
145 /* --- Read the lines from the file --- */
147 for (; dstr_putline(&d
, fp
) != EOF
; DRESET(&d
)) {
152 /* --- Find the field name --- */
154 while (isspace((unsigned char)*p
))
156 if (*p
== 0 || *p
== '#')
159 /* --- Find the end of the field name --- */
162 while (*p
&& *p
!= '=' && !isspace((unsigned char)*p
))
165 /* --- Skip an optional `=' sign --- */
171 while (isspace((unsigned char)*p
))
173 if (*p
== '=' && ch
!= '=') {
175 while (isspace((unsigned char)*p
))
182 /* --- Look up the key in the table --- */
184 for (f
= swfields
; f
->name
; f
++) {
185 if (strcmp(key
, f
->name
) == 0)
188 moan("unknown key `%s' at line %i in `.sw-info'", key
, line
);
191 /* --- Put the value in --- */
194 SWINFO(sw
, f
->off
) = xstrdup(value
);
202 /* --- @swinfo_sanity@ --- *
204 * Arguments: @swinfo *sw@ = pointer to an info block
206 * Returns: Yes, if the block is OK.
208 * Use: Objects if the information in the info block is bad.
211 void swinfo_sanity(swinfo
*sw
)
214 die(1, "unknown package name. Try `%s setup PACKAGE VERSION'.", QUIS
);
216 die(1, "unknown package version. Try `%s setup PACKAGE VERSION'.",
219 die(1, "unknown maintainer. Try `%s setup PACKAGE VERSION'.", QUIS
);
221 die(1, "unknown date. Try `%s setup PACKAGE VERSION'.", QUIS
);
224 /* --- @swinfo_put@ --- *
226 * Arguments: @swinfo *sw@ = pointer to an info block
228 * Returns: Zero if it worked, nonzero if not.
230 * Use: Writes an info block to the appropriate file.
233 int swinfo_put(swinfo
*sw
)
239 /* --- Quick sanity check --- */
243 /* --- Write the new data out --- */
245 if ((fp
= fopen(".sw-info.new", "w")) == 0)
247 for (f
= swfields
; f
->name
; f
++) {
248 if (!SWINFO(sw
, f
->off
))
250 if (fprintf(fp
, "%s = %s\n", f
->name
, SWINFO(sw
, f
->off
)) == EOF
) {
256 if (fclose(fp
) == EOF
) {
261 /* --- Carefully! replace the old one --- *
263 * Keep an old one around just in case, unless the renames fail because
267 remove(".sw-info.older"); /* Don't care if this fails */
268 if (rename(".sw-info.old", ".sw-info.older") && errno
!= ENOENT
)
269 { e
= errno
; goto tidy_0
; }
270 if (rename(".sw-info", ".sw-info.old") && errno
!= ENOENT
)
271 { e
= errno
; goto tidy_1
; }
272 if (rename(".sw-info.new", ".sw-info"))
273 { e
= errno
; goto tidy_2
; }
274 remove(".sw-info.older"); /* Don't care if this fails */
277 /* --- Tidy up if anything went tits-up --- */
280 rename(".sw-info.old", ".sw-info");
282 rename(".sw-info.older", ".sw-info.old");
284 remove(".sw-info.new");
289 /* --- @swinfo_destroy@ --- *
291 * Arguments: @swinfo *sw@ = pointer to info block
295 * Use: Destroys an info block when it's not useful any more.
298 void swinfo_destroy(swinfo
*sw
)
302 for (f
= swfields
; f
->name
; f
++) {
303 if (SWINFO(sw
, f
->off
))
304 free(SWINFO(sw
, f
->off
));
308 /* --- @swinfo_update@ --- *
310 * Arguments: @swinfo *sw@ = pointer to info block
311 * @swinfo *skel@ = pointer to skeleton values
315 * Use: Updates the fields in an information block, except for the
316 * architecture names stuff. (I'll leave that for later,
317 * because it's rather more involved.
320 void swinfo_update(swinfo
*sw
, swinfo
*skel
)
326 /* --- Set up a default maintainer --- */
328 if (!skel
->maintainer
&& !sw
->maintainer
) {
329 char *u
= getenv("USER");
332 u
= getenv("LOGNAME");
334 struct passwd
*pw
= getpwuid(getuid());
336 moan("you don't seem to exist");
337 sprintf(ubuf
, "uid %i", (int)getuid());
342 skel
->maintainer
= u
;
345 /* --- Set up a default date --- */
349 struct tm
*tm
= localtime(&t
);
350 strftime(dbuf
, sizeof(dbuf
), "%Y-%m-%d", tm
);
354 /* --- Set a default architecture list --- */
356 if (!skel
->arch
&& !sw
->arch
)
359 /* --- Grind through all the fields --- */
361 for (f
= swfields
; f
->name
; f
++) {
362 if (!SWINFO(skel
, f
->off
) || strcmp(SWINFO(skel
, f
->off
), "-") == 0)
364 if (SWINFO(sw
, f
->off
))
365 free(SWINFO(sw
, f
->off
));
366 SWINFO(sw
, f
->off
) = xstrdup(SWINFO(skel
, f
->off
));
370 /*----- Subcommands -------------------------------------------------------*/
372 /* --- @sw_setup@ --- */
374 int sw_setup(int argc
, char *argv
[])
377 if (argc
< 3 || argc
> 4)
378 die(1, "Usage: setup PACKAGE VERSION [MAINTAINER]");
381 skel
.package
= argv
[1];
382 skel
.version
= argv
[2];
384 skel
.maintainer
= argv
[3];
385 swinfo_update(&sw
, &skel
);
390 /* --- @sw_status@ --- */
392 int sw_status(int argc
, char *argv
[])
396 if (swinfo_fetch(&sw
)) {
397 die(1, "couldn't read build status: %s (try running setup)",
400 for (f
= swfields
; f
->name
; f
++) {
401 if (SWINFO(&sw
, f
->off
))
402 printf("%s: %s\n", f
->desc
, SWINFO(&sw
, f
->off
));
407 /* --- @sw_commit@ --- */
409 int sw_commit(int argc
, char *argv
[])
414 die(1, "Usage: commit");
415 if (swinfo_fetch(&sw
)) {
416 die(1, "couldn't read build status: %s (try running setup)",
420 /* --- Make sure everything has been built properly --- */
424 archcons
*all
= arch_readtab();
427 for (a
= aa
= arch_filter(all
, sw
.arch
, 0, 0); a
; a
= a
->cdr
)
428 a
->car
->flags
|= archFlag_built
;
432 aa
= arch_filter(all
, sw
.only_arch
, archFlag_built
, 0);
434 const char *sep
= "";
435 fprintf(stderr
, "%s: not built for ", QUIS
);
436 for (a
= aa
; a
; a
= a
->cdr
) {
437 fprintf(stderr
, "%s%s", sep
, a
->car
->arch
);
446 /* --- Run the local precommit check script --- */
450 struct sigaction sa
, sa_int
, sa_quit
;
453 /* --- Make sure I can trap the child's death --- */
455 sa
.sa_handler
= SIG_IGN
;
456 sigemptyset(&sa
.sa_mask
);
458 if (sigaction(SIGINT
, &sa
, &sa_int
) || sigaction(SIGQUIT
, &sa
, &sa_quit
))
459 die(1, "couldn't set signal dispositions: %s", strerror(errno
));
461 /* --- Spawn off a child process --- */
466 die(1, "error from fork: %s", strerror(errno
));
470 /* --- Re-enable signals --- */
472 sigaction(SIGINT
, &sa_int
, 0);
473 sigaction(SIGQUIT
, &sa_quit
, 0);
475 /* --- Set up the environment --- */
478 env_import(&t
, environ
);
479 env_put(&t
, "SW_PACKAGE", sw
.package
);
480 env_put(&t
, "SW_VERSION", sw
.version
);
481 env_put(&t
, "SW_MAINTAINER", sw
.maintainer
);
482 env_put(&t
, "SW_DATE", sw
.date
);
483 env_put(&t
, "SW_ARCHLIST", sw
.arch
);
484 env_put(&t
, "SW_PREFIX", PREFIX
);
485 environ
= env_export(&t
);
487 /* --- Run the commit check script --- */
489 execl(PREFIX
"/share/sw-precommit", "sw-precommit",
490 sw
.package
, (char *)0);
493 die(1, "couldn't run " PREFIX
"/share/sw-precommit: %s",
497 /* --- Wait for the child to finish --- */
499 if (waitpid(kid
, &status
, 0) < 0)
500 die(1, "error waiting for child: %s", strerror(errno
));
501 if (!(WIFEXITED(status
) && WEXITSTATUS(status
) == 0))
502 die(1, "sw-precommit failed");
503 sigaction(SIGINT
, &sa_int
, 0);
504 sigaction(SIGQUIT
, &sa_quit
, 0);
507 /* --- Write to the index file --- */
510 FILE *fp
= fopen(PREFIX
"/sw-index", "a");
512 const char *sep
= "";
515 die(1, "couldn't open index file: %s", strerror(errno
));
516 if (lock_file(fileno(fp
), LOCK_EXCL
))
517 die(1, "couldn't obtain lock on index file: %s", strerror(errno
));
519 for (f
= swfields
; f
->name
; f
++) {
520 if (SWINFO(&sw
, f
->off
)) {
521 fprintf(fp
, "%s%s = %s", sep
, f
->name
, SWINFO(&sw
, f
->off
));
532 /*----- That's all, folks -------------------------------------------------*/