xref: /illumos-gate/usr/src/lib/cfgadm_plugins/fp/common/cfga_rep.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 
28 #include <libgen.h>
29 #include "cfga_fp.h"
30 
31 /* The following are used by update_fabric_wwn_list() */
32 #define	COPY_EXT	".cpy."		/* Extn used in naming backup file */
33 #define	TMP_EXT		".tmp."		/* Extn used in naming temp file */
34 static char *HDR =
35 "#\n"
36 "# fabric_WWN_map\n"
37 "#\n"
38 "# The physical ap_id list of configured fabric devices.\n"
39 "# Do NOT edit this file by hand -- refer to the cfgadm_fp(1M)\n"
40 "# man page and use cfgadm(1m) instead.\n"
41 "#\n";
42 
43 /*
44  * This function searches for "srch_str" (of length "slen") in "buf" (of length
45  * "buflen"). If it is not found, "write_offset" has the offset in "buf" where
46  * "srch_str" would have to be added in "buf". If "srch_str" is found in "buf",
47  * "write_offset" has its offset in "buf"
48  *
49  * ARGUMENTS :
50  * buf		- buffer to search in
51  * buflen	- length of buffer
52  * srch_str	- string to search
53  * slen		- length of srch_str
54  * write_offset	- Set in function on exit
55  *		- It is the offset in buf where srch_str is or should be
56  * bytes_left	- Set in function on exit
57  *		- It is the # of bytes left beyond write_offset in buf
58  *
59  * Notes :
60  * -	This function assumes "buf" is sorted in ascending order
61  * -	If 'buflen' is > 0, it assumes it has a header on top and skips it
62  * -	"srch_str" has '\n' at the end, but when update_fabric_wwn_list() calls
63  *	this function, 'slen' does not include the last `\n'
64  *
65  * RETURN VALUES :
66  * Zero - "srch_str" found in "buf"... "write_offset" has offset in "buf"
67  * > 0  - "srch_str" NOT found in "buf" ... "write_offset" has offset in "buf"
68  *		where "srch_str" can fit in.
69  *		"buf" had contents > "srch_str"
70  * < 0  - "srch_str" NOT found in "buf" ... "write_offset" has offset in "buf"
71  *		where "srch_str" can fit in.
72  *		"buf" had contents < "srch_str"
73  */
74 static int
75 search_line(char *buf, int buflen, char *srch_str, int slen,
76 				int *write_offset, int *bytes_left)
77 {
78 	int	retval, sizeof_rep_hdr = strlen(HDR);
79 	char	*sol;		/* Pointer to Start-Of-Line */
80 	char	*cur_pos;	/* current position */
81 
82 	*bytes_left = buflen;
83 	*write_offset = 0;
84 
85 	if (buf == NULL || *buf == '\0' || buflen <= 0)
86 		return (-2);	/* Arbitrary -ve val. srch_str not found */
87 
88 	if (srch_str == NULL || *srch_str == '\0' || slen <= 0)
89 		return (0);	/* This says srch_str was found */
90 
91 	sol = cur_pos = buf;
92 	if (buflen >= sizeof_rep_hdr) {
93 		/* skip header */
94 		sol = cur_pos = buf + sizeof_rep_hdr;
95 		*bytes_left -= sizeof_rep_hdr;
96 	}
97 
98 	while (*bytes_left >= slen) {
99 		if ((retval = strncmp(sol, srch_str, slen)) >= 0) {
100 			/* strncmp will pass if srch_str is a substring */
101 			if ((retval == 0) && (*bytes_left > slen) &&
102 						(*(sol+slen) != '\n'))
103 				retval = 1;	/* Force it to be > 0 */
104 			*write_offset = sol - buf;
105 			return (retval);
106 		}
107 
108 		/* retval < 0 */
109 		if ((cur_pos = strchr(sol, (int)'\n')) == NULL) {
110 			*write_offset = buflen;
111 			return (retval);
112 		}
113 
114 		/* Get the length of this line */
115 		*cur_pos = '\0';	/* kludge to get string length */
116 		*bytes_left -= (strlen(sol) + 1);
117 		*cur_pos = '\n';	/* Put back the original char */
118 
119 		sol = cur_pos = cur_pos + 1;
120 	}
121 
122 	if (*bytes_left > 0) {
123 		/* In this case the bytes left will be less than slen */
124 		if ((retval = strncmp(sol, srch_str, *bytes_left)) >= 0) {
125 			*write_offset = sol - buf;
126 		} else {
127 			*write_offset = buflen;
128 		}
129 		return (retval);
130 	}
131 	*write_offset = sol - buf;
132 	/* Should return a value < 0 to show that search string goes to eof */
133 	return (-1);
134 }
135 
136 /*
137  * This function sets an advisory lock on the file pointed to by the argument
138  * fd, which is a file descriptor. The lock is set using fcntl() which uses
139  * flock structure.
140  */
141 int
142 lock_register(int fd, int cmd, int type, off_t offset, int whence, off_t len)
143 {
144 	struct flock lock;
145 
146 	lock.l_type = type;
147 	lock.l_start = offset;
148 	lock.l_whence = whence;
149 	lock.l_len = len;
150 
151 	return (fcntl(fd, cmd, &lock));
152 }
153 
154 /* Lot of places to cleanup - Less chance of missing out using this macro */
155 #define	CLEANUP_N_RET(ret)	\
156 			if (fd != -1) { \
157 				close(fd); \
158 			} \
159 			if (copy_fd != -1) { \
160 				close(copy_fd); \
161 			} \
162 			if (tmp_fd != -1) { \
163 				close(tmp_fd); \
164 			} \
165 			if (copy_rep != NULL) { \
166 				remove(copy_rep); \
167 				free(copy_rep); \
168 			} \
169 			if (tmp_rep != NULL) { \
170 				remove(tmp_rep); \
171 				free(tmp_rep); \
172 			} \
173 			if (upd_str != NULL) { \
174 				free(upd_str); \
175 			} \
176 			if (repbuf != NULL) { \
177 				munmap(repbuf, filesize); \
178 			} \
179 			if (c_repbuf != NULL) { \
180 				munmap(c_repbuf, filesize); \
181 			} \
182 			if (t_repbuf != NULL) { \
183 				munmap(t_repbuf, size); \
184 			} \
185 			return (ret)
186 
187 /*
188  * INPUTS:
189  * cmd		- ADD_ENTRY or REMOVE_ENTRY
190  * update_str	- string for repository operation
191  *		- Assumed NOT to have a '\n' and that it is null terminated
192  * errstring	- Pointer that will be updated by this function
193  *		- Any error msgs that has to be sent back to caller
194  *
195  * RETURNS :
196  * FPCFGA_OK on success
197  * FPCFGA_LIB_ERR on error
198  *
199  * SYNOPSIS:
200  * This function adds or deletes 'update_str' from FAB_REPOSITORY based on
201  * value of 'cmd'. The repository has a warning line on the top to disallow
202  * manual editing of the file. If the repository is being created fresh or if
203  * it is of zero length or if it has only warning lines in it, the operation
204  * speicified by 'cmd' is performed and returned. If the repository exists
205  * and has some data, it is expected to be of atleast the size of the lenght
206  * of the warning header. This is the only check that is performed on the
207  * validity of the file. No other checks are performed. On a valid
208  * repository, to perform the update, this function basically makes use of
209  * 3 buffers - the original buffer (repbuf), a copy buffer (c_repbuf) and a
210  * temp buffer (t_repbuf).
211  * The contents of the repository are mmap-ed into the repbuf and then
212  * copied into the c_repbuf. All further operations are done using the copy.
213  * t_repbuf is created to be the size of c_repbuf +/- 'slen' (based on
214  * whether it is add or remove operation). After adding/removing the
215  * 'update_str', the c_repbuf is copied to a OLD_FAB_REPOSITORY and t_repbuf
216  * is made FAB_REPOSITORY.
217  *
218  */
219 int
220 update_fabric_wwn_list(int cmd, const char *update_str, char **errstring)
221 {
222 	int	fd, copy_fd, tmp_fd, new_file_flag = 0;
223 	int	len, write_offset, bytes_left;
224 	int	sizeof_rep_hdr = strlen(HDR);
225 	char	*repbuf, *c_repbuf, *t_repbuf;
226 	char	*copy_rep, *tmp_rep, *upd_str;
227 	off_t	filesize, size;
228 	struct stat	stbuf;
229 
230 	/* Do some initializations */
231 	fd = copy_fd = tmp_fd = -1;
232 	repbuf = c_repbuf = t_repbuf = NULL;
233 	copy_rep = tmp_rep = upd_str = NULL;
234 	size = filesize = write_offset = bytes_left = 0;
235 
236 	/*
237 	 * Set the mode to read only.  Root user can still open as RDWR.
238 	 * We ignore errors in general here. But, just notice ENOENTs
239 	 */
240 	if ((chmod(FAB_REPOSITORY, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
241 							(errno == ENOENT)) {
242 		new_file_flag = 1;
243 		mkdirp(FAB_REPOSITORY_DIR,
244 				S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
245 	}
246 
247 	/* Create the repository if its not there */
248 	if ((fd = open(FAB_REPOSITORY, O_RDWR | O_CREAT)) == -1) {
249 		cfga_err(errstring, errno, ERR_UPD_REP, 0);
250 		return (FPCFGA_LIB_ERR);
251 	}
252 
253 	/* Now try to chmod again. This time we dont ignore errors */
254 	if (fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
255 		close(fd);
256 		cfga_err(errstring, errno, ERR_UPD_REP, 0);
257 		return (FPCFGA_LIB_ERR);
258 	}
259 
260 	if (lock_register(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
261 		close(fd);
262 		cfga_err(errstring, 0, ERR_UPD_REP, 0);
263 		return (FPCFGA_LIB_ERR);
264 	}
265 
266 	if (fstat(fd, &stbuf) == -1) {
267 		close(fd);
268 		cfga_err(errstring, errno, ERR_UPD_REP, 0);
269 		return (FPCFGA_LIB_ERR);
270 	}
271 
272 	filesize = size = stbuf.st_size;
273 
274 	/* A very Minimal check on repository */
275 	if (filesize && filesize < sizeof_rep_hdr) {
276 		/*
277 		 * If there is some data, it should be atleast the size of
278 		 * the header
279 		 */
280 		close(fd);
281 		cfga_err(errstring, errno, ERR_UPD_REP, 0);
282 		return (FPCFGA_LIB_ERR);
283 	}
284 
285 	if ((len = strlen(update_str)) == 0) {
286 		/*
287 		 * We are trying to add/remove a NULL string.
288 		 * Just return success
289 		 */
290 		close(fd);
291 		return (FPCFGA_OK);
292 	}
293 
294 	if ((upd_str = calloc(1, len + 2)) == NULL) {
295 		close(fd);
296 		cfga_err(errstring, errno, ERR_UPD_REP, 0);
297 		return (FPCFGA_LIB_ERR);
298 	}
299 
300 	strcpy(upd_str, update_str);
301 	strcat(upd_str, "\n");		/* Append a new line char */
302 	len = strlen(upd_str);
303 
304 	if (filesize > 0) {
305 		if ((copy_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
306 				sizeof (COPY_EXT) + sizeof (pid_t))) == NULL) {
307 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
308 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
309 		}
310 
311 		(void) sprintf(copy_rep, "%s%s%ld", FAB_REPOSITORY, COPY_EXT,
312 								getpid());
313 
314 		if ((copy_fd = open(copy_rep, O_RDWR | O_CREAT | O_TRUNC,
315 						S_IRUSR | S_IWUSR)) < 0) {
316 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
317 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
318 		}
319 
320 		if ((repbuf = (char *)mmap(0, filesize, PROT_READ,
321 					MAP_SHARED, fd, 0)) == MAP_FAILED) {
322 			close(fd);
323 			free(upd_str);
324 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
325 			return (FPCFGA_LIB_ERR);
326 		}
327 
328 		if (lseek(copy_fd, filesize - 1, SEEK_SET) == -1) {
329 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
330 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
331 		}
332 
333 		if (write(copy_fd, "", 1) != 1) {
334 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
335 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
336 		}
337 
338 		if ((c_repbuf = (char *)mmap(0, filesize,
339 				PROT_READ | PROT_WRITE,
340 				MAP_SHARED, copy_fd, 0)) == MAP_FAILED) {
341 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
342 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
343 		}
344 
345 		memcpy(c_repbuf, repbuf, filesize);
346 		/*
347 		 * We cannot close the repository since we hold a lock
348 		 * But we'll free up the mmap-ed area.
349 		 */
350 		munmap(repbuf, filesize);
351 		repbuf = NULL;
352 	}
353 
354 	/*
355 	 * If we just created this file, or it was an empty repository file
356 	 * add a header to the beginning of file.
357 	 * If it had was a repository file with just the header,
358 	 */
359 	if (new_file_flag != 0 || filesize == 0 || filesize == sizeof_rep_hdr) {
360 		if ((filesize != sizeof_rep_hdr) &&
361 			(write(fd, HDR, sizeof_rep_hdr) != sizeof_rep_hdr)) {
362 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
363 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
364 		}
365 
366 		/*
367 		 * We know its a new file, empty file or a file with only a
368 		 * header so lets get the update operation done with
369 		 */
370 		switch (cmd) {
371 		case ADD_ENTRY:
372 			/* If there is a header, we have to skip it */
373 			if (lseek(fd, 0, SEEK_END) == -1) {
374 				cfga_err(errstring, errno, ERR_UPD_REP, 0);
375 				CLEANUP_N_RET(FPCFGA_LIB_ERR);
376 			}
377 
378 			if (write(fd, upd_str, len) != len) {
379 				cfga_err(errstring, errno, ERR_UPD_REP, 0);
380 				CLEANUP_N_RET(FPCFGA_LIB_ERR);
381 			}
382 
383 			if (filesize > 0) {
384 				/* Now create the '.old' file */
385 				if (msync(c_repbuf, filesize, MS_SYNC) == -1) {
386 					cfga_err(errstring, errno,
387 								ERR_UPD_REP, 0);
388 					CLEANUP_N_RET(FPCFGA_LIB_ERR);
389 				}
390 
391 				if (fchmod(copy_fd,
392 					S_IRUSR | S_IRGRP | S_IROTH) < 0) {
393 					cfga_err(errstring, errno,
394 								ERR_UPD_REP, 0);
395 					CLEANUP_N_RET(FPCFGA_LIB_ERR);
396 				}
397 				rename(copy_rep, OLD_FAB_REPOSITORY);
398 			}
399 
400 			CLEANUP_N_RET(FPCFGA_OK);
401 
402 		case REMOVE_ENTRY:
403 			/*
404 			 * So, the side effect of a remove on an empty or
405 			 * non-existing repository is that the repository got
406 			 * created
407 			 */
408 			CLEANUP_N_RET(FPCFGA_OK);
409 
410 		default:
411 			cfga_err(errstring, 0, ERR_UPD_REP, 0);
412 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
413 		}
414 	}
415 
416 	/* Now, size and filesize are > sizeof_rep_hdr */
417 
418 	switch (cmd) {
419 	case ADD_ENTRY:
420 		size += len;
421 		/*
422 		 * We'll search the full repository, header included, since
423 		 * we dont expect upd_str to match anything in the header.
424 		 */
425 		if (search_line(c_repbuf, filesize, upd_str,
426 				len - 1, &write_offset, &bytes_left) == 0) {
427 			/* line already exists in repository or len == 0 */
428 			CLEANUP_N_RET(FPCFGA_OK); /* SUCCESS */
429 		}
430 
431 		/* construct temp file name using pid. */
432 		if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
433 				sizeof (TMP_EXT) + sizeof (pid_t))) == NULL) {
434 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
435 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
436 		}
437 
438 		(void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
439 							TMP_EXT, getpid());
440 
441 		/* Open tmp repository file in absolute mode */
442 		if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
443 						S_IRUSR | S_IWUSR)) < 0) {
444 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
445 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
446 		}
447 
448 		if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
449 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
450 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
451 		}
452 
453 		if (write(tmp_fd, "", 1) != 1) {
454 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
455 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
456 		}
457 
458 		if ((t_repbuf = (char *)mmap(0, size, PROT_READ|PROT_WRITE,
459 					MAP_SHARED, tmp_fd, 0)) == MAP_FAILED) {
460 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
461 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
462 		}
463 
464 		memcpy(t_repbuf, c_repbuf, write_offset);
465 		strncpy(t_repbuf + write_offset, upd_str, len);
466 		if (write_offset != filesize) {
467 			memcpy(t_repbuf + write_offset + len,
468 					c_repbuf + write_offset, bytes_left);
469 		}
470 
471 		/*
472 		 * we are using the copy of FAB_REPOSITORY and will
473 		 * do msync first since it will be renamed to '.old' file.
474 		 */
475 		if (msync(c_repbuf, filesize, MS_SYNC) == -1) {
476 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
477 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
478 		}
479 
480 		if (fchmod(copy_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
481 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
482 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
483 		}
484 
485 		if (msync(t_repbuf, size, MS_SYNC) == -1) {
486 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
487 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
488 		}
489 
490 		if (fchmod(tmp_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
491 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
492 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
493 		}
494 
495 		close(copy_fd); copy_fd = -1;
496 		close(tmp_fd); tmp_fd = -1;
497 
498 		/* here we do rename and rename before close fd */
499 		rename(copy_rep, OLD_FAB_REPOSITORY);
500 		rename(tmp_rep, FAB_REPOSITORY);
501 
502 		if (lock_register(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) {
503 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
504 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
505 		}
506 
507 		CLEANUP_N_RET(FPCFGA_OK);
508 
509 	case REMOVE_ENTRY:
510 		if (size >= sizeof_rep_hdr + len - 1) {
511 			size -= len;
512 			/*
513 			 * No need to init the 'else' part (size < len) because
514 			 * in that case, there will be nothing to delete from
515 			 * the file and so 'size' will not be used in the code
516 			 * below since search_line() will not find upd_str.
517 			 */
518 		}
519 
520 		if (search_line(c_repbuf, filesize, upd_str, len - 1,
521 					&write_offset, &bytes_left) != 0) {
522 			/* this line does not exists - nothing to remove */
523 			CLEANUP_N_RET(FPCFGA_OK); /* SUCCESS */
524 		}
525 
526 		/* construct temp file name using pid. */
527 		if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
528 				sizeof (TMP_EXT) + sizeof (pid_t))) == NULL) {
529 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
530 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
531 		}
532 
533 		(void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
534 							TMP_EXT, getpid());
535 
536 		/* Open tmp repository file in absolute mode */
537 		if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
538 						S_IRUSR | S_IWUSR)) < 0) {
539 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
540 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
541 		}
542 
543 		if (size > 0) {
544 			if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
545 				cfga_err(errstring, errno, ERR_UPD_REP, 0);
546 				CLEANUP_N_RET(FPCFGA_LIB_ERR);
547 			}
548 
549 			if (write(tmp_fd, "", 1) != 1) {
550 				cfga_err(errstring, errno, ERR_UPD_REP, 0);
551 				CLEANUP_N_RET(FPCFGA_LIB_ERR);
552 			}
553 
554 			if ((t_repbuf = (char *)mmap(0, size,
555 					PROT_READ|PROT_WRITE,
556 					MAP_SHARED, tmp_fd, 0)) == MAP_FAILED) {
557 				cfga_err(errstring, errno, ERR_UPD_REP, 0);
558 				CLEANUP_N_RET(FPCFGA_LIB_ERR);
559 			}
560 
561 			memcpy(t_repbuf, c_repbuf, write_offset);
562 			if ((bytes_left - len) > 0) {
563 				memcpy(t_repbuf + write_offset,
564 					c_repbuf + write_offset + len,
565 							bytes_left - len);
566 			}
567 
568 			if (msync(t_repbuf, size, MS_SYNC) == -1) {
569 				cfga_err(errstring, errno, ERR_UPD_REP, 0);
570 				CLEANUP_N_RET(FPCFGA_LIB_ERR);
571 			}
572 		}
573 
574 		if (fchmod(tmp_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
575 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
576 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
577 		}
578 
579 		/*
580 		 * we are using the copy of FAB_REPOSITORY and will
581 		 * do msync first since it will be renamed to bak file.
582 		 */
583 		if (msync(c_repbuf, filesize, MS_SYNC) == -1) {
584 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
585 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
586 		}
587 
588 		if (fchmod(copy_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
589 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
590 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
591 		}
592 
593 		/* Close and invalidate the fd's */
594 		close(copy_fd); copy_fd = -1;
595 		close(tmp_fd); tmp_fd = -1;
596 
597 		/* here we do rename and rename before close fd */
598 		rename(copy_rep, OLD_FAB_REPOSITORY);
599 		rename(tmp_rep, FAB_REPOSITORY);
600 
601 		if (lock_register(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) {
602 			cfga_err(errstring, errno, ERR_UPD_REP, 0);
603 			CLEANUP_N_RET(FPCFGA_LIB_ERR);
604 		}
605 
606 		CLEANUP_N_RET(FPCFGA_OK);
607 
608 	default:
609 		/* Unexpected - just getout */
610 		break;
611 	}
612 
613 	CLEANUP_N_RET(FPCFGA_OK);			/* SUCCESS */
614 }
615