[patch] Re: getfsent(3) and spaces in fstab
Simon Barner
barner at in.tum.de
Thu Aug 7 07:08:37 PDT 2003
> imho - expensive algorithm... i want to see anything more simple...
> like "gtok()" instead "es_strsep() + remove_escapes()"?
I have adopted my patch to use your neat gtok() function, but I came to
the conclusion that a two-pass algorithm is necessary:
The first pass detects whether a line from fstab is the old or the new
style format (old style lines may only have unescaped white spaces
before a trailing #-comment).
Then, the second pass extracts the information.
I admit this is rather complicated, but I don't how to handle two sets
of delimiters (":\n" and " \n\r\t") with only one pass. Using gtok() to
detect the style of line is not an option IMO, since it would convert
escape sequences.
Now, the following lines can be processed:
1) old style:
<file system>:<mount point>:<mount type>:<dump>:<passno>([' ','\t']*#<comment>)*
2) new style
format as described in fstab(5) + an optional #-comment at the end of the line
3) empty lines, white space lines, deliberately many white spaces + comment
In both the old and the new style lines, white spaces can be written as
escape sequences or in double quotes.
Could somebody please review my patch - if there are no objections (but
I am sure there are some more details that can be improved), I will
write a PR in order
Regards,
Simon
-------------- next part --------------
--- fstab.c.orig Fri Aug 1 17:18:00 2003
+++ fstab.c Thu Aug 7 15:46:39 2003
@@ -84,6 +84,60 @@
_fs_fstab.fs_spec = buf;
}
+/*
+ * Gets a token from a string *s, that is either empty or is separated by
+ * a set of delimiters *delim.
+ * Characters that are in *delim, can occur in the token if the are escaped,
+ * i.e. have a '\' prepended. The character '\' itself is encoded as '\\'.
+ * *s can have a trailing comment (indicated by a '#'), which will cause the
+ * characters after the '#' to be ignored. To encode a '#' within a token,
+ * use '\#'.
+ *
+ * If a token is found, gtok sets the last character after its end
+ * to '\0' and returns a pointer it. Otherwise the return value is NULL.
+ * As a side effect, the input string *s modified and points to the next
+ * character after the end of the current token, i.e. after the '\0'.
+ */
+char *gtok(char **s, char const *delim)
+{
+ int quoted, escaped;
+ static char const esc_set[] = { 't', 'r', 'n', 'a', 0 };
+ static char const esc_rep[] = { '\t', '\r', '\n', '\a', 0 };
+ char *tok, *r, *w, *p;
+
+ if (!s || !*s || !*(tok = *s + strspn(*s, delim)) || *tok == '#')
+ return NULL;
+
+ for (quoted = escaped = 0, r = w = tok; *r; r++) {
+ if (!escaped) {
+ if (*r == '\\') {
+ escaped = 1;
+ continue;
+ }
+ if (*r == '\"') {
+ quoted ^= -1;
+ continue;
+ }
+ if (!quoted) {
+ if (strchr(delim, *r)) {
+ r++;
+ break;
+ }
+ }
+ } else {
+ escaped = 0;
+ if ((p = strchr(esc_set, *r)) != NULL) {
+ *w++ = esc_rep[p - esc_set];
+ continue;
+ }
+ }
+ *w++ = *r;
+ }
+ *w = 0;
+ *s = r;
+ return tok;
+}
+
static int
fstabscan()
{
@@ -91,21 +145,73 @@
#define MAXLINELENGTH 1024
static char line[MAXLINELENGTH];
char subline[MAXLINELENGTH];
- int typexx;
+ int typexx, escaped=0, quoted=0, ws_sep=0;
for (;;) {
if (!(p = fgets(line, sizeof(line), _fs_fp)))
return(0);
-/* OLD_STYLE_FSTAB */
++LineNo;
- if (*line == '#' || *line == '\n')
- continue;
- if (!strpbrk(p, " \t")) {
- _fs_fstab.fs_spec = strsep(&p, ":\n");
- _fs_fstab.fs_file = strsep(&p, ":\n");
+
+ /* Detect whether line is in old or new fstab style */
+ for (cp=p; *cp != '\n'; ++cp) {
+ if (*cp == '\\') {
+ escaped = (escaped ? 0 : 1);
+ continue;
+ }
+ if (!escaped) {
+ /* Quotes */
+ if (*cp == '\"') {
+ quoted = (quoted ? 0 : 1);
+ continue;
+ }
+ if (quoted)
+ continue;
+ /* new white separator found */
+ if (cp > p && strspn (cp, " \n\r\t") &&
+ !strspn(cp-1, " \t"))
+ ++ws_sep;
+
+ /* #-comment found */
+ if (*cp == '#') {
+ *cp = '\0';
+ /* ignore white spaces in front of a comment */
+ if (cp > p && strspn(cp-1, " \t") &&
+ ws_sep > 0)
+ ws_sep--;
+ break;
+ }
+ } else
+ escaped = 0;
+ }
+ /* open quotes and unfinished escape-sequences are bad */
+ if (quoted || escaped)
+ goto bad;
+ /* ignore trailing white spaces */
+ if (*(cp + strspn (cp, " \t")) == '\n' && ws_sep > 0)
+ --ws_sep;
+
+ /* No white space separators found => OLD_STYLE_FSTAB */
+ if (ws_sep == 0) {
+ /*
+ * line consists only of white spaces
+ * (evtl. + #-comment)
+ */
+ if (strspn (p, " \t"))
+ continue;
+ /*
+ * Now read the different values (gtok will convert
+ * escape seq.). Format is:
+ * <fs_spec>:<fs_file>:<fs_type>:<freq>:<passno>
+ * ':' itself can be encodes as '\:'
+ */
+ if (!(_fs_fstab.fs_spec = gtok(&p, ":\n\r")))
+ continue;
+ if (!(_fs_fstab.fs_file = gtok(&p, ":\n\r"))) {
+ goto bad;
+ }
fixfsfile();
- _fs_fstab.fs_type = strsep(&p, ":\n");
+ _fs_fstab.fs_type = gtok(&p, ":\n\r");
if (_fs_fstab.fs_type) {
if (!strcmp(_fs_fstab.fs_type, FSTAB_XX))
continue;
@@ -113,46 +219,43 @@
_fs_fstab.fs_vfstype =
strcmp(_fs_fstab.fs_type, FSTAB_SW) ?
"ufs" : "swap";
- if ((cp = strsep(&p, ":\n")) != NULL) {
+ if ((cp = gtok(&p, ":\n\r")) != NULL) {
_fs_fstab.fs_freq = atoi(cp);
- if ((cp = strsep(&p, ":\n")) != NULL) {
+ if ((cp = gtok(&p, " \n\r\t")) != NULL) {
_fs_fstab.fs_passno = atoi(cp);
+ if (gtok (&p, " \n\r\t"))
+ goto bad;
+
return(1);
}
}
}
goto bad;
}
-/* OLD_STYLE_FSTAB */
- while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
- ;
- _fs_fstab.fs_spec = cp;
- if (!_fs_fstab.fs_spec || *_fs_fstab.fs_spec == '#')
+
+ /* At least one white space sep. found => NEW_STYLE_FSTAB */
+ if (!(_fs_fstab.fs_spec = gtok(&p, " \n\r\t")))
continue;
- while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
- ;
- _fs_fstab.fs_file = cp;
+ if (!(_fs_fstab.fs_file = gtok(&p, " \n\r\t")))
+ goto bad;
fixfsfile();
- while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
- ;
- _fs_fstab.fs_vfstype = cp;
- while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
- ;
- _fs_fstab.fs_mntops = cp;
- if (_fs_fstab.fs_mntops == NULL)
+ if (!(_fs_fstab.fs_vfstype = gtok(&p, " \n\r\t")))
+ goto bad;
+ if (!(_fs_fstab.fs_mntops = gtok(&p, " \n\r\t")))
goto bad;
_fs_fstab.fs_freq = 0;
_fs_fstab.fs_passno = 0;
- while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
- ;
+ cp = gtok(&p, " \n\r\t");
if (cp != NULL) {
_fs_fstab.fs_freq = atoi(cp);
- while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
- ;
+ cp = gtok(&p, " \n\r\t");
if (cp != NULL)
_fs_fstab.fs_passno = atoi(cp);
}
strcpy(subline, _fs_fstab.fs_mntops);
+ if (gtok (&p, " \n\r\t"))
+ goto bad;
+
p = subline;
for (typexx = 0, cp = strsep(&p, ","); cp;
cp = strsep(&p, ",")) {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: Digital signature
Url : http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20030807/fa303b7b/attachment.bin
More information about the freebsd-hackers
mailing list