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 /* Copyright (c) 1988 AT&T */
22 /* All Rights Reserved */
23 /*
24  * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * Copyright 2006-2020 J. Schilling
29  *
30  * @(#)fatal.c	1.14 20/09/06 J. Schilling
31  */
32 #if defined(sun)
33 #pragma ident "@(#)fatal.c 1.14 20/09/06 J. Schilling"
34 #endif
35 /*
36  * @(#)fatal.c 1.8 06/12/12
37  */
38 
39 #if defined(sun)
40 #pragma ident	"@(#)fatal.c"
41 #pragma ident	"@(#)sccs:lib/mpwlib/fatal.c"
42 #endif
43 # include	<defines.h>
44 # include	<fatal.h>
45 # include	<had.h>
46 
47 /*
48 	General purpose error handler.
49 	Typically, low level subroutines which detect error conditions
50 	(an open or create routine, for example) return the
51 	value of calling fatal with an appropriate error message string.
52 	E.g.,	return(fatal("can't do it"));
53 	Higher level routines control the execution of fatal
54 	via the global word Fflags.
55 	The macros FSAVE and FRSTR in <fatal.h> can be used by higher
56 	level subroutines to save and restore the Fflags word.
57 
58 	The argument to fatal is a pointer to an error message string.
59 	The action of this routine is driven completely from
60 	the "Fflags" global word (see <fatal.h>).
61 	The following discusses the interpretation of the various bits
62 	of Fflags.
63 
64 	The FTLMSG bit controls the writing of the error
65 	message on file descriptor 2.  The message is preceded
66 	by the string "ERROR: ", unless the global character pointer
67 	"Ffile" is non-zero, in which case the message is preceded
68 	by the string "ERROR [<Ffile>]: ".  A newline is written
69 	after the user supplied message.
70 
71 	If the FTLCLN bit is on, clean_up is called with an
72 	argument of 0 (see clean.c).
73 
74 	If the FTLFUNC bit is on, the function pointed to by the global
75 	function pointer "Ffunc" is called with the user supplied
76 	error message pointer as argument.
77 	(This feature can be used to log error messages).
78 
79 	The FTLACT bits determine how fatal should return.
80 	If the FTLJMP bit is on longjmp(Fjmp) is called
81        (Fjmp is a global vector, see <setjmp.h>).
82 
83 	If the FTLEXIT bit is on the value of userexit(1) is
84 	passed as an argument to exit(II)
85 	(see userexit.c).
86 
87 	If none of the FTLACT bits are on
88 	(the default value for Fflags is 0), the global word
89 	"Fvalue" (initialized to -1) is returned.
90 
91 	If all fatal globals have their default values, fatal simply
92 	returns -1.
93 */
94 
95 int	Fcnt;
96 int	Fflags;
97 char	*Ffile;
98 int	Fvalue = -1;
99 int	(*Ffunc) __PR((char *));
100 jmp_buf	Fjmp;
101 char    *nsedelim = (char *) 0;
102 
103 	void	set_clean_up	__PR((void (*f)(void)));
104 static	void	dummy_clean_up	__PR((void));
105 	void	(*f_clean_up) __PR((void)) = dummy_clean_up;
106 
107 /* default value for NSE delimiter (currently correct, if NSE ever
108  * changes implementation it will have to pass new delimiter as
109  * value for -q option)
110  */
111 # define NSE_VCS_DELIM "vcs"
112 # define NSE_VCS_GENERIC_NAME "<history file>"
113 static  int     delimlen = 0;
114 
115 int
efatal(msg)116 efatal(msg)
117 char *msg;
118 {
119 	int	errsav = errno;
120 	char	*errstr = NULL;
121 
122 	if (Fflags & FTLMSG) {
123 #ifdef	SCHILY_BUILD
124 		errstr = get_progname();
125 #else
126 #ifdef	HAVE_GETPROGNAME
127 		errstr = (char *)getprogname();
128 #endif
129 #endif
130 		if (errstr) {
131 			write(2, errstr, length(errstr));
132 			write(2, ": ", 2);
133 		}
134 
135 		errno = 0;
136 		errstr = NULL;
137 #ifdef	SCHILY_BUILD
138 		errstr = errmsgstr(errsav);
139 #else
140 #ifdef	HAVE_STRERROR
141 		errstr = strerror(errsav);
142 		if (errno)
143 			errstr = NULL;
144 #endif
145 #endif
146 		if (errsav != 0 && errstr != NULL) {
147 			write(2, errstr, length(errstr));
148 			write(2, ". ", 2);
149 		}
150 	}
151 	return (fatal(msg));
152 }
153 
154 int
fatal(msg)155 fatal(msg)
156 char *msg;
157 {
158 #if	defined(IS_MACOS_X)
159 /*
160  * The Mac OS X static linker is too silly to link in .o files from static libs
161  * if only a variable is referenced. The elegant workaround for this bug (using
162  * common variables) triggers a different bug in the dynamic linker from Mac OS
163  * that is unable to link common variables. This forces us to introduce funcs
164  * that need to be called from central places to enforce to link in the vars.
165  */
166 extern	void __mpw __PR((void));
167 
168 	__mpw();
169 #endif
170 	++Fcnt;
171 	if (Fflags & FTLMSG) {
172 		write(2,gettext("ERROR"),5);
173 		if (Ffile) {
174 			(void) write(2," [",2);
175 			(void) write(2,Ffile,length(Ffile));
176 			(void) write(2,"]",1);
177 		}
178 		(void) write(2,": ",2);
179 		(void) write(2,msg,length(msg));
180 		(void) write(2,"\n",1);
181 	}
182 	if (Fflags & FTLCLN)
183 		(*f_clean_up)();
184 	if (Fflags & FTLFUNC)
185 		(*Ffunc)(msg);
186 	switch (Fflags & FTLACT) {
187 	case FTLJMP:
188 		longjmp(Fjmp, 1);
189 	/*FALLTHRU*/
190 	case FTLEXIT:
191 		if (Fflags & FTLVFORK)
192 			_exit(userexit(1));
193 		exit(userexit(1));
194 	/*FALLTHRU*/
195 	case FTLRET:
196 		return(Fvalue);
197 	}
198 	return(-1);
199 }
200 
201 /* if running under NSE, the path to the directory which heads the
202  * vcs hierarchy and the "s." is removed from the names of s.files
203  *
204  * if `vcshist' is true, a generic name for the history file is returned.
205  */
206 
207 char *
nse_file_trim(f,vcshist)208 nse_file_trim(f, vcshist)
209         char    *f;
210         int     vcshist;
211 {
212         register char   *p;
213         char            *q;
214         char            *r;
215         char            c;
216 
217         r = f;
218         if (HADQ) {
219                 if (vcshist && Ffile && (0 == strcmp(Ffile, f))) {
220                         return NSE_VCS_GENERIC_NAME;
221                 }
222                 if (!nsedelim) {
223                         nsedelim = NSE_VCS_DELIM;
224                 }
225                 if (delimlen == 0) {
226                         delimlen = strlen(nsedelim);
227                 }
228                 p = f;
229                 while ((c = *p++) != '\0') {
230                         /* find the NSE delimiter path component */
231                         if ((c == '/') && (*p == nsedelim[0]) &&
232                             (0 == strncmp(p, nsedelim, delimlen)) &&
233                             (*(p + delimlen) == '/')) {
234                                 break;
235                         }
236                 }
237                 if (c) {
238                         /* if found, new name starts with second "/" */
239                         p += delimlen;
240                         q = strrchr(p, '/');
241                         /* find "s." */
242                         if (q && (q[1] == 's') && (q[2] == '.')) {
243                                 /* build the trimmed name.
244                                  * <small storage leak here> */
245                                 q[1] = '\0';
246                                 r = (char *) malloc((unsigned) (strlen(p) +
247                                                 strlen(q+3) + 1));
248                                 (void) strcpy(r, p);
249                                 q[1] = 's';
250                                 (void) strcat(r, q+3);
251                         }
252                 }
253         }
254         return r;
255 }
256 
257 int
check_permission_SccsDir(path)258 check_permission_SccsDir(path)
259 	char	*path;
260 {
261 	int  desc;
262 	char dir_name[MAXPATHLEN];
263 
264 	strlcpy(dir_name, sname(path), sizeof (dir_name));
265 	strlcat(dir_name, "/.", sizeof (dir_name));
266 	if ((desc = open(dir_name, O_RDONLY|O_BINARY)) < 0) {
267 		if (errno == EACCES) {
268 			fprintf(stderr, gettext("%s: Permission denied\n"), dname(dir_name));
269 			++Fcnt;
270 			return (0);
271 		}
272 		return (1);
273 	}
274 	close(desc);
275 	return(1);
276 
277 }
278 
279 static void
dummy_clean_up()280 dummy_clean_up()
281 {
282 }
283 
284 void
285 set_clean_up(f)
286 	void (*f) __PR((void));
287 {
288 	f_clean_up = f;
289 }
290