aboutsummaryrefslogtreecommitdiff
path: root/mktmp/mktmp.c
blob: 3230ff6dd92ce9e12ff65bdfcbb1dfaeeeec5342 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * 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;
}