1 /*-
2  * Copyright (c) 2014-2018 MongoDB, Inc.
3  * Copyright (c) 2008-2014 WiredTiger, Inc.
4  *	All rights reserved.
5  *
6  * See the file LICENSE for redistribution information.
7  */
8 
9 #include "util.h"
10 
11 int
util_cerr(WT_CURSOR * cursor,const char * op,int ret)12 util_cerr(WT_CURSOR *cursor, const char *op, int ret)
13 {
14 	return (
15 	    util_err(cursor->session, ret, "%s: cursor.%s", cursor->uri, op));
16 }
17 
18 /*
19  * util_err --
20  * 	Report an error.
21  */
22 int
util_err(WT_SESSION * session,int e,const char * fmt,...)23 util_err(WT_SESSION *session, int e, const char *fmt, ...)
24 {
25 	va_list ap;
26 
27 	(void)fprintf(stderr, "%s: ", progname);
28 	if (fmt != NULL) {
29 		va_start(ap, fmt);
30 		(void)vfprintf(stderr, fmt, ap);
31 		va_end(ap);
32 		if (e != 0)
33 			(void)fprintf(stderr, ": ");
34 	}
35 	if (e != 0)
36 		(void)fprintf(stderr, "%s", session == NULL ?
37 		    wiredtiger_strerror(e) : session->strerror(session, e));
38 	(void)fprintf(stderr, "\n");
39 	return (1);
40 }
41 
42 /*
43  * util_read_line --
44  *	Read a line from stdin into a ULINE.
45  */
46 int
util_read_line(WT_SESSION * session,ULINE * l,bool eof_expected,bool * eofp)47 util_read_line(WT_SESSION *session, ULINE *l, bool eof_expected, bool *eofp)
48 {
49 	static uint64_t line = 0;
50 	size_t len;
51 	int ch;
52 
53 	++line;
54 	*eofp = false;
55 
56 	if (l->memsize == 0) {
57 		if ((l->mem = realloc(l->mem, l->memsize + 1024)) == NULL)
58 			return (util_err(session, errno, NULL));
59 		l->memsize = 1024;
60 	}
61 	for (len = 0;; ++len) {
62 		if ((ch = getchar()) == EOF) {
63 			if (len == 0) {
64 				if (eof_expected) {
65 					*eofp = true;
66 					return (0);
67 				}
68 				return (util_err(session, 0,
69 				    "line %" PRIu64 ": unexpected end-of-file",
70 				    line));
71 			}
72 			return (util_err(session, 0,
73 			    "line %" PRIu64 ": no newline terminator", line));
74 		}
75 		if (ch == '\n')
76 			break;
77 		/*
78 		 * We nul-terminate the string so it's easier to convert the
79 		 * line into a record number, that means we always need one
80 		 * extra byte at the end.
81 		 */
82 		if (len >= l->memsize - 1) {
83 			if ((l->mem =
84 			    realloc(l->mem, l->memsize + 1024)) == NULL)
85 				return (util_err(session, errno, NULL));
86 			l->memsize += 1024;
87 		}
88 		((uint8_t *)l->mem)[len] = (uint8_t)ch;
89 	}
90 
91 	((uint8_t *)l->mem)[len] = '\0';		/* nul-terminate */
92 
93 	return (0);
94 }
95 
96 /*
97  * util_str2num --
98  *	Convert a string to a number.
99  */
100 int
util_str2num(WT_SESSION * session,const char * p,bool endnul,uint64_t * vp)101 util_str2num(WT_SESSION *session, const char *p, bool endnul, uint64_t *vp)
102 {
103 	uint64_t v;
104 	char *endptr;
105 
106 	/*
107 	 * strtouq takes lots of things like hex values, signs and so on and so
108 	 * forth -- none of them are OK with us.  Check the string starts with
109 	 * digit, that turns off the special processing.
110 	 */
111 	if (!__wt_isdigit((u_char)p[0]))
112 		goto format;
113 
114 	errno = 0;
115 	v = __wt_strtouq(p, &endptr, 0);
116 	if (v == ULLONG_MAX && errno == ERANGE)
117 		return (util_err(session, ERANGE, "%s: invalid number", p));
118 
119 	/*
120 	 * In most cases we expect the number to be a string and end with a
121 	 * nul byte (and we want to confirm that because it's a user-entered
122 	 * command-line argument), but we allow the caller to configure that
123 	 * test off.
124 	 */
125 	if (endnul && endptr[0] != '\0')
126 format:		return (util_err(session, EINVAL, "%s: invalid number", p));
127 
128 	*vp = v;
129 	return (0);
130 }
131 
132 /*
133  * util_flush --
134  *	Flush the file successfully, or drop it.
135  */
136 int
util_flush(WT_SESSION * session,const char * uri)137 util_flush(WT_SESSION *session, const char *uri)
138 {
139 	WT_DECL_RET;
140 	size_t len;
141 	char *buf;
142 
143 	len = strlen(uri) + 100;
144 	if ((buf = malloc(len)) == NULL)
145 		return (util_err(session, errno, NULL));
146 
147 	if ((ret = __wt_snprintf(buf, len, "target=(\"%s\")", uri)) != 0) {
148 		free(buf);
149 		return (util_err(session, ret, NULL));
150 	}
151 	ret = session->checkpoint(session, buf);
152 	free(buf);
153 
154 	if (ret == 0)
155 		return (0);
156 
157 	(void)util_err(session, ret, "%s: session.checkpoint", uri);
158 	if ((ret = session->drop(session, uri, NULL)) != 0)
159 		(void)util_err(session, ret, "%s: session.drop", uri);
160 	return (1);
161 }
162