2 * Copyright (c) 2015-2021 Baptiste Daroussin <bapt@FreeBSD.org>
3 * Copyright (c) 2015 Xin LI <delphij@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/capsicum.h>
28 #include <sys/types.h>
31 #include <capsicum_helpers.h>
43 /* state condition to transit to next state */
45 DELIM_SEEN
, /* letter */
46 KEYWORD
, /* punctuation mark */
47 PUNC_SEEN
, /* ':' -> _SVN; space -> TEXT */
48 PUNC_SEEN_SVN
, /* space */
53 scan(FILE *fp
, const char *name
, bool quiet
)
57 bool subversion
= false;
58 analyzer_states state
= INIT
;
64 l
= newlocale(LC_ALL_MASK
, "C", NULL
);
67 buffp
= open_memstream(&buf
, &sz
);
69 err(EXIT_FAILURE
, "open_memstream()");
72 printf("%s:\n", name
);
74 while ((c
= fgetc(fp
)) != EOF
) {
78 /* Transit to DELIM_SEEN if we see $ */
81 /* Otherwise, stay in INIT state */
86 if (isalpha_l(c
, l
)) {
87 /* Transit to KEYWORD if we see letter */
96 } else if (c
== '$') {
97 /* Or, stay in DELIM_SEEN if more $ */
100 /* Otherwise, transit back to INIT */
107 if (isalpha_l(c
, l
)) {
109 * Stay in KEYWORD if additional letter is seen
112 } else if (c
== ':') {
114 * See ':' for the first time, transit to
119 } else if (c
== '$') {
121 * Incomplete ident. Go back to DELIM_SEEN
122 * state because we see a '$' which could be
123 * the beginning of a keyword.
128 * Go back to INIT state otherwise.
140 * If we see '::' (seen : in PUNC_SEEN),
141 * activate subversion treatment and transit
142 * to PUNC_SEEN_SVN state.
144 * If more than two :'s were seen, the ident
145 * is invalid and we would therefore go back
148 if (state
== PUNC_SEEN
) {
149 state
= PUNC_SEEN_SVN
;
157 * A space after ':' or '::' indicates we are at the
158 * last component of potential ident.
163 /* All other characters are invalid */
171 if (iscntrl_l(c
, l
)) {
172 /* Control characters are not allowed in this state */
174 } else if (c
== '$') {
177 * valid ident should end with a space.
179 * subversion extension uses '#' to indicate that
180 * the keyword expansion have exceeded the fixed
181 * width, so it is also permitted if we are in
182 * subversion mode. No length check is enforced
183 * because GNU RCS ident(1) does not do it either.
185 c
= buf
[strlen(buf
) -2 ];
186 if (c
== ' ' || (subversion
&& c
== '#')) {
187 printf(" %s\n", buf
);
192 /* Other characters: stay in the state */
202 fprintf(stderr
, "%s warning: no id keywords in %s\n",
203 getprogname(), name
? name
: "standard input");
205 return (EXIT_FAILURE
);
208 return (EXIT_SUCCESS
);
212 main(int argc
, char **argv
)
216 int ret
= EXIT_SUCCESS
;
220 while ((ch
= getopt(argc
, argv
, "qV")) != -1) {
226 /* Do nothing, compat with GNU rcs's ident */
227 return (EXIT_SUCCESS
);
229 errx(EXIT_FAILURE
, "usage: %s [-q] [-V] [file...]",
237 if (caph_limit_stdio() < 0)
238 err(EXIT_FAILURE
, "unable to limit stdio");
242 fds
= malloc(sizeof(*fds
));
244 err(EXIT_FAILURE
, "unable to allocate fds array");
245 fds
[0] = STDIN_FILENO
;
248 fds
= malloc(sizeof(*fds
) * nfds
);
250 err(EXIT_FAILURE
, "unable to allocate fds array");
252 for (i
= 0; i
< argc
; i
++) {
253 fds
[i
] = fd
= open(argv
[i
], O_RDONLY
);
259 if (caph_limit_stream(fd
, CAPH_READ
) < 0)
261 "unable to limit fcntls/rights for %s",
266 /* Enter Capsicum sandbox. */
267 if (caph_enter() < 0)
268 err(EXIT_FAILURE
, "unable to enter capability mode");
270 for (i
= 0; i
< (int)nfds
; i
++) {
274 fp
= fdopen(fds
[i
], "r");
280 if (scan(fp
, argc
== 0 ? NULL
: argv
[i
], quiet
) != EXIT_SUCCESS
)