bootinfo_mysql.c 6.54 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

int
open_bootinfo_db(void)
{
	return 0;
}

28 29 30 31 32 33 34 35
/*
  WARNING!!!
  
  DO NOT change this function without making corresponding changes to
  the perl version of this code in db/libdb.pm . They MUST ALWAYS
  return exactly the same result given the same inputs.
*/

36 37 38 39 40 41 42 43
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;
44 45
	char dbquery[] =
		"select n.next_boot_path, n.next_boot_cmd_line, "
46
		"n.def_boot_osid, p.partition, n.def_boot_cmd_line, "
47 48
	        "n.def_boot_path, o1.path, "
	        "n.next_boot_osid, o2.path from nodes "
49
		"as n left join partitions as p on n.node_id=p.node_id and "
50
		"n.def_boot_osid=p.osid left join interfaces as i on "
51
		"i.node_id=n.node_id "
52 53
    	        "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 "
54
	        "where i.IP = '%s'";
55 56 57

#define NEXT_BOOT_PATH		0
#define NEXT_BOOT_CMD_LINE	1
58
#define DEF_BOOT_OSID		2
59 60 61
#define PARTITION		3
#define DEF_BOOT_CMD_LINE	4
#define DEF_BOOT_PATH		5
62 63 64
#define DEF_BOOT_OSID_PATH	6
#define NEXT_BOOT_OSID		7
#define NEXT_BOOT_OSID_PATH	8
65 66 67

	n = snprintf(querybuf, sizeof querybuf, dbquery, inet_ntoa(ipaddr));
	if (n > sizeof querybuf) {
68
		syslog(LOG_ERR, "query too long for buffer");
69 70
		return 1;
	}
Mike Hibler's avatar
Mike Hibler committed
71
	
72 73
	mysql_init(&db);
	if (mysql_real_connect(&db, 0, 0, 0, dbname, 0, 0, 0) == 0) {
74
		syslog(LOG_ERR, "%s: connect failed: %s",
75 76 77 78
			dbname, mysql_error(&db));
		return 1;
	}

Mike Hibler's avatar
Mike Hibler committed
79 80 81 82
	/* Debug message into log:
	syslog(LOG_ERR, "USING QUERY: %s", querybuf);
	*/
	
83
	if (mysql_real_query(&db, querybuf, n) != 0) {
84
		syslog(LOG_ERR, "%s: query failed: %s",
85 86 87 88 89 90 91
			dbname, mysql_error(&db));
		mysql_close(&db);
		return 1;
	}

	res = mysql_store_result(&db);
	if (res == 0) {
92
		syslog(LOG_ERR, "%s: store_result failed: %s",
93 94 95 96 97 98 99 100 101 102
			dbname, mysql_error(&db));
		mysql_close(&db);
		return 1;

	}
	mysql_close(&db);

	nrows = (int)mysql_num_rows(res);
	switch (nrows) {
	case 0:
103
		syslog(LOG_ERR, "%s: no entry for host %s",
104 105 106 107 108 109
			dbname, inet_ntoa(ipaddr));
		mysql_free_result(res);
		return 1;
	case 1:
		break;
	default:
110
		syslog(LOG_ERR, "%s: %d entries for IP %s, using first",
111 112 113 114 115 116
			dbname, nrows, inet_ntoa(ipaddr));
		break;
	}

	ncols = (int)mysql_num_fields(res);
	switch (ncols) {
117
	case 9: /* Should have 9 fields */
118 119
		break;
	default:
120
		syslog(LOG_ERR, "%s: %d fields in query for IP %s!",
121 122 123 124 125 126
			dbname, ncols, inet_ntoa(ipaddr));
		mysql_free_result(res);
		return 1;
	}

	row = mysql_fetch_row(res);
Mike Hibler's avatar
Mike Hibler committed
127 128

	/*
129
	 * Check next_boot_path.  If set, assume it is a multiboot kernel.
Mike Hibler's avatar
Mike Hibler committed
130
	 */
131 132 133 134
	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
135
		info->type = BIBOOTWHAT_TYPE_MB;
136 137 138 139 140 141
		
		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);
142

143 144 145 146
		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);
147 148
		else
			info->cmdline[0] = 0;	/* Must zero first byte! */
Mike Hibler's avatar
Mike Hibler committed
149 150 151 152
		mysql_free_result(res);
		return 0;
	}

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

#undef NEXT_BOOT_PATH
#undef NEXT_BOOT_CMD_LINE
190
#undef DEF_BOOT_OSID
191 192 193
#undef PARTITION
#undef DEF_BOOT_CMD_LINE
#undef DEF_BOOT_PATH
194 195 196
#undef DEF_BOOT_OSID_PATH
#undef NEXT_BOOT_OSID
#undef NEXT_BOOT_OSID_PATH
197 198
}

199 200 201 202 203 204
int
close_bootinfo_db(void)
{
	return 0;
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
/*
 * 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;
}

235
#ifdef TEST
236 237 238 239 240 241 242 243 244 245 246 247 248
#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
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
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;
	}
267 268 269
	if (bootinfo->cmdline[0])
		printf("Command line %s\n", bootinfo->cmdline);
		
Mike Hibler's avatar
Mike Hibler committed
270 271
}

272 273 274 275 276 277
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;

278
	open_bootinfo_db();
279 280
	while (--argc > 0) {
		if (inet_aton(*++argv, &ipaddr))
Mike Hibler's avatar
Mike Hibler committed
281 282 283 284
			if (query_bootinfo_db(ipaddr, boot_whatp) == 0) {
				printf("%s: ", *argv);
				print_bootwhat(boot_whatp);
			} else
285
				printf("%s: failed\n", *argv);
286 287 288
		else
			printf("bogus IP address `%s'\n", *argv);
	}
289
	close_bootinfo_db();
290 291 292 293 294
	exit(0);
}
#endif

#endif