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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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 */
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"
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"
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
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'
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"
75 search_line(char *buf
, int buflen
, char *srch_str
, int slen
,
76 int *write_offset
, int *bytes_left
)
78 int retval
, sizeof_rep_hdr
= strlen(HDR
);
79 char *sol
; /* Pointer to Start-Of-Line */
80 char *cur_pos
; /* current position */
85 if (buf
== NULL
|| *buf
== '\0'|| buflen
<= 0)
86 return (-2); /* Arbitrary -ve val. srch_str not found */
88 if (srch_str
== NULL
|| *srch_str
== '\0'|| slen
<= 0)
89 return (0); /* This says srch_str was found */
92 if (buflen
>= sizeof_rep_hdr
) {
94 sol
= cur_pos
= buf
+ sizeof_rep_hdr
;
95 *bytes_left
-= sizeof_rep_hdr
;
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
;
109 if ((cur_pos
= strchr(sol
, (int)'\n')) == NULL
) {
110 *write_offset
= buflen
;
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 */
119 sol
= cur_pos
= cur_pos
+ 1;
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
;
127 *write_offset
= buflen
;
131 *write_offset
= sol
- buf
;
132 /* Should return a value < 0 to show that search string goes to eof */
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
142 lock_register(int fd
, int cmd
, int type
, off_t offset
, int whence
, off_t len
)
147 lock
.l_start
= offset
;
148 lock
.l_whence
= whence
;
151 return (fcntl(fd
, cmd
, &lock
));
154 /* Lot of places to cleanup - Less chance of missing out using this macro */
155 #define CLEANUP_N_RET(ret) \
159 if (copy_fd != -1) { \
162 if (tmp_fd != -1) { \
165 if (copy_rep != NULL) { \
169 if (tmp_rep != NULL) { \
173 if (upd_str != NULL) { \
176 if (repbuf != NULL) { \
177 munmap(repbuf, filesize); \
179 if (c_repbuf != NULL) { \
180 munmap(c_repbuf, filesize); \
182 if (t_repbuf != NULL) { \
183 munmap(t_repbuf, size); \
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
196 * FPCFGA_OK on success
197 * FPCFGA_LIB_ERR on error
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.
220 update_fabric_wwn_list(int cmd
, const char *update_str
, char **errstring
)
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
;
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;
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
240 if ((chmod(FAB_REPOSITORY
, S_IRUSR
|S_IRGRP
|S_IROTH
) == -1) &&
243 mkdirp(FAB_REPOSITORY_DIR
,
244 S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
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
);
253 /* Now try to chmod again. This time we dont ignore errors */
254 if (fchmod(fd
, S_IRUSR
| S_IRGRP
| S_IROTH
) < 0) {
256 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
257 return (FPCFGA_LIB_ERR
);
260 if (lock_register(fd
, F_SETLKW
, F_WRLCK
, 0, SEEK_SET
, 0) < 0) {
262 cfga_err(errstring
, 0, ERR_UPD_REP
, 0);
263 return (FPCFGA_LIB_ERR
);
266 if (fstat(fd
, &stbuf
) == -1) {
268 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
269 return (FPCFGA_LIB_ERR
);
272 filesize
= size
= stbuf
.st_size
;
274 /* A very Minimal check on repository */
275 if (filesize
&& filesize
< sizeof_rep_hdr
) {
277 * If there is some data, it should be atleast the size of
281 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
282 return (FPCFGA_LIB_ERR
);
285 if ((len
= strlen(update_str
)) == 0) {
287 * We are trying to add/remove a NULL string.
288 * Just return success
294 if ((upd_str
= calloc(1, len
+ 2)) == NULL
) {
296 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
297 return (FPCFGA_LIB_ERR
);
300 strcpy(upd_str
, update_str
);
301 strcat(upd_str
, "\n"); /* Append a new line char */
302 len
= strlen(upd_str
);
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
);
311 (void) sprintf(copy_rep
, "%s%s%ld", FAB_REPOSITORY
, COPY_EXT
,
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
);
320 if ((repbuf
= mmap(NULL
, filesize
, PROT_READ
,
321 MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
324 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
325 return (FPCFGA_LIB_ERR
);
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
);
333 if (write(copy_fd
, "", 1) != 1) {
334 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
335 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
338 if ((c_repbuf
= mmap(NULL
, 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
);
345 memcpy(c_repbuf
, repbuf
, filesize
);
347 * We cannot close the repository since we hold a lock
348 * But we'll free up the mmap-ed area.
350 munmap(repbuf
, filesize
);
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,
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
);
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
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
);
378 if (write(fd
, upd_str
, len
) != len
) {
379 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
380 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
384 /* Now create the '.old' file */
385 if (msync(c_repbuf
, filesize
, MS_SYNC
) == -1) {
386 cfga_err(errstring
, errno
,
388 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
392 S_IRUSR
| S_IRGRP
| S_IROTH
) < 0) {
393 cfga_err(errstring
, errno
,
395 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
397 rename(copy_rep
, OLD_FAB_REPOSITORY
);
400 CLEANUP_N_RET(FPCFGA_OK
);
404 * So, the side effect of a remove on an empty or
405 * non-existing repository is that the repository got
408 CLEANUP_N_RET(FPCFGA_OK
);
411 cfga_err(errstring
, 0, ERR_UPD_REP
, 0);
412 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
416 /* Now, size and filesize are > sizeof_rep_hdr */
422 * We'll search the full repository, header included, since
423 * we dont expect upd_str to match anything in the header.
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 */
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
);
438 (void) sprintf(tmp_rep
, "%s%s%ld", FAB_REPOSITORY
,
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
);
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
);
453 if (write(tmp_fd
, "", 1) != 1) {
454 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
455 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
458 if ((t_repbuf
= mmap(NULL
, 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
);
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
);
472 * we are using the copy of FAB_REPOSITORY and will
473 * do msync first since it will be renamed to '.old' file.
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
);
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
);
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
);
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
);
495 close(copy_fd
); copy_fd
= -1;
496 close(tmp_fd
); tmp_fd
= -1;
498 /* here we do rename and rename before close fd */
499 rename(copy_rep
, OLD_FAB_REPOSITORY
);
500 rename(tmp_rep
, FAB_REPOSITORY
);
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
);
507 CLEANUP_N_RET(FPCFGA_OK
);
510 if (size
>= sizeof_rep_hdr
+ len
- 1) {
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.
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 */
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
);
533 (void) sprintf(tmp_rep
, "%s%s%ld", FAB_REPOSITORY
,
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
);
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
);
549 if (write(tmp_fd
, "", 1) != 1) {
550 cfga_err(errstring
, errno
, ERR_UPD_REP
, 0);
551 CLEANUP_N_RET(FPCFGA_LIB_ERR
);
554 if ((t_repbuf
= mmap(NULL
, 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
);
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
,
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
);
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
);
580 * we are using the copy of FAB_REPOSITORY and will
581 * do msync first since it will be renamed to bak file.
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
);
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
);
593 /* Close and invalidate the fd's */
594 close(copy_fd
); copy_fd
= -1;
595 close(tmp_fd
); tmp_fd
= -1;
597 /* here we do rename and rename before close fd */
598 rename(copy_rep
, OLD_FAB_REPOSITORY
);
599 rename(tmp_rep
, FAB_REPOSITORY
);
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
);
606 CLEANUP_N_RET(FPCFGA_OK
);
609 /* Unexpected - just getout */
613 CLEANUP_N_RET(FPCFGA_OK
); /* SUCCESS */