Subject: bin/25785: Non strict dependency in rcorder(8)
To: None <gnats-bugs@gnats.NetBSD.org>
From: Mike M. Volokhov <mishka@apk.od.ua>
List: netbsd-bugs
Date: 06/02/2004 15:33:30
>Number: 25785
>Category: bin
>Synopsis: Non strict dependency in rcorder(8)
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Wed Jun 02 12:35:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator: Mike M. Volokhov
>Release: NetBSD current
>Organization:
ISPK
>Environment:
N/V
>Description:
Greetings!
[Excuse me please for annoying, but I really need this feature.
I have wait for response on tech-userlevel@ and current-users@,
but got no reply.]
Sometimes a dependencies required within BEFORE/REQUIRE
keywords at some rcorder-based script may not been available,
and this must not be treated as error. However, in current
rcorder(8) implementation if mentioned keywords declare
such (inavailable) dependencies, this will produce warning
messages and return code for rcorder will be set to non-zero
value.
See also the following messages at the mailing lists:
http://mail-index.NetBSD.org/tech-userlevel/2004/02/04/0001.html
http://mail-index.NetBSD.org/tech-userlevel/2004/02/04/0002.html
http://mail-index.NetBSD.org/tech-userlevel/2004/05/20/0002.html
http://mail-index.NetBSD.org/tech-userlevel/2004/05/24/0000.html
>How-To-Repeat:
For example, we have a program which contains three
independend daemons: network server, processing server,
and some daemon which will link them both together. All
three daemons may be splitted on three separate hosts
accordingly to its architecture, or may be stored on single
host. In latter case, it must be started in the following
order:
1. procsrv,
2. linkd,
3. netsrv.
Thus, we can create three rcorder-based scripts:
# PROVIDE: procsrv
# PROVIDE: netsrv
# PROVIDE: linkd
# REQUIRE: procsrv
# BEFORE: netsrv
or something with similar approach. But, if all three (or
even two) daemons will be served by various network hosts,
that interdependencies for "linkd" will be broken.
The real example is an sendmail Milter filters. They may
be accessed via the network, or via the UNIX sockets. In
second case it must be started *before* sendmail daemon,
but explicit declaration of this fact will produce an error
if filter will be used by the first way.
>Fix:
This problem may be solved using special REQUIRE/BEFORE
keywords for all thus optional requirements. The provided
patch declares three keywords:
"# OPT-REQUIRE:"
"# OPT-REQUIRES:"
"# OPT-BEFORE:"
They may be used together with usual REQUIRE/BEFORE keywords,
for example:
# PROVIDE: linkd
# BEFORE: LOGIN
# OPT-REQUIRE: procsrv
# OPT-BEFORE: netsrv
Thus, if requested by OPT-* keywords dependecies are
available, they will be processed as usual REQUIRE/BEFORE.
If some listed dependencies are not available, the corresponded
OPT-* keywords will be ignored at all.
--
TIA, Mishka.
Index: rcorder.8
===================================================================
RCS file: /cvsroot/src/sbin/rcorder/rcorder.8,v
retrieving revision 1.6
diff -u -r1.6 rcorder.8
--- rcorder.8 24 Apr 2003 03:15:45 -0000 1.6
+++ rcorder.8 24 May 2004 09:04:09 -0000
@@ -60,8 +60,10 @@
.Pp
Within each file, a block containing a series of
.Dq REQUIRE ,
+.Dq OPT-REQUIRE ,
.Dq PROVIDE ,
-.Dq BEFORE
+.Dq BEFORE ,
+.Dq OPT-BEFORE
and
.Dq KEYWORD
lines should appear.
@@ -71,7 +73,9 @@
followed by a single space, followed by
.Dq PROVIDE: ,
.Dq REQUIRE: ,
+.Dq OPT-REQUIRE: ,
.Dq BEFORE: ,
+.Dq OPT-BEFORE: ,
or
.Dq KEYWORD: .
No deviation is permitted.
@@ -80,7 +84,9 @@
Multiple
.Dq PROVIDE ,
.Dq REQUIRE ,
-.Dq BEFORE
+.Dq OPT-REQUIRE: ,
+.Dq BEFORE ,
+.Dq OPT-BEFORE
and
.Dq KEYWORD
lines may appear, but all such lines must appear in a sequence without
@@ -129,11 +135,24 @@
A file containing no
.Dq PROVIDE ,
.Dq REQUIRE ,
+.Dq OPT-REQUIRE ,
+.Dq BEFORE ,
or
-.Dq BEFORE
+.Dq OPT-BEFORE
lines may be output at an arbitrary position in the dependency
ordering.
.Pp
+A special lines
+.Dq OPT-REQUIRE
+and
+.Dq OPT-BEFORE
+should be used in case if given conditions may not have any providers,
+but this must not be treated as error. If providers are existent,
+they works just like plain
+.Dq REQUIRE
+and
+.Dq BEFORE .
+.Pp
There must be at least one file with no dependencies in the set of
arguments passed to
.Nm
Index: rcorder.c
===================================================================
RCS file: /cvsroot/src/sbin/rcorder/rcorder.c,v
retrieving revision 1.12
diff -u -r1.12 rcorder.c
--- rcorder.c 13 Oct 2003 14:22:20 -0000 1.12
+++ rcorder.c 24 May 2004 09:04:34 -0000
@@ -81,12 +81,18 @@
#define REQUIRE_LEN (sizeof(REQUIRE_STR) - 1)
#define REQUIRES_STR "# REQUIRES:"
#define REQUIRES_LEN (sizeof(REQUIRES_STR) - 1)
+#define OPT_REQUIRE_STR "# OPT-REQUIRE:"
+#define OPT_REQUIRE_LEN (sizeof(OPT_REQUIRE_STR) - 1)
+#define OPT_REQUIRES_STR "# OPT-REQUIRES:"
+#define OPT_REQUIRES_LEN (sizeof(OPT_REQUIRES_STR) - 1)
#define PROVIDE_STR "# PROVIDE:"
#define PROVIDE_LEN (sizeof(PROVIDE_STR) - 1)
#define PROVIDES_STR "# PROVIDES:"
#define PROVIDES_LEN (sizeof(PROVIDES_STR) - 1)
#define BEFORE_STR "# BEFORE:"
#define BEFORE_LEN (sizeof(BEFORE_STR) - 1)
+#define OPT_BEFORE_STR "# OPT-BEFORE:"
+#define OPT_BEFORE_LEN (sizeof(OPT_BEFORE_STR) - 1)
#define KEYWORD_STR "# KEYWORD:"
#define KEYWORD_LEN (sizeof(KEYWORD_STR) - 1)
#define KEYWORDS_STR "# KEYWORDS:"
@@ -122,11 +128,13 @@
};
struct f_reqnode {
+ int optional;
Hash_Entry *entry;
f_reqnode *next;
};
struct strnodelist {
+ int optional;
filenode *node;
strnodelist *next;
char s[1];
@@ -156,8 +164,10 @@
void parse_line(filenode *, char *, void (*)(filenode *, char *));
filenode *filenode_new(char *);
void add_require(filenode *, char *);
+void add_opt_require(filenode *, char *);
void add_provide(filenode *, char *);
void add_before(filenode *, char *);
+void add_opt_before(filenode *, char *);
void add_keyword(filenode *, char *);
void insert_before(void);
Hash_Entry *make_fake_provision(filenode *);
@@ -227,6 +237,7 @@
strnodelist *ent;
ent = emalloc(sizeof *ent + strlen(s));
+ ent->optional = RESET;
ent->node = fnode;
strcpy(ent->s, s);
ent->next = *listp;
@@ -285,6 +296,18 @@
rnode->entry = entry;
rnode->next = fnode->req_list;
fnode->req_list = rnode;
+ fnode->req_list->optional = RESET;
+}
+
+/*
+ * add an optional requirement to a filenode.
+ */
+void
+add_opt_require(filenode *fnode, char *s)
+{
+
+ add_require(fnode, s);
+ fnode->req_list->optional = SET;
}
/*
@@ -376,6 +399,16 @@
strnode_add(&bl_list, s, fnode);
}
+/*
+ * put the OPT-BEFORE: lines to a list and handle them later.
+ */
+void
+add_opt_before(filenode *fnode, char *s)
+{
+
+ add_before(fnode, s);
+ bl_list->optional = SET;
+}
/*
* add a key to a filenode.
@@ -411,6 +444,7 @@
FILE *fp;
char *buf;
int require_flag, provide_flag, before_flag, keyword_flag;
+ int opt_require_flag, opt_before_flag;
enum { BEFORE_PARSING, PARSING, PARSING_DONE } state;
filenode *node;
char delims[3] = { '\\', '\\', '\0' };
@@ -444,16 +478,23 @@
for (state = BEFORE_PARSING; state != PARSING_DONE &&
(buf = fparseln(fp, NULL, NULL, delims, 0)) != NULL; free(buf)) {
require_flag = provide_flag = before_flag = keyword_flag = 0;
+ opt_require_flag = opt_before_flag = 0;
if (strncmp(REQUIRE_STR, buf, REQUIRE_LEN) == 0)
require_flag = REQUIRE_LEN;
else if (strncmp(REQUIRES_STR, buf, REQUIRES_LEN) == 0)
require_flag = REQUIRES_LEN;
+ else if (strncmp(OPT_REQUIRE_STR, buf, OPT_REQUIRE_LEN) == 0)
+ opt_require_flag = OPT_REQUIRE_LEN;
+ else if (strncmp(OPT_REQUIRES_STR, buf, OPT_REQUIRES_LEN) == 0)
+ opt_require_flag = OPT_REQUIRES_LEN;
else if (strncmp(PROVIDE_STR, buf, PROVIDE_LEN) == 0)
provide_flag = PROVIDE_LEN;
else if (strncmp(PROVIDES_STR, buf, PROVIDES_LEN) == 0)
provide_flag = PROVIDES_LEN;
else if (strncmp(BEFORE_STR, buf, BEFORE_LEN) == 0)
before_flag = BEFORE_LEN;
+ else if (strncmp(OPT_BEFORE_STR, buf, OPT_BEFORE_LEN) == 0)
+ opt_before_flag = OPT_BEFORE_LEN;
else if (strncmp(KEYWORD_STR, buf, KEYWORD_LEN) == 0)
keyword_flag = KEYWORD_LEN;
else if (strncmp(KEYWORDS_STR, buf, KEYWORDS_LEN) == 0)
@@ -467,10 +508,14 @@
state = PARSING;
if (require_flag)
parse_line(node, buf + require_flag, add_require);
+ else if (opt_require_flag)
+ parse_line(node, buf+opt_require_flag, add_opt_require);
else if (provide_flag)
parse_line(node, buf + provide_flag, add_provide);
else if (before_flag)
- parse_line(node, buf + before_flag, add_before);
+ parse_line(node, buf + before_flag, add_before);
+ else if (opt_before_flag)
+ parse_line(node, buf + opt_before_flag, add_opt_before);
else if (keyword_flag)
parse_line(node, buf + keyword_flag, add_keyword);
}
@@ -538,8 +583,16 @@
fake_prov_entry = make_fake_provision(bl_list->node);
entry = Hash_CreateEntry(provide_hash, bl_list->s, &new);
- if (new == 1)
- warnx("file `%s' is before unknown provision `%s'", bl_list->node->filename, bl_list->s);
+ if (new == 1) {
+ if (bl_list->optional == SET) {
+ DPRINTF((stderr,
+ "unresolved OPT-BEFORE `%s' in file `%s'\n",
+ bl_list->s, bl_list->node->filename));
+ } else {
+ warnx("file `%s' is before unknown provision `%s'",
+ bl_list->node->filename, bl_list->s);
+ }
+ }
for (pnode = Hash_GetValue(entry); pnode; pnode = pnode->next) {
if (pnode->head)
@@ -596,10 +649,17 @@
head = Hash_GetValue(entry);
if (head == NULL) {
- warnx("requirement `%s' in file `%s' has no providers.",
- Hash_GetKey(entry), filename);
- exit_code = 1;
- return;
+ if (rnode->optional == SET) {
+ DPRINTF((stderr,
+ "unresolved OPT-REQUIRE `%s' in file `%s'\n",
+ Hash_GetKey(entry), filename));
+ return;
+ } else {
+ warnx("requirement `%s' in file `%s' has no providers.",
+ Hash_GetKey(entry), filename);
+ exit_code = 1;
+ return;
+ }
}
/* return if the requirement is already satisfied. */
>Release-Note:
>Audit-Trail:
>Unformatted: