Import NetBSD flock(1)
Also fix the MINIX3 libc flock(3) implementation. Change-Id: Ia80280029968786d7f029940ec02e942057701bd
This commit is contained in:
		
							parent
							
								
									875abb8724
								
							
						
					
					
						commit
						9488aa4c04
					
				@ -331,6 +331,7 @@
 | 
				
			|||||||
./usr/bin/fix				minix-sys
 | 
					./usr/bin/fix				minix-sys
 | 
				
			||||||
./usr/bin/flex++			minix-sys
 | 
					./usr/bin/flex++			minix-sys
 | 
				
			||||||
./usr/bin/flex				minix-sys
 | 
					./usr/bin/flex				minix-sys
 | 
				
			||||||
 | 
					./usr/bin/flock				minix-sys
 | 
				
			||||||
./usr/bin/fold				minix-sys
 | 
					./usr/bin/fold				minix-sys
 | 
				
			||||||
./usr/bin/format			minix-sys
 | 
					./usr/bin/format			minix-sys
 | 
				
			||||||
./usr/bin/fpr				minix-sys
 | 
					./usr/bin/fpr				minix-sys
 | 
				
			||||||
@ -2405,6 +2406,7 @@
 | 
				
			|||||||
./usr/man/man1/finger.1			minix-sys
 | 
					./usr/man/man1/finger.1			minix-sys
 | 
				
			||||||
./usr/man/man1/flex.1			minix-sys
 | 
					./usr/man/man1/flex.1			minix-sys
 | 
				
			||||||
./usr/man/man1/flexdoc.1		minix-sys
 | 
					./usr/man/man1/flexdoc.1		minix-sys
 | 
				
			||||||
 | 
					./usr/man/man1/flock.1			minix-sys
 | 
				
			||||||
./usr/man/man1/fold.1			minix-sys
 | 
					./usr/man/man1/fold.1			minix-sys
 | 
				
			||||||
./usr/man/man1/for.1			minix-sys	obsolete
 | 
					./usr/man/man1/for.1			minix-sys	obsolete
 | 
				
			||||||
./usr/man/man1/format.1			minix-sys
 | 
					./usr/man/man1/format.1			minix-sys
 | 
				
			||||||
 | 
				
			|||||||
@ -21,14 +21,15 @@
 | 
				
			|||||||
int flock(int fd, int mode)
 | 
					int flock(int fd, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct flock lck;
 | 
					  struct flock lck;
 | 
				
			||||||
  register int retcode;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  memset((void *) &lck, 0, sizeof(struct flock));
 | 
					  memset((void *) &lck, 0, sizeof(struct flock));
 | 
				
			||||||
  lck.l_type = mode & ~LOCK_NB;
 | 
					  switch (mode & ~LOCK_NB) {
 | 
				
			||||||
  lck.l_pid = getpid();
 | 
					  case LOCK_SH: lck.l_type = F_RDLCK; break;
 | 
				
			||||||
  if ((retcode = fcntl(fd, mode & LOCK_NB ? F_SETLK : F_SETLKW, &lck)) < 0 && errno == EAGAIN)
 | 
					  case LOCK_EX: lck.l_type = F_WRLCK; break;
 | 
				
			||||||
	errno = EWOULDBLOCK;
 | 
					  case LOCK_UN: lck.l_type = F_UNLCK; break;
 | 
				
			||||||
  return retcode;
 | 
					  default: errno = EINVAL; return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return fcntl(fd, mode & LOCK_NB ? F_SETLK : F_SETLKW, &lck);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** flock.c **/
 | 
					/** flock.c **/
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ SUBDIR= asa \
 | 
				
			|||||||
	column comm csplit ctags cut \
 | 
						column comm csplit ctags cut \
 | 
				
			||||||
	deroff dirname du \
 | 
						deroff dirname du \
 | 
				
			||||||
	env expand \
 | 
						env expand \
 | 
				
			||||||
	false find finger fold fpr from \
 | 
						false find finger flock fold fpr from \
 | 
				
			||||||
	fsplit ftp genassym getopt \
 | 
						fsplit ftp genassym getopt \
 | 
				
			||||||
	head hexdump id indent infocmp join jot \
 | 
						head hexdump id indent infocmp join jot \
 | 
				
			||||||
	lam last ldd leave \
 | 
						lam last ldd leave \
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								usr.bin/flock/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								usr.bin/flock/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					#	$NetBSD: Makefile,v 1.1 2012/11/01 23:30:19 christos Exp $
 | 
				
			||||||
 | 
					#	@(#)Makefile	8.1 (Berkeley) 6/6/93
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROG=	flock
 | 
				
			||||||
 | 
					#LDADD+=	-lutil
 | 
				
			||||||
 | 
					#DPADD+=	${LIBUTIL}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.include <bsd.prog.mk>
 | 
				
			||||||
							
								
								
									
										100
									
								
								usr.bin/flock/flock.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								usr.bin/flock/flock.1
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					.\"	$NetBSD: flock.1,v 1.9 2013/09/21 15:01:14 khorben Exp $
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\" Copyright (c) 2012 The NetBSD Foundation, Inc.
 | 
				
			||||||
 | 
					.\" All rights reserved.
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\" This code is derived from software contributed to The NetBSD Foundation
 | 
				
			||||||
 | 
					.\" by Christos Zoulas.
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\" 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.
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.Dd November 2, 2012
 | 
				
			||||||
 | 
					.Dt FLOCK 1
 | 
				
			||||||
 | 
					.Os
 | 
				
			||||||
 | 
					.Sh NAME
 | 
				
			||||||
 | 
					.Nm flock
 | 
				
			||||||
 | 
					.Nd Provide locking API for shell scripts
 | 
				
			||||||
 | 
					.Sh SYNOPSIS
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					.Op Fl dnosvx
 | 
				
			||||||
 | 
					.Op Fl w Ar timeout
 | 
				
			||||||
 | 
					.Ar lockfile|lockdir
 | 
				
			||||||
 | 
					.Op Fl c Ar command
 | 
				
			||||||
 | 
					|
 | 
				
			||||||
 | 
					.Op Ar command ...
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					.Op Fl dnsuvx
 | 
				
			||||||
 | 
					.Op Fl w Ar timeout
 | 
				
			||||||
 | 
					.Ar lockfd
 | 
				
			||||||
 | 
					.Sh DESCRIPTION
 | 
				
			||||||
 | 
					The
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					utility provides
 | 
				
			||||||
 | 
					.Xr flock 2
 | 
				
			||||||
 | 
					access to the command line or scripts.
 | 
				
			||||||
 | 
					The first form locks a file or directory while the command provided is executed.
 | 
				
			||||||
 | 
					If the file or directory does not exist, then a file is created.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The second form can use an arbitrary file descriptor that is provided from a
 | 
				
			||||||
 | 
					shell script for example:
 | 
				
			||||||
 | 
					.Bd -literal
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
						flock -s 100
 | 
				
			||||||
 | 
						# commands to be executed under the lock
 | 
				
			||||||
 | 
					) 100> /path/to/lockfile
 | 
				
			||||||
 | 
					.Ed
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The following options are available:
 | 
				
			||||||
 | 
					.Bl -tag -width "XXXXXXXXXXXXXXXXX"
 | 
				
			||||||
 | 
					.It Fl c Ar command
 | 
				
			||||||
 | 
					Pass a command to a the shell.
 | 
				
			||||||
 | 
					.It Fl d , Fl Fl debug
 | 
				
			||||||
 | 
					Provide debugging output.
 | 
				
			||||||
 | 
					.It Fl n , Fl Fl nb , Fl Fl nonblock
 | 
				
			||||||
 | 
					Don't block and fail immediately if the lock could not be obtained.
 | 
				
			||||||
 | 
					.It Fl o , Fl Fl close
 | 
				
			||||||
 | 
					Close the file before executing the command.
 | 
				
			||||||
 | 
					This is useful if the child forks and should not be holding the lock.
 | 
				
			||||||
 | 
					.It Fl s , Fl Fl shared
 | 
				
			||||||
 | 
					Obtain a shared lock.
 | 
				
			||||||
 | 
					.It Fl u , Fl Fl unlock
 | 
				
			||||||
 | 
					Unlock an existing lock.
 | 
				
			||||||
 | 
					This is available only for a file descriptor.
 | 
				
			||||||
 | 
					.It Fl v , Fl Fl verbose
 | 
				
			||||||
 | 
					On error print an explanation of the failure.
 | 
				
			||||||
 | 
					.It Fl w , Fl Fl wait , Fl Fl timeout Ar seconds
 | 
				
			||||||
 | 
					Fail if the lock could not be obtained after
 | 
				
			||||||
 | 
					.Ar seconds .
 | 
				
			||||||
 | 
					.It Fl x , Fl Fl exclusive
 | 
				
			||||||
 | 
					Obtain an exclusive lock.
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Sh EXIT STATUS
 | 
				
			||||||
 | 
					.Ex -std
 | 
				
			||||||
 | 
					.Sh SEE ALSO
 | 
				
			||||||
 | 
					.Xr shlock 1 ,
 | 
				
			||||||
 | 
					.Xr flock 2
 | 
				
			||||||
 | 
					.Sh HISTORY
 | 
				
			||||||
 | 
					An
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					utility appeared in
 | 
				
			||||||
 | 
					.Nx 6.1 .
 | 
				
			||||||
							
								
								
									
										324
									
								
								usr.bin/flock/flock.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								usr.bin/flock/flock.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,324 @@
 | 
				
			|||||||
 | 
					/*	$NetBSD: flock.c,v 1.8 2013/10/29 16:02:15 christos Exp $	*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-
 | 
				
			||||||
 | 
					 * Copyright (c) 2012 The NetBSD Foundation, Inc.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is derived from software contributed to The NetBSD Foundation
 | 
				
			||||||
 | 
					 * by Christos Zoulas.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 *    from this software without specific prior written permission.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/cdefs.h>
 | 
				
			||||||
 | 
					__RCSID("$NetBSD: flock.c,v 1.8 2013/10/29 16:02:15 christos Exp $");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <err.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					#include <paths.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct option flock_longopts[] = {
 | 
				
			||||||
 | 
						{ "debug",		no_argument,		0, 'd' },
 | 
				
			||||||
 | 
						{ "help",		no_argument,		0, 'h' },
 | 
				
			||||||
 | 
						{ "nonblock",		no_argument,		0, 'n' },
 | 
				
			||||||
 | 
						{ "nb",			no_argument,		0, 'n' },
 | 
				
			||||||
 | 
						{ "close",		no_argument,		0, 'o' },
 | 
				
			||||||
 | 
						{ "shared",		no_argument,		0, 's' },
 | 
				
			||||||
 | 
						{ "exclusive",		no_argument,		0, 'x' },
 | 
				
			||||||
 | 
						{ "unlock",		no_argument,		0, 'u' },
 | 
				
			||||||
 | 
						{ "verbose",		no_argument,		0, 'v' },
 | 
				
			||||||
 | 
						{ "command",		required_argument,	0, 'c' },
 | 
				
			||||||
 | 
						{ "wait",		required_argument,	0, 'w' },
 | 
				
			||||||
 | 
						{ "timeout",		required_argument,	0, 'w' },
 | 
				
			||||||
 | 
						{ NULL,			0,			0, 0   },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static sig_atomic_t timeout_expired;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __dead void
 | 
				
			||||||
 | 
					usage(const char *fmt, ...) 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (fmt) {
 | 
				
			||||||
 | 
							va_list ap;
 | 
				
			||||||
 | 
							va_start(ap, fmt);
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: ", getprogname());
 | 
				
			||||||
 | 
							vfprintf(stderr, fmt, ap);
 | 
				
			||||||
 | 
							fputc('\n', stderr);
 | 
				
			||||||
 | 
							va_end(ap);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(stderr, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir "
 | 
				
			||||||
 | 
						    "[-c command]|command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n",
 | 
				
			||||||
 | 
						    getprogname(), getprogname());
 | 
				
			||||||
 | 
						exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					sigalrm(int sig)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						timeout_expired++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *
 | 
				
			||||||
 | 
					lock2name(int l)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char buf[1024];
 | 
				
			||||||
 | 
						int nb = l & LOCK_NB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l &= ~LOCK_NB;
 | 
				
			||||||
 | 
						if (nb)
 | 
				
			||||||
 | 
							strlcpy(buf, "LOCK_NB|", sizeof(buf));
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							buf[0] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (l) {
 | 
				
			||||||
 | 
						case LOCK_SH:
 | 
				
			||||||
 | 
							strlcat(buf, "LOCK_SH", sizeof(buf));
 | 
				
			||||||
 | 
							return buf;
 | 
				
			||||||
 | 
						case LOCK_EX:
 | 
				
			||||||
 | 
							strlcat(buf, "LOCK_EX", sizeof(buf));
 | 
				
			||||||
 | 
							return buf;
 | 
				
			||||||
 | 
						case LOCK_UN:
 | 
				
			||||||
 | 
							strlcat(buf, "LOCK_UN", sizeof(buf));
 | 
				
			||||||
 | 
							return buf;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "*%d*", l | nb);
 | 
				
			||||||
 | 
							return buf;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char
 | 
				
			||||||
 | 
					lockchar(int l)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (l & ~LOCK_NB) {
 | 
				
			||||||
 | 
						case LOCK_SH:
 | 
				
			||||||
 | 
							return 's';
 | 
				
			||||||
 | 
						case LOCK_EX:
 | 
				
			||||||
 | 
							return 'x';
 | 
				
			||||||
 | 
						case LOCK_UN:
 | 
				
			||||||
 | 
							return 'u';
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return '*';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *
 | 
				
			||||||
 | 
					cmdline(char **av)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *v = NULL;
 | 
				
			||||||
 | 
						while (*av)
 | 
				
			||||||
 | 
							if (v) {
 | 
				
			||||||
 | 
								if (asprintf(&v, "%s %s", v, *av++) < 0)
 | 
				
			||||||
 | 
									err(EXIT_FAILURE, "malloc");
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if ((v = strdup(*av++)) == NULL)
 | 
				
			||||||
 | 
									err(EXIT_FAILURE, "strdup");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						return v;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int c;
 | 
				
			||||||
 | 
						int lock = 0;
 | 
				
			||||||
 | 
						double timeout = 0;
 | 
				
			||||||
 | 
						int cls = 0;
 | 
				
			||||||
 | 
						int fd = -1;
 | 
				
			||||||
 | 
						int debug = 0;
 | 
				
			||||||
 | 
						int verbose = 0;
 | 
				
			||||||
 | 
						char *mcargv[] = {
 | 
				
			||||||
 | 
						    __UNCONST(_PATH_BSHELL), __UNCONST("-c"), NULL, NULL
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						char **cmdargv = NULL, *v;
 | 
				
			||||||
 | 
					#ifndef __minix
 | 
				
			||||||
 | 
						timer_t tm;
 | 
				
			||||||
 | 
					#else /* __minix */
 | 
				
			||||||
 | 
						struct itimerval it;
 | 
				
			||||||
 | 
					#endif /* __minix */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setprogname(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((c = getopt_long(argc, argv, "+dnosuvw:x", flock_longopts, NULL))
 | 
				
			||||||
 | 
						    != -1)
 | 
				
			||||||
 | 
							switch (c) {
 | 
				
			||||||
 | 
							case 'd':
 | 
				
			||||||
 | 
								debug++;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'x':
 | 
				
			||||||
 | 
					#define T(l)	(lock & ~LOCK_NB) != (l) && (lock & ~LOCK_NB) != 0
 | 
				
			||||||
 | 
								if (T(LOCK_EX))
 | 
				
			||||||
 | 
									goto badlock;
 | 
				
			||||||
 | 
								lock |= LOCK_EX;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'n':
 | 
				
			||||||
 | 
								lock |= LOCK_NB;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 's':
 | 
				
			||||||
 | 
								if (T(LOCK_SH))
 | 
				
			||||||
 | 
									goto badlock;
 | 
				
			||||||
 | 
								lock |= LOCK_SH;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'u':
 | 
				
			||||||
 | 
								if (T(LOCK_UN))
 | 
				
			||||||
 | 
									goto badlock;
 | 
				
			||||||
 | 
								lock |= LOCK_UN;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'w':
 | 
				
			||||||
 | 
								timeout = strtod(optarg, NULL);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'v':
 | 
				
			||||||
 | 
								verbose = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'o':
 | 
				
			||||||
 | 
								cls = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								usage("Invalid option '%c'", c);
 | 
				
			||||||
 | 
							badlock:
 | 
				
			||||||
 | 
								usage("-%c can't be used with -%c", c, lockchar(lock));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argc -= optind;
 | 
				
			||||||
 | 
						argv += optind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((lock & ~LOCK_NB) == 0)
 | 
				
			||||||
 | 
							usage("Missing lock type flag");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (argc) {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							usage("Missing lock file argument");
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							if (cls)
 | 
				
			||||||
 | 
								usage("Close is valid only for descriptors");
 | 
				
			||||||
 | 
							fd = strtol(argv[0], NULL, 0);	// XXX: error checking
 | 
				
			||||||
 | 
							if (debug) {
 | 
				
			||||||
 | 
								fprintf(stderr, "descriptor %s lock %s\n",
 | 
				
			||||||
 | 
								    argv[0], lock2name(lock));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							if ((lock & LOCK_NB) == LOCK_UN)
 | 
				
			||||||
 | 
								usage("Unlock is only valid for descriptors");
 | 
				
			||||||
 | 
							if (strcmp(argv[1], "-c") == 0 ||
 | 
				
			||||||
 | 
							    strcmp(argv[1], "--command") == 0) {
 | 
				
			||||||
 | 
								if (argc == 2)
 | 
				
			||||||
 | 
									usage("Missing argument to %s", strcmp(argv[1],
 | 
				
			||||||
 | 
									    "-c") == 0 ? "-c" : "--command");
 | 
				
			||||||
 | 
								mcargv[2] = argv[2];
 | 
				
			||||||
 | 
								cmdargv = mcargv;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								cmdargv = argv + 1;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							if ((fd = open(argv[0], O_RDONLY)) == -1) {
 | 
				
			||||||
 | 
								if (errno != ENOENT || 
 | 
				
			||||||
 | 
								    (fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1)
 | 
				
			||||||
 | 
									err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (debug) {
 | 
				
			||||||
 | 
								fprintf(stderr, "file %s lock %s command %s ...\n",
 | 
				
			||||||
 | 
								    argv[0], lock2name(lock), v = cmdline(cmdargv));
 | 
				
			||||||
 | 
								free(v);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (timeout) {
 | 
				
			||||||
 | 
					#ifndef __minix
 | 
				
			||||||
 | 
							struct sigevent ev;
 | 
				
			||||||
 | 
							struct itimerspec it;
 | 
				
			||||||
 | 
					#endif /* !__minix */
 | 
				
			||||||
 | 
							struct sigaction sa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __minix
 | 
				
			||||||
 | 
							timespecclear(&it.it_interval);
 | 
				
			||||||
 | 
							it.it_value.tv_sec = timeout;
 | 
				
			||||||
 | 
							it.it_value.tv_nsec = (timeout - it.it_value.tv_sec) *
 | 
				
			||||||
 | 
								1000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset(&ev, 0, sizeof(ev));
 | 
				
			||||||
 | 
							ev.sigev_notify = SIGEV_SIGNAL;
 | 
				
			||||||
 | 
							ev.sigev_signo = SIGALRM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (timer_create(CLOCK_REALTIME, &ev, &tm) == -1)
 | 
				
			||||||
 | 
								err(EXIT_FAILURE, "timer_create");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (timer_settime(tm, TIMER_RELTIME, &it, NULL) == -1)
 | 
				
			||||||
 | 
								err(EXIT_FAILURE, "timer_settime");
 | 
				
			||||||
 | 
					#else /* __minix */
 | 
				
			||||||
 | 
							memset(&it.it_interval, 0, sizeof(it.it_interval));
 | 
				
			||||||
 | 
							it.it_value.tv_sec = timeout;
 | 
				
			||||||
 | 
							it.it_value.tv_usec = (timeout - it.it_value.tv_sec) * 1000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (setitimer(ITIMER_REAL, &it, NULL) == -1)
 | 
				
			||||||
 | 
								err(EXIT_FAILURE, "setitimer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset(&it, 0, sizeof(it)); /* for the reset later */
 | 
				
			||||||
 | 
					#endif /* __minix */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset(&sa, 0, sizeof(sa));
 | 
				
			||||||
 | 
							sa.sa_handler = sigalrm;
 | 
				
			||||||
 | 
							sigemptyset(&sa.sa_mask);
 | 
				
			||||||
 | 
							sa.sa_flags = 0;
 | 
				
			||||||
 | 
							if (sigaction(SIGALRM, &sa, NULL) == -1)
 | 
				
			||||||
 | 
								err(EXIT_FAILURE, "sigaction");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (debug)
 | 
				
			||||||
 | 
								fprintf(stderr, "alarm %g\n", timeout);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (flock(fd, lock) == -1) {
 | 
				
			||||||
 | 
							if (errno == EINTR && timeout_expired == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (verbose)
 | 
				
			||||||
 | 
								err(EXIT_FAILURE, "flock(%d, %s)", fd, lock2name(lock));
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								return EXIT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (timeout)
 | 
				
			||||||
 | 
					#ifndef __minix
 | 
				
			||||||
 | 
							timer_delete(tm);
 | 
				
			||||||
 | 
					#else /* __minix */
 | 
				
			||||||
 | 
							setitimer(ITIMER_REAL, &it, NULL);
 | 
				
			||||||
 | 
					#endif /* __minix */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cls)
 | 
				
			||||||
 | 
							(void)close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cmdargv != NULL) {
 | 
				
			||||||
 | 
							execvp(cmdargv[0], cmdargv);
 | 
				
			||||||
 | 
							err(EXIT_FAILURE, "execvp '%s'", v = cmdline(cmdargv));
 | 
				
			||||||
 | 
							free(v);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user