summaryrefslogtreecommitdiff
path: root/cap.c
blob: a1927dfc5b6d16cb7fd798361dafedf1486747b1 (plain)
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
137
138
139
140
141
142
143
/*
 * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc.
 * See COPYING file for license information 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <cbtcommon/debug.h>
#include <cbtcommon/text_util.h>

#include "cap.h"
#include "cvs_direct.h"

extern CvsServerCtx * cvs_direct_ctx;

static char client_version[BUFSIZ];
static char server_version[BUFSIZ];

static int check_cvs_version(int, int, int);
static int check_version_string(const char *, int, int, int);

int cvs_check_cap(int cap)
{
    int ret;

    switch(cap)
    {
    case CAP_HAVE_RLOG:
	if (!(ret = check_cvs_version(1,11,1)))
	{
	    debug(DEBUG_APPERROR, 
		  "WARNING: Your CVS client version:\n[%s]\n"
		  "and/or server version:\n[%s]\n"
		  "are too old to properly support the rlog command. \n"
		  "This command was introduced in 1.11.1.  Cvsps\n"
		  "will use log instead, but PatchSet numbering\n"
		  "may become unstable due to pruned empty\n"
		  "directories.\n", client_version, server_version);
	}
	break;
		  
    default:
	debug(DEBUG_APPERROR, "unknown cvs capability check %d", cap);
	exit(1);
    }

    return ret;
}

static void get_version_external()
{
    FILE * cvsfp;
    
    strcpy(client_version, "(UNKNOWN CLIENT)");
    strcpy(server_version, "(UNKNOWN SERVER)");

    if (!(cvsfp = popen("cvs version 2>/dev/null", "r")))
    {
	debug(DEBUG_APPERROR, "cannot popen cvs version. exiting");
	exit(1);
    }
    
    if (!fgets(client_version, BUFSIZ, cvsfp))
    {
	debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: no data");
	goto out;
    }
    
    chop(client_version);
    
    if (strncmp(client_version, "Client", 6) == 0)
    {
	if (!fgets(server_version, BUFSIZ, cvsfp))
	{
	    debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: no server data");
	    goto out;
	}
	chop(server_version);
    }
    else
    {
	server_version[0] = 0;
    }
    
 out:
    pclose(cvsfp);
}

int check_cvs_version(int req_major, int req_minor, int req_extra)
{
    if (!client_version[0])
    {
	if (cvs_direct_ctx)
	    cvs_version(cvs_direct_ctx, client_version, server_version);
	else
	    get_version_external();
    }

    return (check_version_string(client_version, req_major, req_minor, req_extra) &&
	    (!server_version[0] || check_version_string(server_version, req_major, req_minor, req_extra)));
}

int check_version_string(const char * str, int req_major, int req_minor, int req_extra)
{
    char * p;
    int major, minor, extra;
    int skip = 6;

    p = strstr(str, "(CVS) ");

    if (!p) {
	p = strstr(str, "(CVSNT)");
	skip = 8;
    }

    if (!p)
    {
	debug(DEBUG_APPMSG1, "WARNING: malformed CVS version str: %s", str);
	return 0;
    }

    /* We might have encountered a FreeBSD system which
     * has a mucked up version string of:
     *  Concurrent Versions System (CVS) '1.11.17'-FreeBSD (client/server)
     * so re-test just in case
     */
    p += skip;
    if (sscanf(p, "%d.%d.%d", &major, &minor, &extra) != 3)
    {	
        if (sscanf(p, "'%d.%d.%d'", &major, &minor, &extra) != 3)
	{
		debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: %s", str);
		return 0;
	}
    }

    return (major > req_major || 
	    (major == req_major && minor > req_minor) ||
	    (major == req_major && minor == req_minor && extra >= req_extra));
}