]> git.pld-linux.org Git - projects/setup.git/blame - joinpasswd.c
Check write/close return values.
[projects/setup.git] / joinpasswd.c
CommitLineData
31aff165
MM
1/*
2 * $Id$
3 *
e040c79e 4 * Copyright (c) 2001 Michal Moskal <malekith@pld-linux.org>.
31aff165
MM
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Michal Moskal.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *
35 *
36 * USAGE: joinpasswd
37 *
38 * Add entries from freshly created {passwd,shadow,group}.rpmnew to existing
39 * {passwd,shadow,group}. It is usable as part of setup package, during upgrade
40 * where new system user/group is to be added. If entry is already found in
3da0d83f
MM
41 * system database, it is left, otherwise it is added. UIDs/GIDs are *not*
42 * checked anyhow.
31aff165
MM
43 *
44 * For typical sizes of files in setup package, it takes about 1 second per
45 * 20000 users in system database on Pentium class machine. After static link
46 * against uClibc it is under 2k on x86. Stdio hasn't been used intentionally.
47 *
e040c79e 48 * Written for PLD Linux (http://www.pld-linux.org/) setup package.
31aff165
MM
49 *
50 * Compilation against uClibc:
51 * UCROOT=/usr/lib/bootdisk/usr
52 * gcc -I$UCROOT/include -nostdlib -O2 joinpasswd.c $UCROOT/lib/crt0.o \
53 * $UCROOT/lib/libc.a -lgcc -o joinpasswd
54 * strip -R .comment -R .note joinpasswd
55 *
e040c79e 56 * The idea of this program comes from Lukasz Dobrek <dobrek@pld-linux.org>.
31aff165
MM
57 *
58 */
59
60#include <sys/types.h>
61#include <sys/mman.h>
62#include <sys/stat.h>
63#include <unistd.h>
64#include <fcntl.h>
65#include <stdlib.h>
66#include <string.h>
507b603d 67#include <signal.h>
31aff165
MM
68
69#define FILE1 "/etc/passwd"
70#define FILE2 "/etc/shadow"
71#define FILE3 "/etc/group"
1a43487e 72#define FILE4 "/etc/gshadow"
31aff165 73
507b603d
MM
74/* #define OLD_LOCK */
75
76#define LOCK_FILE "/etc/.pwd.lock"
77
31aff165 78#define SUFFIX ".rpmnew"
f88ff4b9
MM
79/* maybe "-" or sth? */
80#define BACKUP ".old"
31aff165
MM
81
82/* #define SILENT */
83
84void eputs(const char *msg)
85{
86 write(2, msg, strlen(msg));
87}
88
89void fatal(const char *msg)
90{
91 eputs(msg);
92 eputs("\n");
93 exit(1);
94}
95
96char *map_file(const char *name, int *sz)
97{
98 int fd;
99 void *ptr;
100 struct stat st;
101
102 fd = open(name, O_RDONLY);
103 if (fd == -1)
104 return NULL;
bd3b57f6
AM
105 if (fstat(fd, &st) < 0)
106 return NULL;
31aff165
MM
107 *sz = st.st_size;
108 ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
109 if (ptr == MAP_FAILED)
110 return NULL;
111
112 return ptr;
113}
114
115int exist(char *id, int id_len, char *ptr, int sz)
116{
117 int i;
118
119 for (i = 0; i < sz; ) {
120 if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0)
121 return 1;
122 while (i < sz && ptr[i] != '\n')
123 i++;
124 i++;
125 }
126
127 return 0;
128}
129
3da0d83f
MM
130void itoa(char *buf, long i)
131{
132 char tmp[32];
133 char *p;
134
135 if (i < 0) {
136 strcpy(buf, "-");
137 buf++;
138 i = -i;
139 }
140 if (i == 0) {
141 strcpy(buf, "0");
142 return;
143 }
144 for (p = tmp; i; i /= 10)
145 *p++ = (i % 10) + '0';
146 while (p > tmp)
147 *buf++ = *--p;
148 *buf = 0;
149}
150
507b603d
MM
151#ifndef OLD_LOCK
152int lock_fd = -1;
153void noop(int x)
154{
155 (void)x;
156}
157#endif
158
3da0d83f
MM
159int try_lock(const char *name)
160{
507b603d 161#ifdef OLD_LOCK
3da0d83f
MM
162 char file[strlen(name) + 32], lock[strlen(name) + 32];
163 char buf[32];
164 int fd;
165 long pid;
166
167 strcpy(lock, name);
168 strcpy(file, name);
169 strcat(lock, ".lock");
170 itoa(buf, (long)getpid());
171 strcat(file, ".");
172 strcat(file, buf);
173
174 fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
175 if (fd < 0)
176 return -1;
ed0f82b9
AM
177 if (write(fd, buf, strlen(buf)) < 0) {
178 close(fd);
179 return -1;
180 }
181 if (close(fd) < 0)
182 return -1;
3da0d83f
MM
183
184 if (link(file, lock) == 0) {
185 unlink(file);
186 return 0;
187 }
188
189 fd = open(lock, O_RDONLY);
190 if (fd < 0)
191 goto oops;
192 memset(buf, 0, sizeof(buf));
193 read(fd, buf, sizeof(buf));
194 pid = atol(buf);
195 if (pid == 0 || kill(pid, 0) != 0) {
196 /* stale lock */
197 unlink(file);
198 unlink(lock);
199 /* try again */
200 return try_lock(name);
201 }
202
203oops:
204 unlink(file);
205 return -1;
507b603d
MM
206#else
207 struct flock fl;
208
209 if (lock_fd != -1)
210 return -1;
211 lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
212 if (lock_fd == -1)
213 return -1;
214 signal(SIGALRM, noop);
215 alarm(15);
216 memset(&fl, 0, sizeof(fl));
217 fl.l_type = F_WRLCK;
218 fl.l_whence = SEEK_SET;
219 if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
220 alarm(0);
221 close(lock_fd);
222 lock_fd = -1;
223 return -1;
224 }
225 alarm(0);
226
227 return 0;
228#endif
3da0d83f
MM
229}
230
231void unlock(const char *name)
232{
507b603d 233#ifdef OLD_LOCK
3da0d83f
MM
234 char lock[strlen(name) + 32];
235
236 strcpy(lock, name);
237 strcat(lock, ".lock");
238 unlink(lock);
507b603d
MM
239#else
240 if (lock_fd != -1)
241 close(lock_fd);
242 lock_fd = -1;
243#endif
3da0d83f
MM
244}
245
246void lock(const char *name)
247{
248 int n;
249
250 n = 5;
251 while (n--) {
252 if (try_lock(name) == 0)
253 return;
254 eputs("waiting for lock...\n");
255 sleep(1);
256 }
257 fatal("cannot get lock");
258}
259
f88ff4b9 260int join(const char *old_name, const char *new_name, const char *backup_name)
31aff165
MM
261{
262 char *old, *new, *id;
263 int i, fd;
264 int old_sz, new_sz;
265
266 new = map_file(new_name, &new_sz);
267 if (new == NULL)
268 return -1;
3da0d83f
MM
269
270 lock(old_name);
31aff165
MM
271 old = map_file(old_name, &old_sz);
272 if (old == NULL)
273 fatal("cannot mmap old");
f88ff4b9
MM
274
275 fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
276 if (fd < 0)
277 fatal("cannot make backup");
278 write(fd, old, old_sz);
279 close(fd);
280
31aff165 281#ifndef SILENT
128250fd 282 eputs("merging content of `");
31aff165
MM
283 eputs(old_name);
284 eputs("' with `");
285 eputs(new_name);
286 eputs("'\n");
287#endif /* SILENT */
288
289 fd = open(old_name, O_WRONLY|O_APPEND);
bd3b57f6
AM
290 if (fd < 0)
291 fatal("cannot open old file");
31aff165
MM
292
293 for (i = 0; i < new_sz; ) {
294 id = new + i;
295 while (i < new_sz && new[i] != ':' && new[i] != '\n')
296 i++;
297 if (i < new_sz && new[i] == ':') {
298 int id_len, line_len;
299
300 id_len = i - (id - new);
301 while (i < new_sz && new[i] != '\n')
302 i++;
303 if (i < new_sz)
304 i++;
305 line_len = i - (id - new);
306
307 if (!exist(id, id_len, old, old_sz)) {
308#ifndef SILENT
309 eputs(old_name);
310 eputs(": adding `");
311 write(2, id, id_len);
312 eputs("'\n");
313#endif /* SILENT */
314 write(fd, id, line_len);
315 }
316 } else if (i < new_sz)
317 i++;
318 }
319
320#if 0
321 /* user may want to exime this file... */
322 unlink(new_name);
323#endif
3da0d83f 324 unlock(old_name);
31aff165
MM
325
326 return 0;
327}
328
329int main()
330{
1a43487e 331#if 1
3da0d83f
MM
332 join(FILE1, FILE1 SUFFIX, FILE1 BACKUP);
333 join(FILE2, FILE2 SUFFIX, FILE2 BACKUP);
334 join(FILE3, FILE3 SUFFIX, FILE3 BACKUP);
1a43487e 335 join(FILE4, FILE4 SUFFIX, FILE4 BACKUP);
31aff165 336#else
3da0d83f 337 join("test", "test.new", "test.old");
31aff165
MM
338#endif
339 return 0;
340}
This page took 0.119535 seconds and 4 git commands to generate.