aboutsummaryrefslogblamecommitdiff
path: root/mktmp/mktmp.c
blob: 3230ff6dd92ce9e12ff65bdfcbb1dfaeeeec5342 (plain) (tree)







































































































































                                                                                
/*
 * mklock - create a secured lock entry with given data
 * (c) 2003 - willy tarreau - willy@ant-computing.com
 *
 * You may use, copy and redistribute with no restriction. Use at your own
 * risk, I will not be held responsible for any loss or damage.
 *
 * usage :
 *   # mklock <directory> [data]
 *
 * This will create a symlink under <directory>, either pointing to <data> if
 * <data> is specified, or pointing to /proc/<getppid()> if no data is given.
 * This way, the link will automatically be broken as soon as the father dies.
 * The name of the link will be generated randomly until no conflict happens
 * with an existing entry. The full pathname of the resulting link is returned
 * to stdout so that a script can easily use it.
 * This method ensures the use of a secure lock.
 *
 * Example :
 *   # file=`mklock /tmp $$`
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

#define writetxt(fd, text) write(fd, text, strlen(text))
#define LOCK_PREFIX ".lock."
#define PROC_PREFIX "/proc/"
#define MAX_PID_DIGITS	10	/* 10 digits do code a 32bit pid in decimal */

const char lock_prefix[] = LOCK_PREFIX;
const char proc_prefix[] = PROC_PREFIX;

/* writes <l> in at most 9 decimal digits to <to> */
void ultoa(char *to, unsigned long l) {
    unsigned long div = 1000000000;
    int zero = 1;
    while (div > 0) {
	*to = (l / div % 10) + '0';
	div /= 10;
	zero &= (*to == '0');
	if (!zero)
	    to++;
    }
    *to = 0;
}

/* writes <l> as 8 hex digits to <to> */
void ultoh(char *to, unsigned long l) {
    int shift = 32;
    while ((shift -= 4) >= 0) {
	int digit = (l >> shift) & 0xf;
	if (digit > 9)
	    digit += 'A' - '9' - 1;
	*to++ = digit + '0';
    }
    *to = 0;
}

void usage() {
    writetxt(2, "Usage: mklock [ -d ] [ -p prefix ] <directory> [data]\n");
    exit(1);
}

main(int argc, char **argv) {
    char *text, *prefix;
    char *directory;
    char *fullname;
    int len, num = 0, ret;
    int use_dir = 0;
    int plen;

    prefix = lock_prefix;

    argv++; argc--;

    while (argc > 0 && **argv == '-') {
	if (!strcmp(*argv, "-d")) {
	    use_dir = 1;
	}
	else if (!strcmp(*argv, "-p")) {
	    if (argc > 1) {
		argv++; argc--;
		prefix = argv[0];
	    }
	    else
		usage();
	}
	argv++; argc--;
    }

    if (argc < 1)
	usage();

    plen = strlen(prefix);
    directory = argv[0];
    len = strlen(directory);
    while (len > 0 && directory[len - 1] == '/')
	directory[--len] = 0;

    fullname = (char *)calloc(1, len + 1 + plen + 10);
    memcpy(fullname, directory, len);
    fullname[len++] = '/';
    memcpy(fullname + len, prefix, plen + 1);
    len += plen;

    argv++; argc--;

    if (argc > 0) /* use this arg as where the link points to */
	text = argv[0];
    else { /* point to /proc/<getppid()> */
	text = (char *)malloc(strlen(PROC_PREFIX) + MAX_PID_DIGITS + 1);
	memcpy(text, proc_prefix, strlen(PROC_PREFIX) + 1);
	ultoa(text + strlen(PROC_PREFIX), getppid());
    }

    do {
	/* try to create the entry with an increasing suffix until we succeed */
	ultoh(fullname+len, num++);
	
	if (use_dir)
	    ret = mkdir(fullname, 0700);
	else
	    ret = symlink(text, fullname);

	if (ret == 0) {
	    fullname[len + 8]='\n';
	    /* success, return the link or directory name */
	    write(1, fullname, len + 9);
	    return 0;
	}
    } while (errno == EEXIST);
    /* other error, let's return 2 */
    return 2;
}