/*
* $Id$
*
- * Copyright (c) 2001 Michal Moskal <malekith@pld.org.pl>.
+ * Copyright (c) 2001 Michal Moskal <malekith@pld-linux.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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.
+ * 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.
+ * Written for PLD Linux (http://www.pld-linux.org/) setup package.
*
* Compilation against uClibc:
* UCROOT=/usr/lib/bootdisk/usr
* $UCROOT/lib/libc.a -lgcc -o joinpasswd
* strip -R .comment -R .note joinpasswd
*
- * The idea of this program comes from Lukasz Dobrek <dobrek@pld.org.pl>.
+ * The idea of this program comes from Lukasz Dobrek <dobrek@pld-linux.org>.
*
*/
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <signal.h>
#define FILE1 "/etc/passwd"
#define FILE2 "/etc/shadow"
#define FILE3 "/etc/group"
+#define FILE4 "/etc/gshadow"
+
+/* #define OLD_LOCK */
+
+#define LOCK_FILE "/etc/.pwd.lock"
#define SUFFIX ".rpmnew"
/* maybe "-" or sth? */
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 *old_name, const char *new_name, const char *backup_name)
{
char *old, *new, *id;
new = map_file(new_name, &new_sz);
if (new == NULL)
return -1;
-
+
+ lock(old_name);
old = map_file(old_name, &old_sz);
if (old == NULL)
fatal("cannot mmap old");
close(fd);
#ifndef SILENT
- eputs("marging contest of `");
+ eputs("merging content of `");
eputs(old_name);
eputs("' with `");
eputs(new_name);
/* user may want to exime this file... */
unlink(new_name);
#endif
+ unlock(old_name);
return 0;
}
int main()
{
#if 1
- join(FILE1, FILE1 SUFFIX);
- join(FILE2, FILE2 SUFFIX);
- join(FILE3, FILE3 SUFFIX);
+ join(FILE1, FILE1 SUFFIX, FILE1 BACKUP);
+ join(FILE2, FILE2 SUFFIX, FILE2 BACKUP);
+ join(FILE3, FILE3 SUFFIX, FILE3 BACKUP);
+ join(FILE4, FILE4 SUFFIX, FILE4 BACKUP);
#else
- join("test", "test.new");
+ join("test", "test.new", "test.old");
#endif
return 0;
}