1 /* Public domain fmtmsg()
2  * Written by Isaac Dunham, 2014
3  */
4 #include <fmtmsg.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <pthread.h>
11 
12 /*
13  * If lstr is the first part of bstr, check that the next char in bstr
14  * is either \0 or :
15  */
_strcolcmp(const char * lstr,const char * bstr)16 static int _strcolcmp(const char *lstr, const char *bstr)
17 {
18 	size_t i = 0;
19 	while (lstr[i] && bstr[i] && (bstr[i] == lstr[i])) i++;
20 	if ( lstr[i] || (bstr[i] && bstr[i] != ':')) return 1;
21 	return 0;
22 }
23 
fmtmsg(long classification,const char * label,int severity,const char * text,const char * action,const char * tag)24 int fmtmsg(long classification, const char *label, int severity,
25            const char *text, const char *action, const char *tag)
26 {
27 	int ret = 0, i, consolefd, verb = 0;
28 	char *errstring = MM_NULLSEV, *cmsg = getenv("MSGVERB");
29 	char *const msgs[] = {
30 		"label", "severity", "text", "action", "tag", NULL
31 	};
32 	int cs;
33 
34 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
35 
36 	if (severity == MM_HALT) errstring = "HALT: ";
37 	else if (severity == MM_ERROR) errstring = "ERROR: ";
38 	else if (severity == MM_WARNING) errstring = "WARNING: ";
39 	else if (severity == MM_INFO) errstring = "INFO: ";
40 
41 	if (classification & MM_CONSOLE) {
42 		consolefd = open("/dev/console", O_WRONLY);
43 		if (consolefd < 0) {
44 			ret = MM_NOCON;
45 		} else {
46 			if (dprintf(consolefd, "%s%s%s%s%s%s%s%s\n",
47 			            label?label:"", label?": ":"",
48 			            severity?errstring:"", text?text:"",
49 			            action?"\nTO FIX: ":"",
50 			            action?action:"", action?" ":"",
51 			            tag?tag:"" )<1)
52 				ret = MM_NOCON;
53 			close(consolefd);
54 		}
55 	}
56 
57 	if (classification & MM_PRINT) {
58 		while (cmsg && cmsg[0]) {
59 			for(i=0; msgs[i]; i++) {
60 				if (!_strcolcmp(msgs[i], cmsg)) break;
61 			}
62 			if (msgs[i] == NULL) {
63 				//ignore MSGVERB-unrecognized component
64 				verb = 0xFF;
65 				break;
66 			} else {
67 				verb |= (1 << i);
68 				cmsg = strchr(cmsg, ':');
69 				if (cmsg) cmsg++;
70 			}
71 		}
72 		if (!verb) verb = 0xFF;
73 		if (dprintf(2, "%s%s%s%s%s%s%s%s\n",
74 		            (verb&1 && label) ? label : "",
75 		            (verb&1 && label) ? ": " : "",
76 		            (verb&2 && severity) ? errstring : "",
77 		            (verb&4 && text) ? text : "",
78 		            (verb&8 && action) ? "\nTO FIX: " : "",
79 		            (verb&8 && action) ? action : "",
80 		            (verb&8 && action) ? " " : "",
81 		            (verb&16 && tag) ? tag : "" ) < 1)
82 			ret |= MM_NOMSG;
83 	}
84 	if ((ret & (MM_NOCON|MM_NOMSG)) == (MM_NOCON|MM_NOMSG))
85 		ret = MM_NOTOK;
86 
87 	pthread_setcancelstate(cs, 0);
88 
89 	return ret;
90 }
91