]> git.pld-linux.org Git - projects/setup.git/blame - joinpasswd.c
- don't set HISTFILE to .history - nautilus uses it for some stupid xmls
[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>
cbc25e75 63#include <stdio.h>
8356227d 64#include <errno.h>
31aff165 65#include <unistd.h>
cbc25e75 66#include <stdarg.h>
31aff165
MM
67#include <fcntl.h>
68#include <stdlib.h>
69#include <string.h>
507b603d 70#include <signal.h>
31aff165
MM
71
72#define FILE1 "/etc/passwd"
73#define FILE2 "/etc/shadow"
74#define FILE3 "/etc/group"
1a43487e 75#define FILE4 "/etc/gshadow"
31aff165 76
507b603d
MM
77/* #define OLD_LOCK */
78
79#define LOCK_FILE "/etc/.pwd.lock"
80
31aff165 81#define SUFFIX ".rpmnew"
f88ff4b9
MM
82/* maybe "-" or sth? */
83#define BACKUP ".old"
31aff165
MM
84
85/* #define SILENT */
86
cbc25e75 87void eputs(const char *fmt, ...)
31aff165 88{
cbc25e75
AM
89 va_list args;
90
91 va_start(args, fmt);
92 vfprintf(stderr, fmt, args);
93 va_end(args);
31aff165
MM
94}
95
cbc25e75 96void fatal(const char *fmt, ...)
31aff165 97{
cbc25e75
AM
98 va_list args;
99
100 va_start(args, fmt);
101 eputs(fmt, args);
102 va_end(args);
103
31aff165
MM
104 eputs("\n");
105 exit(1);
106}
107
108char *map_file(const char *name, int *sz)
109{
110 int fd;
111 void *ptr;
112 struct stat st;
113
114 fd = open(name, O_RDONLY);
115 if (fd == -1)
116 return NULL;
bd3b57f6
AM
117 if (fstat(fd, &st) < 0)
118 return NULL;
31aff165
MM
119 *sz = st.st_size;
120 ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
121 if (ptr == MAP_FAILED)
122 return NULL;
123
124 return ptr;
125}
126
127int exist(char *id, int id_len, char *ptr, int sz)
128{
129 int i;
130
131 for (i = 0; i < sz; ) {
132 if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0)
133 return 1;
134 while (i < sz && ptr[i] != '\n')
135 i++;
136 i++;
137 }
138
139 return 0;
140}
141
3da0d83f
MM
142void itoa(char *buf, long i)
143{
144 char tmp[32];
145 char *p;
146
147 if (i < 0) {
148 strcpy(buf, "-");
149 buf++;
150 i = -i;
151 }
152 if (i == 0) {
153 strcpy(buf, "0");
154 return;
155 }
156 for (p = tmp; i; i /= 10)
157 *p++ = (i % 10) + '0';
158 while (p > tmp)
159 *buf++ = *--p;
160 *buf = 0;
161}
162
507b603d
MM
163#ifndef OLD_LOCK
164int lock_fd = -1;
165void noop(int x)
166{
167 (void)x;
168}
169#endif
170
3da0d83f
MM
171int try_lock(const char *name)
172{
507b603d 173#ifdef OLD_LOCK
3da0d83f
MM
174 char file[strlen(name) + 32], lock[strlen(name) + 32];
175 char buf[32];
176 int fd;
177 long pid;
178
179 strcpy(lock, name);
180 strcpy(file, name);
181 strcat(lock, ".lock");
182 itoa(buf, (long)getpid());
183 strcat(file, ".");
184 strcat(file, buf);
185
186 fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
187 if (fd < 0)
188 return -1;
ed0f82b9
AM
189 if (write(fd, buf, strlen(buf)) < 0) {
190 close(fd);
191 return -1;
192 }
193 if (close(fd) < 0)
194 return -1;
3da0d83f
MM
195
196 if (link(file, lock) == 0) {
197 unlink(file);
198 return 0;
199 }
200
201 fd = open(lock, O_RDONLY);
202 if (fd < 0)
203 goto oops;
204 memset(buf, 0, sizeof(buf));
205 read(fd, buf, sizeof(buf));
206 pid = atol(buf);
207 if (pid == 0 || kill(pid, 0) != 0) {
208 /* stale lock */
209 unlink(file);
210 unlink(lock);
211 /* try again */
212 return try_lock(name);
213 }
214
215oops:
216 unlink(file);
217 return -1;
507b603d
MM
218#else
219 struct flock fl;
220
221 if (lock_fd != -1)
222 return -1;
223 lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
224 if (lock_fd == -1)
225 return -1;
226 signal(SIGALRM, noop);
227 alarm(15);
228 memset(&fl, 0, sizeof(fl));
229 fl.l_type = F_WRLCK;
230 fl.l_whence = SEEK_SET;
231 if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
232 alarm(0);
233 close(lock_fd);
234 lock_fd = -1;
235 return -1;
236 }
237 alarm(0);
238
239 return 0;
240#endif
3da0d83f
MM
241}
242
243void unlock(const char *name)
244{
507b603d 245#ifdef OLD_LOCK
3da0d83f
MM
246 char lock[strlen(name) + 32];
247
248 strcpy(lock, name);
249 strcat(lock, ".lock");
250 unlink(lock);
507b603d
MM
251#else
252 if (lock_fd != -1)
253 close(lock_fd);
254 lock_fd = -1;
255#endif
3da0d83f
MM
256}
257
258void lock(const char *name)
259{
260 int n;
261
262 n = 5;
263 while (n--) {
264 if (try_lock(name) == 0)
265 return;
266 eputs("waiting for lock...\n");
267 sleep(1);
268 }
269 fatal("cannot get lock");
270}
271
f88ff4b9 272int join(const char *old_name, const char *new_name, const char *backup_name)
31aff165
MM
273{
274 char *old, *new, *id;
275 int i, fd;
276 int old_sz, new_sz;
277
278 new = map_file(new_name, &new_sz);
279 if (new == NULL)
280 return -1;
3da0d83f
MM
281
282 lock(old_name);
31aff165
MM
283 old = map_file(old_name, &old_sz);
284 if (old == NULL)
cbc25e75 285 fatal("cannot mmap file `%s': %m", old_name);
f88ff4b9
MM
286
287 fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
288 if (fd < 0)
cbc25e75 289 fatal("cannot create backup file `%s': %m", backup_name);
8356227d 290 if (write(fd, old, old_sz) < 0)
cbc25e75 291 fatal("writting to backup file `%s' failed: %m", backup_name);
8356227d 292 if (fsync(fd) < 0)
cbc25e75 293 fatal("syncing backup file `%s' failed: %m", backup_name);
8356227d 294 if (close(fd) < 0)
cbc25e75 295 fatal("closing backup file `%s' failed: %m", backup_name);
f88ff4b9 296
31aff165 297#ifndef SILENT
128250fd 298 eputs("merging content of `");
31aff165
MM
299 eputs(old_name);
300 eputs("' with `");
301 eputs(new_name);
302 eputs("'\n");
303#endif /* SILENT */
304
305 fd = open(old_name, O_WRONLY|O_APPEND);
bd3b57f6 306 if (fd < 0)
cbc25e75 307 fatal("cannot open old file `%s': %m", old_name);
31aff165
MM
308
309 for (i = 0; i < new_sz; ) {
310 id = new + i;
311 while (i < new_sz && new[i] != ':' && new[i] != '\n')
312 i++;
313 if (i < new_sz && new[i] == ':') {
314 int id_len, line_len;
315
316 id_len = i - (id - new);
317 while (i < new_sz && new[i] != '\n')
318 i++;
319 if (i < new_sz)
320 i++;
321 line_len = i - (id - new);
322
323 if (!exist(id, id_len, old, old_sz)) {
324#ifndef SILENT
325 eputs(old_name);
326 eputs(": adding `");
327 write(2, id, id_len);
328 eputs("'\n");
329#endif /* SILENT */
8356227d 330 if (write(fd, id, line_len) < 0)
cbc25e75 331 fatal("writting line to `%s' failed, check backup file: %m", old_name);
31aff165
MM
332 }
333 } else if (i < new_sz)
334 i++;
335 }
bd9aee69
AM
336 fsync(fd);
337 close(fd);
31aff165
MM
338
339#if 0
340 /* user may want to exime this file... */
341 unlink(new_name);
342#endif
3da0d83f 343 unlock(old_name);
31aff165
MM
344
345 return 0;
346}
347
348int main()
349{
1a43487e 350#if 1
3da0d83f
MM
351 join(FILE1, FILE1 SUFFIX, FILE1 BACKUP);
352 join(FILE2, FILE2 SUFFIX, FILE2 BACKUP);
353 join(FILE3, FILE3 SUFFIX, FILE3 BACKUP);
1a43487e 354 join(FILE4, FILE4 SUFFIX, FILE4 BACKUP);
31aff165 355#else
3da0d83f 356 join("test", "test.new", "test.old");
31aff165
MM
357#endif
358 return 0;
359}
This page took 0.134694 seconds and 4 git commands to generate.