1 /* $NetBSD: fsshare.c,v 1.1 2009/08/07 20:57:56 haad Exp $ */
4 * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 /* __FBSDID("$FreeBSD: src/compat/opensolaris/misc/fsshare.c,v 1.2 2007/04/21 13:17:23 pjd Exp $"); */
31 __RCSID("$NetBSD: fsshare.c,v 1.1 2009/08/07 20:57:56 haad Exp $");
33 #include <sys/param.h>
42 #include <pathnames.h> /* _PATH_MOUNTDPID */
45 #define FILE_HEADER "# !!! DO NOT EDIT THIS FILE MANUALLY !!!\n\n"
47 #define MAXLINESIZE (PATH_MAX + OPTSSIZE)
55 pfh
= fopen(_PATH_MOUNTDPID
, "r");
58 fscanf(pfh
, "%d", &pid
);
60 kill((pid_t
)pid
, SIGHUP
);
64 * Read one line from a file. Skip comments, empty lines and a line with a
65 * mountpoint specified in the 'skip' argument.
68 zgetline(FILE *fd
, const char *skip
)
70 static char line
[MAXLINESIZE
];
75 skiplen
= strlen(skip
);
77 s
= fgets(line
, sizeof(line
), fd
);
80 /* Skip empty lines and comments. */
81 if (line
[0] == '\n' || line
[0] == '#')
84 if (line
[len
- 1] == '\n')
87 /* Skip the given mountpoint. */
88 if (skip
!= NULL
&& strncmp(skip
, line
, skiplen
) == 0 &&
89 (last
== '\t' || last
== ' ' || last
== '\0')) {
98 * Function translate options to a format acceptable by exports(5), eg.
100 * -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org 69.147.83.54
102 * Accepted input formats:
104 * ro,network=192.168.0.0,mask=255.255.255.0,maproot=0,freefall.freebsd.org
105 * ro network=192.168.0.0 mask=255.255.255.0 maproot=0 freefall.freebsd.org
106 * -ro,-network=192.168.0.0,-mask=255.255.255.0,-maproot=0,freefall.freebsd.org
107 * -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org
109 * Recognized keywords:
111 * ro, maproot, mapall, mask, network, alldirs, public, webnfs, index, quiet
114 static const char *known_opts
[] = { "ro", "maproot", "mapall", "mask",
115 "network", "alldirs", "public", "webnfs", "index", "quiet", NULL
};
117 translate_opts(const char *shareopts
)
119 static char newopts
[OPTSSIZE
];
120 char oldopts
[OPTSSIZE
];
125 strlcpy(oldopts
, shareopts
, sizeof(oldopts
));
128 while ((o
= strsep(&s
, "-, ")) != NULL
) {
131 for (i
= 0; known_opts
[i
] != NULL
; i
++) {
132 len
= strlen(known_opts
[i
]);
133 if (strncmp(known_opts
[i
], o
, len
) == 0 &&
134 (o
[len
] == '\0' || o
[len
] == '=')) {
135 strlcat(newopts
, "-", sizeof(newopts
));
139 strlcat(newopts
, o
, sizeof(newopts
));
140 strlcat(newopts
, " ", sizeof(newopts
));
146 fsshare_main(const char *file
, const char *mountpoint
, const char *shareopts
,
149 char tmpfile
[PATH_MAX
];
154 newfd
= oldfd
= NULL
;
158 * Create temporary file in the same directory, so we can atomically
161 if (strlcpy(tmpfile
, file
, sizeof(tmpfile
)) >= sizeof(tmpfile
))
162 return (ENAMETOOLONG
);
163 if (strlcat(tmpfile
, ".XXXXXXXX", sizeof(tmpfile
)) >= sizeof(tmpfile
))
164 return (ENAMETOOLONG
);
165 fd
= mkstemp(tmpfile
);
169 * File name is random, so we don't really need file lock now, but it
170 * will be needed after rename(2).
172 error
= flock(fd
, LOCK_EX
);
173 assert(error
== 0 || (error
== -1 && errno
== EOPNOTSUPP
));
174 newfd
= fdopen(fd
, "r+");
175 assert(newfd
!= NULL
);
176 /* Open old exports file. */
177 oldfd
= fopen(file
, "r");
180 if (errno
!= ENOENT
) {
185 /* If there is no exports file, ignore the error. */
192 error
= flock(fileno(oldfd
), LOCK_EX
);
193 assert(error
== 0 || (error
== -1 && errno
== EOPNOTSUPP
));
197 /* Place big, fat warning at the begining of the file. */
198 fprintf(newfd
, "%s", FILE_HEADER
);
199 while (oldfd
!= NULL
&& (line
= zgetline(oldfd
, mountpoint
)) != NULL
)
200 fprintf(newfd
, "%s\n", line
);
201 if (oldfd
!= NULL
&& ferror(oldfd
) != 0) {
202 error
= ferror(oldfd
);
205 if (ferror(newfd
) != 0) {
206 error
= ferror(newfd
);
210 fprintf(newfd
, "%s\t%s\n", mountpoint
,
211 translate_opts(shareopts
));
218 if (rename(tmpfile
, file
) == -1) {
223 * Send SIGHUP to mountd, but unlock exports file later.
229 flock(fileno(oldfd
), LOCK_UN
);
233 flock(fileno(newfd
), LOCK_UN
);
240 * Add the given mountpoint to the given exports file.
243 fsshare(const char *file
, const char *mountpoint
, const char *shareopts
)
246 return (fsshare_main(file
, mountpoint
, shareopts
, 1));
250 * Remove the given mountpoint from the given exports file.
253 fsunshare(const char *file
, const char *mountpoint
)
256 return (fsshare_main(file
, mountpoint
, NULL
, 0));