Version 1.8.0.0
[socat.git] / xio-named.c
blob1dec534d6b13dffb45664a1af9a57a5432554a16
1 /* source: xio-named.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for filesystem entry functions */
7 #include "xiosysincludes.h"
9 #if _WITH_NAMED
11 #include "xioopen.h"
12 #include "xio-named.h"
15 #if WITH_NAMED
16 const struct optdesc opt_group_early = { "group-early", NULL, OPT_GROUP_EARLY, GROUP_NAMED, PH_PREOPEN, TYPE_GIDT, OFUNC_SPEC };
17 const struct optdesc opt_perm_early = { "perm-early", NULL, OPT_PERM_EARLY, GROUP_NAMED, PH_PREOPEN, TYPE_MODET,OFUNC_SPEC };
18 const struct optdesc opt_user_early = { "user-early", NULL, OPT_USER_EARLY, GROUP_NAMED, PH_PREOPEN, TYPE_UIDT, OFUNC_SPEC };
19 /*0 const struct optdesc opt_force = { "force", NULL, OPT_FORCE, GROUP_NAMED, PH_???, TYPE_BOOL, OFUNC_SPEC };*/
20 const struct optdesc opt_unlink = { "unlink", NULL, OPT_UNLINK, GROUP_NAMED, PH_PREOPEN, TYPE_BOOL, OFUNC_SPEC };
21 const struct optdesc opt_unlink_early= { "unlink-early",NULL, OPT_UNLINK_EARLY,GROUP_NAMED, PH_EARLY, TYPE_BOOL, OFUNC_SPEC };
22 const struct optdesc opt_unlink_late = { "unlink-late", NULL, OPT_UNLINK_LATE, GROUP_NAMED, PH_PASTOPEN, TYPE_BOOL, OFUNC_SPEC };
23 const struct optdesc opt_unlink_close = { "unlink-close", NULL, OPT_UNLINK_CLOSE, GROUP_NAMED, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
24 #endif /* WITH_NAMED */
26 /* applies to filesystem entry all options belonging to phase */
27 int applyopts_named(const char *filename, struct opt *opts, unsigned int phase) {
28 struct opt *opt;
30 if (!opts) return 0;
32 opt = opts; while (opt->desc != ODESC_END) {
33 if (opt->desc == ODESC_DONE ||
34 opt->desc->phase != phase && phase != PH_ALL ||
35 !(opt->desc->group & GROUP_NAMED)) {
36 ++opt; continue; }
37 switch (opt->desc->optcode) {
38 case OPT_GROUP_EARLY:
39 case OPT_GROUP:
40 if (Chown(filename, -1, opt->value.u_gidt) < 0) {
41 Error3("chown(\"%s\", -1, "F_gid"): %s", filename,
42 opt->value.u_gidt, strerror(errno));
44 break;
45 case OPT_USER_EARLY:
46 case OPT_USER:
47 if (Chown(filename, opt->value.u_uidt, -1) < 0) {
48 Error3("chown(\"%s\", "F_uid", -1): %s", filename,
49 opt->value.u_uidt, strerror(errno));
51 break;
52 case OPT_PERM_EARLY:
53 case OPT_PERM:
54 if (Chmod(filename, opt->value.u_modet) < 0) {
55 Error3("chmod(\"%s\", "F_mode"): %s",
56 filename, opt->value.u_modet, strerror(errno));
58 break;
59 case OPT_UNLINK_EARLY:
60 case OPT_UNLINK:
61 xio_unlink(filename, E_ERROR);
62 break;
63 case OPT_UNLINK_LATE:
64 if (Unlink(filename) < 0) {
65 if (errno == ENOENT) {
66 /* We have just created/opened it, that's - surprising! */
67 Warn2("unlink(\"%s\"): %s", filename, strerror(errno));
68 } else {
69 Error2("unlink(\"%s\"): %s", filename, strerror(errno));
72 break;
73 default: Error1("applyopts_named(): option \"%s\" not implemented",
74 opt->desc->defname);
75 break;
77 opt->desc = ODESC_DONE;
78 ++opt;
80 return 0;
84 /* perform actions that are common to all NAMED group addresses: checking if
85 the entry exists, parsing options, ev.removing old filesystem entry or
86 setting early owners and permissions.
87 It applies options of PH_EARLY and PH_PREOPEN.
88 If the path exists, its st_mode field is returned.
89 After this sub you may proceed with open() or whatever...
91 int _xioopen_named_early(
92 int argc,
93 const char *argv[],
94 xiofile_t *xfd,
95 groups_t groups,
96 bool *exists,
97 struct opt *opts,
98 const char *syntax)
100 const char *path = argv[1];
101 struct single *sfd = &xfd->stream;
102 #if HAVE_STAT64
103 struct stat64 statbuf;
104 #else
105 struct stat statbuf;
106 #endif /* !HAVE_STAT64 */
107 bool opt_unlink_early = false;
109 if (argc != 2) {
110 xio_syntax(argv[0], 1, argc-1, syntax);
111 return STAT_NORETRY;
113 statbuf.st_mode = 0;
114 /* find the appropriate groupbits */
115 if (
116 #if HAVE_STAT64
117 Stat64(path, &statbuf) < 0
118 #else
119 Stat(path, &statbuf) < 0
120 #endif /* !HAVE_STAT64 */
122 if (errno != ENOENT) {
123 Error2("stat(\"%s\"): %s", path, strerror(errno));
124 return STAT_RETRYLATER;
126 *exists = false;
127 } else {
128 *exists = true;
131 if (applyopts_single(sfd, opts, PH_INIT) < 0)
132 return -1;
133 applyopts(sfd, -1, opts, PH_INIT);
135 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
136 if (*exists && opt_unlink_early) {
137 Info1("\"%s\" already exists; removing it", path);
138 if (Unlink(path) < 0) {
139 Error2("unlink(\"%s\"): %s", path, strerror(errno));
140 } else {
141 *exists = false;
145 applyopts_named(path, opts, PH_EARLY);
146 applyopts(sfd, -1, opts, PH_EARLY);
147 if (*exists) {
148 applyopts_named(path, opts, PH_PREOPEN);
149 } else {
150 dropopts(opts, PH_PREOPEN);
153 return statbuf.st_mode;
157 /* retrieve the OPEN group options and perform the open() call.
158 returns the file descriptor or a negative value.
159 Applies options of phases PREOPEN, OPEN, PASTOPEN, and FD
161 int _xioopen_open(const char *path, int rw, struct opt *opts) {
162 mode_t mode = 0666;
163 flags_t flags = rw;
164 bool flag;
165 int fd;
167 applyopts_named(path, opts, PH_PREOPEN);
169 /* this only applies pure OPEN flags, not mixed OPEN/FCNTL options */
170 applyopts_flags(opts, GROUP_OPEN, &flags);
172 /* we have to handle mixed OPEN/FCNTL flags specially */
173 if (retropt_bool(opts, OPT_O_APPEND, &flag) >= 0 && flag)
174 flags |= O_APPEND;
175 if (retropt_bool(opts, OPT_O_NONBLOCK, &flag) >= 0 && flag)
176 flags |= O_NONBLOCK;
177 #ifdef O_ASYNC
178 if (retropt_bool(opts, OPT_O_ASYNC, &flag) >= 0 && flag)
179 flags |= O_ASYNC;
180 #endif
181 if (retropt_bool(opts, OPT_O_TRUNC, &flag) >= 0 && flag)
182 flags |= O_TRUNC;
183 #ifdef O_BINARY
184 if (retropt_bool(opts, OPT_O_BINARY, &flag) >= 0 && flag)
185 flags |= O_BINARY;
186 #endif
187 #ifdef O_TEXT
188 if (retropt_bool(opts, OPT_O_TEXT, &flag) >= 0 && flag)
189 flags |= O_TEXT;
190 #endif
191 #ifdef O_NOINHERIT
192 if (retropt_bool(opts, OPT_O_NOINHERIT, &flag) >= 0 && flag)
193 flags |= O_NOINHERIT;
194 #endif
195 #ifdef O_NOATIME
196 if (retropt_bool(opts, OPT_O_NOATIME, &flag) >= 0 && flag)
197 flags |= O_NOATIME;
198 #endif
200 retropt_modet(opts, OPT_PERM, &mode);
202 do {
203 fd = Open(path, flags, mode);
204 } while (fd < 0 && errno == EINTR);
205 if (fd < 0) {
206 Error4("open(\"%s\", 0%lo, 0%03o): %s",
207 path, flags, mode, strerror(errno));
208 return STAT_RETRYLATER;
210 /*0 Info4("open(\"%s\", 0%o, 0%03o) -> %d", path, flags, mode, fd);*/
211 applyopts_named(path, opts, PH_PASTOPEN);
212 #if 0
213 applyopts_named(path, opts, PH_FD);
214 applyopts(fd, opts, PH_FD);
215 applyopts_cloexec(fd, opts);
216 #endif
217 return fd;
220 /* Wrapper around Unlink() that handles the case of non existing file (ENOENT)
221 just as E_INFO. All other errors are handled with level. */
222 int xio_unlink(
223 const char *filename, /* the file to be removed */
224 int level) /* the severity level for other errors, e.g.E_ERROR */
226 int _errno;
228 if (Unlink(filename) < 0) {
229 _errno = errno;
230 if (errno == ENOENT) {
231 Info2("unlink(\"%s\"): %s", filename, strerror(errno));
232 } else {
233 Msg2(level, "unlink(\"%s\"): %s", filename, strerror(errno));
234 errno = _errno;
235 return -1;
238 return 0;
241 #endif /* _WITH_NAMED */