Home | History | Annotate | Download | only in diskomizer
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  *	Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  *	Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"@(#)usage_tracking.c	1.8	09/05/26 SMI"
     28 
     29 #include <sys/types.h>
     30 #include <sys/systeminfo.h>
     31 #include <sys/stat.h>
     32 #include <fcntl.h>
     33 #include <unistd.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <strings.h>
     37 #include <string.h>
     38 #include <time.h>
     39 #include <limits.h>
     40 #include <signal.h>
     41 
     42 #include <usage_tracking/usage_tracking.h>
     43 
     44 #ifdef ASSERT_USAGE_TRACKING
     45 #include <diskomizer/assert.h>
     46 #else
     47 #define	assert(A)
     48 #endif
     49 
     50 #define	SYSINFO_BUF_SIZE 25
     51 
     52 struct key_list {
     53 	char *key;
     54 	struct key_list *next;
     55 };
     56 
     57 typedef struct usage_track {
     58 	struct key_list *list;
     59 	char *sendmail;
     60 	char *to;
     61 	char *from;
     62 	char *tool;
     63 	char *version;
     64 	char *dom;
     65 	char *str;
     66 	int len;
     67 	int indent;
     68 	int errors;
     69 } usage_track_t;
     70 
     71 static const char xml_version[] = "<?xml version=\"1.0\"?>\n";
     72 
     73 #define	NOT_NULL_FREE(X) if (X != NULL) { free(X); X = NULL; }
     74 
     75 static struct key_list *
     76 push_key(usage_track_t *usage_trackp, const char *key)
     77 {
     78 	struct key_list *x;
     79 
     80 	if ((x = malloc(sizeof (struct key_list))) == NULL) {
     81 		return (NULL);
     82 	}
     83 	if ((x->key = strdup(key)) == NULL) {
     84 		free(x);
     85 		return (NULL);
     86 	}
     87 	x->next = usage_trackp->list;
     88 	usage_trackp->list = x;
     89 	return (x);
     90 }
     91 
     92 static char *
     93 pop_key(usage_track_t *usage_trackp)
     94 {
     95 	char *x;
     96 	struct key_list *l;
     97 
     98 	if ((l = usage_trackp->list) == NULL) {
     99 		return (NULL);
    100 	}
    101 	x = l->key;
    102 	usage_trackp->list = l->next;
    103 	free(l);
    104 
    105 	return (x);
    106 }
    107 
    108 static void
    109 free_usage_track(usage_track_t *usage_trackp)
    110 {
    111 	char *key;
    112 
    113 	NOT_NULL_FREE(usage_trackp->to);
    114 	NOT_NULL_FREE(usage_trackp->from);
    115 	NOT_NULL_FREE(usage_trackp->sendmail);
    116 	NOT_NULL_FREE(usage_trackp->dom);
    117 	NOT_NULL_FREE(usage_trackp->str);
    118 	NOT_NULL_FREE(usage_trackp->tool);
    119 	NOT_NULL_FREE(usage_trackp->version);
    120 
    121 	while ((key = pop_key(usage_trackp)) != NULL) {
    122 		free(key);
    123 	}
    124 	free(usage_trackp);
    125 }
    126 
    127 
    128 static void
    129 close_open_keys(usage_track_t *usage_trackp)
    130 {
    131 	while (usage_trackp->list != NULL) {
    132 		usage_tracking_close_key((void *)usage_trackp);
    133 	}
    134 }
    135 
    136 static void
    137 indent(usage_track_t *usage_trackp)
    138 {
    139 	int i;
    140 
    141 	for (i = 0; i < usage_trackp->indent; i++) {
    142 		usage_trackp->str[usage_trackp->len++] = '\t';
    143 	}
    144 }
    145 
    146 void
    147 usage_tracking_store_key_value(void *handle,
    148 		const char *key, const char *value)
    149 {
    150 	/*
    151 	 * No need to push and pop the key as we are just doing the whole
    152 	 * thing in one hit.
    153 	 */
    154 	int this_len;
    155 	char *tmp;
    156 	usage_track_t *usage_trackp = handle;
    157 
    158 	if (usage_trackp == NULL) {
    159 		return;
    160 	}
    161 
    162 	this_len = (3 * usage_trackp->indent) + (2 * strlen(key)) +
    163 	    strlen(value) + 9;
    164 
    165 	if ((tmp = realloc(usage_trackp->str,
    166 	    usage_trackp->len + this_len + 1)) == NULL) {
    167 		usage_trackp->errors++;
    168 	} else {
    169 		int x =  usage_trackp->len;
    170 
    171 		usage_trackp->str = tmp;
    172 		indent(usage_trackp);
    173 		usage_trackp->len +=
    174 		    sprintf(&usage_trackp->str[usage_trackp->len],
    175 		    "<%s>\n", key);
    176 
    177 		indent(usage_trackp);
    178 
    179 		usage_trackp->len +=
    180 		    sprintf(&usage_trackp->str[usage_trackp->len],
    181 		    "\t%s\n", value);
    182 		indent(usage_trackp);
    183 
    184 		usage_trackp->len +=
    185 		    sprintf(&usage_trackp->str[usage_trackp->len],
    186 		    "</%s>\n", key);
    187 
    188 		assert(x + this_len ==  usage_trackp->len);
    189 	}
    190 }
    191 
    192 void
    193 usage_tracking_store_key_value_int(void *handle,
    194 		const char *key, const long long value)
    195 {
    196 	char buf[64];
    197 	sprintf(buf, "%lld", value);
    198 	usage_tracking_store_key_value(handle, key, buf);
    199 }
    200 
    201 int
    202 usage_tracking_open_key(void *handle,
    203 	const char *key, const char *version, const char *id)
    204 {
    205 	int this_len;
    206 	char *tmp;
    207 	usage_track_t *usage_trackp = handle;
    208 
    209 	if (usage_trackp == NULL) {
    210 		return (0);
    211 	}
    212 
    213 	this_len = strlen(key) + /* "<>\n" */  3 + usage_trackp->indent;
    214 
    215 	if (version != NULL) {
    216 		this_len += strlen(version) + /* " version=\"\"" */ 11;
    217 	}
    218 
    219 	if (id != NULL) {
    220 		this_len += strlen(id) + /* " id=\"\"" */ 6;
    221 	}
    222 
    223 	if ((tmp = realloc(usage_trackp->str,
    224 	    usage_trackp->len + this_len + 1)) == NULL) {
    225 		usage_trackp->errors++;
    226 		return (0);
    227 	} else {
    228 		int x =  usage_trackp->len;
    229 		int i;
    230 
    231 		if (push_key(usage_trackp, key) == NULL) {
    232 			usage_trackp->errors++;
    233 			return (0);
    234 		}
    235 
    236 		usage_trackp->str = tmp;
    237 
    238 		indent(usage_trackp);
    239 
    240 		i = sprintf(&usage_trackp->str[usage_trackp->len], "<%s", key);
    241 		usage_trackp->len += i;
    242 
    243 		if (version != NULL) {
    244 			i = sprintf(&usage_trackp->str[usage_trackp->len],
    245 			    " version=\"%s\"", version);
    246 			usage_trackp->len += i;
    247 		}
    248 
    249 		if (id != NULL) {
    250 			i = sprintf(&usage_trackp->str[usage_trackp->len],
    251 			    " id=\"%s\"", id);
    252 			usage_trackp->len += i;
    253 		}
    254 
    255 		i = sprintf(&usage_trackp->str[usage_trackp->len], ">\n");
    256 		usage_trackp->len += i;
    257 
    258 		usage_trackp->indent++;
    259 
    260 		assert(x + this_len ==  usage_trackp->len);
    261 	}
    262 	return (1);
    263 }
    264 
    265 int
    266 usage_tracking_close_key(void *handle)
    267 {
    268 	int this_len;
    269 	int ret;
    270 	char *key;
    271 	char *tmp;
    272 	usage_track_t *usage_trackp = handle;
    273 
    274 	if (usage_trackp == NULL) {
    275 		return (0);
    276 	}
    277 
    278 	if ((key = pop_key(usage_trackp)) == NULL ||
    279 	    --usage_trackp->indent < 0) {
    280 		usage_trackp->indent = 0;
    281 		usage_trackp->errors++;
    282 		usage_tracking_store_key_value(handle, "usage_track_error",
    283 		    "Unbalanced close");
    284 		return (0);
    285 	}
    286 	this_len = strlen(key) + /* "</>\n" */ 4 + usage_trackp->indent;
    287 
    288 	if ((tmp = realloc(usage_trackp->str,
    289 	    usage_trackp->len + this_len + 1)) == NULL) {
    290 		usage_trackp->errors++;
    291 		ret = 0;
    292 	} else {
    293 		int x =  usage_trackp->len;
    294 
    295 		usage_trackp->str = tmp;
    296 
    297 		indent(usage_trackp);
    298 
    299 		sprintf(&usage_trackp->str[usage_trackp->len],
    300 		    "</%s>\n", key);
    301 		usage_trackp->len += strlen(key) + 4;
    302 		assert(x + this_len ==  usage_trackp->len);
    303 		ret = 1;
    304 	}
    305 	free(key);
    306 	return (ret);
    307 }
    308 
    309 void
    310 usage_tracking_store_value(void *handle,
    311 		const char *value)
    312 {
    313 	int this_len;
    314 	char *tmp;
    315 	usage_track_t *usage_trackp = handle;
    316 
    317 	if (usage_trackp == NULL) {
    318 		return;
    319 	}
    320 
    321 	this_len = strlen(value) + /* "\n" */  1 + usage_trackp->indent;
    322 
    323 	if ((tmp = realloc(usage_trackp->str,
    324 	    usage_trackp->len + this_len + 1)) == NULL) {
    325 		usage_trackp->errors++;
    326 		return;
    327 	} else {
    328 		int x =  usage_trackp->len;
    329 		usage_trackp->str = tmp;
    330 
    331 		indent(handle);
    332 
    333 		usage_trackp->len +=
    334 		    sprintf(&usage_trackp->str[usage_trackp->len],
    335 		    "%s\n", value);
    336 		assert(x + this_len ==  usage_trackp->len);
    337 	}
    338 }
    339 
    340 static int
    341 usage_tracking_ok(const char *dom, const char *host)
    342 {
    343 	char *buf;
    344 	char *tmp;
    345 	int dom_len = strlen(dom);
    346 	long len = 0;
    347 	long ret;
    348 	char x[1];
    349 
    350 	if (dom_len == 0 || (ret = sysinfo(SI_SRPC_DOMAIN, x, 1)) <= dom_len) {
    351 		return (0);
    352 	}
    353 	if ((buf = malloc(ret)) == NULL) {
    354 		return (0);
    355 	}
    356 	len = ret;
    357 
    358 	if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, len)) > len) {
    359 		free(buf);
    360 		return (0);
    361 	}
    362 
    363 	ret--; /* remove the space for the NULL from the length */
    364 
    365 	tmp = &buf[ret - dom_len];
    366 
    367 	if (strcasecmp(tmp, dom) != 0) {
    368 		free(buf);
    369 		return (0);
    370 	}
    371 	free(buf);
    372 	return (1);
    373 }
    374 
    375 static char *
    376 now_str(char *str)
    377 {
    378 	time_t now = time(NULL);
    379 
    380 	cftime(str, "%D %T %z", &now);
    381 	return (str);
    382 }
    383 
    384 static void
    385 usage_tracking_start_time(usage_track_t *usage_trackp)
    386 {
    387 	if (usage_tracking_open_key(usage_trackp, "START_TIME", NULL, NULL)) {
    388 		time_t now = time(NULL);
    389 		char buf[128];
    390 		int len;
    391 
    392 		ctime_r(&now, buf, sizeof (buf));
    393 
    394 		len = strlen(buf) - 1;
    395 
    396 		if (buf[len] = '\n') {
    397 			buf[len] = NULL;
    398 		}
    399 
    400 		usage_tracking_store_key_value(usage_trackp,
    401 		    "LOCAL_TIME", buf);
    402 		usage_tracking_store_key_value_int(usage_trackp,
    403 		    "UNIX_TIME", now);
    404 
    405 		usage_tracking_close_key((void *)usage_trackp);
    406 	}
    407 }
    408 
    409 static void
    410 usage_tracking_sysinfo(usage_track_t *usage_trackp,
    411 	int command, const char *str)
    412 {
    413 	char buf[SYSINFO_BUF_SIZE];
    414 	char *t;
    415 	int x;
    416 
    417 	if ((x = sysinfo(command, buf, sizeof (buf))) > sizeof (buf)) {
    418 		if ((t = malloc(x)) != NULL) {
    419 			(void) sysinfo(command, t, x);
    420 		} else {
    421 			t = buf;
    422 		}
    423 	} else {
    424 		t = buf;
    425 	}
    426 
    427 	usage_tracking_store_key_value(usage_trackp, str, t);
    428 
    429 	if (t != buf) {
    430 		free(t);
    431 	}
    432 
    433 }
    434 
    435 
    436 static void
    437 usage_tracking_system_info(usage_track_t *usage_trackp)
    438 {
    439 	if (usage_tracking_open_key(usage_trackp, "SYSTEM_INFO",
    440 	    NULL, NULL)) {
    441 
    442 		usage_tracking_sysinfo(usage_trackp, SI_SYSNAME, "OSNAME");
    443 
    444 		usage_tracking_sysinfo(usage_trackp, SI_HOSTNAME, "NODENAME");
    445 
    446 		usage_tracking_sysinfo(usage_trackp, SI_SRPC_DOMAIN,
    447 		    "DOMAINNAME");
    448 
    449 		usage_tracking_sysinfo(usage_trackp, SI_RELEASE, "OSVERSION");
    450 
    451 		usage_tracking_sysinfo(usage_trackp, SI_MACHINE, "MACHINE");
    452 
    453 		usage_tracking_sysinfo(usage_trackp, SI_PLATFORM, "PLATFORM");
    454 
    455 		usage_tracking_sysinfo(usage_trackp, SI_HW_SERIAL, "SERIAL");
    456 
    457 		usage_tracking_sysinfo(usage_trackp, SI_HW_PROVIDER,
    458 		    "HWPROVIDER");
    459 
    460 		usage_tracking_sysinfo(usage_trackp, SI_ISALIST,
    461 		    "ISALIST");
    462 
    463 		usage_tracking_close_key((void *)usage_trackp);
    464 	}
    465 }
    466 
    467 static void
    468 usage_tracking_tool_info(usage_track_t *usage_trackp)
    469 {
    470 	if (usage_tracking_open_key(usage_trackp, "TOOL_INFO", NULL, NULL)) {
    471 		usage_tracking_store_key_value(usage_trackp, "NAME",
    472 		    usage_trackp->tool);
    473 		usage_tracking_store_key_value(usage_trackp, "VERSION",
    474 		    usage_trackp->version);
    475 		usage_tracking_store_key_value_int(usage_trackp,
    476 		    "POINTER_BITS", sizeof (void *) * CHAR_BIT);
    477 
    478 		usage_tracking_close_key((void *)usage_trackp);
    479 	}
    480 }
    481 
    482 
    483 static void
    484 usage_tracking_general(usage_track_t *usage_trackp)
    485 {
    486 	if (usage_tracking_open_key(usage_trackp, "GENERAL", NULL, NULL)) {
    487 		usage_tracking_start_time(usage_trackp);
    488 		usage_tracking_system_info(usage_trackp);
    489 		usage_tracking_tool_info(usage_trackp);
    490 
    491 		usage_tracking_close_key((void *)usage_trackp);
    492 	}
    493 }
    494 
    495 void *
    496 open_usage_tracking(const char *dom,
    497 	const char *sendmail,
    498 	const char *to,
    499 	const char *from,
    500 	const char *tool,
    501 	const char *version)
    502 {
    503 	usage_track_t *usage_trackp;
    504 
    505 	if ((usage_trackp = malloc(sizeof (usage_track_t))) == NULL) {
    506 		return (NULL);
    507 	}
    508 
    509 	memset(usage_trackp, 0, sizeof (usage_track_t));
    510 
    511 	if ((usage_trackp->dom = strdup(dom)) == NULL ||
    512 	    (usage_trackp->sendmail = strdup(sendmail)) == NULL ||
    513 	    (usage_trackp->from = strdup(from)) == NULL ||
    514 	    (usage_trackp->to = strdup(to)) == NULL ||
    515 	    (usage_trackp->tool = strdup(tool)) == NULL ||
    516 	    (usage_trackp->version = strdup(version)) == NULL) {
    517 		free_usage_track(usage_trackp);
    518 		return (NULL);
    519 	}
    520 
    521 	if ((usage_trackp->str = strdup(xml_version)) != NULL) {
    522 		usage_trackp->len = sizeof (xml_version) - 1;
    523 	}
    524 
    525 	if (usage_tracking_open_key(usage_trackp,
    526 	    USAGE_TRACKING, USAGE_TRACKING_VERSION, tool)) {
    527 
    528 		usage_tracking_general(usage_trackp);
    529 
    530 		usage_tracking_open_key(
    531 		    usage_trackp, "TOOLDEFINED", NULL, NULL);
    532 	}
    533 
    534 	return (usage_trackp);
    535 }
    536 
    537 void
    538 close_usage_tracking(void *handle)
    539 {
    540 	usage_track_t *usage_trackp = handle;
    541 
    542 	if (usage_trackp == NULL) {
    543 		return;
    544 	}
    545 
    546 	free_usage_track(usage_trackp);
    547 }
    548 
    549 
    550 void
    551 send_usage_tracking(void *handle)
    552 {
    553 	FILE *fd;
    554 	char *command;
    555 	char now[256];
    556 	sigset_t nset; /* new set */
    557 	sigset_t oset; /* old set */
    558 	int sigprocmask_status;
    559 	usage_track_t *usage_trackp = handle;
    560 
    561 	if (usage_trackp == NULL) {
    562 		return;
    563 	}
    564 
    565 	now_str(now);
    566 
    567 	if (!usage_tracking_ok(usage_trackp->dom, NULL)) {
    568 		return;
    569 	}
    570 
    571 	close_open_keys(usage_trackp);
    572 
    573 	if ((command = malloc(strlen(usage_trackp->sendmail) +
    574 	    strlen(usage_trackp->to) + 2)) == NULL) {
    575 		return;
    576 	}
    577 
    578 	sprintf(command, "%s %s", usage_trackp->sendmail, usage_trackp->to);
    579 
    580 	if (access(usage_trackp->sendmail, X_OK) != 0) {
    581 		free(command);
    582 		return;
    583 	}
    584 
    585 	fd = popen(command, "w");
    586 
    587 	free(command);
    588 
    589 	if (fd == NULL) {
    590 		return;
    591 	}
    592 
    593 	sigaddset(&nset, SIGPIPE);
    594 	sigprocmask_status = sigprocmask(SIG_BLOCK, &nset, &oset);
    595 
    596 	fprintf(fd, "From: %s\nTo: %s\nDate: %s\nSubject: %s\n%s\n.\n",
    597 	    usage_trackp->from,
    598 	    usage_trackp->to, now,
    599 	    usage_trackp->tool, usage_trackp->str);
    600 
    601 	pclose(fd);
    602 	if (sigprocmask_status == 0) {
    603 		(void) sigprocmask(SIG_SETMASK, &nset, &oset);
    604 	}
    605 }
    606 
    607 void
    608 save_usage_tracking(void *handle, const char *file)
    609 {
    610 	int fd;
    611 	int i;
    612 	int written;
    613 	usage_track_t *usage_trackp = handle;
    614 
    615 	if (usage_trackp == NULL) {
    616 		return;
    617 	}
    618 
    619 	if (file == NULL ||
    620 	    (fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
    621 		return;
    622 	}
    623 
    624 	close_open_keys(usage_trackp);
    625 
    626 	for (written = 0; written < usage_trackp->len; written += i) {
    627 		i = write(fd, &usage_trackp->str[written],
    628 		    usage_trackp->len - written);
    629 		if (i == -1) {
    630 			break;
    631 		}
    632 	}
    633 	close(fd);
    634 }
    635