bootinfo_mysql.c 6.33 KB
Newer Older
Leigh Stoller's avatar
Leigh Stoller committed
1 2 3 4 5 6
/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2000-2002 University of Utah and the Flux Group.
 * All rights reserved.
 */

7 8
#include <sys/types.h>
#include <netinet/in.h>
9
#include <netdb.h>
10
#include <stdio.h>
11
#include <syslog.h>
12

13
#include "bootwhat.h"
14 15 16 17
#include <mysql/mysql.h>

#ifdef USE_MYSQL_DB

18
static char dbname[] = TBDBNAME;
19
static MYSQL db;
20
static int parse_multiboot_path(char *path, boot_what_t *info);
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

int
open_bootinfo_db(void)
{
	return 0;
}

int
query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
{
	char querybuf[1024];
	int n, nrows, ncols, part;
	MYSQL db;
	MYSQL_RES *res;
	MYSQL_ROW row;
36 37
	char dbquery[] =
		"select n.next_boot_path, n.next_boot_cmd_line, "
38
		"n.def_boot_osid, p.partition, n.def_boot_cmd_line, "
39 40
	        "n.def_boot_path, o1.path, "
	        "n.next_boot_osid, o2.path from nodes "
41
		"as n left join partitions as p on n.node_id=p.node_id and "
42
		"n.def_boot_osid=p.osid left join interfaces as i on "
43
		"i.node_id=n.node_id "
44 45
    	        "left join os_info as o1 on o1.osid=n.def_boot_osid "
    	        "left join os_info as o2 on o2.osid=n.next_boot_osid "
46
	        "where i.IP = '%s'";
47 48 49

#define NEXT_BOOT_PATH		0
#define NEXT_BOOT_CMD_LINE	1
50
#define DEF_BOOT_OSID		2
51 52 53
#define PARTITION		3
#define DEF_BOOT_CMD_LINE	4
#define DEF_BOOT_PATH		5
54 55 56
#define DEF_BOOT_OSID_PATH	6
#define NEXT_BOOT_OSID		7
#define NEXT_BOOT_OSID_PATH	8
57 58 59

	n = snprintf(querybuf, sizeof querybuf, dbquery, inet_ntoa(ipaddr));
	if (n > sizeof querybuf) {
60
		syslog(LOG_ERR, "query too long for buffer");
61 62
		return 1;
	}
Mike Hibler's avatar
Mike Hibler committed
63
	
64 65
	mysql_init(&db);
	if (mysql_real_connect(&db, 0, 0, 0, dbname, 0, 0, 0) == 0) {
66
		syslog(LOG_ERR, "%s: connect failed: %s",
67 68 69 70
			dbname, mysql_error(&db));
		return 1;
	}

Mike Hibler's avatar
Mike Hibler committed
71 72 73 74
	/* Debug message into log:
	syslog(LOG_ERR, "USING QUERY: %s", querybuf);
	*/
	
75
	if (mysql_real_query(&db, querybuf, n) != 0) {
76
		syslog(LOG_ERR, "%s: query failed: %s",
77 78 79 80 81 82 83
			dbname, mysql_error(&db));
		mysql_close(&db);
		return 1;
	}

	res = mysql_store_result(&db);
	if (res == 0) {
84
		syslog(LOG_ERR, "%s: store_result failed: %s",
85 86 87 88 89 90 91 92 93 94
			dbname, mysql_error(&db));
		mysql_close(&db);
		return 1;

	}
	mysql_close(&db);

	nrows = (int)mysql_num_rows(res);
	switch (nrows) {
	case 0:
95
		syslog(LOG_ERR, "%s: no entry for host %s",
96 97 98 99 100 101
			dbname, inet_ntoa(ipaddr));
		mysql_free_result(res);
		return 1;
	case 1:
		break;
	default:
102
		syslog(LOG_ERR, "%s: %d entries for IP %s, using first",
103 104 105 106 107 108
			dbname, nrows, inet_ntoa(ipaddr));
		break;
	}

	ncols = (int)mysql_num_fields(res);
	switch (ncols) {
109
	case 9: /* Should have 9 fields */
110 111
		break;
	default:
112
		syslog(LOG_ERR, "%s: %d fields in query for IP %s!",
113 114 115 116 117 118
			dbname, ncols, inet_ntoa(ipaddr));
		mysql_free_result(res);
		return 1;
	}

	row = mysql_fetch_row(res);
Mike Hibler's avatar
Mike Hibler committed
119 120

	/*
121
	 * Check next_boot_path.  If set, assume it is a multiboot kernel.
Mike Hibler's avatar
Mike Hibler committed
122
	 */
123 124 125 126
	if ((row[NEXT_BOOT_PATH] != 0 &&
	     row[NEXT_BOOT_PATH][0] != '\0') ||
	    (row[NEXT_BOOT_OSID_PATH] != 0 &&
	     row[NEXT_BOOT_OSID_PATH][0] != '\0')) {
Mike Hibler's avatar
Mike Hibler committed
127
		info->type = BIBOOTWHAT_TYPE_MB;
128 129 130 131 132 133
		
		if (row[NEXT_BOOT_PATH] != 0 &&
		    row[NEXT_BOOT_PATH][0] != '\0')
		    parse_multiboot_path(row[NEXT_BOOT_PATH], info);
		else
		    parse_multiboot_path(row[NEXT_BOOT_OSID_PATH], info);
134

135 136 137 138
		if (row[NEXT_BOOT_CMD_LINE] != 0 &&
		    row[NEXT_BOOT_CMD_LINE][0] != '\0')
			strncpy(info->cmdline, row[NEXT_BOOT_CMD_LINE],
				MAX_BOOT_CMDLINE-1);
139 140
		else
			info->cmdline[0] = 0;	/* Must zero first byte! */
Mike Hibler's avatar
Mike Hibler committed
141 142 143 144
		mysql_free_result(res);
		return 0;
	}

145 146 147 148
	/*
	 * There is either a partition number or default boot path.
	 * The default boot path overrides the partition.
	 */
149
	if (row[DEF_BOOT_PATH] != 0 && row[DEF_BOOT_PATH][0] != '\0') {
150
		info->type = BIBOOTWHAT_TYPE_MB;
151
		parse_multiboot_path(row[DEF_BOOT_PATH], info);
152
	}
153 154
	else if (row[DEF_BOOT_OSID_PATH] != 0 &&
		 row[DEF_BOOT_OSID_PATH][0] != '\0') {
155
		info->type = BIBOOTWHAT_TYPE_MB;
156
		parse_multiboot_path(row[DEF_BOOT_OSID_PATH], info);
157
	}
158
	else if (row[PARTITION] != 0 && row[PARTITION][0] != '\0') {
159
		info->type = BIBOOTWHAT_TYPE_PART;
160
		info->what.partition = atoi(row[PARTITION]);
161 162
	}
	else {
163
		syslog(LOG_ERR, "%s: null query result for IP %s!",
164 165 166 167
			dbname, inet_ntoa(ipaddr));
		mysql_free_result(res);
		return 1;
	}
168 169 170
	if (row[DEF_BOOT_CMD_LINE] != 0 && row[DEF_BOOT_CMD_LINE][0] != '\0')
		strncpy(info->cmdline, row[DEF_BOOT_CMD_LINE],
			MAX_BOOT_CMDLINE-1);
171 172 173
	else
		info->cmdline[0] = 0;	/* Must zero first byte! */
	
174 175 176 177 178
	/*
	 * Just 45040 lines of code later, we are done. 
	 */
	mysql_free_result(res);
	return 0;
179 180 181

#undef NEXT_BOOT_PATH
#undef NEXT_BOOT_CMD_LINE
182
#undef DEF_BOOT_OSID
183 184 185
#undef PARTITION
#undef DEF_BOOT_CMD_LINE
#undef DEF_BOOT_PATH
186 187 188
#undef DEF_BOOT_OSID_PATH
#undef NEXT_BOOT_OSID
#undef NEXT_BOOT_OSID_PATH
189 190
}

191 192 193 194 195 196
int
close_bootinfo_db(void)
{
	return 0;
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
/*
 * Split a multiboot path into the IP and Path.
 */
static int
parse_multiboot_path(char *path, boot_what_t *info)
{
	char		*p  = path;
	struct hostent	*he;

	info->type = BIBOOTWHAT_TYPE_MB;
	info->what.mb.tftp_ip.s_addr = 0;

	strsep(&p, ":");
	if (p) {
		he = gethostbyname(path);
		path = p;
	}
	else {
		he = gethostbyname("users.emulab.net");
	}
	if (he) {
		memcpy((char *)&info->what.mb.tftp_ip,
		       he->h_addr, sizeof(info->what.mb.tftp_ip));
	}

	strncpy(info->what.mb.filename, path, MAX_BOOT_PATH-1);

	return 0;
}

227
#ifdef TEST
228 229 230 231 232 233 234 235 236 237 238 239 240
#include <stdarg.h>

void
syslog(int prio, const char *msg, ...)
{
	va_list ap;

	va_start(ap, msg);
	vfprintf(stderr, msg, ap);
	va_end(ap);
	fprintf(stderr, "\n");
}

Mike Hibler's avatar
Mike Hibler committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
static void
print_bootwhat(boot_what_t *bootinfo)
{
	switch (bootinfo->type) {
	case BIBOOTWHAT_TYPE_PART:
		printf("boot from partition %d\n",
		       bootinfo->what.partition);
		break;
	case BIBOOTWHAT_TYPE_SYSID:
		printf("boot from partition with sysid %d\n",
		       bootinfo->what.sysid);
		break;
	case BIBOOTWHAT_TYPE_MB:
		printf("boot multiboot image %s:%s\n",
		       inet_ntoa(bootinfo->what.mb.tftp_ip),
		       bootinfo->what.mb.filename);
		break;
	}
259 260 261
	if (bootinfo->cmdline[0])
		printf("Command line %s\n", bootinfo->cmdline);
		
Mike Hibler's avatar
Mike Hibler committed
262 263
}

264 265 266 267 268 269
main(int argc, char **argv)
{
	struct in_addr ipaddr;
	boot_info_t boot_info;
	boot_what_t *boot_whatp = (boot_what_t *)&boot_info.data;

270
	open_bootinfo_db();
271 272
	while (--argc > 0) {
		if (inet_aton(*++argv, &ipaddr))
Mike Hibler's avatar
Mike Hibler committed
273 274 275 276
			if (query_bootinfo_db(ipaddr, boot_whatp) == 0) {
				printf("%s: ", *argv);
				print_bootwhat(boot_whatp);
			} else
277
				printf("%s: failed\n", *argv);
278 279 280
		else
			printf("bogus IP address `%s'\n", *argv);
	}
281
	close_bootinfo_db();
282 283 284 285 286
	exit(0);
}
#endif

#endif