/* * dotlockfile.c Command line version of liblockfile. * Runs setgid mail so is able to lock mailboxes * as well. Liblockfile can call this command. * * Copyright (C) Miquel van Smoorenburg and contributors 1999-2021 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version.
*/
/* * If we got SIGINT, SIGQUIT, SIGHUP, remove the * tempfile and re-raise the signal.
*/ staticvoid got_signal(int sig)
{ if (tmplock && tmplock[0])
unlink((char *)tmplock);
signal(sig, SIG_DFL);
raise(sig);
}
staticvoid ignore_signal(int sig)
{
(void)sig;
}
/* * Install signal handler only if the signal was * not ignored already.
*/ staticint set_signal(int sig, void (*handler)(int))
{ struct sigaction sa;
/* * Sleep for an amount of time while regularly checking if * our parent is still alive.
*/ int check_sleep(int sleeptime, int flags)
{ int i; int interval = 5; staticint ppid = 0;
if (ppid == 0) ppid = getppid();
if (flags & L_INTERVAL_D_)
interval = 1;
for (i = 0; i < sleeptime; i += interval) {
sleep(interval); if (kill(ppid, 0) < 0 && errno == ESRCH) return L_ERROR;
} return 0;
}
/* * Split a filename up in file and directory.
*/ #ifdef MAILGROUP staticint fn_split(char *fn, char **fn_p, char **dir_p)
{ staticchar *buf = NULL; char *p;
int main(int argc, char **argv)
{ struct passwd *pwd; struct lockargs_s_ args = { 0 };
gid_t gid, egid; char *lockfile = NULL; char **cmd = NULL; int c, r; int retries = 5; int interval = 0; int flags = 0; int lock = 0; int unlock = 0; int check = 0; int touch = 0; int writepid = 0; int passthrough = 0; int cwd_fd = -1; int need_privs = 0;
pid_t pid = -1; int e, wstatus;
/* * Remember real and effective gid, and * drop privs for now.
*/
gid = getgid();
egid = getegid(); if (gid != egid) { if (setregid(-1, gid) < 0)
perror_exit("setregid(-1, gid)");
}
#ifdef MAXPATHLEN if (strlen(lockfile) >= MAXPATHLEN) { if (!quiet)
fprintf(stderr, "dotlockfile: %s: name too long\n", lockfile); return L_NAMELEN;
} #endif
/* * Check if we run setgid.
*/ #ifdef MAILGROUP if (gid != egid) { /* * See if the requested lock is for a mailbox. * First, remember current working directory.
*/ #ifdef O_PATH
cwd_fd = open(".", O_PATH|O_CLOEXEC); #else
cwd_fd = open(".", O_RDONLY|O_CLOEXEC); #endif if (cwd_fd < 0) { if (!quiet)
fprintf(stderr, "dotlockfile: opening \".\": %s\n",
strerror(errno)); return L_ERROR;
} /* * Now change directory to the directory the lockfile is in.
*/ char *file, *dir;
r = fn_split(lockfile, &file, &dir); if (r != L_SUCCESS) { if (!quiet)
perror("dotlockfile"); return L_ERROR;
} if (chdir(dir) != 0) { if (!quiet)
fprintf(stderr, "dotlockfile: %s: %s\n", dir, strerror(errno)); return L_ERROR;
}
/* * See if we actually need to run setgid.
*/ if (need_privs) { if (setregid(gid, egid) != 0)
perror_exit("setregid");
} else { if (gid != egid && setgid(gid) != 0)
perror_exit("setgid");
}
/* * Simple check for a valid lockfile ?
*/ if (check) return (lockfile_check(lockfile, flags) < 0) ? 1 : 0;
/* * No, lock.
*/
r = lockfile_create_set_tmplock(lockfile, &tmplock, retries, flags, &args); if (r != 0 || !cmd) return r;
/* * Spawn command. * * Using an empty signal handler means that we ignore the * signal, but that it's restored to SIG_DFL at execve().
*/
set_signal(SIGINT, ignore_signal);
set_signal(SIGQUIT, ignore_signal);
set_signal(SIGHUP, ignore_signal);
set_signal(SIGALRM, ignore_signal);
pid = fork(); if (pid < 0) { if (!quiet)
perror("fork");
lockfile_remove(lockfile); exit(L_ERROR);
} if (pid == 0) { /* drop setgid */ if (gid != egid && setgid(gid) < 0) {
perror("setgid"); exit(127);
} /* restore current working directory */ if (cwd_fd >= 0) { if (fchdir(cwd_fd) < 0) {
perror("dotlockfile: restoring cwd:"); exit(127);
}
close(cwd_fd);
} /* exec */
execvp(cmd[0], cmd);
perror(cmd[0]); exit(127);
}
/* wait for child */ while (1) { if (!writepid)
alarm(30);
e = waitpid(pid, &wstatus, 0); if (e >= 0 || errno != EINTR) break; if (!writepid)
lockfile_touch(lockfile);
}
alarm(0);
lockfile_remove(lockfile);
if (passthrough) { if (WIFEXITED(wstatus)) return WEXITSTATUS(wstatus); if (WIFSIGNALED(wstatus)) return 128+WTERMSIG(wstatus);
} return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.