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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*    Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28/*      All Rights Reserved   */
29
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33/*
34 *	devfree key [device [...]]
35 */
36
37#include	<sys/types.h>
38#include	<sys/param.h>
39#include	<stdio.h>
40#include	<errno.h>
41#include	<stdlib.h>
42#include	<string.h>
43#include	<fmtmsg.h>
44#include	<devmgmt.h>
45#include	<values.h>
46#include	<devtab.h>
47
48
49/*
50 *  Local definitions
51 *	TRUE		Boolean TRUE value
52 *	FALSE		Boolean FALSE value
53 */
54#ifndef		TRUE
55#define		TRUE		('t')
56#endif
57
58#ifndef		FALSE
59#define		FALSE		0
60#endif
61
62
63/*
64 *  Exit codes:
65 *	EX_OK		Exit code for all went well
66 *	EX_ERROR	Exit code for something failed
67 *	EX_TBLERR	Exit code for errors relating to device or lock tables
68 *	EX_NOFREE	Exit code for free failed
69 */
70
71#define		EX_OK		0
72#define		EX_ERROR	1
73#define		EX_TBLERR	2
74#define		EX_NOFREE	3
75
76
77/*
78 * Messages
79 *	M_USAGE		Usage error
80 *	M_INVKEY	Invalid key specified
81 *	M_NOTRSVD	Attempting to free something not alloc'd
82 *	M_NOTONKEY	Attempting to free with wrong key
83 *	M_DEVTAB	Error opening the device table
84 *	M_RSVTAB	Error opening the device-reservation table
85 *	M_ERROR		Some internal error
86 */
87
88#define		M_USAGE		"usage: devfree key [device [...]]"
89#define		M_INVKEY	"Invalid key: %s"
90#define		M_NOTRSVD	"Device not reserved: %s"
91#define		M_NOTONKEY	"Cannot unreserve device: %s"
92#define		M_DEVTAB	"Cannot open the device table: %s"
93#define		M_RSVTAB	"Cannot open the device-reservation table: %s"
94#define		M_ERROR		"Internal error, errno=%d"
95
96
97/*
98 *  Local functions and static data
99 *	stdmsg(r,l,s,m)		Macro for standard message generation
100 *				r	MM_NRECOV or MM_RECOV (recoverability)
101 *				l	Label
102 *				s	Severity
103 *				m	Message
104 *	lbl			Buffer for the label-component of a message.
105 *	msg			Buffer for the text-component of a message.
106 */
107
108#define	stdmsg(r,l,s,m)	(void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,m,MM_NULLACT,MM_NULLTAG)
109
110static	char	lbl[MM_MXLABELLN+1];
111static	char	msg[MM_MXTXTLN+1];
112
113/*
114 *  devfree key [device [device [...]]]
115 *
116 *	This command frees devices that have been reserved using
117 *	the devreserv command (or the devreserv() function).
118 *
119 *  Options:  None
120 *
121 *  Arguments:
122 *	key		The key on which the device to free was allocated on.
123 *			If omitted, all keys are assumed.
124 *	device		The device to free.  If omitted, all devices allocated
125 *			using the key are freed.
126 *
127 *  Command Values:
128 *	EX_OK		0	Device(s) successfully freed
129 *	EX_ERROR	1	A syntax error or other error occurred
130 *	EX_TBLERR	2	A problem with device management tables
131 *	EX_NOFREE	3	A requested device couldn't be freed
132 */
133
134int
135main(int argc, char *argv[])
136{
137	/* Automatics */
138	char		      **argp;		/* Ptr to current argument */
139	struct reservdev      **rsvd;		/* Ptr to list of locks */
140	struct reservdev      **plk;		/* Running ptr to locks */
141	char		       *devtab;		/* Ptr to device table name */
142	char		       *rsvtab;		/* Ptr to dev-rsv-tbl name */
143	char		       *p;		/* Temp char pointer */
144	int			argcount;	/* Number of args on cmd */
145	long			lkey;		/* Key for locking (long) */
146	int			key;		/* Key for locking */
147	int			halt;		/* TRUE if we need to stop */
148	int			sev;		/* Message severity */
149	int			exitcode;	/* Value of command */
150	int			syntaxerr;	/* Flag, TRUE if syntax error */
151	int			exitcd;		/* Value for exit() */
152	int			c;		/* Option character */
153
154
155	/*
156	 * Initializations
157	 */
158
159	/* Build a message label */
160	if (p = strrchr(argv[0], '/')) p++;
161	else p = argv[0];
162	(void) strlcat(strcpy(lbl, "UX:"), p, sizeof(lbl));
163
164	/* Make only the text component of messages appear (remove this in SVR4.1) */
165	(void) putenv("MSGVERB=text");
166
167
168	/*
169	 * Parse the options from the command line
170	 */
171
172	opterr = 0;
173	syntaxerr = FALSE;
174	while ((c = getopt(argc, argv, "")) != EOF) switch(c) {
175	default:
176	    syntaxerr = FALSE;
177	    break;
178	}
179
180
181	/* Argument initializations */
182	argp = &argv[optind];
183	if ((argcount = argc-optind) < 1) syntaxerr = TRUE;
184
185
186	/* If there's (an obvious) syntax error, write a message and quit */
187	if (syntaxerr) {
188	    stdmsg(MM_NRECOV, lbl, MM_ERROR, M_USAGE);
189	    exit(EX_ERROR);
190	}
191
192
193	/*
194	 *  devfree key
195	 *
196	 *  	Free all devices that have been reserved using the key "key".
197	 */
198
199	if (argcount == 1) {
200
201	    /* Extract the key from the command */
202	    lkey = strtol(*argp, &p, 10);
203	    if (*p || (lkey <= 0) || (lkey > MAXINT)) {
204		(void) snprintf(msg, sizeof (msg), M_INVKEY, *argp);
205		stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
206		exit(EX_ERROR);
207	    }
208	    key = (int) lkey;
209
210	    /* Get the list of devices currently reserved */
211	    if (rsvd = reservdev()) {
212		exitcd = EX_OK;
213		for (plk = rsvd ; *plk ; plk++) {
214		    if ((*plk)->key == key)
215			if (devfree(key, (*plk)->devname) != 0)
216			    exitcd = EX_NOFREE;
217		}
218	    } else {
219		if (((errno == ENOENT) || (errno == EACCES)) && (rsvtab = _rsvtabpath())) {
220		    (void) snprintf(msg, sizeof(msg), M_RSVTAB, rsvtab);
221		    exitcd = EX_TBLERR;
222		    sev = MM_ERROR;
223		} else {
224		    (void) snprintf(msg, sizeof (msg), M_ERROR, errno);
225		    exitcd = EX_ERROR;
226		    sev = MM_HALT;
227		}
228		stdmsg(MM_NRECOV, lbl, sev, msg);
229	    }
230
231	    /* Done */
232	    exit(exitcd);
233	}
234
235
236	/*
237	 *  devfree key device [...]
238	 *
239	 *	Free specific devices
240	 */
241
242	/* Open the device file (if there's one to be opened) */
243	if (!_opendevtab("r")) {
244	    if (devtab = _devtabpath()) {
245		(void) snprintf(msg, sizeof(msg), M_DEVTAB, devtab);
246		exitcd = EX_TBLERR;
247		sev = MM_ERROR;
248	    } else {
249		(void) snprintf(msg, sizeof (msg), M_ERROR, errno);
250		exitcd = EX_ERROR;
251		sev = MM_HALT;
252	    }
253	    stdmsg(MM_NRECOV, lbl, sev, msg);
254	    exit(exitcd);
255	}
256
257	/* Extract the key from the command */
258	lkey = strtol(*argp, &p, 10);
259	if (*p || (lkey <= 0) || (lkey > MAXINT)) {
260	    (void) snprintf(msg, sizeof(msg), M_INVKEY, *argp);
261	    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
262	    exit(EX_ERROR);
263	}
264	key = (int) lkey;
265	argp++;
266
267	/* Loop through the list of devices to free */
268	exitcode = EX_OK;
269	halt = FALSE;
270	while (!halt && *argp) {
271
272	    /* Try to free the device */
273	    if (devfree(key, *argp) != 0) {
274		if ((errno == EACCES) || (errno == ENOENT)) {
275
276		    /* Can't get at reservation file */
277		    if (rsvtab = _rsvtabpath()) {
278			exitcode = EX_TBLERR;
279			(void) snprintf(msg, sizeof(msg), M_RSVTAB, rsvtab);
280			sev = MM_ERROR;
281		    }
282		    else {
283			exitcode = EX_ERROR;
284			(void) snprintf(msg, sizeof (msg), M_ERROR, errno);
285			sev = MM_HALT;
286		    }
287		    stdmsg(MM_NRECOV, lbl, sev, msg);
288		    halt = TRUE;
289		}
290	        else if (errno == EPERM) {
291
292		    /* Wrong key */
293		    (void) snprintf(msg, sizeof(msg), M_NOTONKEY, *argp);
294		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
295		    exitcode = EX_NOFREE;
296		}
297		else if (errno == EINVAL) {
298
299		    /* Device not reserved */
300		    (void) snprintf(msg, sizeof(msg), M_NOTRSVD, *argp);
301		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
302		    exitcode = EX_NOFREE;
303		}
304
305		else {
306
307		    /* Some other strange error occurred */
308		    (void) snprintf(msg, sizeof (msg), M_ERROR, errno);
309		    stdmsg(MM_NRECOV, lbl, MM_HALT, msg);
310		    exitcode = EX_ERROR;
311		    halt = TRUE;
312		}
313	    }
314	    argp++;
315	}
316
317
318	/* Exit with the appropriate code */
319	return(exitcode);
320}
321