OSDN Git Service

3c54495489bf0857475cf0bce0a63d12eed79c26
[uclinux-h8/uClibc.git] / libc / pwd_grp / lckpwdf.c
1 /* vi: set sw=4 ts=4: */
2 /* Handle locking of password file.
3    Copyright (C) 1996,98,2000,02 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #include <features.h>
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/file.h>
28 #include <paths.h>
29 #include <shadow.h>
30
31 /* How long to wait for getting the lock before returning with an error.  */
32 #define TIMEOUT 15 /* sec */
33
34 /* File descriptor for lock file.  */
35 static int lock_fd = -1;
36
37 /* Prevent problems in multithreaded program by using mutex.  */
38 #include <bits/uClibc_mutex.h>
39 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
40
41 /* Prototypes for local functions.  */
42 static void noop_handler (int __sig);
43
44
45 int
46 lckpwdf (void)
47 {
48   sigset_t saved_set;                   /* Saved set of caught signals.  */
49   struct sigaction saved_act;           /* Saved signal action.  */
50   sigset_t new_set;                     /* New set of caught signals.  */
51   struct sigaction new_act;             /* New signal action.  */
52   struct flock fl;                      /* Information struct for locking.  */
53   int result;
54   int rv = -1;
55
56   if (lock_fd != -1)
57     /* Still locked by own process.  */
58     return -1;
59
60   /* Prevent problems caused by multiple threads.  */
61   __UCLIBC_MUTEX_LOCK(mylock);
62
63   lock_fd = open (_PATH_PASSWD, O_WRONLY | O_CLOEXEC);
64   if (lock_fd == -1) {
65     goto DONE;
66   }
67 #ifndef __ASSUME_O_CLOEXEC
68   /* Make sure file gets correctly closed when process finished.  */
69   fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
70 #endif
71
72   /* Now we have to get exclusive write access.  Since multiple
73      process could try this we won't stop when it first fails.
74      Instead we set a timeout for the system call.  Once the timer
75      expires it is likely that there are some problems which cannot be
76      resolved by waiting. (sa_flags have no SA_RESTART. Thus SIGALRM
77      will EINTR fcntl(F_SETLKW)
78
79      It is important that we don't change the signal state.  We must
80      restore the old signal behaviour.  */
81   memset (&new_act, '\0', sizeof (new_act));
82   new_act.sa_handler = noop_handler;
83   __sigfillset (&new_act.sa_mask);
84
85   /* Install new action handler for alarm and save old.
86    * This never fails in Linux.  */
87   sigaction (SIGALRM, &new_act, &saved_act);
88
89   /* Now make sure the alarm signal is not blocked.  */
90   __sigemptyset (&new_set);
91   __sigaddset (&new_set, SIGALRM);
92   sigprocmask (SIG_UNBLOCK, &new_set, &saved_set);
93
94   /* Start timer.  If we cannot get the lock in the specified time we
95      get a signal.  */
96   alarm (TIMEOUT);
97
98   /* Try to get the lock.  */
99   memset (&fl, '\0', sizeof (fl));
100   if (F_WRLCK)
101     fl.l_type = F_WRLCK;
102   if (SEEK_SET)
103     fl.l_whence = SEEK_SET;
104   result = fcntl (lock_fd, F_SETLKW, &fl);
105
106   /* Clear alarm.  */
107   alarm (0);
108
109   sigprocmask (SIG_SETMASK, &saved_set, NULL);
110   sigaction (SIGALRM, &saved_act, NULL);
111
112   if (result < 0) {
113     close(lock_fd);
114     lock_fd = -1;
115     goto DONE;
116   }
117   rv = 0;
118
119 DONE:
120   __UCLIBC_MUTEX_UNLOCK(mylock);
121   return rv;
122 }
123
124
125 int
126 ulckpwdf (void)
127 {
128   int result;
129
130   if (lock_fd == -1)
131     /* There is no lock set.  */
132     result = -1;
133   else
134     {
135       /* Prevent problems caused by multiple threads.  */
136       __UCLIBC_MUTEX_LOCK(mylock);
137
138       result = close (lock_fd);
139
140       /* Mark descriptor as unused.  */
141       lock_fd = -1;
142
143       /* Clear mutex.  */
144       __UCLIBC_MUTEX_UNLOCK(mylock);
145     }
146
147   return result;
148 }
149
150
151 static void
152 noop_handler (int sig attribute_unused) {
153
154   /* We simply return which makes the `fcntl' call return with an error.  */
155 }