bootinfo_mysql.c 6.52 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
/*
 * EMULAB-COPYRIGHT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
3
 * Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
4
5
6
 * 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, "
Leigh B. Stoller's avatar
Leigh B. Stoller committed
46
47
48
49
50
51
52
53
		"  n.def_boot_osid, p.partition, n.def_boot_cmd_line, "
		"  n.def_boot_path, o1.path, n.next_boot_osid, o2.path "
		" from interfaces as i "
		"left join nodes as n on i.node_id=n.node_id "
		"left join partitions as p on "
		" n.node_id=p.node_id and n.def_boot_osid=p.osid "
		"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
	mysql_init(&db);
73
	if (mysql_real_connect(&db, 0, "bootinfo", 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