Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 May 2009 22:17:59 +0000 (UTC)
From:      John Birrell <jb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r192703 - projects/jbuild/usr.bin/jdirdep
Message-ID:  <200905242217.n4OMHxQ2002886@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jb
Date: Sun May 24 22:17:59 2009
New Revision: 192703
URL: http://svn.freebsd.org/changeset/base/192703

Log:
  Add jdirdep, a program to parse the directory dependencies from the meta data
  files that jbuild creates. Part of jdirdep is built into jbuild itself so that
  directory dependencies update automatically when you build.

Added:
  projects/jbuild/usr.bin/jdirdep/
  projects/jbuild/usr.bin/jdirdep/Makefile
  projects/jbuild/usr.bin/jdirdep/Makefile.common
  projects/jbuild/usr.bin/jdirdep/jdirdep.c
  projects/jbuild/usr.bin/jdirdep/jdirdep.h
  projects/jbuild/usr.bin/jdirdep/jdirdep_mysql.c
  projects/jbuild/usr.bin/jdirdep/jdirdep_sqlite3.c
  projects/jbuild/usr.bin/jdirdep/jgetsrc

Added: projects/jbuild/usr.bin/jdirdep/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jdirdep/Makefile	Sun May 24 22:17:59 2009	(r192703)
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+PROG = jdirdep
+
+.include "Makefile.common"
+
+BINDIR?=	/usr/local/bin
+WARNS=		6
+NO_MAN=
+CFLAGS+=	-DJDIRDEP_MAIN
+CFLAGS+=	-DDEBUG
+CFLAGS+=	-g
+STRIP=
+
+
+.include <bsd.prog.mk>

Added: projects/jbuild/usr.bin/jdirdep/Makefile.common
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jdirdep/Makefile.common	Sun May 24 22:17:59 2009	(r192703)
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+SRCS += jdirdep.c
+
+CFLAGS += -I${.CURDIR}/../jdirdep -DJDIRDEP
+
+.if defined(USE_SQLITE3)
+CFLAGS += -DUSE_SQLITE3 -pthread
+CFLAGS += -I/usr/local/include
+SRCS += jdirdep_sqlite3.c
+LDADD += /usr/local/lib/libsqlite3.a
+.else
+SRCS += jdirdep_mysql.c
+MYSQL_CFLAGS != mysql_config --cflags
+MYSQL_LIBS != mysql_config --libs
+CFLAGS += -DUSE_MYSQL ${MYSQL_CFLAGS}
+LDADD += ${MYSQL_LIBS}
+.endif

Added: projects/jbuild/usr.bin/jdirdep/jdirdep.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jdirdep/jdirdep.c	Sun May 24 22:17:59 2009	(r192703)
@@ -0,0 +1,1378 @@
+/* $FreeBSD$ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "jdirdep.h"
+
+#ifdef JDIRDEP
+#define	MAKEFILE	"Buildfile"
+#define	MAKEFILED	"Buildfile.dirdep"
+#define	MAKEFILEDEP	"Buildfile.dep"
+#else
+#define	MAKEFILE	"Makefile"
+#define	MAKEFILED	"Makefile.dirdep"
+#define	MAKEFILEDEP	"Makefile.dep"
+#endif
+
+struct dirdep {
+	char *srcrel;
+	int subcnt;
+	TAILQ_ENTRY(dirdep) link;
+};
+
+struct march {
+	char *machine;
+	char *machine_arch;
+	TAILQ_ENTRY(march) link;
+};
+
+struct incmk {
+	char *s;
+	size_t l;
+	TAILQ_ENTRY(incmk) link;
+};
+
+struct file_track {
+	int64_t *filids;
+	int max_idx;
+	int next_idx;
+};
+
+static TAILQ_HEAD(, dirdep) dirdeps = TAILQ_HEAD_INITIALIZER(dirdeps);
+static TAILQ_HEAD(, dirdep) srcdirdeps = TAILQ_HEAD_INITIALIZER(srcdirdeps);
+static TAILQ_HEAD(, incmk) incmks = TAILQ_HEAD_INITIALIZER(incmks);
+static TAILQ_HEAD(, march) marchs = TAILQ_HEAD_INITIALIZER(marchs);
+static int f_db = 0;
+static int f_quiet = 1;
+static struct file_track read_filids = { NULL, 0, 0 };
+static struct file_track write_filids = { NULL, 0, 0 };
+
+static void
+file_track_add(struct file_track *ft, int64_t filid)
+{
+	int i;
+
+	for (i = 0; i < ft->max_idx; i++)
+		if (ft->filids[i] == filid)
+			return;;
+
+	if (ft->next_idx == ft->max_idx) {
+		int max_idx = ft->max_idx + 256;
+		int64_t *filids;
+
+		if ((filids = realloc(ft->filids, sizeof(int64_t) * max_idx)) == NULL)
+			errx(1, "Error reallocating memory");
+
+		ft->filids = filids;
+		ft->max_idx = max_idx;
+	}
+
+	ft->filids[ft->next_idx++] = filid;
+}
+
+static void
+file_track_reset(void)
+{
+	read_filids.next_idx = 0;
+	write_filids.next_idx = 0;
+}
+
+/*
+ * Clean the directory dependency list ready to process another file.
+ */
+static void
+clean_subdep(void)
+{
+	struct dirdep *dd;
+	struct dirdep *dt;
+
+	TAILQ_FOREACH_SAFE(dd, &dirdeps, link, dt) {
+		TAILQ_REMOVE(&dirdeps, dd, link);
+		if (dd->srcrel != NULL)
+			free(dd->srcrel);
+		free(dd);
+	}
+
+	TAILQ_FOREACH_SAFE(dd, &srcdirdeps, link, dt) {
+		TAILQ_REMOVE(&srcdirdeps, dd, link);
+		if (dd->srcrel != NULL)
+			free(dd->srcrel);
+		free(dd);
+	}
+}
+
+/*
+ * Check if a source relative directory path is in the list and add it
+ * if not. Keep the list sorted.
+ */
+static void
+srcdirdep_add(const char *srcrel)
+{
+	int v = 0;
+	struct dirdep *dd;
+	struct dirdep *dn = NULL;
+
+	TAILQ_FOREACH(dd, &srcdirdeps, link) {
+		if ((v = strcmp(srcrel, dd->srcrel)) == 0)
+			return;
+
+		if (v < 0 && dn == NULL) {
+			dn = dd;
+			break;
+		}
+	}
+
+	if ((dd = malloc(sizeof(struct dirdep))) == NULL)
+		err(1, "Could not allocate memory for struct dirdep");
+
+	if ((dd->srcrel = strdup(srcrel)) == NULL)
+		err(1, "Could not duplicate srcrel string");
+
+	dd->subcnt = 0;
+
+	if (dn == NULL)
+		TAILQ_INSERT_TAIL(&srcdirdeps, dd, link);
+	else
+		TAILQ_INSERT_BEFORE(dn, dd, link);
+}
+
+/*
+ * Check if a source relative directory path is in the list and add it
+ * if not. Keep the list sorted.
+ */
+static void
+dirdep_add(const char *srcrel, const char *from __unused, struct march *march)
+{
+	char *p2;
+	char s[MAXPATHLEN];
+	const char *p1;
+	int v = 0;
+	size_t len = 0;
+	struct dirdep *dd;
+	struct dirdep *dn = NULL;
+
+	if (march != NULL)
+		len = strlen(march->machine_arch);
+
+	for (p1 = srcrel, p2 = s; *p1 != '\0'; ) {
+		if (march != NULL &&
+		    strcmp(march->machine_arch, "common") != 0 &&
+		    strncmp(p1, march->machine_arch, len) == 0) {
+			strcpy(p2, "MACHINE_ARCH");
+			p1 += len;
+			p2 += 12;
+		} else
+			*p2++ = *p1++;
+	}
+	*p2 = '\0';
+
+	TAILQ_FOREACH(dd, &dirdeps, link) {
+		if ((v = strcmp(s, dd->srcrel)) == 0)
+			return;
+
+		if (v < 0 && dn == NULL) {
+			dn = dd;
+			break;
+		}
+	}
+
+#ifdef DEBUG
+	if (!f_quiet) {
+		printf("%s from %s\n", s, from);
+		fflush(stdout);
+	}
+#endif
+
+	if ((dd = malloc(sizeof(struct dirdep))) == NULL)
+		err(1, "Could not allocate memory for struct dirdep");
+
+	if ((dd->srcrel = strdup(s)) == NULL)
+		err(1, "Could not duplicate srcrel string");
+
+	dd->subcnt = 0;
+
+	if (dn == NULL)
+		TAILQ_INSERT_TAIL(&dirdeps, dd, link);
+	else
+		TAILQ_INSERT_BEFORE(dn, dd, link);
+}
+
+static int
+recid_lookup(void *thing, int argc __unused, char **argv __unused, char **colname __unused)
+{
+	int64_t *recid = thing;
+
+	*recid = strtoimax(argv[0], NULL, 10);
+
+	return(0);
+}
+
+static int64_t
+reldir_table_add(const char *reldir)
+{
+	int64_t relid = 0;
+
+	jdirdep_db_command(recid_lookup, &relid, "SELECT relid FROM reldir WHERE name='%s';", reldir);
+
+	if (relid == 0) {
+		jdirdep_db_command(NULL, NULL, "INSERT INTO reldir ( name ) VALUES ('%s');", reldir);
+
+		relid = jdirdep_db_rowid();
+	}
+
+	return(relid);
+}
+
+static int64_t
+file_table_add(const char *relname, const char *reldir)
+{
+	int64_t filid = 0;
+	int64_t relid = 0;
+
+	if (reldir != NULL && f_db)
+		relid = reldir_table_add(reldir);
+
+	jdirdep_db_command(recid_lookup, &filid, "SELECT filid FROM file WHERE name='%s';", relname);
+
+	if (filid == 0) {
+		jdirdep_db_command(NULL, NULL, "INSERT INTO file VALUES (0, '%s', %jd);", relname, relid);
+
+		filid = jdirdep_db_rowid();
+	} else if (relid != 0) {
+		jdirdep_db_command(NULL, NULL, "UPDATE file SET relid=%jd WHERE filid=%jd;", relid, filid);
+
+#ifdef DOODAD
+		/* Delete the files_using tuples for this file. */
+		jdirdep_db_command(NULL, NULL, "DELETE FROM files_using WHERE filid_used=%jd;", filid);
+
+		/* Now delete the files_used by this file. */
+		jdirdep_db_command(NULL, NULL, "DELETE FROM files_used WHERE filid=%jd;", filid);
+#endif
+	}
+
+	return(filid);
+}
+
+static void
+file_dep_add(int64_t filid_using, int64_t filid_used)
+{
+	int64_t filid = 0;
+
+	if (!f_db)
+		return;
+
+	if (filid_using == filid_used)
+		return;
+
+	jdirdep_db_command(recid_lookup, &filid, "SELECT filid_used FROM files_using WHERE filid=%jd AND filid_used=%jd;", filid_using, filid_used);
+
+	if (filid == 0)
+		jdirdep_db_command(NULL, NULL, "INSERT INTO files_using VALUES (%jd, %jd);", filid_using, filid_used);
+
+	filid = 0;
+
+	jdirdep_db_command(recid_lookup, &filid, "SELECT filid_using FROM files_used WHERE filid=%jd AND filid_using=%jd;", filid_used, filid_using);
+
+	if (filid == 0)
+		jdirdep_db_command(NULL, NULL, "INSERT INTO files_used VALUES (%jd, %jd);", filid_used, filid_using);
+}
+
+static void
+meta_dep_add(void)
+{
+	int i;
+	int j;
+
+	if (!f_db)
+		return;
+
+	for (i = 0; i < write_filids.next_idx; i++) {
+		for (j = 0; j < read_filids.next_idx; j++) {
+			file_dep_add(write_filids.filids[i], read_filids.filids[j]);
+		}
+	}
+}
+
+static void
+delete_dep(const char *relname __unused)
+{
+	/* Don't need this info (yet). */
+}
+
+static void
+move_dep(const char *srcname, const char *dstname, const char *reldir)
+{
+	int64_t filid_used;
+	int64_t filid_using;
+
+	if (!f_db)
+		return;
+
+	filid_using = file_table_add(dstname, reldir);
+	filid_used = file_table_add(srcname, NULL);
+
+	file_dep_add(filid_using, filid_used);
+}
+
+static void
+read_dep(const char *relname)
+{
+	int64_t filid;
+
+	if (!f_db)
+		return;
+
+	filid = file_table_add(relname, NULL);
+
+	file_track_add(&read_filids, filid);
+}
+
+static void
+write_dep(const char *relname, const char *reldir)
+{
+	int64_t filid;
+
+	if (!f_db)
+		return;
+
+	filid = file_table_add(relname, reldir);
+
+	file_track_add(&write_filids, filid);
+}
+
+/*
+ * Read a meta data file looking for referenced files. For each referenced
+ * file, open the associated source relative directory file (.srcrel) if
+ * it exists and read the source relative directory from which the file
+ * was released.
+ */
+static void
+parse_meta(const char *srctop, const char *thissrcrel, const char *objtop, const char *objroot,
+    const char *sharedobj, const char *mname, struct march *march)
+{
+	FILE *fp;
+	FILE *fp1;
+	char fname[MAXPATHLEN];
+	char srcrel[MAXPATHLEN];
+	char tname[MAXPATHLEN];
+	char tname1[MAXPATHLEN];
+	char tname2[MAXPATHLEN];
+	size_t l_objroot;
+	size_t l_objtop;
+	size_t l_sharedobj;
+	size_t l_srctop;
+	struct stat fs;
+
+	l_objroot = strlen(objroot);
+	l_objtop = strlen(objtop);
+	l_sharedobj = strlen(sharedobj);
+	l_srctop = strlen(srctop);
+
+	if ((fp = fopen(mname, "r")) != NULL) {
+		char *bufr;
+		char *p;
+		char *p1;
+		char *p2;
+		int f = 0;
+		size_t len;
+		size_t s_bufr = 128 * 1024;
+
+		if ((bufr = malloc(s_bufr)) == NULL)
+			err(1, "Cannot allocate memory for a read buffer");
+
+		while (fgets(bufr, s_bufr, fp) != NULL) {
+			/* Whack the trailing newline. */
+			bufr[strlen(bufr) - 1] = '\0';
+
+			/* Find the start of the build monitor section. */
+			if (strncmp(bufr, "-- buildmon", 11) == 0) {
+				f = 1;
+				continue;
+			}
+
+			/* Check for the end of the build monitor section. */
+			if (strncmp(bufr, "# Session completed", 19) == 0) {
+				f = 0;
+				continue;
+			}
+
+			/* Delimit the record type. */
+			p = bufr;
+			strsep(&p, " ");
+
+			if (f) {
+				/* Process according to record type. */
+				switch (bufr[0]) {
+				case 'D':
+				case 'E':
+				case 'R':
+				case 'S':
+				case 'W':
+					/* Skip the pid. */
+					if (strsep(&p, " ") == NULL)
+						break;
+
+					if (*p != '/')
+						snprintf(tname1, sizeof(tname1), "%s/%s/%s",
+							objtop, thissrcrel, p);
+					else
+						strlcpy(tname1, p, sizeof(tname1));
+
+					if (realpath(tname1, tname) == NULL)
+						break;
+
+					/* Deleted file: */
+					if (bufr[0] == 'D') {
+						if ((len = strlen(tname)) < l_objroot)
+							break;
+
+						if (strncmp(tname, objroot, l_objroot) != 0)
+							break;
+
+						delete_dep(tname + l_objroot - 3);
+						break;
+
+					/* Written file: */
+					} else if (bufr[0] == 'W') {
+						len = strlen(tname);
+
+						if (strcmp(tname + len - 7, ".srcrel") == 0)
+							break;
+
+						if ((len = strlen(tname)) < l_objroot)
+							break;
+
+						if (strncmp(tname, objroot, l_objroot) != 0)
+							break;
+
+						write_dep(tname + l_objroot - 3, thissrcrel);
+						break;
+					}
+
+					if (stat(tname, &fs) == 0 && !S_ISREG(fs.st_mode))
+						break;
+
+					/*
+					 * If there is a source relative directory file
+					 * for the referenced file, then read it.
+					 */
+					snprintf(fname, sizeof(fname), "%s.srcrel", tname);
+
+					if ((fp1 = fopen(fname, "r")) != NULL) {
+						if (l_sharedobj > 0 && strncmp(tname, sharedobj, l_sharedobj) == 0)
+							read_dep(tname + l_sharedobj - 3);
+						else if (l_objroot > 0 && strncmp(tname, objroot, l_objroot) == 0)
+							read_dep(tname + l_objroot - 3);
+
+						if (fgets(srcrel, sizeof(srcrel), fp1) != NULL) {
+							char *sp;
+
+							/* Whack the trailing newline. */
+							srcrel[strlen(srcrel) - 1] = '\0';
+
+							/* Avoid bogus additional slashes. */
+							sp = srcrel;
+							while (*sp == '/' || *sp == '#' || isspace(*sp))
+								sp++;
+
+							/*
+							 * Watch out for the current directory
+							 * because that can confuse things!
+							 */
+							if (strcmp(sp, thissrcrel) != 0)
+								dirdep_add(sp, p, march);
+						}
+						fclose(fp1);
+
+					/* Check if the file is in the object tree. */
+					} else if (strncmp(tname, objtop, l_objtop) == 0) {
+						char *sp;
+
+						read_dep(tname + l_objroot - 3);
+
+						/* Get the parent directory path. */
+						strlcpy(srcrel, dirname(tname), sizeof(srcrel));
+
+						/* Avoid bogus additional slashes. */
+						sp = srcrel + l_objtop + 1;
+						while (*sp == '/')
+							sp++;
+
+						/*
+						 * Watch out for the current directory
+						 * because that can confuse things!
+						 */
+						if (strcmp(sp, thissrcrel) != 0)
+							dirdep_add(sp, p, march);
+
+					/*
+					 * Check if the file is in the source tree, but not
+					 * in the current source directory.
+					 */
+					} else if (strncmp(tname, srctop, l_srctop) == 0) {
+						read_dep(tname + l_srctop - 3);
+
+						if (strcmp(dirname(tname + l_srctop + 1), thissrcrel) != 0)
+							srcdirdep_add(dirname(tname + l_srctop + 1));
+					}
+					break;
+
+				case 'M':
+					/* Skip the pid. */
+					if (strsep(&p, " ") == NULL)
+						break;
+
+					/* Get the src file name. */
+					if (strsep(&p, "'") == NULL)
+						break;
+					p1 = p;
+					if (strsep(&p, "'") == NULL)
+						break;
+					if (strsep(&p, " ") == NULL)
+						break;
+
+					/* Get the dst file name. */
+					if (strsep(&p, "'") == NULL)
+						break;
+					p2 = p;
+					if (strsep(&p, "'") == NULL)
+						break;
+
+					if (*p1 != '/')
+						snprintf(tname1, sizeof(tname1), "%s/%s/%s",
+							objtop, thissrcrel, p1);
+					else
+						strlcpy(tname1, p1, sizeof(tname1));
+
+					if (realpath(tname1, tname) == NULL)
+						break;
+
+					if (*p2 != '/')
+						snprintf(tname1, sizeof(tname1), "%s/%s/%s",
+							objtop, thissrcrel, p2);
+					else
+						strlcpy(tname1, p2, sizeof(tname1));
+
+					if (realpath(tname1, tname2) == NULL)
+						break;
+
+					move_dep(tname + l_objroot - 3, tname2 + l_objroot - 3, thissrcrel);
+					break;
+				default:
+					break;
+				}
+			}
+		}
+
+		free(bufr);
+		fclose(fp);
+	}
+
+	meta_dep_add();
+
+	file_track_reset();
+}
+
+static char lockf_created[MAXPATHLEN];
+static int lockf_fd = -1;
+
+static void
+lockf_create(const char *curdir)
+{
+	int i;
+
+	if (lockf_fd >= 0)
+		return;
+
+	snprintf(lockf_created, sizeof(lockf_created), "%s/.jdirdep_lockf", curdir);
+
+	for (i = 0; i < 300; i++) {
+		if ((lockf_fd = open(lockf_created, O_CREAT | O_EXCL, 0600)) >= 0) {
+			return;
+		}
+
+		if (errno != EEXIST)
+			err(1, "Could not create lock file '%s'", lockf_created);
+
+		sleep(1);
+	}
+
+	err(1, "Could not create lock file '%s'", lockf_created);
+}
+
+static void
+lockf_delete(void)
+{
+	if (lockf_fd >= 0) {
+		close(lockf_fd);
+		if (unlink(lockf_created) != 0)
+			err(1, "Could not unlink file '%s'", lockf_created);
+		lockf_fd = -1;
+	}
+	lockf_created[0] = '\0';
+}
+
+static void
+do_dirdep(const char *srctop, const char *curdir, const char *srcrel, const char *objroot,
+    const char *sharedobj, int options)
+{
+	DIR *d;
+	FILE *fp;
+	FILE *fp1;
+	char *bufr;
+	char cmd[MAXPATHLEN];
+	char *dirdep = NULL;
+	char fname[MAXPATHLEN];
+	char fname1[MAXPATHLEN];
+	char fname2[MAXPATHLEN];
+	char mname[MAXPATHLEN];
+	char objdir[MAXPATHLEN];
+	char objtop[MAXPATHLEN];
+	char *s = NULL;
+	char *s1 = NULL;
+	char *srcdirdep = NULL;
+	int f_add = (options & JDIRDEP_OPT_ADD);
+	int f_dirdep = 1;
+	int f_doit = 0;
+	int f_error = 0;
+	int f_force = (options & JDIRDEP_OPT_FORCE);
+	int f_rewrite = 0;
+	int f_src = (options & JDIRDEP_OPT_SOURCE);
+	int f_update = (options & JDIRDEP_OPT_UPDATE);
+	int fd;
+	size_t l;
+	size_t ss;
+	size_t ss1;
+	struct dirdep *dd;
+	struct dirent *de;
+	struct march *march;
+	struct stat fs;
+
+	if (strcmp(srcrel, "stage") != 0)
+		dirdep_add("stage", "", NULL);
+	snprintf(fname, sizeof(fname), "%s/%s", curdir, MAKEFILE);
+	snprintf(fname2, sizeof(fname2), "%s/%s", curdir, MAKEFILEDEP);
+
+	if ((fp = fopen(fname, "r")) == NULL)
+		return;
+
+	if (fstat(fileno(fp), &fs) != 0)
+		err(1, "Could not get file status of file '%s'", fname);
+
+	if (f_db)
+		reldir_table_add(srcrel);
+
+	if ((bufr = malloc(fs.st_size)) == NULL)
+		err(1, "Could not allocate %zd bytes for the dirdep buffer", (size_t) fs.st_size);
+
+	/*
+	 * Read through the Makefile/Buildfile to look for the .include system makefile
+	 * to determine if this directory needs to have a .dep file.
+	 */
+	while (fgets(bufr, fs.st_size, fp) != NULL) {
+		/* Whack the trailing newline. */
+		bufr[strlen(bufr) - 1] = '\0';
+
+		if (bufr[0] != '#' && strstr(bufr, "<bsd.dirdep.mk>") != NULL) {
+			f_dirdep = 0;
+			f_rewrite = 0;
+			break;
+		}
+
+		if (bufr[0] != '#' && strstr(bufr, "<bsd.subdir.mk>") != NULL) {
+			f_dirdep = 0;
+			f_rewrite = 0;
+			break;
+		}
+
+		/*
+		 * Check if this file needs to be rewritten to remove the old DIRDEP and/or
+		 * SRCDIRDEP lines.
+		 */
+		if (strncmp(bufr, "DIRDEP", 6) == 0 || strncpy(bufr, "SRCDIRDEP", 9) == 0) {
+			f_rewrite = 1;
+			f_force = 1;
+		}
+	}
+
+	fclose(fp);
+
+	/*
+	 * If this directory needs a .dep file, then try to read the current one.
+	 * This initialises the global lists for DIRDEP and SRCDIRDEP.
+	 */
+	if (f_dirdep && (fp = fopen(fname2, "r")) != NULL) {
+		char *p = NULL;
+		char *p1;
+		char *p2;
+
+		/*
+		 * Get the size of the current .dep file to use it as a maximum
+		 * length for the DIRDEP and SRCDIRDEP strings.
+		 */
+		if (fstat(fileno(fp), &fs) != 0)
+			err(1, "Could not get file status of file '%s'", fname2);
+
+		if ((dirdep = malloc(fs.st_size)) == NULL)
+			err(1, "Could not allocate %zd bytes for the dirdep buffer", (size_t) fs.st_size);
+
+		if ((srcdirdep = malloc(fs.st_size)) == NULL)
+			err(1, "Could not allocate %zd bytes for the dirdep buffer", (size_t) fs.st_size);
+
+		*dirdep = '\0';
+		*srcdirdep = '\0';
+
+		/* Always add the stage directory since there is nothing in the meta data to
+		 * indicate that it is always needed. The stage directory itself obviously can't
+		 * depend on itself, but this is handled in bsd.dirdep.mk.
+		 */
+		dirdep_add("stage", "", NULL);
+
+		/*
+		 * Read through the existing .dep file and add paths to the DIRDEP and
+		 * SRCDIRDEP global lists.
+		 */
+		while (fgets(bufr, fs.st_size, fp) != NULL) {
+			if (bufr[0] == '#' || bufr[0] == '\n')
+				continue;
+			else if (strncmp(bufr, "DIRDEP", 6) == 0)
+				p = dirdep;
+			else if (strncmp(bufr, "SRCDIRDEP", 9) == 0)
+				p = srcdirdep;
+			else if (bufr[0] == '\t' && p != NULL) {
+				/*
+				 * Found a continution line which should contain a source
+				 * relative directory path. Skip the tab and point to the
+				 * start of the path.
+				 */
+				p1 = bufr + 1;
+
+				/* Get the path with always has a space after it. */
+				if ((p2 = strsep(&p1, " ")) != NULL) {
+					if (p == dirdep) {
+						/* Append to the reference dirdep string. */
+						strcat(dirdep, " ");
+						strcat(dirdep, p2);
+
+						if (f_add)
+							dirdep_add(p2, "", NULL);
+					}
+
+					if (p == srcdirdep) {
+						/* Append to the reference srcdirdep string. */
+						strcat(srcdirdep, " ");
+						strcat(srcdirdep, p2);
+
+						if (f_add)
+							srcdirdep_add(p2);
+					}
+				}
+			}
+		}
+
+		fclose(fp);
+	}
+
+	/* Check if the DIRDEP= isn't needed for this directory. */
+	if (!f_force && !f_dirdep) {
+		if (dirdep != NULL)
+			free(dirdep);
+		if (srcdirdep != NULL)
+			free(srcdirdep);
+		return;
+	} else {
+		/* Loop through the supported machine types... */
+		TAILQ_FOREACH(march, &marchs, link) {
+			/*
+			 * Format the path to the current machine-specific object
+			 * directory:
+			 */
+			snprintf(objdir, sizeof(objdir), "%s/%s/%s",
+			   objroot, march->machine, srcrel);
+			snprintf(objtop, sizeof(objtop), "%s/%s",
+			   objroot, march->machine);
+
+			/*
+			 * Open the object directory and parse all meta data files we
+			 * can find in there. These tell us what was referenced when the
+			 * objects were built.
+			 */
+			if ((d = opendir(objdir)) != NULL) {
+				while((de = readdir(d)) != NULL) {
+					if ((l = strlen(de->d_name)) < 6)
+						continue;
+
+					if (strcmp(de->d_name + l - 5, ".meta") != 0)
+						continue;
+
+					snprintf(mname, sizeof(mname), "%s/%s", objdir, de->d_name);
+
+					/*
+					 * Parse the meta data file and watch out that we don't get
+					 * confused with references to the current directory -- they
+					 * are almost certain to occur if there are include files
+					 * released from here because that happens early in the
+					 * build (so that there are no differences between the
+					 * released headers and the local ones).
+					 */
+					parse_meta(srctop, srcrel, objtop, objroot, sharedobj, mname, march);
+				}
+
+				closedir(d);
+			}
+		}
+
+		ss = 1;
+		TAILQ_FOREACH(dd, &dirdeps, link) {
+			ss += strlen(dd->srcrel) + 1;
+		}
+
+		if ((s = malloc(ss)) == NULL)
+			err(1, "Could not allocate %zd bytes for the dirdep buffer", ss);
+
+		ss1 = 1;
+		TAILQ_FOREACH(dd, &srcdirdeps, link) {
+			ss1 += strlen(dd->srcrel) + 1;
+		}
+
+		if ((s1 = malloc(ss1)) == NULL)
+			err(1, "Could not allocate %zd bytes for the srcdirdep buffer", ss1);
+
+		l = 0;
+		*s = '\0';
+
+		/*
+		 * There are a couple of special cases we have to handle here. If we've
+		 * got source relative directory elements, then we simply report
+		 * that list, but if we have none, then we still have to report that we
+		 * depend on the stage directory (which doesn't have a .srcrel file
+		 * for us to discover). And finally we have to avoid making the 'stage'
+		 * directory depend on itself.
+		 */
+		if (!TAILQ_EMPTY(&dirdeps)) {
+			TAILQ_FOREACH(dd, &dirdeps, link) {
+				l += snprintf(s + l, ss - l, " %s", dd->srcrel);
+			}
+		} else if (strcmp(srcrel, "stage") != 0)
+			l += snprintf(s + l, ss - l, " stage");
+
+		l = 0;
+		*s1 = '\0';
+
+		TAILQ_FOREACH(dd, &srcdirdeps, link) {
+			l += snprintf(s1 + l, ss1 - l, " %s", dd->srcrel);
+		}
+
+		if (f_update && dirdep != NULL && strcmp(s, dirdep) != 0) {
+			printf("Directory dependencies are being updated:\n");
+			printf("%s\n", s);
+			fflush(stdout);
+			f_doit = 1;
+		}
+
+		if (f_update && f_src && srcdirdep != NULL && strcmp(s1, srcdirdep) != 0) {
+			printf("Source dependencies are being updated:\n");
+			printf("%s\n", s1);
+			fflush(stdout);
+			f_doit = 1;
+		}
+
+		if (f_update && dirdep == NULL) {
+			printf("Directory dependencies are being added:\n");
+			printf("%s\n", s);
+			fflush(stdout);
+			f_doit = 1;
+		}
+
+		if (f_update && f_src && srcdirdep == NULL && ss1 > 11) {
+			printf("Source dependencies are being added:\n");
+			printf("%s\n", s1);
+			fflush(stdout);
+			f_doit = 1;
+		}
+
+		if (!f_update && f_src) {
+			printf("%s\n", s1);
+			fflush(stdout);
+		}
+
+		if (f_update && f_doit) {
+			lockf_create(curdir);
+
+			if (f_rewrite) {
+				snprintf(fname1, sizeof(fname1), "%s.XXXXXX", fname);
+				if ((fd = mkstemp(fname1)) < 0)
+					err(1, "Could not create temporary file '%s'", fname1);
+
+				if ((fp1 = fdopen(fd, "w")) == NULL)
+					err(1, "Could not open stream for temporary file '%s'", fname1);
+
+				if ((fp = fopen(fname, "r")) == NULL) {
+					f_error = 1;
+					warn("Could not open '%s' again", fname);
+				} else {
+					while (fgets(bufr, fs.st_size, fp) != NULL) {
+						/* Whack the trailing newline. */
+						bufr[strlen(bufr) - 1] = '\0';
+
+						/* Ignore lines that start with DIRDEP. */
+						if (strncmp(bufr, "DIRDEP", 6) == 0)
+							continue;
+
+						if (f_src && strncmp(bufr, "SRCDIRDEP", 9) == 0)
+							continue;
+
+						fprintf(fp1, "%s\n", bufr);
+					}
+
+					fclose(fp);
+				}
+
+				fclose(fp1);
+
+				if (f_error)
+					unlink(fname1);
+				else {
+					if (unlink(fname) != 0)
+						err(1, "Could not delete old file '%s'", fname);
+
+					if (rename(fname1, fname) != 0)
+						err(1, "Could not rename file '%s' to '%s'", fname1, fname);
+
+					if (chmod(fname, fs.st_mode) != 0)
+						err(1, "Could not chmod file '%s'", fname);
+				}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905242217.n4OMHxQ2002886>