xref: /illumos-gate/usr/src/cmd/sgs/crle/common/config.c (revision 1a220b56b93ff1dc80855691548503117af4cc10)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include	<sys/mman.h>
28 #include	<sys/types.h>
29 #include	<fcntl.h>
30 #include	<unistd.h>
31 #include	<errno.h>
32 #include	<stdio.h>
33 #include	<string.h>
34 #include	"rtc.h"
35 #include	"_crle.h"
36 #include	"msg.h"
37 
38 
39 #define	MAXNBKTS 10007
40 
41 static const int hashsize[] = {
42 	3,	7,	13,	31,	53,	67,	83,	97,
43 	101,	151,	211,	251,	307,	353,	401,	457,	503,
44 	557,	601,	653,	701,	751,	809,	859,	907,	953,
45 	1009,	1103,	1201,	1301,	1409,	1511,	1601,	1709,	1801,
46 	1901,	2003,	2111,	2203,	2309,	2411,	2503,	2609,	2707,
47 	2801,	2903,	3001,	3109,	3203,	3301,	3407,	3511,	3607,
48 	3701,	3803,	3907,	4001,	5003,   6101,   7001,   8101,   9001,
49 	MAXNBKTS
50 };
51 
52 /*
53  * Generate a configuration file from the internal configuration information.
54  * (very link-editor like).
55  */
56 int
57 genconfig(Crle_desc * crle)
58 {
59 	int		ndx, bkt;
60 	size_t		size, hashoff = 0, stroff = 0, objoff = 0;
61 	size_t		diroff = 0, fileoff = 0, envoff = 0;
62 	size_t		fltroff = 0, flteoff = 0;
63 	Addr		addr;
64 	Rtc_id		*id;
65 	Rtc_head	*head;
66 	Word		*hashtbl, * hashbkt, * hashchn, hashbkts = 0;
67 	char		*strtbl, *_strtbl;
68 	Rtc_obj		*objtbl;
69 	Rtc_dir		*dirtbl;
70 	Rtc_file	*filetbl;
71 	Rtc_env		*envtbl;
72 	Rtc_fltr	*fltrtbl;
73 	Rtc_flte	*fltetbl, * _fltetbl;
74 	Hash_tbl	*stbl = crle->c_strtbl;
75 	Hash_ent	*ent;
76 
77 	/*
78 	 * Establish the size of the configuration file.
79 	 */
80 	size = S_ROUND(sizeof (Rtc_head), sizeof (Word));
81 
82 	if (crle->c_hashstrnum) {
83 		hashoff = size;
84 
85 		/*
86 		 * Increment the hash string number to account for an initial
87 		 * null entry.  Indexes start at 1 to simplify hash lookup.
88 		 */
89 		crle->c_hashstrnum++;
90 
91 		/*
92 		 * Determine the hash table size.  Establish the number of
93 		 * buckets from the number of strings, the number of chains is
94 		 * equivalent to the number of objects, and two entries for the
95 		 * nbucket and nchain entries.
96 		 */
97 		for (ndx = 0; ndx < (sizeof (hashsize) / sizeof (int)); ndx++) {
98 			if (crle->c_hashstrnum > hashsize[ndx])
99 				continue;
100 			hashbkts = hashsize[ndx];
101 			break;
102 		}
103 		if (hashbkts == 0)
104 			hashbkts = MAXNBKTS;
105 		size += ((2 + hashbkts + crle->c_hashstrnum) * sizeof (Word));
106 		size = S_ROUND(size, sizeof (Lword));
107 		objoff = size;
108 
109 		/*
110 		 * Add the object table size (account for an 8-byte alignment
111 		 * requirement for each object).
112 		 */
113 		size += (crle->c_hashstrnum *
114 		    S_ROUND(sizeof (Rtc_obj), sizeof (Lword)));
115 
116 		/*
117 		 * Add the file descriptor arrays.
118 		 */
119 		fileoff = size;
120 		size += S_ROUND((crle->c_filenum * sizeof (Rtc_file)),
121 		    sizeof (Word));
122 
123 		/*
124 		 * Add the directory descriptor array.
125 		 */
126 		diroff = size;
127 		size += S_ROUND((crle->c_dirnum * sizeof (Rtc_dir)),
128 		    sizeof (Word));
129 	}
130 
131 	/*
132 	 * Add any environment string array (insure zero last entry).
133 	 */
134 	if (crle->c_envnum) {
135 		envoff = size;
136 		size += S_ROUND(((crle->c_envnum + 1) * sizeof (Rtc_env)),
137 		    sizeof (Word));
138 	}
139 
140 	/*
141 	 * Add any filter/filtee association arrays (insure zero last entry for
142 	 * the filter array, the filtee arrays are already accounted for).
143 	 */
144 	if (crle->c_fltrnum) {
145 		fltroff = size;
146 		size += S_ROUND(((crle->c_fltrnum + 1) * sizeof (Rtc_fltr)),
147 		    sizeof (Word));
148 		flteoff = size;
149 		size += S_ROUND((crle->c_fltenum * sizeof (Rtc_flte)),
150 		    sizeof (Word));
151 	}
152 
153 	/*
154 	 * Add the string table size (this may contain library and/or secure
155 	 * path strings, in addition to any directory/file strings).
156 	 */
157 	if (crle->c_strsize) {
158 		stroff = size;
159 		size += S_ROUND(crle->c_strsize, sizeof (Word));
160 	}
161 
162 	/* Account for addition of Rtc_id block at the start */
163 	if (crle->c_flags & CRLE_ADDID)
164 		size += sizeof (Rtc_id);
165 
166 	/*
167 	 * Truncate our temporary file now that we know its size and map it.
168 	 */
169 	if (ftruncate(crle->c_tempfd, size) == -1) {
170 		int err = errno;
171 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
172 		    crle->c_name, crle->c_tempname, strerror(err));
173 		(void) close(crle->c_tempfd);
174 		return (1);
175 	}
176 	if ((addr = (Addr)mmap(0, size, (PROT_READ | PROT_WRITE), MAP_SHARED,
177 	    crle->c_tempfd, 0)) == (Addr)-1) {
178 		int err = errno;
179 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP),
180 		    crle->c_name, crle->c_tempname, strerror(err));
181 		(void) close(crle->c_tempfd);
182 		return (1);
183 	}
184 
185 	/*
186 	 * Save the mapped files info for possible dldump(3dl) updates.
187 	 */
188 	crle->c_tempaddr = addr;
189 	crle->c_tempsize = size;
190 
191 	/*
192 	 * Rtc_id goes at the top, followed by the Rtc_head. We base
193 	 * all offset calculations relative to Rtc_head, not from
194 	 * the top of the file. This eases backwards compatability to
195 	 * older versons that lacked the Rtc_id at the top.
196 	 */
197 	if (crle->c_flags & CRLE_ADDID) {
198 		/* The contents of the Rtc_id are all known at compile time */
199 		static const Rtc_id id_template = {
200 			RTC_ID_MAG0, RTC_ID_MAG1, RTC_ID_MAG2, RTC_ID_MAG3,
201 			M_CLASS, M_DATA, M_MACH,
202 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
203 
204 		id = (Rtc_id *) addr;
205 		*id = id_template;	/* Fill in the Rtc_id data */
206 		addr += sizeof (Rtc_id);
207 	} else {
208 		id = NULL;
209 	}
210 	crle->c_tempheadaddr = addr;
211 	head = (Rtc_head *)addr;
212 
213 	/*
214 	 * Establish the real address of each of the structures within the file.
215 	 */
216 	head->ch_hash = hashoff;
217 	/* LINTED */
218 	hashtbl = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr);
219 
220 	head->ch_obj = objoff;
221 	/* LINTED */
222 	objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr);
223 	objtbl = (Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword));
224 
225 	head->ch_file = fileoff;
226 	/* LINTED */
227 	filetbl = (Rtc_file *)(CAST_PTRINT(char *, head->ch_file) + addr);
228 
229 	head->ch_dir = diroff;
230 	/* LINTED */
231 	dirtbl = (Rtc_dir *)(CAST_PTRINT(char *, head->ch_dir) + addr);
232 
233 	head->ch_env = envoff;
234 	/* LINTED */
235 	envtbl = (Rtc_env *)(CAST_PTRINT(char *, head->ch_env) + addr);
236 
237 	head->ch_fltr = fltroff;
238 	/* LINTED */
239 	fltrtbl = (Rtc_fltr *)(CAST_PTRINT(char *, head->ch_fltr) + addr);
240 	head->ch_flte = flteoff;
241 	/* LINTED */
242 	fltetbl = _fltetbl = (Rtc_flte *)
243 		(CAST_PTRINT(char *, head->ch_flte) + addr);
244 
245 	head->ch_str = stroff;
246 	strtbl = _strtbl = (char *)(CAST_PTRINT(char *, head->ch_str) + addr);
247 
248 	/*
249 	 * Fill in additional basic header information.
250 	 */
251 	head->ch_version = RTC_VER_CURRENT;
252 
253 	if (crle->c_flags & CRLE_ALTER)
254 		head->ch_cnflags |= RTC_HDR_ALTER;
255 	if (crle->c_flags & CRLE_DUMP) {
256 		head->ch_cnflags |= RTC_HDR_IGNORE;
257 		head->ch_dlflags = crle->c_dlflags;
258 	}
259 #ifdef _ELF64
260 	head->ch_cnflags |= RTC_HDR_64;
261 #endif
262 
263 #ifndef	SGS_PRE_UNIFIED_PROCESS
264 	head->ch_cnflags |= RTC_HDR_UPM;
265 #endif
266 	/*
267 	 * If we have a hash table then there are directory and file entries
268 	 * to process.
269 	 */
270 	if (crle->c_hashstrnum) {
271 		hashtbl[0] = hashbkts;
272 		hashtbl[1] = crle->c_hashstrnum;
273 		hashbkt = &hashtbl[2];
274 		hashchn = &hashtbl[2 + hashbkts];
275 
276 		/*
277 		 * Insure all hash chain and directory/filename table entries
278 		 * are cleared.
279 		 */
280 		(void) memset(hashchn, 0, (crle->c_hashstrnum * sizeof (Word)));
281 		(void) memset(dirtbl, 0, (strtbl - (char *)dirtbl));
282 
283 		/*
284 		 * Loop through the current string table list inspecting only
285 		 * directories.
286 		 */
287 		for (ndx = 1, bkt = 0; bkt < stbl->t_size; bkt++) {
288 			for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
289 				Word		hashval;
290 				Hash_obj	*obj = ent->e_obj;
291 				char		*dir = (char *)ent->e_key;
292 				Rtc_dir		*_dirtbl;
293 
294 				/*
295 				 * Skip any empty and non-directory entries.
296 				 */
297 				if ((obj == 0) ||
298 				    ((obj->o_flags & RTC_OBJ_DIRENT) == 0))
299 					continue;
300 
301 				/*
302 				 * Assign basic object attributes.
303 				 */
304 				objtbl->co_hash = ent->e_hash;
305 				objtbl->co_id = ent->e_id;
306 				objtbl->co_flags = obj->o_flags | ent->e_flags;
307 				objtbl->co_info = obj->o_info;
308 
309 				ent->e_cobj = objtbl;
310 
311 				/*
312 				 * Assign the directory name (from its key),
313 				 * and copy its name to the string table.
314 				 */
315 				objtbl->co_name = (Addr)(_strtbl - strtbl);
316 				(void) strcpy(_strtbl, dir);
317 				_strtbl += strlen(dir) + 1;
318 
319 				/*
320 				 * Establish an entry in the directory table and
321 				 * reserve space for its associated filename
322 				 * entries (note, we add a trailing null file
323 				 * entry to simplify later inspection of the
324 				 * final configuration file.
325 				 */
326 				_dirtbl = &dirtbl[ent->e_id - 1];
327 				_dirtbl->cd_file =
328 				    CAST_PTRINT(Word, ((char *)filetbl- addr));
329 				_dirtbl->cd_obj =
330 				    CAST_PTRINT(Word, ((char *)objtbl - addr));
331 
332 				/* LINTED */
333 				filetbl = (Rtc_file *)((char *)filetbl +
334 				    ((ent->e_cnt + 1) * sizeof (Rtc_file)));
335 
336 				/*
337 				 * Add this object to the hash table.
338 				 */
339 				hashval = ent->e_hash % hashbkts;
340 				hashchn[ndx] = hashbkt[hashval];
341 				hashbkt[hashval] = ndx++;
342 
343 				/*
344 				 * Increment Rt_obj pointer (make sure pointer
345 				 * falls on an 8-byte boundary).
346 				 */
347 				objtbl = (Rtc_obj *)
348 					S_ROUND((uintptr_t)(objtbl + 1),
349 						sizeof (Lword));
350 			}
351 		}
352 
353 		/*
354 		 * Now collect all pathnames.  These are typically full
355 		 * pathnames, but may also be relative.  Simple filenames are
356 		 * recorded as offsets into these pathnames, thus we need to
357 		 * establish the new pathname first.
358 		 */
359 		for (bkt = 0; bkt < stbl->t_size; bkt++) {
360 			for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
361 				Word		hashval;
362 				Hash_obj	*obj = ent->e_obj;
363 				char		*file = (char *)ent->e_key;
364 				char		*_str;
365 				Rtc_dir		*_dirtbl;
366 				Rtc_file	*_filetbl;
367 				int		_id;
368 
369 				/*
370 				 * Skip empty and directory entries, and any
371 				 * simple filename entries.
372 				 */
373 				if ((obj == 0) ||
374 				    (obj->o_flags & RTC_OBJ_DIRENT) ||
375 				    (ent->e_off))
376 					continue;
377 
378 				/*
379 				 * Assign basic object attributes.
380 				 */
381 				objtbl->co_hash = ent->e_hash;
382 				objtbl->co_id = ent->e_id;
383 				objtbl->co_flags = obj->o_flags | ent->e_flags;
384 				objtbl->co_info = obj->o_info;
385 
386 				ent->e_cobj = objtbl;
387 
388 				/*
389 				 * Assign the file name (from its key),
390 				 * and copy its name to the string table.
391 				 */
392 				objtbl->co_name = (Addr)(_strtbl - strtbl);
393 				(void) strcpy(_strtbl, file);
394 				_strtbl += strlen(file) + 1;
395 
396 				/*
397 				 * Add this file to its associated directory.
398 				 */
399 				_dirtbl = &dirtbl[ent->e_id - 1];
400 				/* LINTED */
401 				_filetbl = (Rtc_file *)
402 				    (CAST_PTRINT(char *, _dirtbl->cd_file)
403 					+ addr);
404 
405 				_id = --ent->e_dir->e_cnt;
406 				_filetbl[_id].cf_obj =
407 				    CAST_PTRINT(Word, ((char *)objtbl - addr));
408 
409 				/*
410 				 * If object has an alternative, record it in
411 				 * the string table and assign the alternate
412 				 * pointer.  The new alternative offset is
413 				 * retained for reuse in other filename entries.
414 				 */
415 				if ((objtbl->co_flags & RTC_OBJ_ALTER) &&
416 				    (obj->o_calter == 0)) {
417 					_str = obj->o_alter;
418 					objtbl->co_alter = obj->o_calter =
419 					    (Addr)(_strtbl - strtbl);
420 					(void) strcpy(_strtbl, _str);
421 					_strtbl += strlen(_str) + 1;
422 				} else
423 					objtbl->co_alter = obj->o_calter;
424 
425 				/*
426 				 * If object identifies the specific application
427 				 * for which this cache is relevant, record it
428 				 * in the header.
429 				 */
430 				if ((objtbl->co_flags &
431 				    (RTC_OBJ_APP | RTC_OBJ_REALPTH)) ==
432 				    (RTC_OBJ_APP | RTC_OBJ_REALPTH))
433 					head->ch_app = _filetbl[_id].cf_obj;
434 
435 				/*
436 				 * Add this object to the hash table.
437 				 */
438 				hashval = ent->e_hash % hashbkts;
439 				hashchn[ndx] = hashbkt[hashval];
440 				hashbkt[hashval] = ndx++;
441 
442 				/*
443 				 * Increment Rt_obj pointer (make sure pointer
444 				 * falls on an 8-byte boundary).
445 				 */
446 				objtbl = (Rtc_obj *)
447 				    S_ROUND((uintptr_t)(objtbl + 1),
448 				    sizeof (Lword));
449 			}
450 		}
451 
452 		/*
453 		 * Finally pick off any simple filenames.
454 		 */
455 		for (bkt = 0; bkt < stbl->t_size; bkt++) {
456 			for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
457 				Word		hashval;
458 				Hash_obj *	obj = ent->e_obj;
459 				Rtc_dir *	_dirtbl;
460 				Rtc_file *	_filetbl;
461 				int		_id;
462 
463 				/*
464 				 * Skip everything except simple filenames.
465 				 */
466 				if (ent->e_off == 0)
467 					continue;
468 
469 				/*
470 				 * Assign basic object attributes.
471 				 */
472 				objtbl->co_hash = ent->e_hash;
473 				objtbl->co_id = ent->e_id;
474 				objtbl->co_flags = obj->o_flags | ent->e_flags;
475 				objtbl->co_info = obj->o_info;
476 				objtbl->co_alter = obj->o_calter;
477 
478 				ent->e_cobj = objtbl;
479 
480 				/*
481 				 * Assign the file name from its full name.
482 				 */
483 				objtbl->co_name = (Addr)(CAST_PTRINT(char *,
484 				    ent->e_path->e_cobj->co_name) + ent->e_off);
485 
486 				/*
487 				 * Add this file to its associated directory.
488 				 */
489 				_dirtbl = &dirtbl[ent->e_id - 1];
490 				/* LINTED */
491 				_filetbl = (Rtc_file *)
492 				    (CAST_PTRINT(char *, _dirtbl->cd_file) +
493 				    addr);
494 
495 				_id = --ent->e_dir->e_cnt;
496 				_filetbl[_id].cf_obj =
497 				    CAST_PTRINT(Word, ((char *)objtbl - addr));
498 
499 				/*
500 				 * Add this object to the hash table.
501 				 */
502 				hashval = ent->e_hash % hashbkts;
503 				hashchn[ndx] = hashbkt[hashval];
504 				hashbkt[hashval] = ndx++;
505 
506 				/*
507 				 * Increment Rt_obj pointer (make sure pointer
508 				 * falls on an 8-byte boundary).
509 				 */
510 				objtbl = (Rtc_obj *)
511 				    S_ROUND((uintptr_t)(objtbl + 1),
512 				    sizeof (Lword));
513 			}
514 		}
515 	}
516 
517 	/*
518 	 * Add any library, or secure path definitions.
519 	 */
520 	if (crle->c_edlibpath) {
521 		head->ch_edlibpath = head->ch_str + (_strtbl - strtbl);
522 
523 		(void) strcpy(_strtbl, crle->c_edlibpath);
524 		_strtbl += strlen((char *)crle->c_edlibpath) + 1;
525 	} else
526 		head->ch_edlibpath = 0;
527 
528 	if (crle->c_adlibpath) {
529 		head->ch_adlibpath = head->ch_str + (_strtbl - strtbl);
530 
531 		(void) strcpy(_strtbl, crle->c_adlibpath);
532 		_strtbl += strlen((char *)crle->c_adlibpath) + 1;
533 	} else
534 		head->ch_adlibpath = 0;
535 
536 	if (crle->c_eslibpath) {
537 		head->ch_eslibpath = head->ch_str + (_strtbl - strtbl);
538 
539 		(void) strcpy(_strtbl, crle->c_eslibpath);
540 		_strtbl += strlen((char *)crle->c_eslibpath) + 1;
541 	} else
542 		head->ch_eslibpath = 0;
543 
544 	if (crle->c_aslibpath) {
545 		head->ch_aslibpath = head->ch_str + (_strtbl - strtbl);
546 
547 		(void) strcpy(_strtbl, crle->c_aslibpath);
548 		_strtbl += strlen((char *)crle->c_aslibpath) + 1;
549 	} else
550 		head->ch_aslibpath = 0;
551 
552 	/*
553 	 * Add any environment variable entries.
554 	 */
555 	if (crle->c_envnum) {
556 		Env_desc *	env;
557 		Listnode *	lnp;
558 
559 		for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) {
560 			envtbl->env_str = head->ch_str + (_strtbl - strtbl);
561 			envtbl->env_flags = env->e_flags;
562 
563 			(void) strcpy(_strtbl, env->e_str);
564 			_strtbl += env->e_totsz;
565 
566 			envtbl++;
567 		}
568 		envtbl->env_str = 0;
569 		envtbl->env_flags = 0;
570 	}
571 
572 	/*
573 	 * Add any filter/filtee association entries.
574 	 */
575 	if (crle->c_fltrnum) {
576 		Flt_desc *	flt;
577 		Listnode *	lnp1;
578 
579 		for (LIST_TRAVERSE(&(crle->c_flt), lnp1, flt)) {
580 			Hash_ent *	flte;
581 			Listnode *	lnp2;
582 
583 			/*
584 			 * Establish the filter name, and filtee string, as
585 			 * offsets into the configuration files string table.
586 			 * Establish the filtee as the offset into the filtee
587 			 * table.
588 			 */
589 			fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name;
590 			fltrtbl->fr_string = _strtbl - strtbl;
591 			(void) strcpy(_strtbl, flt->f_str);
592 			_strtbl += flt->f_strsz;
593 			fltrtbl->fr_filtee = (Word)
594 			    ((uintptr_t)_fltetbl - (uintptr_t)fltetbl);
595 
596 			for (LIST_TRAVERSE(&(flt->f_filtee), lnp2, flte)) {
597 				/*
598 				 * Establish the filtee name as the offset into
599 				 * the configuration files string table.
600 				 */
601 				_fltetbl->fe_filtee = flte->e_cobj->co_name;
602 				_fltetbl++;
603 			}
604 			_fltetbl->fe_filtee = 0;
605 			_fltetbl++, fltrtbl++;
606 		}
607 		fltrtbl->fr_filter = 0;
608 		fltrtbl->fr_filtee = 0;
609 	}
610 
611 	/*
612 	 * Flush everything out.
613 	 */
614 	(void) close(crle->c_tempfd);
615 	if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) {
616 		int err = errno;
617 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
618 		    crle->c_name, crle->c_tempname, strerror(err));
619 		return (1);
620 	}
621 
622 	return (0);
623 }
624 
625 /*
626  * Update a configuration file.  If dldump()'ed images have been created then
627  * the memory reservation of those images is added to the configuration file.
628  * The temporary file is then moved into its final resting place.
629  */
630 int
631 updateconfig(Crle_desc * crle)
632 {
633 	Rtc_head *head = (Rtc_head *)crle->c_tempheadaddr;
634 
635 	if (crle->c_flags & CRLE_DUMP) {
636 		head->ch_cnflags &= ~RTC_HDR_IGNORE;
637 
638 		if (msync((void *)crle->c_tempaddr, crle->c_tempsize,
639 		    MS_ASYNC) == -1) {
640 			int err = errno;
641 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
642 			    crle->c_name, crle->c_tempname, strerror(err));
643 			return (1);
644 		}
645 	}
646 
647 	/*
648 	 * If an original configuration file exists, remove it.
649 	 */
650 	if (crle->c_flags & CRLE_EXISTS)
651 		(void) unlink(crle->c_confil);
652 
653 	/*
654 	 * Move the config file to its final resting place.  If the two files
655 	 * exist on the same filesystem a rename is sufficient.
656 	 */
657 	if (crle->c_flags & CRLE_DIFFDEV) {
658 		int	fd;
659 
660 		if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC),
661 		    0666)) == -1) {
662 			int err = errno;
663 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
664 			    crle->c_name, crle->c_confil, strerror(err));
665 			return (1);
666 		}
667 		if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) !=
668 		    crle->c_tempsize) {
669 			int err = errno;
670 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
671 			    crle->c_name, crle->c_confil, strerror(err));
672 			return (1);
673 		}
674 		(void) close(fd);
675 		(void) unlink(crle->c_tempname);
676 	} else
677 		(void) rename(crle->c_tempname, crle->c_confil);
678 
679 	return (0);
680 }
681