xref: /illumos-gate/usr/src/cmd/srchtxt/srchtxt.c (revision defc4c8acfa01dba1ef3c13ca0cafccfcede51c0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include	<stdio.h>
33 #include	<dirent.h>
34 #include	<regexpr.h>
35 #include	<string.h>
36 #include	<errno.h>
37 #include	<fcntl.h>
38 #include	<locale.h>
39 #include	<sys/types.h>
40 #include	<sys/file.h>
41 #include	<sys/mman.h>
42 #include	<sys/stat.h>
43 #include	<unistd.h>
44 
45 #define	P_locale	"/usr/lib/locale/"
46 #define	L_locale	(sizeof (P_locale))
47 #define	MESSAGES	"/LC_MESSAGES/"
48 #define	ESIZE		BUFSIZ
49 
50 /* External functions */
51 
52 extern	int	getopt();
53 extern	void	exit();
54 extern	char	*strecpy();
55 extern	char	*strrchr();
56 extern	char	*strchr();
57 
58 
59 /* External variables */
60 
61 extern	char	*optarg;
62 extern	int	optind;
63 
64 /* Internal functions */
65 
66 static	void	usage();
67 static	void	prnt_str();
68 static	int	attach();
69 static	void	find_msgs();
70 static	char	*syserr();
71 
72 /* Internal variables */
73 
74 static	char	*cmdname; 	/* points to the name of the command */
75 static	int	lflg;		/* set if locale is specified on command line */
76 static	int	mflg;		/* set if message file is specified on */
77 				/* command line */
78 static	char	locale[15];	/* save name of current locale */
79 static  char	*msgfile;	/* points to the argument immediately */
80 				/* following the m option */
81 static	char	*text;		/* pointer to search pattern */
82 static	int	textflg;	/* set if text pattern is specified on */
83 				/* command line */
84 static	int	sflg;		/* set if the s option is specified */
85 static	char	*fname;		/* points to message file name */
86 static	int	msgnum;		/* message number */
87 
88 int
89 main(int argc, char **argv)
90 {
91 	int	ch;
92 	char	*end;
93 	int	addr;
94 	int	len;
95 	int	len1;
96 	int	fd;
97 	size_t	size;
98 	char	pathname[128];
99 	char	*cp;
100 	char	ebuf[ESIZE];
101 	DIR	*dirp;
102 	struct	dirent	*dp;
103 
104 	/* find last level of path in command name */
105 	if (cmdname = strrchr(*argv, '/'))
106 		++cmdname;
107 	else
108 		cmdname = *argv;
109 
110 	/* parse command line */
111 	while ((ch = getopt(argc, argv, "sl:m:")) != -1)
112 		switch (ch) {
113 			case	'l':
114 				lflg++;
115 				(void) strcpy(locale, optarg);
116 				continue;
117 			case	'm':
118 				mflg++;
119 				msgfile = optarg;
120 				continue;
121 			case	's':
122 				sflg++;
123 				continue;
124 			default:
125 				usage();
126 			}
127 	if (mflg && optind < argc) {
128 		text = argv[optind++];
129 		textflg++;
130 	}
131 	if (optind != argc)
132 		usage();
133 
134 	/* create full path name to message files */
135 	if (!lflg)
136 		(void) strcpy(locale, setlocale(LC_MESSAGES, ""));
137 	(void) strcpy(pathname, P_locale);
138 	(void) strcpy(&pathname[L_locale - 1], locale);
139 	(void) strcat(pathname, MESSAGES);
140 	len = strlen(pathname);
141 
142 	if (textflg) {
143 			/* compile regular expression */
144 		if (compile(text, &ebuf[0], &ebuf[ESIZE]) == (char *)NULL) {
145 			(void) fprintf(stderr,
146 			    "%s: ERROR: regular expression compile failed\n",
147 			    cmdname);
148 			exit(1);
149 		}
150 	}
151 
152 	/* access message files */
153 	if (mflg) {
154 		end = msgfile + strlen(msgfile) + 1;
155 		if (*msgfile == ',' || *(end - 2) == ',')
156 			usage();
157 		while ((fname = strtok(msgfile, ",\0")) != NULL) {
158 			if (strchr(fname, '/') != (char *)NULL) {
159 				cp = fname;
160 				len1 = 0;
161 			} else {
162 				cp = pathname;
163 				len1 = len;
164 			}
165 			msgfile = msgfile + strlen(fname) + 1;
166 			if ((addr = attach(cp, len1, &fd, &size)) == -1) {
167 				(void) fprintf(stderr,
168 	"%s: ERROR: failed to access message file '%s'\n", cmdname, cp);
169 				if (end != msgfile)
170 					continue;
171 				else
172 					break;
173 			}
174 			find_msgs(addr, ebuf);
175 			(void) munmap((caddr_t)addr, size);
176 			(void) close(fd);
177 			if (end == msgfile)
178 				break;
179 		}
180 	} else { /* end if (mflg) */
181 		if ((dirp = opendir(pathname)) == NULL) {
182 			(void) fprintf(stderr, "%s: ERROR: %s %s\n",
183 			    cmdname, pathname, syserr());
184 			exit(1);
185 		}
186 		while ((dp = readdir(dirp)) != NULL) {
187 			if (dp->d_name[0] == '.')
188 				continue;
189 			fname = dp->d_name;
190 			if ((addr = attach(pathname, len, &fd, &size)) == -1) {
191 				(void) fprintf(stderr,
192 	"%s: ERROR: failed to access message file '%s'\n", cmdname, pathname);
193 				continue;
194 			}
195 			find_msgs(addr, ebuf);
196 			(void) munmap((caddr_t)addr, size);
197 			(void) close(fd);
198 		}
199 		(void) closedir(dirp);
200 	}
201 	return (0);
202 }
203 
204 
205 /* print usage message */
206 static void
207 usage()
208 {
209 	(void) fprintf(stderr,
210 	    "usage: srchtxt [-s]\n       srchtxt [-s] -l locale\n"
211 	    "       srchtxt [-s] [-l locale] [-m msgfile,...] [text]\n");
212 	exit(1);
213 }
214 
215 /*
216  * print string - non-graphic characters are printed as alphabetic
217  * escape sequences
218  */
219 static	void
220 prnt_str(instring)
221 char	*instring;
222 {
223 	char	outstring[1024];
224 
225 	(void) strecpy(outstring, instring, NULL);
226 	if (sflg)
227 		(void) fprintf(stdout, "%s\n", outstring);
228 	else
229 		(void) fprintf(stdout, "<%s:%d>%s\n", fname, msgnum, outstring);
230 }
231 
232 /* mmap a message file to the address space */
233 static int
234 attach(path, len, fdescr, size)
235 char	*path;
236 int	len;
237 int	*fdescr;
238 size_t	*size;
239 {
240 	int	fd = -1;
241 	caddr_t	addr;
242 	struct	stat	sb;
243 
244 	(void) strcpy(&path[len], fname);
245 	if ((fd = open(path, O_RDONLY)) != -1 &&
246 	    fstat(fd, &sb) != -1 &&
247 	    (addr = mmap(0, sb.st_size,
248 		PROT_READ, MAP_SHARED,
249 		fd, 0)) != (caddr_t)-1) {
250 		*fdescr = fd;
251 		*size = sb.st_size;
252 		return ((int)addr);
253 	} else {
254 		if (fd == -1)
255 			(void) close(fd);
256 		return (-1);
257 	}
258 }
259 
260 
261 /* find messages in message files */
262 static void
263 find_msgs(addr, regexpr)
264 int	addr;
265 char	*regexpr;
266 {
267 	int	num_msgs;
268 	char	*msg;
269 
270 	num_msgs = *(int *)addr;
271 	for (msgnum = 1; msgnum <= num_msgs; msgnum++) {
272 		msg = (char *)(*(int *)(addr + sizeof (int) * msgnum) + addr);
273 		if (textflg)
274 			if (step(msg, regexpr)) {
275 				prnt_str(msg);
276 					continue;
277 				}
278 				else
279 					continue;
280 			prnt_str(msg);
281 	}
282 }
283 
284 /* print description of error */
285 static char *
286 syserr()
287 {
288 	return (strerror(errno));
289 }
290