1/*
2 * utils.c - various utility functions used in pppd.
3 *
4 * Copyright (c) 1999 The Australian National University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by the Australian National University.  The name of the University
13 * may not be used to endorse or promote products derived from this
14 * software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20#define RCSID	"$Id: utils.c 241182 2011-02-17 21:50:03Z $"
21
22#include <stdio.h>
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <signal.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <syslog.h>
31#include <netdb.h>
32#include <utmp.h>
33#include <pwd.h>
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/wait.h>
37#include <sys/time.h>
38#include <sys/resource.h>
39#include <sys/stat.h>
40#include <sys/socket.h>
41#include <netinet/in.h>
42#ifdef SVR4
43#include <sys/mkdev.h>
44#endif
45
46#include "pppd.h"
47
48static const char rcsid[] = RCSID;
49
50#if defined(SUNOS4)
51extern char *strerror();
52#endif
53
54static void logit __P((int, char *, va_list));
55static void log_write __P((int, char *));
56static void vslp_printer __P((void *, char *, ...));
57static void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
58			       void *));
59
60struct buffer_info {
61    char *ptr;
62    int len;
63};
64
65/*
66 * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
67 * always leaves destination null-terminated (for len > 0).
68 */
69size_t
70strlcpy(dest, src, len)
71    char *dest;
72    const char *src;
73    size_t len;
74{
75    size_t ret = strlen(src);
76
77    if (len != 0) {
78	if (ret < len)
79	    strcpy(dest, src);
80	else {
81	    strncpy(dest, src, len - 1);
82	    dest[len-1] = 0;
83	}
84    }
85    return ret;
86}
87
88/*
89 * strlcat - like strcat/strncat, doesn't overflow destination buffer,
90 * always leaves destination null-terminated (for len > 0).
91 */
92size_t
93strlcat(dest, src, len)
94    char *dest;
95    const char *src;
96    size_t len;
97{
98    size_t dlen = strlen(dest);
99
100    return dlen + strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
101}
102
103
104/*
105 * slprintf - format a message into a buffer.  Like sprintf except we
106 * also specify the length of the output buffer, and we handle
107 * %r (recursive format), %m (error message), %v (visible string),
108 * %q (quoted string), %t (current time) and %I (IP address) formats.
109 * Doesn't do floating-point formats.
110 * Returns the number of chars put into buf.
111 */
112int
113slprintf __V((char *buf, int buflen, char *fmt, ...))
114{
115    va_list args;
116    int n;
117
118#if defined(__STDC__)
119    va_start(args, fmt);
120#else
121    char *buf;
122    int buflen;
123    char *fmt;
124    va_start(args);
125    buf = va_arg(args, char *);
126    buflen = va_arg(args, int);
127    fmt = va_arg(args, char *);
128#endif
129    n = vslprintf(buf, buflen, fmt, args);
130    va_end(args);
131    return n;
132}
133
134/*
135 * vslprintf - like slprintf, takes a va_list instead of a list of args.
136 */
137#define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
138
139int
140vslprintf(buf, buflen, fmt, args)
141    char *buf;
142    int buflen;
143    char *fmt;
144    va_list args;
145{
146    int c, i, n;
147    int width, prec, fillch;
148    int base, len, neg, quoted;
149    unsigned long val = 0;
150    char *str, *f, *buf0;
151    unsigned char *p;
152    char num[32];
153    time_t t;
154    u_int32_t ip;
155    static char hexchars[] = "0123456789abcdef";
156    struct buffer_info bufinfo;
157
158    buf0 = buf;
159    --buflen;
160    while (buflen > 0) {
161	for (f = fmt; *f != '%' && *f != 0; ++f)
162	    ;
163	if (f > fmt) {
164	    len = f - fmt;
165	    if (len > buflen)
166		len = buflen;
167	    memcpy(buf, fmt, len);
168	    buf += len;
169	    buflen -= len;
170	    fmt = f;
171	}
172	if (*fmt == 0)
173	    break;
174	c = *++fmt;
175	width = 0;
176	prec = -1;
177	fillch = ' ';
178	if (c == '0') {
179	    fillch = '0';
180	    c = *++fmt;
181	}
182	if (c == '*') {
183	    width = va_arg(args, int);
184	    c = *++fmt;
185	} else {
186	    while (isdigit(c)) {
187		width = width * 10 + c - '0';
188		c = *++fmt;
189	    }
190	}
191	if (c == '.') {
192	    c = *++fmt;
193	    if (c == '*') {
194		prec = va_arg(args, int);
195		c = *++fmt;
196	    } else {
197		prec = 0;
198		while (isdigit(c)) {
199		    prec = prec * 10 + c - '0';
200		    c = *++fmt;
201		}
202	    }
203	}
204	str = 0;
205	base = 0;
206	neg = 0;
207	++fmt;
208	switch (c) {
209	case 'd':
210	    i = va_arg(args, int);
211	    if (i < 0) {
212		neg = 1;
213		val = -i;
214	    } else
215		val = i;
216	    base = 10;
217	    break;
218	case 'u':
219	    val = va_arg(args, unsigned int);
220	    base = 10;
221	    break;
222	case 'o':
223	    val = va_arg(args, unsigned int);
224	    base = 8;
225	    break;
226	case 'x':
227	case 'X':
228	    val = va_arg(args, unsigned int);
229	    base = 16;
230	    break;
231	case 'p':
232	    val = (unsigned long) va_arg(args, void *);
233	    base = 16;
234	    neg = 2;
235	    break;
236	case 's':
237	    str = va_arg(args, char *);
238	    break;
239	case 'c':
240	    num[0] = va_arg(args, int);
241	    num[1] = 0;
242	    str = num;
243	    break;
244	case 'm':
245	    str = strerror(errno);
246	    break;
247	case 'I':
248	    ip = va_arg(args, u_int32_t);
249	    ip = ntohl(ip);
250	    slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
251		     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
252	    str = num;
253	    break;
254	case 'r':
255	    f = va_arg(args, char *);
256#ifndef __powerpc__
257	    n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
258#else
259	    /* On the powerpc, a va_list is an array of 1 structure */
260	    n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
261#endif
262	    buf += n;
263	    buflen -= n;
264	    continue;
265	case 't':
266	    time(&t);
267	    str = ctime(&t);
268	    str += 4;		/* chop off the day name */
269	    str[15] = 0;	/* chop off year and newline */
270	    break;
271	case 'v':		/* "visible" string */
272	case 'q':		/* quoted string */
273	    quoted = c == 'q';
274	    p = va_arg(args, unsigned char *);
275	    if (fillch == '0' && prec >= 0) {
276		n = prec;
277	    } else {
278		n = strlen((char *)p);
279		if (prec >= 0 && n > prec)
280		    n = prec;
281	    }
282	    while (n > 0 && buflen > 0) {
283		c = *p++;
284		--n;
285		if (!quoted && c >= 0x80) {
286		    OUTCHAR('M');
287		    OUTCHAR('-');
288		    c -= 0x80;
289		}
290		if (quoted && (c == '"' || c == '\\'))
291		    OUTCHAR('\\');
292		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
293		    if (quoted) {
294			OUTCHAR('\\');
295			switch (c) {
296			case '\t':	OUTCHAR('t');	break;
297			case '\n':	OUTCHAR('n');	break;
298			case '\b':	OUTCHAR('b');	break;
299			case '\f':	OUTCHAR('f');	break;
300			default:
301			    OUTCHAR('x');
302			    OUTCHAR(hexchars[c >> 4]);
303			    OUTCHAR(hexchars[c & 0xf]);
304			}
305		    } else {
306			if (c == '\t')
307			    OUTCHAR(c);
308			else {
309			    OUTCHAR('^');
310			    OUTCHAR(c ^ 0x40);
311			}
312		    }
313		} else
314		    OUTCHAR(c);
315	    }
316	    continue;
317	case 'P':		/* print PPP packet */
318	    bufinfo.ptr = buf;
319	    bufinfo.len = buflen + 1;
320	    p = va_arg(args, unsigned char *);
321	    n = va_arg(args, int);
322	    format_packet(p, n, vslp_printer, &bufinfo);
323	    buf = bufinfo.ptr;
324	    buflen = bufinfo.len - 1;
325	    continue;
326	case 'B':
327	    p = va_arg(args, unsigned char *);
328	    for (n = prec; n > 0; --n) {
329		c = *p++;
330		if (fillch == ' ')
331		    OUTCHAR(' ');
332		OUTCHAR(hexchars[(c >> 4) & 0xf]);
333		OUTCHAR(hexchars[c & 0xf]);
334	    }
335	    continue;
336	default:
337	    *buf++ = '%';
338	    if (c != '%')
339		--fmt;		/* so %z outputs %z etc. */
340	    --buflen;
341	    continue;
342	}
343	if (base != 0) {
344	    str = num + sizeof(num);
345	    *--str = 0;
346	    while (str > num + neg) {
347		*--str = hexchars[val % base];
348		val = val / base;
349		if (--prec <= 0 && val == 0)
350		    break;
351	    }
352	    switch (neg) {
353	    case 1:
354		*--str = '-';
355		break;
356	    case 2:
357		*--str = 'x';
358		*--str = '0';
359		break;
360	    }
361	    len = num + sizeof(num) - 1 - str;
362	} else {
363	    len = strlen(str);
364	    if (prec >= 0 && len > prec)
365		len = prec;
366	}
367	if (width > 0) {
368	    if (width > buflen)
369		width = buflen;
370	    if ((n = width - len) > 0) {
371		buflen -= n;
372		for (; n > 0; --n)
373		    *buf++ = fillch;
374	    }
375	}
376	if (len > buflen)
377	    len = buflen;
378	memcpy(buf, str, len);
379	buf += len;
380	buflen -= len;
381    }
382    *buf = 0;
383    return buf - buf0;
384}
385
386/*
387 * vslp_printer - used in processing a %P format
388 */
389static void
390vslp_printer __V((void *arg, char *fmt, ...))
391{
392    int n;
393    va_list pvar;
394    struct buffer_info *bi;
395
396#if defined(__STDC__)
397    va_start(pvar, fmt);
398#else
399    void *arg;
400    char *fmt;
401    va_start(pvar);
402    arg = va_arg(pvar, void *);
403    fmt = va_arg(pvar, char *);
404#endif
405
406    bi = (struct buffer_info *) arg;
407    n = vslprintf(bi->ptr, bi->len, fmt, pvar);
408    va_end(pvar);
409
410    bi->ptr += n;
411    bi->len -= n;
412}
413
414#ifdef unused
415/*
416 * log_packet - format a packet and log it.
417 */
418
419void
420log_packet(p, len, prefix, level)
421    u_char *p;
422    int len;
423    char *prefix;
424    int level;
425{
426	init_pr_log(prefix, level);
427	format_packet(p, len, pr_log, &level);
428	end_pr_log();
429}
430#endif /* unused */
431
432/*
433 * format_packet - make a readable representation of a packet,
434 * calling `printer(arg, format, ...)' to output it.
435 */
436static void
437format_packet(p, len, printer, arg)
438    u_char *p;
439    int len;
440    void (*printer) __P((void *, char *, ...));
441    void *arg;
442{
443    int i, n;
444    u_short proto;
445    struct protent *protp;
446
447    if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
448	p += 2;
449	GETSHORT(proto, p);
450	len -= PPP_HDRLEN;
451	for (i = 0; (protp = protocols[i]) != NULL; ++i)
452	    if (proto == protp->protocol)
453		break;
454	if (protp != NULL) {
455	    printer(arg, "[%s", protp->name);
456	    n = (*protp->printpkt)(p, len, printer, arg);
457	    printer(arg, "]");
458	    p += n;
459	    len -= n;
460	} else {
461	    for (i = 0; (protp = protocols[i]) != NULL; ++i)
462		if (proto == (protp->protocol & ~0x8000))
463		    break;
464	    if (protp != 0 && protp->data_name != 0) {
465		printer(arg, "[%s data]", protp->data_name);
466		if (len > 8)
467		    printer(arg, "%.8B ...", p);
468		else
469		    printer(arg, "%.*B", len, p);
470		len = 0;
471	    } else
472		printer(arg, "[proto=0x%x]", proto);
473	}
474    }
475
476    if (len > 32)
477	printer(arg, "%.32B ...", p);
478    else
479	printer(arg, "%.*B", len, p);
480}
481
482/*
483 * init_pr_log, end_pr_log - initialize and finish use of pr_log.
484 */
485
486static char line[256];		/* line to be logged accumulated here */
487static char *linep;		/* current pointer within line */
488static int llevel;		/* level for logging */
489
490void
491init_pr_log(prefix, level)
492     char *prefix;
493     int level;
494{
495	linep = line;
496	if (prefix != NULL) {
497		strlcpy(line, prefix, sizeof(line));
498		linep = line + strlen(line);
499	}
500	llevel = level;
501}
502
503void
504end_pr_log()
505{
506	if (linep != line) {
507		*linep = 0;
508		log_write(llevel, line);
509	}
510}
511
512/*
513 * pr_log - printer routine for outputting to syslog
514 */
515void
516pr_log __V((void *arg, char *fmt, ...))
517{
518	int l, n;
519	va_list pvar;
520	char *p, *eol;
521	char buf[256];
522
523#if defined(__STDC__)
524	va_start(pvar, fmt);
525#else
526	void *arg;
527	char *fmt;
528	va_start(pvar);
529	arg = va_arg(pvar, void *);
530	fmt = va_arg(pvar, char *);
531#endif
532
533	n = vslprintf(buf, sizeof(buf), fmt, pvar);
534	va_end(pvar);
535
536	p = buf;
537	eol = strchr(buf, '\n');
538	if (linep != line) {
539		l = (eol == NULL)? n: eol - buf;
540		if (linep + l < line + sizeof(line)) {
541			if (l > 0) {
542				memcpy(linep, buf, l);
543				linep += l;
544			}
545			if (eol == NULL)
546				return;
547			p = eol + 1;
548			eol = strchr(p, '\n');
549		}
550		*linep = 0;
551		log_write(llevel, line);
552		linep = line;
553	}
554
555	while (eol != NULL) {
556		*eol = 0;
557		log_write(llevel, p);
558		p = eol + 1;
559		eol = strchr(p, '\n');
560	}
561
562	/* assumes sizeof(buf) <= sizeof(line) */
563	l = buf + n - p;
564	if (l > 0) {
565		memcpy(line, p, n);
566		linep = line + l;
567	}
568}
569
570/*
571 * print_string - print a readable representation of a string using
572 * printer.
573 */
574void
575print_string(p, len, printer, arg)
576    char *p;
577    int len;
578    void (*printer) __P((void *, char *, ...));
579    void *arg;
580{
581    int c;
582
583    printer(arg, "\"");
584    for (; len > 0; --len) {
585	c = *p++;
586	if (' ' <= c && c <= '~') {
587	    if (c == '\\' || c == '"')
588		printer(arg, "\\");
589	    printer(arg, "%c", c);
590	} else {
591	    switch (c) {
592	    case '\n':
593		printer(arg, "\\n");
594		break;
595	    case '\r':
596		printer(arg, "\\r");
597		break;
598	    case '\t':
599		printer(arg, "\\t");
600		break;
601	    default:
602		printer(arg, "\\%.3o", c);
603	    }
604	}
605    }
606    printer(arg, "\"");
607}
608
609/*
610 * logit - does the hard work for fatal et al.
611 */
612static void
613logit(level, fmt, args)
614    int level;
615    char *fmt;
616    va_list args;
617{
618    int n;
619    char buf[1024];
620
621    n = vslprintf(buf, sizeof(buf), fmt, args);
622    log_write(level, buf);
623}
624
625static void
626log_write(level, buf)
627    int level;
628    char *buf;
629{
630    syslog(level, "%s", buf);
631    if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
632	int n = strlen(buf);
633
634	if (n > 0 && buf[n-1] == '\n')
635	    --n;
636	if (write(log_to_fd, buf, n) != n
637	    || write(log_to_fd, "\n", 1) != 1)
638	    log_to_fd = -1;
639    }
640}
641
642/*
643 * fatal - log an error message and die horribly.
644 */
645void
646fatal __V((char *fmt, ...))
647{
648    va_list pvar;
649
650#if defined(__STDC__)
651    va_start(pvar, fmt);
652#else
653    char *fmt;
654    va_start(pvar);
655    fmt = va_arg(pvar, char *);
656#endif
657
658    logit(LOG_ERR, fmt, pvar);
659    va_end(pvar);
660
661    die(1);			/* as promised */
662}
663
664/*
665 * error - log an error message.
666 */
667void
668error __V((char *fmt, ...))
669{
670    va_list pvar;
671
672#if defined(__STDC__)
673    va_start(pvar, fmt);
674#else
675    char *fmt;
676    va_start(pvar);
677    fmt = va_arg(pvar, char *);
678#endif
679
680    logit(LOG_ERR, fmt, pvar);
681    va_end(pvar);
682}
683
684/*
685 * warn - log a warning message.
686 */
687void
688warn __V((char *fmt, ...))
689{
690    va_list pvar;
691
692#if defined(__STDC__)
693    va_start(pvar, fmt);
694#else
695    char *fmt;
696    va_start(pvar);
697    fmt = va_arg(pvar, char *);
698#endif
699
700    logit(LOG_WARNING, fmt, pvar);
701    va_end(pvar);
702}
703
704/*
705 * notice - log a notice-level message.
706 */
707void
708notice __V((char *fmt, ...))
709{
710    va_list pvar;
711
712#if defined(__STDC__)
713    va_start(pvar, fmt);
714#else
715    char *fmt;
716    va_start(pvar);
717    fmt = va_arg(pvar, char *);
718#endif
719
720    logit(LOG_NOTICE, fmt, pvar);
721    va_end(pvar);
722}
723
724/*
725 * info - log an informational message.
726 */
727void
728info __V((char *fmt, ...))
729{
730    va_list pvar;
731
732#if defined(__STDC__)
733    va_start(pvar, fmt);
734#else
735    char *fmt;
736    va_start(pvar);
737    fmt = va_arg(pvar, char *);
738#endif
739
740    logit(LOG_INFO, fmt, pvar);
741    va_end(pvar);
742}
743
744/*
745 * dbglog - log a debug message.
746 */
747void
748dbglog __V((char *fmt, ...))
749{
750    va_list pvar;
751
752#if defined(__STDC__)
753    va_start(pvar, fmt);
754#else
755    char *fmt;
756    va_start(pvar);
757    fmt = va_arg(pvar, char *);
758#endif
759
760    logit(LOG_DEBUG, fmt, pvar);
761    va_end(pvar);
762}
763
764/* Procedures for locking the serial device using a lock file. */
765#ifndef LOCK_DIR
766#ifdef _linux_
767#define LOCK_DIR	"/var/lock"
768#else
769#ifdef SVR4
770#define LOCK_DIR	"/var/spool/locks"
771#else
772#define LOCK_DIR	"/var/spool/lock"
773#endif
774#endif
775#endif /* LOCK_DIR */
776
777static char lock_file[MAXPATHLEN];
778
779/*
780 * lock - create a lock file for the named device
781 */
782int
783lock(dev)
784    char *dev;
785{
786#ifdef LOCKLIB
787    int result;
788
789    result = mklock (dev, (void *) 0);
790    if (result == 0) {
791	strlcpy(lock_file, sizeof(lock_file), dev);
792	return 0;
793    }
794
795    if (result > 0)
796        notice("Device %s is locked by pid %d", dev, result);
797    else
798	error("Can't create lock file %s", lock_file);
799    return -1;
800
801#else /* LOCKLIB */
802
803    char lock_buffer[12];
804    int fd, pid, n;
805
806#ifdef SVR4
807    struct stat sbuf;
808
809    if (stat(dev, &sbuf) < 0) {
810	error("Can't get device number for %s: %m", dev);
811	return -1;
812    }
813    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
814	error("Can't lock %s: not a character device", dev);
815	return -1;
816    }
817    slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
818	     LOCK_DIR, major(sbuf.st_dev),
819	     major(sbuf.st_rdev), minor(sbuf.st_rdev));
820#else
821    char *p;
822
823    if ((p = strrchr(dev, '/')) != NULL)
824	dev = p + 1;
825    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
826#endif
827
828    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
829	if (errno != EEXIST) {
830	    error("Can't create lock file %s: %m", lock_file);
831	    break;
832	}
833
834	/* Read the lock file to find out who has the device locked. */
835	fd = open(lock_file, O_RDONLY, 0);
836	if (fd < 0) {
837	    if (errno == ENOENT) /* This is just a timing problem. */
838		continue;
839	    error("Can't open existing lock file %s: %m", lock_file);
840	    break;
841	}
842#ifndef LOCK_BINARY
843	n = read(fd, lock_buffer, 11);
844#else
845	n = read(fd, &pid, sizeof(pid));
846#endif /* LOCK_BINARY */
847	close(fd);
848	fd = -1;
849	if (n <= 0) {
850	    error("Can't read pid from lock file %s", lock_file);
851	    break;
852	}
853
854	/* See if the process still exists. */
855#ifndef LOCK_BINARY
856	lock_buffer[n] = 0;
857	pid = atoi(lock_buffer);
858#endif /* LOCK_BINARY */
859	if (pid == getpid())
860	    return 1;		/* somebody else locked it for us */
861	if (pid == 0
862	    || (kill(pid, 0) == -1 && errno == ESRCH)) {
863	    if (unlink (lock_file) == 0) {
864		notice("Removed stale lock on %s (pid %d)", dev, pid);
865		continue;
866	    }
867	    warn("Couldn't remove stale lock on %s", dev);
868	} else
869	    notice("Device %s is locked by pid %d", dev, pid);
870	break;
871    }
872
873    if (fd < 0) {
874	lock_file[0] = 0;
875	return -1;
876    }
877
878    pid = getpid();
879#ifndef LOCK_BINARY
880    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
881    write (fd, lock_buffer, 11);
882#else
883    write(fd, &pid, sizeof (pid));
884#endif
885    close(fd);
886    return 0;
887
888#endif
889}
890
891/*
892 * relock - called to update our lockfile when we are about to detach,
893 * thus changing our pid (we fork, the child carries on, and the parent dies).
894 * Note that this is called by the parent, with pid equal to the pid
895 * of the child.  This avoids a potential race which would exist if
896 * we had the child rewrite the lockfile (the parent might die first,
897 * and another process could think the lock was stale if it checked
898 * between when the parent died and the child rewrote the lockfile).
899 */
900int
901relock(pid)
902    int pid;
903{
904#ifdef LOCKLIB
905    return -1;
906#else /* LOCKLIB */
907
908    int fd;
909    char lock_buffer[12];
910
911    if (lock_file[0] == 0)
912	return -1;
913    fd = open(lock_file, O_WRONLY, 0);
914    if (fd < 0) {
915	error("Couldn't reopen lock file %s: %m", lock_file);
916	lock_file[0] = 0;
917	return -1;
918    }
919
920#ifndef LOCK_BINARY
921    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
922    write (fd, lock_buffer, 11);
923#else
924    write(fd, &pid, sizeof(pid));
925#endif /* LOCK_BINARY */
926    close(fd);
927    return 0;
928
929#endif /* LOCKLIB */
930}
931
932/*
933 * unlock - remove our lockfile
934 */
935void
936unlock()
937{
938    if (lock_file[0]) {
939#ifdef LOCKLIB
940	(void) rmlock(lock_file, (void *) 0);
941#else
942	unlink(lock_file);
943#endif
944	lock_file[0] = 0;
945    }
946}
947