/* * $Id$ * * Copyright (c) 2001 Michal Moskal . * Copyright (c) 2009 Jan Rękorajski . * 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: grouprename old-name new-name * * Change the name of a group from old-name to new-name, * It is usable as part of setup package, during upgrade in case a group name * has to change. If new-name is already found in system database or old-name * is not found, nothing changes,. UIDs/GIDs are *not* checked anyhow. * * Written for PLD Linux (http://www.pld-linux.org/) setup package. * * Compilation against uClibc: * UCROOT=/usr/lib/bootdisk/usr * gcc -I$UCROOT/include -nostdlib -O2 grouprename.c $UCROOT/lib/crt0.o \ * $UCROOT/lib/libc.a -lgcc -o grouprename * strip -R .comment -R .note grouprename * * Shamelss ripoff of the joinpasswd.c program * */ #include #include #include #include #include #include #include // for rename(2) #include #include #define FILE3 "/etc/group" #define FILE4 "/etc/gshadow" /* #define OLD_LOCK */ #define LOCK_FILE "/etc/.pwd.lock" /* 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 *mfd) { int fd; void *ptr; struct stat st; fd = open(name, O_RDONLY); if (fd == -1) return NULL; *mfd = fd; 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, id_len) == 0) return 1; while (i < sz && ptr[i] != '\n') i++; i++; } return 0; } void itoa(char *buf, long i) { char tmp[32]; char *p; if (i < 0) { strcpy(buf, "-"); buf++; i = -i; } if (i == 0) { strcpy(buf, "0"); return; } for (p = tmp; i; i /= 10) *p++ = (i % 10) + '0'; while (p > tmp) *buf++ = *--p; *buf = 0; } #ifndef OLD_LOCK int lock_fd = -1; void noop(int x) { (void)x; } #endif int try_lock(const char *name) { #ifdef OLD_LOCK char file[strlen(name) + 32], lock[strlen(name) + 32]; char buf[32]; int fd; long pid; strcpy(lock, name); strcpy(file, name); strcat(lock, ".lock"); itoa(buf, (long)getpid()); strcat(file, "."); strcat(file, buf); fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); if (fd < 0) return -1; write(fd, buf, strlen(buf)); close(fd); if (link(file, lock) == 0) { unlink(file); return 0; } fd = open(lock, O_RDONLY); if (fd < 0) goto oops; memset(buf, 0, sizeof(buf)); read(fd, buf, sizeof(buf)); pid = atol(buf); if (pid == 0 || kill(pid, 0) != 0) { /* stale lock */ unlink(file); unlink(lock); /* try again */ return try_lock(name); } oops: unlink(file); return -1; #else struct flock fl; if (lock_fd != -1) return -1; lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600); if (lock_fd == -1) return -1; signal(SIGALRM, noop); alarm(15); memset(&fl, 0, sizeof(fl)); fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; if (fcntl(lock_fd, F_SETLKW, &fl) != 0) { alarm(0); close(lock_fd); lock_fd = -1; return -1; } alarm(0); return 0; #endif } void unlock(const char *name) { #ifdef OLD_LOCK char lock[strlen(name) + 32]; strcpy(lock, name); strcat(lock, ".lock"); unlink(lock); #else if (lock_fd != -1) close(lock_fd); lock_fd = -1; #endif } void lock(const char *name) { int n; n = 5; while (n--) { if (try_lock(name) == 0) return; eputs("waiting for lock...\n"); sleep(1); } fatal("cannot get lock"); } int join(const char *oldgr, const char *newgr, const char *name, const char *backup) { char *old, *id; int i, fd, mfd; int sz; // lock(name); old = map_file(name, &sz, &mfd); if (old == NULL) fatal("cannot mmap old"); fd = open(backup, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd < 0) fatal("cannot make backup"); write(fd, old, sz); close(fd); munmap(old, sz); close(mfd); #ifndef SILENT eputs("working on `"); eputs(name); eputs("'\n"); #endif /* SILENT */ old = map_file(backup, &sz, &mfd); if (old == NULL) fatal("cannot mmap backup"); fd = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); if (fd < 0) fatal("cannot open new file"); for (i = 0; i < sz; ) { id = old + i; while (i < sz && old[i] != ':' && old[i] != '\n') i++; if (i < sz && old[i] == ':') { int id_len, line_len; char *rem = old + i; id_len = i - (id - old); while (i < sz && old[i] != '\n') i++; if (i < sz) i++; line_len = i - (rem - old); if (id_len == strlen(oldgr) && memcmp(id, oldgr, id_len) == 0) { #ifndef SILENT eputs(oldgr); eputs(": ranaming to `"); eputs(newgr); eputs("'\n"); #endif /* SILENT */ write(fd, newgr, strlen(newgr)); } else write(fd, id, id_len); write(fd, rem, line_len); } else if (i < sz) i++; } close(fd); munmap(old, sz); close(mfd); // unlock(name); return 0; } int main(int argc, const char *argv[]) { const char *oldgr, *newgr; if (argc != 3) { eputs("Usage: grouprename old-name new-name"); return 1; } oldgr = argv[1]; newgr = argv[2]; #if 0 join(oldgr, newgr, FILE3, FILE3 BACKUP); join(oldgr, newgr, FILE4, FILE4 BACKUP); #else join(oldgr, newgr, "test", "test.old"); #endif return 0; }