GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/which/which.c Lines: 0 59 0.0 %
Date: 2016-12-06 Branches: 0 56 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: which.c,v 1.25 2016/01/14 22:02:13 millert Exp $	*/
2
3
/*
4
 * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/stat.h>
20
#include <sys/sysctl.h>
21
22
#include <err.h>
23
#include <errno.h>
24
#include <locale.h>
25
#include <paths.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
#include <limits.h>
31
32
#define PROG_WHICH	1
33
#define PROG_WHEREIS	2
34
35
extern char *__progname;
36
37
int findprog(char *, char *, int, int);
38
__dead void usage(void);
39
40
/*
41
 * which(1) -- find an executable(s) in the user's path
42
 * whereis(1) -- find an executable(s) in the default user path
43
 *
44
 * Return values:
45
 *	0 - all executables found
46
 *	1 - some found, some not
47
 *	2 - none found
48
 */
49
50
int
51
main(int argc, char *argv[])
52
{
53
	char *path;
54
	size_t n;
55
	int ch, allmatches = 0, notfound = 0, progmode = PROG_WHICH;
56
57
	(void)setlocale(LC_ALL, "");
58
59
	while ((ch = getopt(argc, argv, "a")) != -1)
60
		switch (ch) {
61
		case 'a':
62
			allmatches = 1;
63
			break;
64
		default:
65
			usage();
66
		}
67
	argc -= optind;
68
	argv += optind;
69
70
	if (argc == 0)
71
		usage();
72
73
	if (strcmp(__progname, "whereis") == 0) {
74
		progmode = PROG_WHEREIS;
75
		path = _PATH_STDPATH;
76
	} else {
77
		if ((path = getenv("PATH")) == NULL || *path == '\0')
78
			path = _PATH_DEFPATH;
79
	}
80
81
	/* To make access(2) do what we want */
82
	if (setgid(getegid()))
83
		err(1, "Can't set gid to %u", getegid());
84
	if (setuid(geteuid()))
85
		err(1, "Can't set uid to %u", geteuid());
86
87
	if (pledge("stdio rpath wpath cpath", NULL) == -1)
88
		err(2, "pledge");
89
90
	for (n = 0; n < argc; n++)
91
		if (findprog(argv[n], path, progmode, allmatches) == 0)
92
			notfound++;
93
94
	exit((notfound == 0) ? 0 : ((notfound == argc) ? 2 : 1));
95
}
96
97
int
98
findprog(char *prog, char *path, int progmode, int allmatches)
99
{
100
	char *p, filename[PATH_MAX];
101
	int len, rval = 0;
102
	struct stat sbuf;
103
	char *pathcpy;
104
105
	/* Special case if prog contains '/' */
106
	if (strchr(prog, '/')) {
107
		if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
108
		    access(prog, X_OK) == 0) {
109
			(void)puts(prog);
110
			return (1);
111
		} else {
112
			warnx("%s: Command not found.", prog);
113
			return (0);
114
		}
115
	}
116
117
	if ((path = strdup(path)) == NULL)
118
		err(1, "strdup");
119
	pathcpy = path;
120
121
	while ((p = strsep(&pathcpy, ":")) != NULL) {
122
		if (*p == '\0')
123
			p = ".";
124
125
		len = strlen(p);
126
		while (len > 0 && p[len-1] == '/')
127
			p[--len] = '\0';	/* strip trailing '/' */
128
129
		len = snprintf(filename, sizeof(filename), "%s/%s", p, prog);
130
		if (len < 0 || len >= sizeof(filename)) {
131
			warnc(ENAMETOOLONG, "%s/%s", p, prog);
132
			free(path);
133
			return (0);
134
		}
135
		if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
136
		    access(filename, X_OK) == 0) {
137
			(void)puts(filename);
138
			rval = 1;
139
			if (!allmatches) {
140
				free(path);
141
				return (rval);
142
			}
143
		}
144
	}
145
	(void)free(path);
146
147
	/* whereis(1) is silent on failure. */
148
	if (!rval && progmode != PROG_WHEREIS)
149
		warnx("%s: Command not found.", prog);
150
	return (rval);
151
}
152
153
__dead void
154
usage(void)
155
{
156
	(void)fprintf(stderr, "usage: %s [-a] name ...\n", __progname);
157
	exit(1);
158
}