GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/which/which.c Lines: 31 58 53.4 %
Date: 2017-11-13 Branches: 25 56 44.6 %

Line Branch Exec Source
1
/*	$OpenBSD: which.c,v 1.26 2016/10/28 07:22:59 schwarze 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 <limits.h>
25
#include <paths.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
31
#define PROG_WHICH	1
32
#define PROG_WHEREIS	2
33
34
extern char *__progname;
35
36
int findprog(char *, char *, int, int);
37
static void __dead usage(void);
38
39
/*
40
 * which(1) -- find an executable(s) in the user's path
41
 * whereis(1) -- find an executable(s) in the default user path
42
 *
43
 * Return values:
44
 *	0 - all executables found
45
 *	1 - some found, some not
46
 *	2 - none found
47
 */
48
49
int
50
main(int argc, char *argv[])
51
{
52
	char *path;
53
	size_t n;
54
	int ch, allmatches = 0, notfound = 0, progmode = PROG_WHICH;
55
56
36
	while ((ch = getopt(argc, argv, "a")) != -1)
57
		switch (ch) {
58
		case 'a':
59
			allmatches = 1;
60
			break;
61
		default:
62
			usage();
63
		}
64
12
	argc -= optind;
65
12
	argv += optind;
66
67
12
	if (argc == 0)
68
		usage();
69
70
12
	if (strcmp(__progname, "whereis") == 0) {
71
		progmode = PROG_WHEREIS;
72
		path = _PATH_STDPATH;
73
	} else {
74

24
		if ((path = getenv("PATH")) == NULL || *path == '\0')
75
			path = _PATH_DEFPATH;
76
	}
77
78
	/* To make access(2) do what we want */
79
12
	if (setgid(getegid()))
80
		err(1, "Can't set gid to %u", getegid());
81
12
	if (setuid(geteuid()))
82
		err(1, "Can't set uid to %u", geteuid());
83
84
12
	if (pledge("stdio rpath flock cpath wpath", NULL) == -1)
85
		err(2, "pledge");
86
87
48
	for (n = 0; n < argc; n++)
88
12
		if (findprog(argv[n], path, progmode, allmatches) == 0)
89
			notfound++;
90
91
24
	return ((notfound == 0) ? 0 : ((notfound == argc) ? 2 : 1));
92
}
93
94
int
95
findprog(char *prog, char *path, int progmode, int allmatches)
96
{
97
24
	char *p, filename[PATH_MAX];
98
	int len, rval = 0;
99
12
	struct stat sbuf;
100
12
	char *pathcpy;
101
102
	/* Special case if prog contains '/' */
103
12
	if (strchr(prog, '/')) {
104
		if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
105
		    access(prog, X_OK) == 0) {
106
			(void)puts(prog);
107
			return (1);
108
		} else {
109
			warnx("%s: Command not found.", prog);
110
			return (0);
111
		}
112
	}
113
114
12
	if ((path = strdup(path)) == NULL)
115
		err(1, "strdup");
116
12
	pathcpy = path;
117
118
168
	while ((p = strsep(&pathcpy, ":")) != NULL) {
119
84
		if (*p == '\0')
120
			p = ".";
121
122
84
		len = strlen(p);
123

252
		while (len > 0 && p[len-1] == '/')
124
			p[--len] = '\0';	/* strip trailing '/' */
125
126
84
		len = snprintf(filename, sizeof(filename), "%s/%s", p, prog);
127

168
		if (len < 0 || len >= sizeof(filename)) {
128
			warnc(ENAMETOOLONG, "%s/%s", p, prog);
129
			free(path);
130
			return (0);
131
		}
132

108
		if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
133
12
		    access(filename, X_OK) == 0) {
134
12
			(void)puts(filename);
135
			rval = 1;
136
12
			if (!allmatches) {
137
12
				free(path);
138
12
				return (rval);
139
			}
140
		}
141
	}
142
	(void)free(path);
143
144
	/* whereis(1) is silent on failure. */
145
	if (!rval && progmode != PROG_WHEREIS)
146
		warnx("%s: Command not found.", prog);
147
	return (rval);
148
12
}
149
150
static void __dead
151
usage(void)
152
{
153
	(void)fprintf(stderr, "usage: %s [-a] name ...\n", __progname);
154
	exit(1);
155
}