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 == NULL || buflen <= 0)
  86                 return (-2);    /* Arbitrary -ve val. srch_str not found */
  87 
  88         if (srch_str == NULL || *srch_str == NULL || 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 }