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#include	<stdio.h>
31#include	<dirent.h>
32#include	<regexpr.h>
33#include	<string.h>
34#include	<errno.h>
35#include	<fcntl.h>
36#include	<locale.h>
37#include	<sys/types.h>
38#include	<sys/file.h>
39#include	<sys/mman.h>
40#include	<sys/stat.h>
41#include	<unistd.h>
42
43#define	P_locale	"/usr/lib/locale/"
44#define	L_locale	(sizeof (P_locale))
45#define	MESSAGES	"/LC_MESSAGES/"
46#define	ESIZE		BUFSIZ
47
48/* External functions */
49
50extern	int	getopt();
51extern	void	exit();
52extern	char	*strecpy();
53extern	char	*strrchr();
54extern	char	*strchr();
55
56
57/* External variables */
58
59extern	char	*optarg;
60extern	int	optind;
61
62/* Internal functions */
63
64static	void	usage();
65static	void	prnt_str();
66static	int	attach();
67static	void	find_msgs();
68static	char	*syserr();
69
70/* Internal variables */
71
72static	char	*cmdname; 	/* points to the name of the command */
73static	int	lflg;		/* set if locale is specified on command line */
74static	int	mflg;		/* set if message file is specified on */
75				/* command line */
76static	char	locale[15];	/* save name of current locale */
77static  char	*msgfile;	/* points to the argument immediately */
78				/* following the m option */
79static	char	*text;		/* pointer to search pattern */
80static	int	textflg;	/* set if text pattern is specified on */
81				/* command line */
82static	int	sflg;		/* set if the s option is specified */
83static	char	*fname;		/* points to message file name */
84static	int	msgnum;		/* message number */
85
86int
87main(int argc, char **argv)
88{
89	int	ch;
90	char	*end;
91	int	addr;
92	int	len;
93	int	len1;
94	int	fd;
95	size_t	size;
96	char	pathname[128];
97	char	*cp;
98	char	ebuf[ESIZE];
99	DIR	*dirp;
100	struct	dirent	*dp;
101
102	/* find last level of path in command name */
103	if (cmdname = strrchr(*argv, '/'))
104		++cmdname;
105	else
106		cmdname = *argv;
107
108	/* parse command line */
109	while ((ch = getopt(argc, argv, "sl:m:")) != -1)
110		switch (ch) {
111			case	'l':
112				lflg++;
113				(void) strcpy(locale, optarg);
114				continue;
115			case	'm':
116				mflg++;
117				msgfile = optarg;
118				continue;
119			case	's':
120				sflg++;
121				continue;
122			default:
123				usage();
124			}
125	if (mflg && optind < argc) {
126		text = argv[optind++];
127		textflg++;
128	}
129	if (optind != argc)
130		usage();
131
132	/* create full path name to message files */
133	if (!lflg)
134		(void) strcpy(locale, setlocale(LC_MESSAGES, ""));
135	(void) strcpy(pathname, P_locale);
136	(void) strcpy(&pathname[L_locale - 1], locale);
137	(void) strcat(pathname, MESSAGES);
138	len = strlen(pathname);
139
140	if (textflg) {
141			/* compile regular expression */
142		if (compile(text, &ebuf[0], &ebuf[ESIZE]) == (char *)NULL) {
143			(void) fprintf(stderr,
144			    "%s: ERROR: regular expression compile failed\n",
145			    cmdname);
146			exit(1);
147		}
148	}
149
150	/* access message files */
151	if (mflg) {
152		end = msgfile + strlen(msgfile) + 1;
153		if (*msgfile == ',' || *(end - 2) == ',')
154			usage();
155		while ((fname = strtok(msgfile, ",\0")) != NULL) {
156			if (strchr(fname, '/') != (char *)NULL) {
157				cp = fname;
158				len1 = 0;
159			} else {
160				cp = pathname;
161				len1 = len;
162			}
163			msgfile = msgfile + strlen(fname) + 1;
164			if ((addr = attach(cp, len1, &fd, &size)) == -1) {
165				(void) fprintf(stderr,
166	"%s: ERROR: failed to access message file '%s'\n", cmdname, cp);
167				if (end != msgfile)
168					continue;
169				else
170					break;
171			}
172			find_msgs(addr, ebuf);
173			(void) munmap((caddr_t)addr, size);
174			(void) close(fd);
175			if (end == msgfile)
176				break;
177		}
178	} else { /* end if (mflg) */
179		if ((dirp = opendir(pathname)) == NULL) {
180			(void) fprintf(stderr, "%s: ERROR: %s %s\n",
181			    cmdname, pathname, syserr());
182			exit(1);
183		}
184		while ((dp = readdir(dirp)) != NULL) {
185			if (dp->d_name[0] == '.')
186				continue;
187			fname = dp->d_name;
188			if ((addr = attach(pathname, len, &fd, &size)) == -1) {
189				(void) fprintf(stderr,
190	"%s: ERROR: failed to access message file '%s'\n", cmdname, pathname);
191				continue;
192			}
193			find_msgs(addr, ebuf);
194			(void) munmap((caddr_t)addr, size);
195			(void) close(fd);
196		}
197		(void) closedir(dirp);
198	}
199	return (0);
200}
201
202
203/* print usage message */
204static void
205usage()
206{
207	(void) fprintf(stderr,
208	    "usage: srchtxt [-s]\n       srchtxt [-s] -l locale\n"
209	    "       srchtxt [-s] [-l locale] [-m msgfile,...] [text]\n");
210	exit(1);
211}
212
213/*
214 * print string - non-graphic characters are printed as alphabetic
215 * escape sequences
216 */
217static	void
218prnt_str(instring)
219char	*instring;
220{
221	char	outstring[1024];
222
223	(void) strecpy(outstring, instring, NULL);
224	if (sflg)
225		(void) fprintf(stdout, "%s\n", outstring);
226	else
227		(void) fprintf(stdout, "<%s:%d>%s\n", fname, msgnum, outstring);
228}
229
230/* mmap a message file to the address space */
231static int
232attach(path, len, fdescr, size)
233char	*path;
234int	len;
235int	*fdescr;
236size_t	*size;
237{
238	int	fd = -1;
239	caddr_t	addr;
240	struct	stat	sb;
241
242	(void) strcpy(&path[len], fname);
243	if ((fd = open(path, O_RDONLY)) != -1 &&
244	    fstat(fd, &sb) != -1 &&
245	    (addr = mmap(0, sb.st_size,
246		PROT_READ, MAP_SHARED,
247		fd, 0)) != (caddr_t)-1) {
248		*fdescr = fd;
249		*size = sb.st_size;
250		return ((int)addr);
251	} else {
252		if (fd == -1)
253			(void) close(fd);
254		return (-1);
255	}
256}
257
258
259/* find messages in message files */
260static void
261find_msgs(addr, regexpr)
262int	addr;
263char	*regexpr;
264{
265	int	num_msgs;
266	char	*msg;
267
268	num_msgs = *(int *)addr;
269	for (msgnum = 1; msgnum <= num_msgs; msgnum++) {
270		msg = (char *)(*(int *)(addr + sizeof (int) * msgnum) + addr);
271		if (textflg) {
272			if (step(msg, regexpr))
273				prnt_str(msg);
274			continue;
275		}
276		prnt_str(msg);
277	}
278}
279
280/* print description of error */
281static char *
282syserr()
283{
284	return (strerror(errno));
285}
286