GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amd/util.c Lines: 0 191 0.0 %
Date: 2017-11-07 Branches: 0 154 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1990 Jan-Simon Pendry
3
 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4
 * Copyright (c) 1990, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Jan-Simon Pendry at Imperial College, London.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	from: @(#)util.c	8.1 (Berkeley) 6/6/93
35
 *	$Id: util.c,v 1.16 2015/12/12 20:06:42 mmcc Exp $
36
 */
37
38
/*
39
 * Utils
40
 */
41
42
#include "am.h"
43
#include <ctype.h>
44
#include <unistd.h>
45
#include <sys/stat.h>
46
#include <netdb.h>
47
48
49
char *
50
strnsave(const char *str, int len)
51
{
52
	char *sp = xmalloc(len+1);
53
54
	bcopy(str, sp, len);
55
	sp[len] = 0;
56
57
	return sp;
58
}
59
60
/*
61
 * Concatenate three strings and store in buffer pointed to
62
 * by p, making p large enough to hold the strings
63
 */
64
char *
65
str3cat(char *p, char *s1, char *s2, char *s3)
66
{
67
	size_t l1 = strlen(s1);
68
	size_t l2 = strlen(s2);
69
	size_t l3 = strlen(s3);
70
71
	if (l1 > SIZE_MAX - l2 || l1 + l2 > SIZE_MAX - l3)
72
		 xmallocfailure();
73
	p = xreallocarray(p, l1 + l2 + l3 + 1, 1);
74
	bcopy(s1, p, l1);
75
	bcopy(s2, p + l1, l2);
76
	bcopy(s3, p + l1 + l2, l3 + 1);
77
	return p;
78
}
79
80
char *
81
strealloc(char *p, char *s)
82
{
83
	size_t len = strlen(s) + 1;
84
85
	if (len > SIZE_MAX - 1)
86
		 xmallocfailure();
87
	p = xreallocarray(p, len, 1);
88
89
	strlcpy(p, s, len);
90
	return p;
91
}
92
93
char **
94
strsplit(char *s, int ch, int qc)
95
{
96
	char **ivec;
97
	int ic = 0;
98
	int done = 0;
99
100
	ivec = xreallocarray(NULL, ic + 1, sizeof *ivec);
101
102
	while (!done) {
103
		char *v;
104
		/*
105
		 * skip to split char
106
		 */
107
		while (*s && (ch == ' ' ?
108
		    (isascii((unsigned char)*s) && isspace((unsigned char)*s)) :
109
		    *s == ch))
110
				*s++ = '\0';
111
112
		/*
113
		 * End of string?
114
		 */
115
		if (!*s)
116
			break;
117
118
		/*
119
		 * remember start of string
120
		 */
121
		v = s;
122
123
		/*
124
		 * skip to split char
125
		 */
126
		while (*s && !(ch == ' ' ?
127
		    (isascii((unsigned char)*s) && isspace((unsigned char)*s)) :
128
		    *s == ch)) {
129
			if (*s++ == qc) {
130
				/*
131
				 * Skip past string.
132
				 */
133
				s++;
134
				while (*s && *s != qc)
135
					s++;
136
				if (*s == qc)
137
					s++;
138
			}
139
		}
140
141
		if (!*s)
142
			done = 1;
143
		*s++ = '\0';
144
145
		/*
146
		 * save string in new ivec slot
147
		 */
148
		ivec[ic++] = v;
149
		ivec = xreallocarray(ivec, ic + 1, sizeof *ivec);
150
#ifdef DEBUG
151
		Debug(D_STR)
152
			plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
153
#endif /* DEBUG */
154
	}
155
156
#ifdef DEBUG
157
	Debug(D_STR)
158
		plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
159
#endif /* DEBUG */
160
161
	ivec[ic] = 0;
162
163
	return ivec;
164
}
165
166
/*
167
 * Strip off the trailing part of a domain
168
 * to produce a short-form domain relative
169
 * to the local host domain.
170
 * Note that this has no effect if the domain
171
 * names do not have the same number of
172
 * components.  If that restriction proves
173
 * to be a problem then the loop needs recoding
174
 * to skip from right to left and do partial
175
 * matches along the way -- ie more expensive.
176
 */
177
static void
178
domain_strip(char *otherdom, char *localdom)
179
{
180
#ifdef PARTIAL_DOMAINS
181
        char *p1 = otherdom-1;
182
	char *p2 = localdom-1;
183
184
        do {
185
                if (p1 = strchr(p1+1, '.'))
186
                if (p2 = strchr(p2+1, '.'))
187
                if (strcmp(p1+1, p2+1) == 0) {
188
                        *p1 = '\0';
189
                        break;
190
                }
191
        } while (p1 && p2);
192
#else
193
	char *p1, *p2;
194
195
	if ((p1 = strchr(otherdom, '.')) &&
196
			(p2 = strchr(localdom, '.')) &&
197
			(strcmp(p1+1, p2+1) == 0))
198
		*p1 = '\0';
199
#endif /* PARTIAL_DOMAINS */
200
}
201
202
/*
203
 * Normalize a host name
204
 */
205
void
206
host_normalize(char **chp)
207
{
208
	/*
209
	 * Normalize hosts is used to resolve host name aliases
210
	 * and replace them with the standard-form name.
211
	 * Invoked with "-n" command line option.
212
	 */
213
	if (normalize_hosts) {
214
		struct hostent *hp;
215
		clock_valid = 0;
216
		hp = gethostbyname(*chp);
217
		if (hp && hp->h_addrtype == AF_INET) {
218
#ifdef DEBUG
219
			dlog("Hostname %s normalized to %s", *chp, hp->h_name);
220
#endif /* DEBUG */
221
			*chp = strealloc(*chp, hp->h_name);
222
		}
223
	}
224
	domain_strip(*chp, hostd);
225
}
226
227
/*
228
 * Make a dotted quad from a 32bit IP address
229
 * addr is in network byte order.
230
 * sizeof(buf) needs to be at least 16.
231
 */
232
char *
233
inet_dquad(char *buf, size_t buflen, u_int32_t addr)
234
{
235
	addr = ntohl(addr);
236
	snprintf(buf, buflen, "%d.%d.%d.%d",
237
		((addr >> 24) & 0xff),
238
		((addr >> 16) & 0xff),
239
		((addr >> 8) & 0xff),
240
		((addr >> 0) & 0xff));
241
	return buf;
242
}
243
244
/*
245
 * Keys are not allowed to contain " ' ! or ; to avoid
246
 * problems with macro expansions.
247
 */
248
static char invalid_keys[] = "\"'!;@ \t\n";
249
int
250
valid_key(char *key)
251
{
252
	while (*key)
253
		if (strchr(invalid_keys, *key++))
254
			return FALSE;
255
	return TRUE;
256
}
257
258
void
259
going_down(int rc)
260
{
261
	if (foreground) {
262
		if (amd_state != Start) {
263
			if (amd_state != Done)
264
				return;
265
			unregister_amq();
266
		}
267
	}
268
	if (foreground) {
269
		plog(XLOG_INFO, "Finishing with status %d", rc);
270
	} else {
271
#ifdef DEBUG
272
		dlog("background process exiting with status %d", rc);
273
#endif /* DEBUG */
274
	}
275
276
	exit(rc);
277
}
278
279
280
int
281
bind_resv_port(int so, u_short *pp)
282
{
283
	struct sockaddr_in sin;
284
	int rc;
285
286
	bzero(&sin, sizeof(sin));
287
	sin.sin_family = AF_INET;
288
289
	rc = bindresvport(so, &sin);
290
	if (pp && rc == 0)
291
		*pp = ntohs(sin.sin_port);
292
	return rc;
293
}
294
295
void
296
forcibly_timeout_mp(am_node *mp)
297
{
298
	mntfs *mf = mp->am_mnt;
299
	/*
300
	 * Arrange to timeout this node
301
	 */
302
	if (mf && ((mp->am_flags & AMF_ROOT) ||
303
		(mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)))) {
304
		if (!(mf->mf_flags & MFF_UNMOUNTING))
305
			plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
306
	} else {
307
		plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
308
		mp->am_flags &= ~AMF_NOTIMEOUT;
309
		mp->am_ttl = clocktime();
310
		reschedule_timeout_mp();
311
	}
312
}
313
314
void
315
mf_mounted(mntfs *mf)
316
{
317
	int quoted;
318
	int wasmounted = mf->mf_flags & MFF_MOUNTED;
319
320
	if (!wasmounted) {
321
		/*
322
		 * If this is a freshly mounted
323
		 * filesystem then update the
324
		 * mntfs structure...
325
		 */
326
		mf->mf_flags |= MFF_MOUNTED;
327
		mf->mf_error = 0;
328
329
		/*
330
		 * Do mounted callback
331
		 */
332
		if (mf->mf_ops->mounted)
333
			(*mf->mf_ops->mounted)(mf);
334
335
		mf->mf_fo = 0;
336
	}
337
338
	/*
339
	 * Log message
340
	 */
341
	quoted = strchr(mf->mf_info, ' ') != 0;
342
	plog(XLOG_INFO, "%s%s%s %s fstype %s on %s",
343
		quoted ? "\"" : "",
344
		mf->mf_info,
345
		quoted ? "\"" : "",
346
		wasmounted ? "referenced" : "mounted",
347
		mf->mf_ops->fs_type, mf->mf_mount);
348
}
349
350
void
351
am_mounted(am_node *mp)
352
{
353
	mntfs *mf = mp->am_mnt;
354
355
	mf_mounted(mf);
356
357
	/*
358
	 * Patch up path for direct mounts
359
	 */
360
	if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &dfs_ops)
361
		mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
362
363
	/*
364
	 * Check whether this mount should be cached permanently
365
	 */
366
	if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
367
		mp->am_flags |= AMF_NOTIMEOUT;
368
	} else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
369
		mp->am_flags |= AMF_NOTIMEOUT;
370
	} else {
371
		struct mntent mnt;
372
		if (mf->mf_mopts) {
373
			mnt.mnt_opts = mf->mf_mopts;
374
			if (hasmntopt(&mnt, "nounmount"))
375
				mp->am_flags |= AMF_NOTIMEOUT;
376
			if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
377
				mp->am_timeo = am_timeo;
378
		}
379
	}
380
381
	/*
382
	 * If this node is a symlink then
383
	 * compute the length of the returned string.
384
	 */
385
	if (mp->am_fattr.type == NFLNK)
386
		mp->am_fattr.size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
387
388
	/*
389
	 * Record mount time
390
	 */
391
	mp->am_fattr.mtime.seconds = mp->am_stats.s_mtime = clocktime();
392
	new_ttl(mp);
393
	/*
394
	 * Update mtime of parent node
395
	 */
396
	if (mp->am_parent && mp->am_parent->am_mnt)
397
		mp->am_parent->am_fattr.mtime.seconds = mp->am_stats.s_mtime;
398
399
400
	/*
401
	 * Update stats
402
	 */
403
	amd_stats.d_mok++;
404
}
405
406
int
407
mount_node(am_node *mp)
408
{
409
	mntfs *mf = mp->am_mnt;
410
	int error;
411
412
	mf->mf_flags |= MFF_MOUNTING;
413
	error = (*mf->mf_ops->mount_fs)(mp);
414
	mf = mp->am_mnt;
415
	if (error >= 0)
416
		mf->mf_flags &= ~MFF_MOUNTING;
417
	if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
418
		/* ...but see ifs_mount */
419
		am_mounted(mp);
420
	}
421
422
	return error;
423
}
424
425
void
426
am_unmounted(am_node *mp)
427
{
428
	mntfs *mf = mp->am_mnt;
429
430
	if (!foreground) /* firewall - should never happen */
431
		return;
432
433
#ifdef DEBUG
434
	/*dlog("in am_unmounted(), foreground = %d", foreground);*/
435
#endif /* DEBUG */
436
437
	/*
438
	 * Do unmounted callback
439
	 */
440
	if (mf->mf_ops->umounted)
441
		(*mf->mf_ops->umounted)(mp);
442
443
	/*
444
	 * Update mtime of parent node
445
	 */
446
	if (mp->am_parent && mp->am_parent->am_mnt)
447
		mp->am_parent->am_fattr.mtime.seconds = clocktime();
448
449
	free_map(mp);
450
}
451
452
int
453
auto_fmount(am_node *mp)
454
{
455
	mntfs *mf = mp->am_mnt;
456
	return (*mf->mf_ops->fmount_fs)(mf);
457
}
458
459
int
460
auto_fumount(am_node *mp)
461
{
462
	mntfs *mf = mp->am_mnt;
463
	return (*mf->mf_ops->fumount_fs)(mf);
464
}
465
466
/*
467
 * Fork the automounter
468
 *
469
 * TODO: Need a better strategy for handling errors
470
 */
471
static pid_t
472
dofork(void)
473
{
474
	pid_t pid;
475
top:
476
	pid = fork();
477
478
	if (pid < 0) {
479
		sleep(1);
480
		goto top;
481
	}
482
483
	if (pid == 0) {
484
		mypid = getpid();
485
		foreground = 0;
486
	}
487
488
	return pid;
489
}
490
491
pid_t
492
background(void)
493
{
494
	pid_t pid = dofork();
495
	if (pid == 0) {
496
#ifdef DEBUG
497
		dlog("backgrounded");
498
#endif
499
		foreground = 0;
500
	}
501
502
	return pid;
503
}
504
505
/*
506
 * Make all the directories in the path.
507
 */
508
int
509
mkdirs(char *path, int mode)
510
{
511
	/*
512
	 * take a copy in case path is in readonly store
513
	 */
514
	char *p2 = strdup(path);
515
	char *sp = p2;
516
	struct stat stb;
517
	int error_so_far = 0;
518
519
	/*
520
	 * Skip through the string make the directories.
521
	 * Mostly ignore errors - the result is tested at the end.
522
	 *
523
	 * This assumes we are root so that we can do mkdir in a
524
	 * mode 555 directory...
525
	 */
526
	while ((sp = strchr(sp+1, '/'))) {
527
		*sp = '\0';
528
		if (mkdir(p2, mode) < 0) {
529
			error_so_far = errno;
530
		} else {
531
#ifdef DEBUG
532
			dlog("mkdir(%s)", p2);
533
#endif
534
		}
535
		*sp = '/';
536
	}
537
538
	if (mkdir(p2, mode) < 0) {
539
		error_so_far = errno;
540
	} else {
541
#ifdef DEBUG
542
		dlog("mkdir(%s)", p2);
543
#endif
544
	}
545
546
547
	free(p2);
548
549
	return stat(path, &stb) == 0 &&
550
		(stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far;
551
}
552
553
/*
554
 * Remove as many directories in the path as possible.
555
 * Give up if the directory doesn't appear to have
556
 * been created by Amd (not mode dr-x) or an rmdir
557
 * fails for any reason.
558
 */
559
void
560
rmdirs(char *dir)
561
{
562
	char *xdp = strdup(dir);
563
	char *dp;
564
565
	do {
566
		struct stat stb;
567
		/*
568
		 * Try to find out whether this was
569
		 * created by amd.  Do this by checking
570
		 * for owner write permission.
571
		 */
572
		if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) {
573
			if (rmdir(xdp) < 0) {
574
				if (errno != ENOTEMPTY &&
575
				    errno != EBUSY &&
576
				    errno != EEXIST &&
577
				    errno != EINVAL)
578
					plog(XLOG_ERROR, "rmdir(%s): %m", xdp);
579
				break;
580
			} else {
581
#ifdef DEBUG
582
				dlog("rmdir(%s)", xdp);
583
#endif
584
			}
585
		} else {
586
			break;
587
		}
588
		dp = strrchr(xdp, '/');
589
		if (dp)
590
			*dp = '\0';
591
	} while (dp && dp > xdp);
592
	free(xdp);
593
}