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 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <procfs.h>
30 #include <project.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include "rcapd.h"
34 #include "utils.h"
35 
36 				/* absolute cap name */
37 #define	PJ_ABS_ATTR_NAME	"rcap.max-rss"
38 				/* round up to next y = 2^n */
39 #define	ROUNDUP(x, y)		(((x) + ((y) - 1)) & ~((y) - 1))
40 
41 static rcid_t rc_proj_getidbypsinfo(psinfo_t *);
42 
43 void
44 lcollection_set_type_project(void)
45 {
46 	rc_getidbypsinfo = rc_proj_getidbypsinfo;
47 }
48 
49 static int
50 lcollection_update_project_cb(const struct project *proj, void *walk_data)
51 {
52 	void(*update_notification_cb)(char *, int, uint64_t, int) =
53 	    (void(*)(char *, int, uint64_t, int))walk_data;
54 	char *capattr_abs;
55 	char *end;
56 	int changes;
57 	int64_t max_rss;
58 	lcollection_t *lcol;
59 
60 	capattr_abs = strstr(proj->pj_attr, PJ_ABS_ATTR_NAME "=");
61 	if (capattr_abs != NULL) {
62 		if (capattr_abs > proj->pj_attr)
63 			if (*(capattr_abs - 1) != ';') {
64 				/*
65 				 * PJ_ABS_ATTR_NAME only matched part
66 				 * of an attribute.
67 				 */
68 				return (0);
69 			}
70 		capattr_abs += strlen(PJ_ABS_ATTR_NAME "=");
71 		max_rss = ROUNDUP(strtoll(capattr_abs, &end, 10), 1024) / 1024;
72 		if (end == capattr_abs || *end != ';' && *end != 0)
73 			warn(gettext("%s %s: malformed %s value "
74 			    "'%s'\n"), rcfg.rcfg_mode_name, proj->pj_name,
75 			    PJ_ABS_ATTR_NAME, capattr_abs);
76 	} else
77 		max_rss = 0;
78 
79 	lcol = lcollection_insert_update(proj->pj_projid, max_rss,
80 	    proj->pj_name, &changes);
81 	if (update_notification_cb != NULL)
82 		update_notification_cb(proj->pj_name, changes, max_rss, (lcol !=
83 		    NULL) ? lcol->lcol_mark : 0);
84 
85 	return (0);
86 }
87 
88 static int
89 lcollection_update_project_byid_cb(const projid_t id, void *walk_data)
90 {
91 	char buf[PROJECT_BUFSZ];
92 	struct project proj;
93 
94 	if (getprojbyid(id, &proj, buf, sizeof (buf)) != NULL && proj.pj_attr !=
95 	    NULL)
96 		return (lcollection_update_project_cb(&proj, walk_data));
97 
98 	return (0);
99 }
100 
101 static int
102 lcollection_update_onceactive_cb(lcollection_t *lcol, void *walk_data)
103 {
104 	void(*update_notification_cb)(char *, int, uint64_t, int) =
105 	    (void(*)(char *, int, uint64_t, int))walk_data;
106 
107 	return (lcollection_update_project_byid_cb(lcol->lcol_id,
108 	    (void *)update_notification_cb));
109 }
110 
111 static int
112 project_walk_all(int(*cb)(const struct project *, void *), void *walk_data)
113 {
114 	char buf[PROJECT_BUFSZ];
115 	struct project proj;
116 	int res = 0;
117 
118 	setprojent();
119 	while (getprojent(&proj, buf, sizeof (buf)) != NULL && res == 0)
120 		res = cb(&proj, walk_data);
121 	endprojent();
122 
123 	return (res);
124 }
125 
126 void
127 lcollection_update_project(lcollection_update_type_t ut,
128     void(*update_notification_cb)(char *, int, uint64_t, int))
129 {
130 	switch (ut) {
131 	case LCU_ACTIVE_ONLY:
132 		/*
133 		 * Enumerate active projects.  This is much faster than
134 		 * enumerating all projects (as is done below, in the default
135 		 * case), and is done to efficiently and incrementally update
136 		 * lcollection with capped projects.  The default case performs
137 		 * the initialization.
138 		 */
139 		(void) project_walk(lcollection_update_project_byid_cb,
140 		    (void *)update_notification_cb);
141 		/*
142 		 * Enumerate once-active projects, including the active
143 		 * projects just enumerated, meaning active projects will be
144 		 * updated and marked twice.
145 		 */
146 		list_walk_collection(lcollection_update_onceactive_cb,
147 		    (void *)update_notification_cb);
148 		break;
149 	default:
150 		/*
151 		 * Enumerate all projects.
152 		 */
153 		(void) project_walk_all(lcollection_update_project_cb,
154 		    (void *)update_notification_cb);
155 	}
156 }
157 
158 static rcid_t
159 rc_proj_getidbypsinfo(psinfo_t *psinfo)
160 {
161 	return (psinfo->pr_projid);
162 }
163