xref: /netbsd-src/external/bsd/am-utils/dist/conf/mtab/mtab_svr4.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	$NetBSD: mtab_svr4.c,v 1.1.1.2 2009/03/20 20:26:50 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2009 Erez Zadok
5  * Copyright (c) 1990 Jan-Simon Pendry
6  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7  * Copyright (c) 1990 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry at Imperial College, London.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgment:
23  *      This product includes software developed by the University of
24  *      California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *
42  * File: am-utils/conf/mtab/mtab_svr4.c
43  *
44  * How to manage the mount table file.  Based on other SVR3 ports.
45  *      -Erez Zadok <ezk@cs.columbia.edu>
46  */
47 
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <amu.h>
53 
54 /*
55  * file descriptor for lock file
56  * values: -1  no file-descriptor was set yet (or mnttab unlocked, or error
57  *             in locking).
58  *         >=0 legal file-descriptor value (file lock succeeded)
59  */
60 static int mntent_lock_fd = -1;
61 
62 
63 #ifdef MOUNT_TABLE_ON_FILE
64 static char mtlckname[] = "/etc/.mnttab.lock";
65 #endif /* MOUNT_TABLE_ON_FILE */
66 
67 
68 /****************************************************************************/
69 /*** Private functions                                                      */
70 /****************************************************************************/
71 
72 static void
73 unlockmnttab(void)
74 {
75 #ifdef MOUNT_TABLE_ON_FILE
76   if (mntent_lock_fd >= 0) {
77     close(mntent_lock_fd);
78     mntent_lock_fd = -1;
79   }
80 #endif /* MOUNT_TABLE_ON_FILE */
81 }
82 
83 
84 #ifdef MOUNT_TABLE_ON_FILE
85 static int
86 lockfile(int fd, int type)
87 {
88   struct flock lk;
89   int ret;
90 
91   lk.l_type = type;
92   lk.l_whence = 0;
93   lk.l_start = 0;
94   lk.l_len = 0;
95 
96   /*
97    * F_SETLKW means to block until the read or write block is free to be
98    * locked.
99    */
100   ret = fcntl(fd, F_SETLKW, &lk);
101   return ret;
102 }
103 #endif /* MOUNT_TABLE_ON_FILE */
104 
105 
106 /* return 0 if locking succeeded, -1 if failed */
107 static int
108 lockmnttab(void)
109 {
110 #ifdef MOUNT_TABLE_ON_FILE
111   /* if mnttab file is locked, all is well */
112   if (mntent_lock_fd >= 0)
113     return 0;
114 
115   /* need to lock mnttab file. first, open the file */
116   mntent_lock_fd = open(mtlckname, O_RDWR | O_CREAT, 0600);
117   if (mntent_lock_fd < 0) {
118     plog(XLOG_ERROR, "Unable to open/creat %s: %m", mtlckname);
119     return -1;
120   }
121 
122   /* if succeeded in opening the file, try to lock it */
123   if (lockfile(mntent_lock_fd, F_WRLCK) < 0) {
124     close(mntent_lock_fd);
125     mntent_lock_fd = -1;
126 #ifdef DEBUG
127     dlog("lock %s failed: %m", mtlckname);
128 #endif /* DEBUG */
129     return -1;
130   }
131 #else /* not MOUNT_TABLE_ON_FILE */
132   /* fake lock for in-kernel mount table */
133 #endif /* not MOUNT_TABLE_ON_FILE */
134 
135   /* finally, succeeded in also locking the file */
136   return 0;
137 }
138 
139 
140 /*
141  * Convert from solaris mnttab to Amd mntent.  Since am-utils uses
142  * native "struct mnttab" if available, this really copies fields of
143  * the same structure.
144  */
145 static mntent_t *
146 mnt_dup(const mntent_t *mtp)
147 {
148   mntent_t *mep = ALLOC(mntent_t);
149 
150   mep->mnt_fsname = strdup(mtp->mnt_fsname);
151   mep->mnt_dir = strdup(mtp->mnt_dir);
152   mep->mnt_type = strdup(mtp->mnt_type);
153   mep->mnt_opts = strdup(mtp->mnt_opts);
154   mep->mnt_time = strdup(mtp->mnt_time);
155 
156   return mep;
157 }
158 
159 
160 /*
161  * Adjust arguments in mntent_t.
162  */
163 #ifdef MOUNT_TABLE_ON_FILE
164 static mntent_t *
165 update_mnttab_fields(const mntent_t *mnt)
166 {
167   static mntent_t mt;
168   static char timestr[16];
169   struct timeval tv;
170 
171   /* most fields don't change, only update mnt_time below */
172   mt.mnt_fsname = mnt->mnt_fsname;
173   mt.mnt_dir = mnt->mnt_dir;
174   mt.mnt_type = mnt->mnt_type;
175   mt.mnt_opts = mnt->mnt_opts;
176 
177   /*
178    * Solaris 2.5 and newer take a second argument to gettimeofday().  If you
179    * find a useful svr4-like OS that uses the old style, and this code here
180    * fails, then create a new autoconf test that will determine the number
181    * of arguments gettimeofday() takes.  -Erez.
182    */
183   if (gettimeofday(&tv, NULL) < 0)
184     timestr[0] = '\0';
185   else
186     xsnprintf(timestr, sizeof(timestr), "%ld", tv.tv_sec);
187 
188   mt.mnt_time = timestr;
189 
190   return &mt;
191 }
192 #endif /* MOUNT_TABLE_ON_FILE */
193 
194 
195 static void
196 write_mntent_to_mtab(FILE *fp, const mntent_t *mnt)
197 {
198 #ifdef MOUNT_TABLE_ON_FILE
199   putmntent(fp, update_mnttab_fields(mnt));
200 #endif /* MOUNT_TABLE_ON_FILE */
201 }
202 
203 
204 /****************************************************************************/
205 /*** Public functions                                                       */
206 /****************************************************************************/
207 
208 
209 void
210 unlock_mntlist(void)
211 {
212   unlockmnttab();
213 }
214 
215 
216 /*
217  * Read a mount table into memory
218  */
219 mntlist *
220 read_mtab(char *fs, const char *mnttabname)
221 {
222   mntlist **mpp, *mhp;
223   FILE *fp;
224   mntent_t mountbuf;
225   int ret;
226 
227   if (lockmnttab() < 0)		/* failed locking */
228     return NULL;
229 
230   fp = fopen(mnttabname, "r");
231   if (fp == NULL) {
232     plog(XLOG_ERROR, "Can't open %s: %m", mnttabname);
233     return NULL;
234   }
235   mpp = &mhp;
236 
237   while ((ret = getmntent(fp, &mountbuf)) == 0) {
238     /*
239      * Allocate a new slot
240      */
241     *mpp = ALLOC(struct mntlist);
242 
243     /*
244      * Copy the data returned by getmntent
245      */
246     (*mpp)->mnt = mnt_dup(&mountbuf);
247 
248     /*
249      * Move to next pointer
250      */
251     mpp = &(*mpp)->mnext;
252   }
253 
254   if (ret > 0) {
255     plog(XLOG_ERROR, "read error on %s: %m", mnttabname);
256     unlockmnttab();
257     mhp = NULL;
258   }
259   *mpp = NULL;
260 
261   fclose(fp);
262   return mhp;
263 }
264 
265 
266 void
267 rewrite_mtab(mntlist *mp, const char *mnttabname)
268 {
269   FILE *fp;
270 
271   assert(mntent_lock_fd >= 0);	/* ensure lock fd is valid */
272 
273   fp = fopen(mnttabname, "r+");
274   if (fp == NULL) {
275     plog(XLOG_ERROR, "Can't open %s: %m", mnttabname);
276     unlockmnttab();
277     return;
278   }
279   while (mp) {
280     if (mp->mnt)
281       write_mntent_to_mtab(fp, mp->mnt);
282     mp = mp->mnext;
283   }
284 
285   ftruncate(fileno(fp), ftell(fp));
286   fclose(fp);
287   unlockmnttab();
288 }
289 
290 
291 void
292 write_mntent(mntent_t *mtp, const char *mnttabname)
293 {
294   FILE *fp;
295 
296   if (lockmnttab() < 0)
297     return;
298 
299   fp = fopen(mnttabname, "a");
300   if (fp == NULL) {
301     plog(XLOG_ERROR, "Unable to append %s: %m", mnttabname);
302     return;
303   }
304   write_mntent_to_mtab(fp, mtp);
305 
306   fclose(fp);
307   unlockmnttab();
308 }
309