aboutsummaryrefslogtreecommitdiff
path: root/lib/functions.c
blob: 7ef3a70cfe7bc2782156196cb069326c1f630663 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* vi: set sw=4 ts=4 :*/
/* functions.c - reusable stuff.
 *
 * Functions with the x prefix are wrappers for library functions.  They either
 * succeed or kill the program with an error message, but never return failure.
 * They usually have the same arguments and return value as the function they
 * wrap.
 */

#include "toys.h"

// Die with an error message.
void error_exit(char *msg, ...)
{
	va_list args;

	va_start(args, msg);
	fprintf(stderr, "%s: ", toys.which->name);
	vfprintf(stderr, msg, args);
	va_end(args);
	exit(toys.exitval);
}

// Like strncpy but always null terminated.
void strlcpy(char *dest, char *src, size_t size)
{
	strncpy(dest,src,size);
	dest[size-1] = 0;
}

// Die unless we can allocate memory.
void *xmalloc(size_t size)
{
	void *ret = malloc(size);
	if (!ret) error_exit("xmalloc");

	return ret;
}

// Die unless we can allocate prezeroed memory.
void *xzalloc(size_t size)
{
	void *ret = xmalloc(size);
	bzero(ret,size);
	return ret;
}

// Die unless we can change the size of an existing allocation, possibly
// moving it.  (Notice different arguments from libc function.)
void xrealloc(void **ptr, size_t size)
{
	*ptr = realloc(*ptr, size);
	if (!*ptr) error_exit("xrealloc");
}

// Die unless we can allocate a copy of this string.
void *xstrndup(char *s, size_t n)
{
	void *ret = xmalloc(++n);
	strlcpy(ret, s, n);
	
	return ret;
}

// Die unless we can allocate enough space to sprintf() into.
char *xmsprintf(char *format, ...)
{
	va_list va;
	int len;
	char *ret;
	
	// How long is it?

	va_start(va, format);
	len = vsnprintf(0, 0, format, va);
	len++;
	va_end(va);

	// Allocate and do the sprintf()
	ret = xmalloc(len);
	va_start(va, format);
	vsnprintf(ret, len, format, va);	
	va_end(va);

	return ret;
}

// Die unless we can exec argv[] (or run builtin command).  Note that anything
// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
void *xexec(char **argv)
{
	toy_exec(argv);
	execvp(argv[0], argv);
	error_exit("No %s", argv[0]);
}

// Die unless we can open/create a file, returning file descriptor.
int xopen(char *path, int flags, int mode)
{
	int fd = open(path, flags, mode);
	if (fd == -1) error_exit("No file %s\n", path);
	return fd;
}

// Die unless we can open/create a file, returning FILE *.
FILE *xfopen(char *path, char *mode)
{
	FILE *f = fopen(path, mode);
	if (!f) error_exit("No file %s\n", path);
	return f;
}

// int xread(int fd, char *buf, int len)     // Die if can't fill buffer
// int readall(int fd, char *buf, int len)   // Keep reading until full or EOF
// int toy_read(int fd, char *buf, int len)  // retry if interrupted

char *xgetcwd(void)
{
	char *buf = getcwd(NULL, 0);
	if (!buf) error_exit("xgetcwd");
}

// Find this file in a colon-separated path.

char *find_in_path(char *path, char *filename)
{
	char *next, *res = NULL, *cwd = xgetcwd();

	while (next = index(path,':')) {
		int len = next-path;

		if (len==1) res = xmsprintf("%s/%s", cwd, filename);
		else res = xmsprintf("%*s/%s",len-1,path,filename);
		// Is there a file here we can execute?
		if (!access(res, X_OK)) {
			struct stat st;
			// Confirm it's not a directory.
			if (!stat(res, &st) && S_ISREG(st.st_mode)) break;
		}
		free(res);
		res = NULL;
	}
	free(cwd);

	return res;
}