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