1 /*
2  * mf_proc.c
3  * Copyright (C) 2001 Kyle A. Lucke  IBM Corporation
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  */
19 
20 
21 /* Change Activity: */
22 /* End Change Activity */
23 
24 #ifndef _MF_PROC_H
25 #include <asm/iSeries/mf_proc.h>
26 #endif
27 #ifndef MF_H_INCLUDED
28 #include <asm/iSeries/mf.h>
29 #endif
30 #include <asm/uaccess.h>
31 
32 static struct proc_dir_entry *mf_proc_root = NULL;
33 
34 int proc_mf_dump_cmdline
35 (char *page, char **start, off_t off, int count, int *eof, void *data);
36 
37 int proc_mf_dump_vmlinux
38 (char *page, char **start, off_t off, int count, int *eof, void *data);
39 
40 int proc_mf_dump_side
41 (char *page, char **start, off_t off, int count, int *eof, void *data);
42 
43 int proc_mf_change_side
44 (struct file *file, const char *buffer, unsigned long count, void *data);
45 
46 int proc_mf_dump_src
47 (char *page, char **start, off_t off, int count, int *eof, void *data);
48 int proc_mf_change_src (struct file *file, const char *buffer, unsigned long count, void *data);
49 int proc_mf_change_cmdline(struct file *file, const char *buffer, unsigned long count, void *data);
50 int proc_mf_change_vmlinux(struct file *file, const char *buffer, unsigned long count, void *data);
51 
52 
mf_proc_init(struct proc_dir_entry * iSeries_proc)53 void mf_proc_init(struct proc_dir_entry *iSeries_proc)
54 {
55 	struct proc_dir_entry *ent = NULL;
56 	struct proc_dir_entry *mf_a = NULL;
57 	struct proc_dir_entry *mf_b = NULL;
58 	struct proc_dir_entry *mf_c = NULL;
59 	struct proc_dir_entry *mf_d = NULL;
60 
61 	mf_proc_root = proc_mkdir("mf", iSeries_proc);
62 	if (!mf_proc_root) return;
63 
64 	mf_a = proc_mkdir("A", mf_proc_root);
65 	if (!mf_a) return;
66 
67 	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_a);
68 	if (!ent) return;
69 	ent->nlink = 1;
70 	ent->data = (void *)0;
71 	ent->read_proc = proc_mf_dump_cmdline;
72 	ent->write_proc = proc_mf_change_cmdline;
73 
74 	ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf_a);
75 	if (!ent) return;
76 	ent->nlink = 1;
77 	ent->data = (void *)0;
78 	ent->write_proc = proc_mf_change_vmlinux;
79 	ent->read_proc = NULL;
80 
81 	mf_b = proc_mkdir("B", mf_proc_root);
82 	if (!mf_b) return;
83 
84 	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_b);
85 	if (!ent) return;
86 	ent->nlink = 1;
87 	ent->data = (void *)1;
88 	ent->read_proc = proc_mf_dump_cmdline;
89 	ent->write_proc = proc_mf_change_cmdline;
90 
91 	ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf_b);
92 	if (!ent) return;
93 	ent->nlink = 1;
94 	ent->data = (void *)1;
95 	ent->write_proc = proc_mf_change_vmlinux;
96 	ent->read_proc = NULL;
97 
98 	mf_c = proc_mkdir("C", mf_proc_root);
99 	if (!mf_c) return;
100 
101 	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_c);
102 	if (!ent) return;
103 	ent->nlink = 1;
104 	ent->data = (void *)2;
105 	ent->read_proc = proc_mf_dump_cmdline;
106 	ent->write_proc = proc_mf_change_cmdline;
107 
108 	ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf_c);
109 	if (!ent) return;
110 	ent->nlink = 1;
111 	ent->data = (void *)2;
112 	ent->write_proc = proc_mf_change_vmlinux;
113 	ent->read_proc = NULL;
114 
115 	mf_d = proc_mkdir("D", mf_proc_root);
116 	if (!mf_d) return;
117 
118 
119 	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_d);
120 	if (!ent) return;
121 	ent->nlink = 1;
122 	ent->data = (void *)3;
123 	ent->read_proc = proc_mf_dump_cmdline;
124 	ent->write_proc = proc_mf_change_cmdline;
125 #if 0
126 	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR, mf_d);
127 	if (!ent) return;
128 	ent->nlink = 1;
129 	ent->data = (void *)3;
130 	ent->read_proc = proc_mf_dump_vmlinux;
131 	ent->write_proc = NULL;
132 #endif
133 	ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
134 	if (!ent) return;
135 	ent->nlink = 1;
136 	ent->data = (void *)0;
137 	ent->read_proc = proc_mf_dump_side;
138 	ent->write_proc = proc_mf_change_side;
139 
140 	ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
141 	if (!ent) return;
142 	ent->nlink = 1;
143 	ent->data = (void *)0;
144 	ent->read_proc = proc_mf_dump_src;
145 	ent->write_proc = proc_mf_change_src;
146 }
147 
proc_mf_dump_cmdline(char * page,char ** start,off_t off,int count,int * eof,void * data)148 int proc_mf_dump_cmdline
149 (char *page, char **start, off_t off, int count, int *eof, void *data)
150 {
151 	int		len = count;
152 	char *p;
153 
154 	len = mf_getCmdLine(page, &len, (u64)data);
155 
156 	p = page + len - 1;
157 	while ( p > page ) {
158 		if ( (*p == 0) || (*p == ' ') )
159 			--p;
160 		else
161 			break;
162 	}
163 	if ( *p != '\n' ) {
164 		++p;
165 		*p = '\n';
166 	}
167 	++p;
168 	*p = 0;
169 	len = p - page;
170 
171 	len -= off;
172 	if (len < count) {
173 		*eof = 1;
174 		if (len <= 0)
175 			return 0;
176 	} else
177 		len = count;
178 	*start = page + off;
179 	return len;
180 }
181 
proc_mf_dump_vmlinux(char * page,char ** start,off_t off,int count,int * eof,void * data)182 int proc_mf_dump_vmlinux
183 (char *page, char **start, off_t off, int count, int *eof, void *data)
184 {
185 	int sizeToGet = count;
186 	if (!capable(CAP_SYS_ADMIN))
187 		return -EACCES;
188 
189 	if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0)
190 	{
191 		if (sizeToGet != 0)
192 		{
193 			*start = page + off;
194 			return sizeToGet;
195 		} else {
196 			*eof = 1;
197 			return 0;
198 		}
199 	} else {
200 		*eof = 1;
201 		return 0;
202 	}
203 }
204 
proc_mf_dump_side(char * page,char ** start,off_t off,int count,int * eof,void * data)205 int proc_mf_dump_side
206 (char *page, char **start, off_t off, int count, int *eof, void *data)
207 {
208 	int		len = 0;
209 
210 	char mf_current_side = mf_getSide();
211 	len = sprintf(page, "%c\n", mf_current_side);
212 
213 	if (len <= off+count) *eof = 1;
214 	*start = page + off;
215 	len -= off;
216 	if (len>count) len = count;
217 	if (len<0) len = 0;
218 	return len;
219 }
220 
proc_mf_change_side(struct file * file,const char * buffer,unsigned long count,void * data)221 int proc_mf_change_side(struct file *file, const char *buffer, unsigned long count, void *data)
222 {
223 	char side;
224 
225 	if (!capable(CAP_SYS_ADMIN))
226 		return -EACCES;
227 	if (count == 0)
228 		return 0;
229 	if (get_user(side, buffer))
230 		return -EFAULT;
231 
232 	if ((side != 'A') && (side != 'B') && (side != 'C') && (side != 'D'))
233 	{
234 		printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
235 		return -EINVAL;
236 	}
237 
238 	mf_setSide(side);
239 
240 	return count;
241 }
242 
proc_mf_dump_src(char * page,char ** start,off_t off,int count,int * eof,void * data)243 int proc_mf_dump_src
244 (char *page, char **start, off_t off, int count, int *eof, void *data)
245 {
246 	int		len = 0;
247 	mf_getSrcHistory(page, count);
248 	len = count;
249 	len -= off;
250 	if (len < count) {
251 		*eof = 1;
252 		if (len <= 0)
253 			return 0;
254 	} else
255 		len = count;
256 	*start = page + off;
257 	return len;
258 }
259 
proc_mf_change_src(struct file * file,const char * buffer,unsigned long count,void * data)260 int proc_mf_change_src(struct file *file, const char *buffer, unsigned long count, void *data)
261 {
262 	char stkbuf[10];
263 	if (!capable(CAP_SYS_ADMIN))
264 		return -EACCES;
265 
266 	if ((count < 4) && (count != 1)) {
267 		printk(KERN_ERR "mf_proc: invalid src\n");
268 		return -EINVAL;
269 	}
270 
271 	if (count > 9)
272 		count = 9;
273 	if (copy_from_user (stkbuf, buffer, count))
274 		return -EFAULT;
275 
276 	if ((count == 1) && ((*stkbuf) == '\0')) {
277 		mf_clearSrc();
278 	} else {
279 		mf_displaySrc(*(u32 *)stkbuf);
280 	}
281 
282 	return count;
283 }
284 
proc_mf_change_cmdline(struct file * file,const char * buffer,unsigned long count,void * data)285 int proc_mf_change_cmdline(struct file *file, const char *buffer, unsigned long count, void *data)
286 {
287 	if (!capable(CAP_SYS_ADMIN))
288 		return -EACCES;
289 
290 	mf_setCmdLine(buffer, count, (u64)data);
291 
292 	return count;
293 }
294 
proc_mf_change_vmlinux(struct file * file,const char * buffer,unsigned long count,void * data)295 int proc_mf_change_vmlinux(struct file *file, const char *buffer, unsigned long count, void *data)
296 {
297 	if (!capable(CAP_SYS_ADMIN))
298 		return -EACCES;
299 
300 	mf_setVmlinuxChunk(buffer, count, file->f_pos, (u64)data);
301 	file->f_pos += count;
302 
303 	return count;
304 }
305