/* * $Id$ * * Copyright (c) 2001 Michal Moskal . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Michal Moskal. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * * USAGE: joinpasswd * * Add entries from freshly created {passwd,shadow,group}.rpmnew to existing * {passwd,shadow,group}. It is usable as part of setup package, during upgrade * where new system user/group is to be added. If entry is already found in * system database, it is left, otherwise it is added. UIDs/GIDs are *not* checked * anyhow. * * For typical sizes of files in setup package, it takes about 1 second per * 20000 users in system database on Pentium class machine. After static link * against uClibc it is under 2k on x86. Stdio hasn't been used intentionally. * * Written for PLD GNU/Linux (http://www.pld.org.pl) setup package. * * Compilation against uClibc: * UCROOT=/usr/lib/bootdisk/usr * gcc -I$UCROOT/include -nostdlib -O2 joinpasswd.c $UCROOT/lib/crt0.o \ * $UCROOT/lib/libc.a -lgcc -o joinpasswd * strip -R .comment -R .note joinpasswd * * The idea of this program comes from Lukasz Dobrek . * */ #include #include #include #include #include #include #include #define FILE1 "/etc/passwd" #define FILE2 "/etc/shadow" #define FILE3 "/etc/group" #define SUFFIX ".rpmnew" /* maybe "-" or sth? */ #define BACKUP ".old" /* #define SILENT */ void eputs(const char *msg) { write(2, msg, strlen(msg)); } void fatal(const char *msg) { eputs(msg); eputs("\n"); exit(1); } char *map_file(const char *name, int *sz) { int fd; void *ptr; struct stat st; fd = open(name, O_RDONLY); if (fd == -1) return NULL; fstat(fd, &st); *sz = st.st_size; ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (ptr == MAP_FAILED) return NULL; return ptr; } int exist(char *id, int id_len, char *ptr, int sz) { int i; for (i = 0; i < sz; ) { if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0) return 1; while (i < sz && ptr[i] != '\n') i++; i++; } return 0; } int join(const char *old_name, const char *new_name, const char *backup_name) { char *old, *new, *id; int i, fd; int old_sz, new_sz; new = map_file(new_name, &new_sz); if (new == NULL) return -1; old = map_file(old_name, &old_sz); if (old == NULL) fatal("cannot mmap old"); fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd < 0) fatal("cannot make backup"); write(fd, old, old_sz); close(fd); #ifndef SILENT eputs("marging contest of `"); eputs(old_name); eputs("' with `"); eputs(new_name); eputs("'\n"); #endif /* SILENT */ fd = open(old_name, O_WRONLY|O_APPEND); for (i = 0; i < new_sz; ) { id = new + i; while (i < new_sz && new[i] != ':' && new[i] != '\n') i++; if (i < new_sz && new[i] == ':') { int id_len, line_len; id_len = i - (id - new); while (i < new_sz && new[i] != '\n') i++; if (i < new_sz) i++; line_len = i - (id - new); if (!exist(id, id_len, old, old_sz)) { #ifndef SILENT eputs(old_name); eputs(": adding `"); write(2, id, id_len); eputs("'\n"); #endif /* SILENT */ write(fd, id, line_len); } } else if (i < new_sz) i++; } #if 0 /* user may want to exime this file... */ unlink(new_name); #endif return 0; } int main() { #if 1 join(FILE1, FILE1 SUFFIX); join(FILE2, FILE2 SUFFIX); join(FILE3, FILE3 SUFFIX); #else join("test", "test.new"); #endif return 0; }