4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains functions that allow applications to roll the log.
31 * It is intended for use by applications that open a raw device with the
32 * understanding that it contains a Unix File System.
42 #include <sys/filio.h>
43 #include <sys/mnttab.h>
44 #include <sys/mntent.h>
45 #include <sys/mount.h>
46 #include <sys/param.h>
47 #include <sys/types.h>
49 #include <sys/fs/ufs_mount.h>
50 #include <sys/fs/ufs_log.h>
55 * The following is the template string passed to mktemp(3C). This
56 * string is used as the name of a temporary mount point which is
57 * used to roll the log.
59 #define RLG_TEMPLATE ".rlg.XXXXXX"
67 * Structure definitions:
70 typedef struct log_info
{
71 char *li_blkname
; /* Path of block device. */
72 char *li_mntpoint
; /* Path of mounted device. */
73 char *li_tmpmp_parent
; /* Temporary parent directory of mount point */
74 char *li_tmpmp
; /* Temporary mount point. */
78 * Static function declarations:
81 static rl_result_t
is_mounted(log_info_t
*lip
, char *dev
);
82 static void cleanup(log_info_t
*lip
);
83 static rl_result_t
make_mp(log_info_t
*lip
);
84 static rl_result_t
rlflush(log_info_t
*lip
);
85 static rl_result_t
rlmount(log_info_t
*lip
, int mntopt
);
86 static rl_result_t
rlumount(log_info_t
*lip
);
93 * rl_roll_log(block_dev)
96 * Roll the log for the block device "block_dev".
100 rl_roll_log(char *bdev
)
103 rl_result_t rv
= RL_SUCCESS
;
105 (void) memset((void *)&li
, 0, (size_t)sizeof (li
));
106 if (is_mounted(&li
, bdev
) == RL_TRUE
) {
110 * Device appears not to be mounted.
111 * We need to mount the device read only.
112 * This automatically causes the log to be rolled, then we can
113 * unmount the device again. To do the mount, we need to
114 * create a temporary directory, and then remove it when we
120 /* corrupt mnttab - the file sys really was mounted */
124 rv
= rlmount(&li
, RLM_RO
);
125 if (rv
== RL_SUCCESS
) {
127 if (umount(li
.li_blkname
) == SYSERR
) {
128 (void) fprintf(stderr
,
129 "WARNING: rl_roll_log(): Can't unmount %s\n", li
.li_blkname
);
141 * Static function definitions:
152 * Remove the temporary mount directroy and free the dynamically
153 * allocated memory that is pointed to by log_infop.
157 cleanup(log_info_t
*lip
)
159 if (lip
->li_blkname
!= (char *)NULL
) {
160 free(lip
->li_blkname
);
161 lip
->li_blkname
= (char *)NULL
;
163 if (lip
->li_mntpoint
!= (char *)NULL
) {
164 free(lip
->li_mntpoint
);
165 lip
->li_mntpoint
= (char *)NULL
;
167 if (lip
->li_tmpmp
!= (char *)NULL
) {
168 (void) rmdir(lip
->li_tmpmp
);
170 lip
->li_tmpmp
= (char *)NULL
;
172 if (lip
->li_tmpmp_parent
!= (char *)NULL
) {
173 (void) rmdir(lip
->li_tmpmp_parent
);
174 free(lip
->li_tmpmp_parent
);
175 lip
->li_tmpmp_parent
= (char *)NULL
;
184 * is_mounted(log_infop, dev)
187 * Determine if device dev is mounted, and return RL_TRUE if it is.
188 * As a side effect, li_blkname is set to point the the full path
189 * names of the block device. Memory for this path is dynamically
190 * allocated and must be freed by the caller.
193 extern char *getfullblkname(char *);
196 is_mounted(log_info_t
*lip
, char *dev
)
199 struct mnttab mntbuf
;
201 rl_result_t rv
= RL_FALSE
;
203 /* Make sure that we have the full path name. */
204 lip
->li_blkname
= getfullblkname(dev
);
205 if (lip
->li_blkname
== NULL
)
206 lip
->li_blkname
= strdup(dev
);
208 /* Search mnttab to see if it device is mounted. */
209 if ((mnttable
= fopen(MNTTAB
, "r")) == NULL
)
211 while (getmntent(mnttable
, &mntbuf
) == NULL
) {
212 if (strcmp(mntbuf
.mnt_fstype
, MNTTYPE_UFS
) == 0) {
214 if ((strcmp(mntbuf
.mnt_mountp
, dev
) == 0) ||
215 (strcmp(mntbuf
.mnt_special
, lip
->li_blkname
)
217 (strcmp(mntbuf
.mnt_special
, dev
) == 0)) {
218 lip
->li_mntpoint
= strdup(mntbuf
.mnt_mountp
);
224 (void) fclose(mnttable
);
238 * Create a temporary directory to be used as a mount point. li_tmpmp
239 * will be set to the path of the mount point. li_tmpmp_parent is the
240 * parent directory of the mount point. The parent directory is
241 * created with restrictive permissions. Memory pointed to by
242 * li_tmpmp and li_tmpmp_parent should be freed by the caller.
246 make_mp(log_info_t
*lip
)
249 rl_result_t rv
= RL_FAIL
;
251 * Note tmp_dir_list[] should all be directories in the
252 * original root file system.
254 static const char *tmp_dir_list
[] = {
259 char dirname
[] = RLG_TEMPLATE
;
260 char tmp_dir
[MAXPATHLEN
+ 1];
261 char mountpt_dir
[MAXPATHLEN
+ 1];
262 static size_t list_len
= sizeof (tmp_dir_list
) /
263 sizeof (const char *);
267 * Sequence of events:
268 * - Create a random name using mktemp(3C) (e.g., ".rlg.123456")
269 * - Cycle through tmp_dir_list to find a path where we can create
270 * a temporary parent directory (e.g., /tmp/.rlg.123456) with
271 * restrictive permissions. This prevents any non-root processes,
272 * such as a 'find', from wandering in where it doesn't belong.
273 * - Create the mount-point (/tmp/.rlg.123456/.rlg.123456).
275 (void) mktemp(dirname
);
276 for (i
= 0; i
< list_len
; i
++) {
277 /* Make the directory containing the mount-point */
278 (void) snprintf(tmp_dir
, sizeof (tmp_dir
), "%s%s",
279 tmp_dir_list
[i
], dirname
);
280 if (mkdir(tmp_dir
, 0) == SYSERR
) {
285 /* Now, make the mount-point */
286 (void) snprintf(mountpt_dir
, sizeof (mountpt_dir
), "%s/%s",
288 if (mkdir(mountpt_dir
, 0) == SYSERR
) {
292 lip
->li_tmpmp
= strdup(mountpt_dir
);
293 lip
->li_tmpmp_parent
= strdup(tmp_dir
);
295 /* Make sure that the strdup()s both succeeded */
296 if ((lip
->li_tmpmp
!= NULL
) && (lip
->li_tmpmp_parent
!= NULL
)) {
302 /* Get some help if we cannot make the directory. */
303 if (rv
!= RL_SUCCESS
) {
305 * If we get a read only filesystem failure (EROFS)
306 * to make a directory in "/", then we must be fsck'ing
307 * at boot with a incorrect mnttab.
309 * Just return RL_CORRUPT to indicate it really
313 lip
->li_mntpoint
= strdup("/");
317 (void) fprintf(stderr
, gettext(
318 "Unable to create temporary "
319 "directory in any of the directories listed "
321 for (i
= 0; i
< list_len
; i
++) {
322 (void) fprintf(stderr
, "\t%s\n", tmp_dir_list
[i
]);
324 (void) fprintf(stderr
, gettext(
325 "Please correct this problem "
326 "and rerun the program.\n"));
340 * Open the mount point of the file system (li_mntpoint) to get a
341 * file descriptor. Issue the _FIOFFS ioctl to flush the file system
342 * and then close the device.
346 rlflush(log_info_t
*lip
)
348 int fd
; /* File descriptor. */
349 rl_result_t rv
= RL_SUCCESS
;
351 if ((fd
= open((lip
->li_mntpoint
? lip
->li_mntpoint
: lip
->li_tmpmp
),
352 O_RDONLY
)) == SYSERR
) {
355 if (ioctl(fd
, _FIOFFS
, NULL
) == SYSERR
) {
367 * rlmount(log_infop, mntopt)
370 * Mount the device specified by li_blkname on li_tmpmp. mntopt specifies
371 * whether it's mounted RLM_RO or RLM_RW.
375 rlmount(log_info_t
*lip
, int mntopt
)
377 struct ufs_args args
;
378 rl_result_t rv
= RL_SUCCESS
;
379 char opt
[MAX_MNTOPT_STR
];
383 args
.flags
= 0; /* Initialize ufs_args */
386 * Use a minimal restrictive set of mount options. Make sure
387 * to use "largefiles" option otherwise mount() can fail w/EFBIG.
388 * (Although "nosub" isn't a currently supported option on UFS,
389 * it would be a good one to have if it ever is implemented
390 * since submounts would prevent a umount.)
392 args
.flags
|= UFSMNT_LARGEFILES
;
405 (void) snprintf(opt
, sizeof (opt
), "%s,%s,%s",
406 optstr
, MNTOPT_NOSUID
, MNTOPT_LARGEFILES
);
407 if (mount(lip
->li_blkname
, lip
->li_tmpmp
,
408 optflg
| MS_DATA
| MS_OPTIONSTR
,
409 MNTTYPE_UFS
, &args
, sizeof (args
),
410 opt
, MAX_MNTOPT_STR
) == SYSERR
) {
421 * rlumount(log_infop)
424 * Unmounts the device specified by li_blkname, printing an
425 * error message on failure.
429 rlumount(log_info_t
*lip
)
431 rl_result_t rv
= RL_SUCCESS
;
433 if (umount(lip
->li_blkname
) == SYSERR
) {
434 (void) fprintf(stderr
, gettext(
435 "WARNING: rlumount(): Can't unmount %s\n"),
447 * rl_log_control(block_dev, request)
450 * Enable/disable logging for the block device "block_dev".
451 * The request parameter should be set to _FIOLOGENABLE or
456 rl_log_control(char *bdev
, int request
)
459 rl_result_t rv
= RL_SUCCESS
;
460 rl_result_t alreadymounted
;
465 if ((request
!= _FIOLOGENABLE
) && (request
!= _FIOLOGDISABLE
))
468 (void) memset((void *)&li
, '\0', (size_t)sizeof (li
));
469 if ((alreadymounted
= is_mounted(&li
, bdev
)) != RL_TRUE
) {
471 * Device is not mounted. Need to mount it rw to allow
472 * the log to be enabled/disabled. To do the mount, we need
473 * to create a temporary directory, and then remove it when
476 if (make_mp(&li
) != RL_SUCCESS
) {
480 if (rlmount(&li
, RLM_RW
) != RL_SUCCESS
) {
486 if (alreadymounted
== RL_TRUE
)
487 fd
= open(li
.li_mntpoint
, O_RDONLY
);
489 fd
= open(li
.li_tmpmp
, O_RDONLY
);
496 fl
.nbytes_requested
= 0;
497 fl
.nbytes_actual
= 0;
498 fl
.error
= FIOLOG_ENONE
;
500 if (ioctl(fd
, request
, &fl
) == SYSERR
) {
506 if (ioctl(fd
, _FIOISLOG
, &logenabled
) == SYSERR
) {
512 if (((request
== _FIOLOGENABLE
) && (!logenabled
)) ||
513 ((request
== _FIOLOGDISABLE
) && logenabled
))
518 if (alreadymounted
!= RL_TRUE
)
519 (void) rlumount(&li
);