static FILE *open_and_lock_cached_policy_file(const char *filename, int *readwrite) { int fd; int save_errno; *readwrite=1; fd=open(filename, O_RDWR | O_CREAT, 0644); if (fd >= 0 && ll_lock_ex(fd) >= 0) { FILE *fp=fdopen(fd, "r+"); if (fp) return fp; } /* ** Non-root will not be able to write to the cache. ** ** Do not pollute terminal output, but if this is run from the ** script let's bark this somewhere where someone will hopefully ** notice this. */ save_errno=errno; if (!isatty(2)) { errno=save_errno; perror(filename); } if (fd >= 0) close(fd); *readwrite=0; fd=open(filename, O_RDONLY); if (fd >= 0 && ll_lockfd(fd, ll_readlock|ll_whence_start|ll_wait, 0, 0) >= 0) { FILE *fp=fdopen(fd, "r"); if (fp) return fp; } if (fd >= 0) close(fd); return NULL; }
static int ll_mail_open_do(struct ll_mail *p, int ro) { char *dotlock; char myidbuf[IDBUFSIZE]; int save_errno; int fd; getid(myidbuf); if (p->dotlock) /* Already locked */ { fd=open(p->file, ro ? O_RDONLY:O_RDWR); if (fd >= 0 && (ll_lockfd(fd, ro ? ll_readlock:ll_writelock, 0, 0) < 0 || fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)) { close(fd); fd= -1; } return fd; } if ((dotlock=malloc(strlen(p->file)+sizeof(".lock"))) == NULL) return -1; strcat(strcpy(dotlock, p->file), ".lock"); if (try_mail_dotlock(dotlock, myidbuf) == 0) { fd=open(p->file, ro ? O_RDONLY:O_RDWR); if (fd >= 0 && (ll_lockfd(fd, ro ? ll_readlock:ll_writelock, 0, 0) || fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)) { close(fd); fd= -1; } p->dotlock=dotlock; return fd; } save_errno=errno; /* ** Last fallback: for EEXIST, a read-only lock should suffice ** In all other instances, we'll fallback to read/write or read-only ** flock as last resort. */ if ((errno == EEXIST && ro) || errno == EPERM || errno == EACCES) { fd=open(p->file, ro ? O_RDONLY:O_RDWR); if (fd >= 0) { if (ll_lockfd(fd, ro ? ll_readlock:ll_writelock, 0, 0) == 0 && fcntl(fd, F_SETFD, FD_CLOEXEC) == 0) { free(dotlock); return fd; } close(fd); } } /* ** If try_dotlock blew up for anything other than EEXIST, we don't ** know what the deal is, so punt. */ if (save_errno != EEXIST) { free(dotlock); return (-1); } dotlock_exists(dotlock, myidbuf, 300); free(dotlock); return (-1); }
int ll_mail_lock(struct ll_mail *p) { struct stat stat_buf; char idbuf[IDBUFSIZE]; char idbuf2[IDBUFSIZE]; char fn[NUMBUFSIZE*2 + 20]; char *f; int fd; getid(idbuf); if (p->cclientfd >= 0) return 0; if (stat(p->file, &stat_buf) < 0) return -1; if (snprintf(fn, sizeof(fn), "/tmp/.%lx.%lx", (unsigned long)stat_buf.st_dev, (unsigned long)stat_buf.st_ino) < 0) { errno=ENOSPC; return (-1); } if ((f=strdup(fn)) == NULL) return (-1); /* We do things a bit differently. First, try O_EXCL */ if ((fd=open(f, O_RDWR|O_CREAT|O_EXCL, 0644)) >= 0) { struct stat stat_buf2; if (ll_lockfd(fd, ll_writelock, ll_whence_start, 0) < 0 || fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 || writeid(idbuf, fd) < 0) { /* This shouldn't happen */ close(fd); free(f); return (-1); } /* Rare race condition: */ if (fstat(fd, &stat_buf) < 0 || lstat(f, &stat_buf2) < 0 || stat_buf.st_dev != stat_buf2.st_dev || stat_buf.st_ino != stat_buf2.st_ino) { errno=EAGAIN; close(fd); free(f); return (-1); } p->cclientfd=fd; p->cclientfile=f; return 0; } /* ** An existing lockfile. See if it's tagged with another ** pid on this server, which no longer exists. */ if ((fd=open(f, O_RDONLY)) >= 0) { pid_t p=-1; if (readid(idbuf2, fd) == 0 && (p=getpidid(idbuf2, idbuf)) != 0 && kill(p, 0) < 0 && errno == ESRCH) { errno=EAGAIN; close(fd); unlink(f); /* Don't try again right away */ free(f); return (-1); } /* If we can't lock, someone must have it open, game over. */ if (p == getpid() /* It's us! */ || ll_lockfd(fd, ll_readlock, ll_whence_start, 0) < 0) { errno=EEXIST; close(fd); free(f); return (-1); } close(fd); } /* Stale 0-length lockfiles are blown away after 5 mins */ if (lstat(f, &stat_buf) == 0 && stat_buf.st_size == 0 && stat_buf.st_mtime + 300 < time(NULL)) { errno=EAGAIN; unlink(f); free(f); return (-1); } errno=EAGAIN; free(f); return (-1); }