xref: /illumos-gate/usr/src/cmd/prstat/prfile.c (revision 012e6ce759c490003aed29439cc47d3d73a99ad3)
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 (c) 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <strings.h>
34 
35 #include "prtable.h"
36 #include "prutil.h"
37 #include "prfile.h"
38 
39 #define	FDS_TABLE_SIZE	1024
40 
41 static fd_t *fd_tbl = NULL;
42 static int fd_max;
43 static int fd_cnt;
44 static int fd_cnt_cur;
45 static int fd_cnt_old;
46 static fds_t *fds_tbl[FDS_TABLE_SIZE];
47 
48 void
49 fd_init(int n)
50 {
51 	fd_max = n;
52 	fd_cnt = fd_cnt_cur = fd_cnt_old = 0;
53 	fd_tbl = Zalloc(sizeof (fd_t) * n);
54 	(void) memset(fds_tbl, 0, sizeof (fds_t *) * FDS_TABLE_SIZE);
55 }
56 
57 void
58 fd_exit()
59 {
60 	if (fd_tbl)
61 		free(fd_tbl);
62 }
63 
64 void
65 fd_close(fd_t *fdp)
66 {
67 	if (fdp) {
68 		if (fdp->fd_fd >= 0 && fdp->fd_name[0] != '\0') {
69 			(void) close(fdp->fd_fd);
70 			fd_cnt--;
71 		}
72 
73 		(void) memset(fdp, 0, sizeof (fd_t));
74 		fdp->fd_fd = -1;
75 	}
76 }
77 
78 void
79 fd_closeall()
80 {
81 	fd_t *fdp = fd_tbl;
82 	int i;
83 
84 	for (i = 0; i < fd_max; i++) {
85 		fd_close(fdp);
86 		fdp++;
87 	}
88 }
89 
90 static void
91 fd_recycle()
92 {
93 	fd_t *fdp = fd_tbl;
94 	int counter;
95 	int i;
96 
97 	counter = abs(fd_cnt_old - fd_cnt) + NUM_RESERVED_FD;
98 
99 	for (i = 0; i < fd_max; i++, fdp++) {
100 
101 		if (fdp->fd_fd == -1)
102 			continue;	/* skip recycled ones */
103 
104 		if (fdp->fd_name[0] != '\0') {	/* file has name */
105 			(void) close(fdp->fd_fd);
106 			fd_cnt--;
107 			counter--;
108 			fdp->fd_fd = -1;
109 		}
110 
111 		if (counter == 0)
112 			break;
113 	}
114 }
115 
116 fd_t *
117 fd_open(char *name, int flags, fd_t *fdp)
118 {
119 	fd_t *fdp_new;
120 	int fd;
121 
122 	if (fd_cnt > fd_max - NUM_RESERVED_FD)
123 		fd_recycle();
124 
125 	if (fdp != NULL) {
126 		if ((strcmp(fdp->fd_name, name) == 0) && (fdp->fd_fd >= 0)) {
127 			fd_cnt_cur++;
128 			return (fdp);
129 		}
130 	}
131 
132 again:	fd = open(name, flags);
133 
134 	if (fd == -1) {
135 		if ((errno == EMFILE) || (errno == ENFILE)) {
136 			fd_recycle();
137 			goto again;
138 		}
139 		fdp_new = NULL;
140 	} else {
141 		fdp_new = &fd_tbl[fd];
142 		fdp_new->fd_fd = fd;
143 		fdp_new->fd_flags = flags;
144 		(void) strcpy(fdp_new->fd_name, name);
145 		fd_cnt++;
146 		fd_cnt_cur++;
147 	}
148 	return (fdp_new);
149 }
150 
151 int
152 fd_getfd(fd_t *fdp)
153 {
154 	return (fdp->fd_fd);
155 }
156 
157 void
158 fd_update()
159 {
160 	fd_cnt_old = fd_cnt_cur;
161 	fd_cnt_cur = 0;
162 }
163 
164 fds_t *
165 fds_get(pid_t pid)
166 {
167 	fds_t *fdsp;
168 	int hash = pid % FDS_TABLE_SIZE;
169 
170 	for (fdsp = fds_tbl[hash]; fdsp; fdsp = fdsp->fds_next)
171 		if (fdsp->fds_pid == pid)	/* searching for pid */
172 			return (fdsp);
173 
174 	fdsp = Zalloc(sizeof (fds_t));	/* adding new if pid was not found */
175 	fdsp->fds_pid = pid;
176 	fdsp->fds_next = fds_tbl[hash];
177 	fds_tbl[hash] = fdsp;
178 	return (fdsp);
179 }
180 
181 void
182 fds_rm(pid_t pid)
183 {
184 	fds_t *fds;
185 	fds_t *fds_prev = NULL;
186 	int hash = pid % FDS_TABLE_SIZE;
187 
188 	for (fds = fds_tbl[hash]; fds && fds->fds_pid != pid;
189 	    fds = fds->fds_next)	/* finding pid */
190 		fds_prev = fds;
191 
192 	if (fds) {			/* if pid was found */
193 
194 		fd_close(fds->fds_psinfo);
195 		fd_close(fds->fds_usage);
196 		fd_close(fds->fds_lpsinfo);
197 		fd_close(fds->fds_lusage);
198 
199 		if (fds_prev)
200 			fds_prev->fds_next = fds->fds_next;
201 		else
202 			fds_tbl[hash] = fds->fds_next;
203 
204 		free(fds);
205 	}
206 }
207