OSDN Git Service

Replace FSF snail mail address with URLs
[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, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <features.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/file.h>
27 #include <paths.h>
28 #include <shadow.h>
29
30 /* How long to wait for getting the lock before returning with an error.  */
31 #define TIMEOUT 15 /* sec */
32
33 /* File descriptor for lock file.  */
34 static int lock_fd = -1;
35
36 /* Prevent problems in multithreaded program by using mutex.  */
37 #include <bits/uClibc_mutex.h>
38 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
39
40 /* Prototypes for local functions.  */
41 static void noop_handler (int __sig);
42
43
44 int
45 lckpwdf (void)
46 {
47   sigset_t saved_set;                   /* Saved set of caught signals.  */
48   struct sigaction saved_act;           /* Saved signal action.  */
49   sigset_t new_set;                     /* New set of caught signals.  */
50   struct sigaction new_act;             /* New signal action.  */
51   struct flock fl;                      /* Information struct for locking.  */
52   int result;
53   int rv = -1;
54
55   if (lock_fd != -1)
56     /* Still locked by own process.  */
57     return -1;
58
59   /* Prevent problems caused by multiple threads.  */
60   __UCLIBC_MUTEX_LOCK(mylock);
61
62   lock_fd = open (_PATH_PASSWD, O_WRONLY | O_CLOEXEC);
63   if (lock_fd == -1) {
64     goto DONE;
65   }
66 #ifndef __ASSUME_O_CLOEXEC
67   /* Make sure file gets correctly closed when process finished.  */
68   fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
69 #endif
70
71   /* Now we have to get exclusive write access.  Since multiple
72      process could try this we won't stop when it first fails.
73      Instead we set a timeout for the system call.  Once the timer
74      expires it is likely that there are some problems which cannot be
75      resolved by waiting. (sa_flags have no SA_RESTART. Thus SIGALRM
76      will EINTR fcntl(F_SETLKW)
77
78      It is important that we don't change the signal state.  We must
79      restore the old signal behaviour.  */
80   memset (&new_act, '\0', sizeof (new_act));
81   new_act.sa_handler = noop_handler;
82   __sigfillset (&new_act.sa_mask);
83
84   /* Install new action handler for alarm and save old.
85    * This never fails in Linux.  */
86   sigaction (SIGALRM, &new_act, &saved_act);
87
88   /* Now make sure the alarm signal is not blocked.  */
89   __sigemptyset (&new_set);
90   __sigaddset (&new_set, SIGALRM);
91   sigprocmask (SIG_UNBLOCK, &new_set, &saved_set);
92
93   /* Start timer.  If we cannot get the lock in the specified time we
94      get a signal.  */
95   alarm (TIMEOUT);
96
97   /* Try to get the lock.  */
98   memset (&fl, '\0', sizeof (fl));
99   if (F_WRLCK)
100     fl.l_type = F_WRLCK;
101   if (SEEK_SET)
102     fl.l_whence = SEEK_SET;
103   result = fcntl (lock_fd, F_SETLKW, &fl);
104
105   /* Clear alarm.  */
106   alarm (0);
107
108   sigprocmask (SIG_SETMASK, &saved_set, NULL);
109   sigaction (SIGALRM, &saved_act, NULL);
110
111   if (result < 0) {
112     close(lock_fd);
113     lock_fd = -1;
114     goto DONE;
115   }
116   rv = 0;
117
118 DONE:
119   __UCLIBC_MUTEX_UNLOCK(mylock);
120   return rv;
121 }
122
123
124 int
125 ulckpwdf (void)
126 {
127   int result;
128
129   if (lock_fd == -1)
130     /* There is no lock set.  */
131     result = -1;
132   else
133     {
134       /* Prevent problems caused by multiple threads.  */
135       __UCLIBC_MUTEX_LOCK(mylock);
136
137       result = close (lock_fd);
138
139       /* Mark descriptor as unused.  */
140       lock_fd = -1;
141
142       /* Clear mutex.  */
143       __UCLIBC_MUTEX_UNLOCK(mylock);
144     }
145
146   return result;
147 }
148
149
150 static void
151 noop_handler (int sig attribute_unused) {
152
153   /* We simply return which makes the `fcntl' call return with an error.  */
154 }