16691 zfstest: rootpool tests do not make sense when rootfs is not zfs
[illumos-gate.git] / usr / src / lib / librename / common / librename.c
blobf3ef8163cb9d5fe9cf91539b3f345920b057c2de
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2014 Joyent, Inc. All rights reserved.
16 #include <librename.h>
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <sys/debug.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <synch.h>
29 typedef enum librename_atomic_state {
30 LIBRENAME_ATOMIC_INITIAL = 0x0,
31 LIBRENAME_ATOMIC_FSYNC,
32 LIBRENAME_ATOMIC_RENAME,
33 LIBRENAME_ATOMIC_POSTSYNC,
34 LIBRENAME_ATOMIC_COMPLETED
35 } librename_atomic_state_t;
37 struct librename_atomic {
38 char *lra_fname; /* RO */
39 char *lra_altname; /* RO */
40 int lra_dirfd; /* RO */
41 int lra_tmpfd; /* RO */
42 mutex_t lra_lock;
43 librename_atomic_state_t lra_state; /* lra_lock */
46 int
47 librename_atomic_fdinit(int fd, const char *file, const char *prefix,
48 int mode, int flags, librename_atomic_t **outp)
50 int ret;
51 int oflags;
52 librename_atomic_t *lrap;
53 struct stat st;
55 if (fd < 0 || file == NULL || outp == NULL)
56 return (EINVAL);
58 if (flags & ~(LIBRENAME_ATOMIC_NOUNLINK | LIBRENAME_ATOMIC_CLOEXEC))
59 return (EINVAL);
61 if (strchr(file, '/') != NULL)
62 return (EINVAL);
64 if (prefix != NULL && strchr(prefix, '/') != NULL)
65 return (EINVAL);
67 *outp = NULL;
68 lrap = malloc(sizeof (librename_atomic_t));
69 if (lrap == NULL)
70 return (errno);
72 if (fstat(fd, &st) != 0) {
73 ret = errno;
74 free(lrap);
75 return (ret);
78 if (!S_ISDIR(st.st_mode)) {
79 free(lrap);
80 return (ENOTDIR);
83 if ((lrap->lra_dirfd = dup(fd)) == -1) {
84 ret = errno;
85 free(lrap);
86 return (ret);
89 lrap->lra_fname = strdup(file);
90 if (lrap->lra_fname == NULL) {
91 ret = errno;
92 VERIFY0(close(lrap->lra_dirfd));
93 free(lrap);
94 return (ret);
97 if (prefix == NULL) {
98 ret = asprintf(&lrap->lra_altname, ".%d.%s", (int)getpid(),
99 file);
100 } else {
101 ret = asprintf(&lrap->lra_altname, "%s%s", prefix, file);
103 if (ret == -1) {
104 ret = errno;
105 free(lrap->lra_fname);
106 VERIFY0(close(lrap->lra_dirfd));
107 free(lrap);
108 return (errno);
111 oflags = O_CREAT | O_TRUNC | O_RDWR | O_NOFOLLOW;
112 if (flags & LIBRENAME_ATOMIC_NOUNLINK)
113 oflags |= O_EXCL;
115 if (flags & LIBRENAME_ATOMIC_CLOEXEC)
116 oflags |= O_CLOEXEC;
118 lrap->lra_tmpfd = openat(lrap->lra_dirfd, lrap->lra_altname,
119 oflags, mode);
120 if (lrap->lra_tmpfd < 0) {
121 ret = errno;
122 free(lrap->lra_altname);
123 free(lrap->lra_fname);
124 VERIFY0(close(lrap->lra_dirfd));
125 free(lrap);
126 return (ret);
129 VERIFY0(mutex_init(&lrap->lra_lock, USYNC_THREAD, NULL));
131 lrap->lra_state = LIBRENAME_ATOMIC_INITIAL;
132 *outp = lrap;
133 return (0);
137 librename_atomic_init(const char *dir, const char *file, const char *prefix,
138 int mode, int flags, librename_atomic_t **outp)
140 int fd, ret;
142 if ((fd = open(dir, O_RDONLY)) < 0)
143 return (errno);
145 ret = librename_atomic_fdinit(fd, file, prefix, mode, flags, outp);
146 VERIFY0(close(fd));
148 return (ret);
152 librename_atomic_fd(librename_atomic_t *lrap)
154 return (lrap->lra_tmpfd);
158 * To atomically commit a file, we need to go through and do the following:
160 * o fsync the source
161 * o run rename
162 * o fsync the source again and the directory.
165 librename_atomic_commit(librename_atomic_t *lrap)
167 int ret = 0;
169 VERIFY0(mutex_lock(&lrap->lra_lock));
170 if (lrap->lra_state == LIBRENAME_ATOMIC_COMPLETED) {
171 ret = EINVAL;
172 goto out;
175 if (fsync(lrap->lra_tmpfd) != 0) {
176 ret = errno;
177 goto out;
179 lrap->lra_state = LIBRENAME_ATOMIC_FSYNC;
181 if (renameat(lrap->lra_dirfd, lrap->lra_altname, lrap->lra_dirfd,
182 lrap->lra_fname) != 0) {
183 ret = errno;
184 goto out;
186 lrap->lra_state = LIBRENAME_ATOMIC_RENAME;
188 if (fsync(lrap->lra_tmpfd) != 0) {
189 ret = errno;
190 goto out;
192 lrap->lra_state = LIBRENAME_ATOMIC_POSTSYNC;
194 if (fsync(lrap->lra_dirfd) != 0) {
195 ret = errno;
196 goto out;
198 lrap->lra_state = LIBRENAME_ATOMIC_COMPLETED;
200 out:
201 VERIFY0(mutex_unlock(&lrap->lra_lock));
202 return (ret);
205 void
206 librename_atomic_fini(librename_atomic_t *lrap)
209 free(lrap->lra_altname);
210 free(lrap->lra_fname);
211 VERIFY0(close(lrap->lra_tmpfd));
212 VERIFY0(close(lrap->lra_dirfd));
213 VERIFY0(mutex_destroy(&lrap->lra_lock));
214 free(lrap);