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.
28 * This file contains functions that allow applications to roll the log.
29 * It is intended for use by applications that open a raw device with the
30 * understanding that it contains a Unix File System.
40 #include <sys/filio.h>
41 #include <sys/mnttab.h>
42 #include <sys/mntent.h>
43 #include <sys/mount.h>
44 #include <sys/param.h>
45 #include <sys/types.h>
47 #include <sys/fs/ufs_mount.h>
48 #include <sys/fs/ufs_log.h>
53 * The following is the template string passed to mktemp(3C). This
54 * string is used as the name of a temporary mount point which is
55 * used to roll the log.
57 #define RLG_TEMPLATE ".rlg.XXXXXX"
65 * Structure definitions:
68 typedef struct log_info
{
69 char *li_blkname
; /* Path of block device. */
70 char *li_mntpoint
; /* Path of mounted device. */
71 char *li_tmpmp_parent
; /* Temporary parent directory of mount point */
72 char *li_tmpmp
; /* Temporary mount point. */
76 * Static function declarations:
79 static rl_result_t
is_mounted(log_info_t
*lip
, char *dev
);
80 static void cleanup(log_info_t
*lip
);
81 static rl_result_t
make_mp(log_info_t
*lip
);
82 static rl_result_t
rlflush(log_info_t
*lip
);
83 static rl_result_t
rlmount(log_info_t
*lip
, int mntopt
);
84 static rl_result_t
rlumount(log_info_t
*lip
);
91 * rl_roll_log(block_dev)
94 * Roll the log for the block device "block_dev".
98 rl_roll_log(char *bdev
)
101 rl_result_t rv
= RL_SUCCESS
;
103 (void) memset(&li
, 0, (size_t)sizeof (li
));
104 if (is_mounted(&li
, bdev
) == RL_TRUE
) {
108 * Device appears not to be mounted.
109 * We need to mount the device read only.
110 * This automatically causes the log to be rolled, then we can
111 * unmount the device again. To do the mount, we need to
112 * create a temporary directory, and then remove it when we
118 /* corrupt mnttab - the file sys really was mounted */
122 rv
= rlmount(&li
, RLM_RO
);
123 if (rv
== RL_SUCCESS
) {
125 if (umount(li
.li_blkname
) == SYSERR
) {
126 (void) fprintf(stderr
,
127 "WARNING: rl_roll_log(): Can't unmount %s\n", li
.li_blkname
);
139 * Static function definitions:
150 * Remove the temporary mount directroy and free the dynamically
151 * allocated memory that is pointed to by log_infop.
155 cleanup(log_info_t
*lip
)
157 if (lip
->li_blkname
!= NULL
) {
158 free(lip
->li_blkname
);
159 lip
->li_blkname
= NULL
;
161 if (lip
->li_mntpoint
!= NULL
) {
162 free(lip
->li_mntpoint
);
163 lip
->li_mntpoint
= NULL
;
165 if (lip
->li_tmpmp
!= NULL
) {
166 (void) rmdir(lip
->li_tmpmp
);
168 lip
->li_tmpmp
= NULL
;
170 if (lip
->li_tmpmp_parent
!= NULL
) {
171 (void) rmdir(lip
->li_tmpmp_parent
);
172 free(lip
->li_tmpmp_parent
);
173 lip
->li_tmpmp_parent
= NULL
;
182 * is_mounted(log_infop, dev)
185 * Determine if device dev is mounted, and return RL_TRUE if it is.
186 * As a side effect, li_blkname is set to point the the full path
187 * names of the block device. Memory for this path is dynamically
188 * allocated and must be freed by the caller.
191 extern char *getfullblkname(char *);
194 is_mounted(log_info_t
*lip
, char *dev
)
197 struct mnttab mntbuf
;
199 rl_result_t rv
= RL_FALSE
;
201 /* Make sure that we have the full path name. */
202 lip
->li_blkname
= getfullblkname(dev
);
203 if (lip
->li_blkname
== NULL
)
204 lip
->li_blkname
= strdup(dev
);
206 /* Search mnttab to see if it device is mounted. */
207 if ((mnttable
= fopen(MNTTAB
, "r")) == NULL
)
209 while (getmntent(mnttable
, &mntbuf
) == 0) {
210 if (strcmp(mntbuf
.mnt_fstype
, MNTTYPE_UFS
) == 0) {
212 if ((strcmp(mntbuf
.mnt_mountp
, dev
) == 0) ||
213 (strcmp(mntbuf
.mnt_special
, lip
->li_blkname
)
215 (strcmp(mntbuf
.mnt_special
, dev
) == 0)) {
216 lip
->li_mntpoint
= strdup(mntbuf
.mnt_mountp
);
222 (void) fclose(mnttable
);
236 * Create a temporary directory to be used as a mount point. li_tmpmp
237 * will be set to the path of the mount point. li_tmpmp_parent is the
238 * parent directory of the mount point. The parent directory is
239 * created with restrictive permissions. Memory pointed to by
240 * li_tmpmp and li_tmpmp_parent should be freed by the caller.
244 make_mp(log_info_t
*lip
)
247 rl_result_t rv
= RL_FAIL
;
249 * Note tmp_dir_list[] should all be directories in the
250 * original root file system.
252 static const char *tmp_dir_list
[] = {
257 char dirname
[] = RLG_TEMPLATE
;
258 char tmp_dir
[MAXPATHLEN
+ 1];
259 char mountpt_dir
[MAXPATHLEN
+ 1];
260 static size_t list_len
= sizeof (tmp_dir_list
) /
261 sizeof (const char *);
265 * Sequence of events:
266 * - Create a random name using mktemp(3C) (e.g., ".rlg.123456")
267 * - Cycle through tmp_dir_list to find a path where we can create
268 * a temporary parent directory (e.g., /tmp/.rlg.123456) with
269 * restrictive permissions. This prevents any non-root processes,
270 * such as a 'find', from wandering in where it doesn't belong.
271 * - Create the mount-point (/tmp/.rlg.123456/.rlg.123456).
273 (void) mktemp(dirname
);
274 for (i
= 0; i
< list_len
; i
++) {
275 /* Make the directory containing the mount-point */
276 (void) snprintf(tmp_dir
, sizeof (tmp_dir
), "%s%s",
277 tmp_dir_list
[i
], dirname
);
278 if (mkdir(tmp_dir
, 0) == SYSERR
) {
283 /* Now, make the mount-point */
284 (void) snprintf(mountpt_dir
, sizeof (mountpt_dir
), "%s/%s",
286 if (mkdir(mountpt_dir
, 0) == SYSERR
) {
290 lip
->li_tmpmp
= strdup(mountpt_dir
);
291 lip
->li_tmpmp_parent
= strdup(tmp_dir
);
293 /* Make sure that the strdup()s both succeeded */
294 if ((lip
->li_tmpmp
!= NULL
) && (lip
->li_tmpmp_parent
!= NULL
)) {
300 /* Get some help if we cannot make the directory. */
301 if (rv
!= RL_SUCCESS
) {
303 * If we get a read only filesystem failure (EROFS)
304 * to make a directory in "/", then we must be fsck'ing
305 * at boot with a incorrect mnttab.
307 * Just return RL_CORRUPT to indicate it really
311 lip
->li_mntpoint
= strdup("/");
315 (void) fprintf(stderr
, gettext(
316 "Unable to create temporary "
317 "directory in any of the directories listed "
319 for (i
= 0; i
< list_len
; i
++) {
320 (void) fprintf(stderr
, "\t%s\n", tmp_dir_list
[i
]);
322 (void) fprintf(stderr
, gettext(
323 "Please correct this problem "
324 "and rerun the program.\n"));
338 * Open the mount point of the file system (li_mntpoint) to get a
339 * file descriptor. Issue the _FIOFFS ioctl to flush the file system
340 * and then close the device.
344 rlflush(log_info_t
*lip
)
346 int fd
; /* File descriptor. */
347 rl_result_t rv
= RL_SUCCESS
;
349 if ((fd
= open((lip
->li_mntpoint
? lip
->li_mntpoint
: lip
->li_tmpmp
),
350 O_RDONLY
)) == SYSERR
) {
353 if (ioctl(fd
, _FIOFFS
, NULL
) == SYSERR
) {
365 * rlmount(log_infop, mntopt)
368 * Mount the device specified by li_blkname on li_tmpmp. mntopt specifies
369 * whether it's mounted RLM_RO or RLM_RW.
373 rlmount(log_info_t
*lip
, int mntopt
)
375 struct ufs_args args
;
376 rl_result_t rv
= RL_SUCCESS
;
377 char opt
[MAX_MNTOPT_STR
];
381 args
.flags
= 0; /* Initialize ufs_args */
384 * Use a minimal restrictive set of mount options. Make sure
385 * to use "largefiles" option otherwise mount() can fail w/EFBIG.
386 * (Although "nosub" isn't a currently supported option on UFS,
387 * it would be a good one to have if it ever is implemented
388 * since submounts would prevent a umount.)
390 args
.flags
|= UFSMNT_LARGEFILES
;
403 (void) snprintf(opt
, sizeof (opt
), "%s,%s,%s",
404 optstr
, MNTOPT_NOSUID
, MNTOPT_LARGEFILES
);
405 if (mount(lip
->li_blkname
, lip
->li_tmpmp
,
406 optflg
| MS_DATA
| MS_OPTIONSTR
,
407 MNTTYPE_UFS
, &args
, sizeof (args
),
408 opt
, MAX_MNTOPT_STR
) == SYSERR
) {
419 * rlumount(log_infop)
422 * Unmounts the device specified by li_blkname, printing an
423 * error message on failure.
427 rlumount(log_info_t
*lip
)
429 rl_result_t rv
= RL_SUCCESS
;
431 if (umount(lip
->li_blkname
) == SYSERR
) {
432 (void) fprintf(stderr
, gettext(
433 "WARNING: rlumount(): Can't unmount %s\n"),
445 * rl_log_control(block_dev, request)
448 * Enable/disable logging for the block device "block_dev".
449 * The request parameter should be set to _FIOLOGENABLE or
454 rl_log_control(char *bdev
, int request
)
457 rl_result_t rv
= RL_SUCCESS
;
458 rl_result_t alreadymounted
;
463 if ((request
!= _FIOLOGENABLE
) && (request
!= _FIOLOGDISABLE
))
466 (void) memset(&li
, 0, (size_t)sizeof (li
));
467 if ((alreadymounted
= is_mounted(&li
, bdev
)) != RL_TRUE
) {
469 * Device is not mounted. Need to mount it rw to allow
470 * the log to be enabled/disabled. To do the mount, we need
471 * to create a temporary directory, and then remove it when
474 if (make_mp(&li
) != RL_SUCCESS
) {
478 if (rlmount(&li
, RLM_RW
) != RL_SUCCESS
) {
484 if (alreadymounted
== RL_TRUE
)
485 fd
= open(li
.li_mntpoint
, O_RDONLY
);
487 fd
= open(li
.li_tmpmp
, O_RDONLY
);
494 fl
.nbytes_requested
= 0;
495 fl
.nbytes_actual
= 0;
496 fl
.error
= FIOLOG_ENONE
;
498 if (ioctl(fd
, request
, &fl
) == SYSERR
) {
504 if (ioctl(fd
, _FIOISLOG
, &logenabled
) == SYSERR
) {
510 if (((request
== _FIOLOGENABLE
) && (!logenabled
)) ||
511 ((request
== _FIOLOGDISABLE
) && logenabled
))
516 if (alreadymounted
!= RL_TRUE
)
517 (void) rlumount(&li
);