diff options
-rw-r--r-- | Config.h | 5 | ||||
-rw-r--r-- | addgroup.c | 178 | ||||
-rw-r--r-- | adduser.c | 366 | ||||
-rw-r--r-- | applets.h | 16 | ||||
-rw-r--r-- | applets/usage.h | 41 | ||||
-rw-r--r-- | deluser.c | 175 | ||||
-rw-r--r-- | getty.c | 1230 | ||||
-rw-r--r-- | include/applets.h | 16 | ||||
-rw-r--r-- | include/usage.h | 41 | ||||
-rw-r--r-- | usage.h | 41 |
10 files changed, 2109 insertions, 0 deletions
@@ -7,6 +7,8 @@ | |||
7 | // | 7 | // |
8 | // | 8 | // |
9 | // BusyBox Applications | 9 | // BusyBox Applications |
10 | #define BB_ADDGROUP | ||
11 | #define BB_ADDUSER | ||
10 | //#define BB_ADJTIMEX | 12 | //#define BB_ADJTIMEX |
11 | //#define BB_AR | 13 | //#define BB_AR |
12 | //#define BB_ASH | 14 | //#define BB_ASH |
@@ -26,6 +28,8 @@ | |||
26 | //#define BB_DC | 28 | //#define BB_DC |
27 | #define BB_DD | 29 | #define BB_DD |
28 | //#define BB_DEALLOCVT | 30 | //#define BB_DEALLOCVT |
31 | #define BB_DELGROUP | ||
32 | #define BB_DELUSER | ||
29 | #define BB_DF | 33 | #define BB_DF |
30 | #define BB_DIRNAME | 34 | #define BB_DIRNAME |
31 | #define BB_DMESG | 35 | #define BB_DMESG |
@@ -45,6 +49,7 @@ | |||
45 | //#define BB_FREERAMDISK | 49 | //#define BB_FREERAMDISK |
46 | //#define BB_FSCK_MINIX | 50 | //#define BB_FSCK_MINIX |
47 | //#define BB_GETOPT | 51 | //#define BB_GETOPT |
52 | #define BB_GETTY | ||
48 | #define BB_GREP | 53 | #define BB_GREP |
49 | #define BB_GUNZIP | 54 | #define BB_GUNZIP |
50 | #define BB_GZIP | 55 | #define BB_GZIP |
diff --git a/addgroup.c b/addgroup.c new file mode 100644 index 000000000..3d932011c --- /dev/null +++ b/addgroup.c | |||
@@ -0,0 +1,178 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * addgroup - add users to /etc/passwd and /etc/shadow | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 1999 by Lineo, inc. | ||
7 | * Written by John Beppu <beppu@lineo.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <errno.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdarg.h> | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | #include <sys/param.h> | ||
32 | #include <sys/stat.h> | ||
33 | #include <sys/types.h> | ||
34 | #include <unistd.h> | ||
35 | #include "busybox.h" | ||
36 | #include "pwd_grp/pwd.h" | ||
37 | #include "pwd_grp/grp.h" | ||
38 | |||
39 | #define GROUP_FILE "/etc/group" | ||
40 | #define SHADOW_FILE "/etc/gshadow" | ||
41 | |||
42 | |||
43 | /* structs __________________________ */ | ||
44 | |||
45 | /* data _____________________________ */ | ||
46 | |||
47 | /* defaults : should this be in an external file? */ | ||
48 | static char *default_passwd = "x"; | ||
49 | |||
50 | |||
51 | /* make sure gr_name isn't taken, make sure gid is kosher | ||
52 | * return 1 on failure */ | ||
53 | static int group_study(const char *filename, struct group *g) | ||
54 | { | ||
55 | FILE *etc_group; | ||
56 | gid_t desired; | ||
57 | |||
58 | struct group *grp; | ||
59 | const int max = 65000; | ||
60 | |||
61 | /* FIXME : make an fopen_wrapper */ | ||
62 | etc_group = fopen(filename, "r"); | ||
63 | if (!etc_group) { | ||
64 | perror_msg_and_die("%s", filename); | ||
65 | } | ||
66 | |||
67 | /* make sure gr_name isn't taken, make sure gid is kosher */ | ||
68 | desired = g->gr_gid; | ||
69 | while ((grp = fgetgrent(etc_group))) { | ||
70 | if ((strcmp(grp->gr_name, g->gr_name)) == 0) { | ||
71 | error_msg_and_die("%s: group already in use\n", g->gr_name); | ||
72 | } | ||
73 | if ((desired) && grp->gr_gid == desired) { | ||
74 | error_msg_and_die("%d: gid has already been allocated\n", | ||
75 | desired); | ||
76 | } | ||
77 | if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) { | ||
78 | g->gr_gid = grp->gr_gid; | ||
79 | } | ||
80 | } | ||
81 | fclose(etc_group); | ||
82 | |||
83 | /* gid */ | ||
84 | if (desired) { | ||
85 | g->gr_gid = desired; | ||
86 | } else { | ||
87 | g->gr_gid++; | ||
88 | } | ||
89 | /* return 1; */ | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | /* append a new user to the passwd file */ | ||
94 | static int addgroup(const char *filename, char *group, gid_t gid) | ||
95 | { | ||
96 | FILE *etc_group; | ||
97 | FILE *etc_gshadow; | ||
98 | char *gshadow = SHADOW_FILE; | ||
99 | |||
100 | struct group gr; | ||
101 | |||
102 | /* group:passwd:gid:userlist */ | ||
103 | const char *entryfmt = "%s:%s:%d:%s\n"; | ||
104 | |||
105 | /* make sure gid and group haven't already been allocated */ | ||
106 | gr.gr_gid = gid; | ||
107 | gr.gr_name = group; | ||
108 | if (group_study(filename, &gr)) | ||
109 | return 1; | ||
110 | |||
111 | /* add entry to group */ | ||
112 | etc_group = fopen(filename, "a"); | ||
113 | if (!etc_group) { | ||
114 | perror_msg_and_die("%s", filename); | ||
115 | } | ||
116 | fprintf(etc_group, entryfmt, group, default_passwd, gr.gr_gid, ""); | ||
117 | fclose(etc_group); | ||
118 | |||
119 | /* add entry to gshadow if necessary */ | ||
120 | if (access(gshadow, F_OK|W_OK) == 0) { | ||
121 | etc_gshadow = xfopen(gshadow, "a"); | ||
122 | fprintf(etc_gshadow, "%s:!::\n", group); | ||
123 | fclose(etc_gshadow); | ||
124 | } | ||
125 | |||
126 | /* return 1; */ | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * addgroup will take a login_name as its first parameter. | ||
132 | * | ||
133 | * gid | ||
134 | * | ||
135 | * can be customized via command-line parameters. | ||
136 | * ________________________________________________________________________ */ | ||
137 | int addgroup_main(int argc, char **argv) | ||
138 | { | ||
139 | int i; | ||
140 | char opt; | ||
141 | char *group; | ||
142 | gid_t gid = 0; | ||
143 | |||
144 | /* get remaining args */ | ||
145 | for (i = 1; i < argc; i++) { | ||
146 | if (argv[i][0] == '-') { | ||
147 | opt = argv[i][1]; | ||
148 | switch (opt) { | ||
149 | case 'h': | ||
150 | show_usage(); | ||
151 | break; | ||
152 | case 'g': | ||
153 | gid = strtol(argv[++i], NULL, 10); | ||
154 | break; | ||
155 | default: | ||
156 | error_msg_and_die("addgroup: invalid option -- %c\n", opt); | ||
157 | } | ||
158 | } else { | ||
159 | break; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | if (i >= argc) { | ||
164 | show_usage(); | ||
165 | } else { | ||
166 | group = argv[i]; | ||
167 | } | ||
168 | |||
169 | if (geteuid() != 0) { | ||
170 | error_msg_and_die | ||
171 | ("addgroup: Only root may add a group to the system.\n"); | ||
172 | } | ||
173 | |||
174 | /* werk */ | ||
175 | return addgroup(GROUP_FILE, group, gid); | ||
176 | } | ||
177 | |||
178 | /* $Id: addgroup.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */ | ||
diff --git a/adduser.c b/adduser.c new file mode 100644 index 000000000..6bd2c253e --- /dev/null +++ b/adduser.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * adduser - add users to /etc/passwd and /etc/shadow | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 1999 by Lineo, inc. | ||
7 | * Written by John Beppu <beppu@lineo.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <errno.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdarg.h> | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | #include <shadow.h> | ||
32 | #include <time.h> | ||
33 | #include <unistd.h> | ||
34 | #include <sys/param.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <sys/types.h> | ||
37 | #include "busybox.h" | ||
38 | #include "pwd_grp/pwd.h" | ||
39 | #include "pwd_grp/grp.h" | ||
40 | |||
41 | #define PASSWD_FILE "/etc/passwd" | ||
42 | #define SHADOW_FILE "/etc/gshadow" | ||
43 | |||
44 | #if 0 | ||
45 | # define PASSWD_FILE "passwd" | ||
46 | # define SHADOW_FILE "shadow" | ||
47 | #endif | ||
48 | |||
49 | /* structs __________________________ */ | ||
50 | |||
51 | typedef struct { | ||
52 | uid_t u; | ||
53 | gid_t g; | ||
54 | } Id; | ||
55 | |||
56 | /* data _____________________________ */ | ||
57 | |||
58 | /* defaults : should this be in an external file? */ | ||
59 | static char *default_passwd = "x"; | ||
60 | static char *default_gecos = "Embedix User,,,"; | ||
61 | static char *default_home_prefix = "/home"; | ||
62 | static char *default_shell = "/bin/sh"; | ||
63 | |||
64 | /* shadow in use? */ | ||
65 | static int shadow_enabled = 0; | ||
66 | |||
67 | /* I was doing this all over the place */ | ||
68 | static FILE *fopen_wrapper(const char *filename, const char *mode) | ||
69 | { | ||
70 | FILE *f; | ||
71 | |||
72 | f = fopen(filename, mode); | ||
73 | if (f == NULL) { | ||
74 | fprintf(stderr, "adduser: %s: %s\n", filename, strerror(errno)); | ||
75 | } | ||
76 | return f; | ||
77 | } | ||
78 | |||
79 | /* remix */ | ||
80 | /* EDR recoded such that the uid may be passed in *p */ | ||
81 | static int passwd_study(const char *filename, struct passwd *p) | ||
82 | { | ||
83 | struct passwd *pw; | ||
84 | FILE *passwd; | ||
85 | |||
86 | const int min = 500; | ||
87 | const int max = 65000; | ||
88 | |||
89 | passwd = fopen_wrapper(filename, "r"); | ||
90 | if (!passwd) | ||
91 | return 4; | ||
92 | |||
93 | /* EDR if uid is out of bounds, set to min */ | ||
94 | if ((p->pw_uid > max) || (p->pw_uid < min)) | ||
95 | p->pw_uid = min; | ||
96 | |||
97 | /* stuff to do: | ||
98 | * make sure login isn't taken; | ||
99 | * find free uid and gid; | ||
100 | */ | ||
101 | while ((pw = fgetpwent(passwd))) { | ||
102 | if (strcmp(pw->pw_name, p->pw_name) == 0) { | ||
103 | /* return 0; */ | ||
104 | return 1; | ||
105 | } | ||
106 | if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max) | ||
107 | && (pw->pw_uid >= min)) { | ||
108 | p->pw_uid = pw->pw_uid + 1; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | /* EDR check for an already existing gid */ | ||
113 | while (getgrgid(p->pw_uid) != NULL) | ||
114 | p->pw_uid++; | ||
115 | |||
116 | /* EDR also check for an existing group definition */ | ||
117 | if (getgrnam(p->pw_name) != NULL) | ||
118 | return 3; | ||
119 | |||
120 | /* EDR bounds check */ | ||
121 | if ((p->pw_uid > max) || (p->pw_uid < min)) | ||
122 | return 2; | ||
123 | |||
124 | /* EDR create new gid always = uid */ | ||
125 | p->pw_gid = p->pw_uid; | ||
126 | |||
127 | /* return 1; */ | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void addgroup_wrapper(const char *login, gid_t gid) | ||
132 | { | ||
133 | int argc = 4; | ||
134 | char *argv[] = { "addgroup", "-g", NULL, NULL }; | ||
135 | char group_id[8]; | ||
136 | char group_name[32]; | ||
137 | |||
138 | strncpy(group_name, login, 32); | ||
139 | argv[3] = group_name; | ||
140 | sprintf(group_id, "%d", gid); | ||
141 | argv[2] = group_id; | ||
142 | addgroup_main(argc, argv); | ||
143 | } | ||
144 | |||
145 | static void passwd_wrapper(const char *login) | ||
146 | { | ||
147 | char *prog = "passwd"; | ||
148 | execlp(prog, prog, login, NULL); | ||
149 | error_msg_and_die("Failed to execute 'passwd', you must set the password for '%s' manually\n", login); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * pwd_to_spwd - create entries for new spwd structure | ||
154 | * | ||
155 | * pwd_to_spwd() creates a new (struct spwd) containing the | ||
156 | * information in the pointed-to (struct passwd). | ||
157 | */ | ||
158 | #define DAY (24L*3600L) | ||
159 | #define WEEK (7*DAY) | ||
160 | #define SCALE DAY | ||
161 | static struct spwd *pwd_to_spwd(const struct passwd *pw) | ||
162 | { | ||
163 | static struct spwd sp; | ||
164 | |||
165 | /* | ||
166 | * Nice, easy parts first. The name and passwd map directly | ||
167 | * from the old password structure to the new one. | ||
168 | */ | ||
169 | sp.sp_namp = pw->pw_name; | ||
170 | sp.sp_pwdp = pw->pw_passwd; | ||
171 | |||
172 | /* | ||
173 | * Defaults used if there is no pw_age information. | ||
174 | */ | ||
175 | sp.sp_min = 0; | ||
176 | sp.sp_max = (10000L * DAY) / SCALE; | ||
177 | sp.sp_lstchg = time((time_t *) 0) / SCALE; | ||
178 | |||
179 | /* | ||
180 | * These fields have no corresponding information in the password | ||
181 | * file. They are set to uninitialized values. | ||
182 | */ | ||
183 | sp.sp_warn = -1; | ||
184 | sp.sp_expire = -1; | ||
185 | sp.sp_inact = -1; | ||
186 | sp.sp_flag = -1; | ||
187 | |||
188 | return &sp; | ||
189 | } | ||
190 | |||
191 | /* putpwent(3) remix */ | ||
192 | static int adduser(const char *filename, struct passwd *p) | ||
193 | { | ||
194 | FILE *passwd; | ||
195 | int r; | ||
196 | FILE *shadow; | ||
197 | struct spwd *sp; | ||
198 | |||
199 | /* make sure everything is kosher and setup uid && gid */ | ||
200 | passwd = fopen_wrapper(filename, "a"); | ||
201 | if (passwd == NULL) { | ||
202 | /* return -1; */ | ||
203 | return 1; | ||
204 | } | ||
205 | fseek(passwd, 0, SEEK_END); | ||
206 | |||
207 | /* if (passwd_study(filename, p) == 0) { */ | ||
208 | r = passwd_study(filename, p); | ||
209 | if (r) { | ||
210 | if (r == 1) | ||
211 | error_msg("%s: login already in use\n", p->pw_name); | ||
212 | else if (r == 2) | ||
213 | error_msg("illegal uid or no uids left\n"); | ||
214 | else if (r == 3) | ||
215 | error_msg("group name %s already in use\n", p->pw_name); | ||
216 | else | ||
217 | error_msg("generic error.\n"); | ||
218 | /* return -1; */ | ||
219 | return 1; | ||
220 | } | ||
221 | |||
222 | /* add to passwd */ | ||
223 | if (putpwent(p, passwd) == -1) { | ||
224 | /* return -1; */ | ||
225 | return 1; | ||
226 | } | ||
227 | fclose(passwd); | ||
228 | |||
229 | /* add to shadow if necessary */ | ||
230 | if (shadow_enabled) { | ||
231 | shadow = fopen_wrapper(SHADOW_FILE, "a"); | ||
232 | if (shadow == NULL) { | ||
233 | /* return -1; */ | ||
234 | return 1; | ||
235 | } | ||
236 | fseek(shadow, 0, SEEK_END); | ||
237 | sp = pwd_to_spwd(p); | ||
238 | sp->sp_max = 99999; /* debianish */ | ||
239 | sp->sp_warn = 7; | ||
240 | fprintf(shadow, "%s:!:%ld:%ld:%ld:%ld:::\n", | ||
241 | sp->sp_namp, sp->sp_lstchg, sp->sp_min, sp->sp_max, | ||
242 | sp->sp_warn); | ||
243 | fclose(shadow); | ||
244 | } | ||
245 | |||
246 | /* add to group */ | ||
247 | /* addgroup should be responsible for dealing w/ gshadow */ | ||
248 | addgroup_wrapper(p->pw_name, p->pw_gid); | ||
249 | |||
250 | /* Clear the umask for this process so it doesn't | ||
251 | * * screw up the permissions on the mkdir and chown. */ | ||
252 | umask(0); | ||
253 | |||
254 | /* mkdir */ | ||
255 | if (mkdir(p->pw_dir, 0755)) { | ||
256 | perror_msg("%s", p->pw_dir); | ||
257 | } | ||
258 | /* Set the owner and group so it is owned by the new user. */ | ||
259 | if (chown(p->pw_dir, p->pw_uid, p->pw_gid)) { | ||
260 | perror_msg("%s", p->pw_dir); | ||
261 | } | ||
262 | /* Now fix up the permissions to 2755. Can't do it before now | ||
263 | * since chown will clear the setgid bit */ | ||
264 | if (chmod(p->pw_dir, 02755)) { | ||
265 | perror_msg("%s", p->pw_dir); | ||
266 | } | ||
267 | /* interactively set passwd */ | ||
268 | passwd_wrapper(p->pw_name); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | |||
274 | /* return current uid (root is always uid == 0, right?) */ | ||
275 | static uid_t i_am_not_root() | ||
276 | { | ||
277 | return geteuid(); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * adduser will take a login_name as its first parameter. | ||
282 | * | ||
283 | * home | ||
284 | * shell | ||
285 | * gecos | ||
286 | * | ||
287 | * can be customized via command-line parameters. | ||
288 | * ________________________________________________________________________ */ | ||
289 | int adduser_main(int argc, char **argv) | ||
290 | { | ||
291 | int i; | ||
292 | char opt; | ||
293 | char *login; | ||
294 | char *gecos; | ||
295 | char *home = NULL; | ||
296 | char *shell; | ||
297 | char path[MAXPATHLEN]; | ||
298 | |||
299 | struct passwd pw; | ||
300 | |||
301 | /* init */ | ||
302 | if (argc < 2) { | ||
303 | show_usage(); | ||
304 | } | ||
305 | gecos = default_gecos; | ||
306 | shell = default_shell; | ||
307 | |||
308 | /* get args */ | ||
309 | for (i = 1; i < argc; i++) { | ||
310 | if (argv[i][0] == '-') { | ||
311 | opt = argv[i][1]; | ||
312 | switch (opt) { | ||
313 | case 'h': | ||
314 | home = argv[++i]; | ||
315 | break; | ||
316 | case 'g': | ||
317 | gecos = argv[++i]; | ||
318 | break; | ||
319 | case 's': | ||
320 | shell = argv[++i]; | ||
321 | break; | ||
322 | default: | ||
323 | error_msg("invalid option -- %c\n", opt); | ||
324 | break; | ||
325 | } | ||
326 | } else { | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /* got root? */ | ||
332 | if (i_am_not_root()) { | ||
333 | error_msg_and_die( "Only root may add a user or group to the system.\n"); | ||
334 | } | ||
335 | |||
336 | /* get login */ | ||
337 | if (i >= argc) { | ||
338 | error_msg_and_die( "adduser: no user specified\n"); | ||
339 | } | ||
340 | login = argv[i]; | ||
341 | |||
342 | /* create string for $HOME if not specified already */ | ||
343 | if (!home) { | ||
344 | snprintf(path, MAXPATHLEN, "%s/%s", default_home_prefix, login); | ||
345 | path[MAXPATHLEN - 1] = 0; | ||
346 | home = path; | ||
347 | } | ||
348 | /* is /etc/shadow in use? */ | ||
349 | shadow_enabled = (0 == access(SHADOW_FILE, F_OK)); | ||
350 | |||
351 | /* create a passwd struct */ | ||
352 | pw.pw_name = login; | ||
353 | pw.pw_passwd = default_passwd; | ||
354 | pw.pw_uid = 0; | ||
355 | pw.pw_gid = 0; | ||
356 | pw.pw_gecos = gecos; | ||
357 | pw.pw_dir = home; | ||
358 | pw.pw_shell = shell; | ||
359 | |||
360 | /* grand finale */ | ||
361 | i = adduser(PASSWD_FILE, &pw); | ||
362 | |||
363 | return (i); | ||
364 | } | ||
365 | |||
366 | /* $Id: adduser.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */ | ||
@@ -46,6 +46,12 @@ | |||
46 | #ifdef BB_TEST | 46 | #ifdef BB_TEST |
47 | APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) | 47 | APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) |
48 | #endif | 48 | #endif |
49 | #ifdef BB_ADDGROUP | ||
50 | APPLET(addgroup, addgroup_main, _BB_DIR_BIN) | ||
51 | #endif | ||
52 | #ifdef BB_ADDUSER | ||
53 | APPLET(adduser, adduser_main, _BB_DIR_BIN) | ||
54 | #endif | ||
49 | #ifdef BB_ADJTIMEX | 55 | #ifdef BB_ADJTIMEX |
50 | APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) | 56 | APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) |
51 | #endif | 57 | #endif |
@@ -104,6 +110,12 @@ | |||
104 | #ifdef BB_DEALLOCVT | 110 | #ifdef BB_DEALLOCVT |
105 | APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) | 111 | APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) |
106 | #endif | 112 | #endif |
113 | #ifdef BB_DELGROUP | ||
114 | APPLET(delgroup, delgroup_main, _BB_DIR_BIN) | ||
115 | #endif | ||
116 | #ifdef BB_DELUSER | ||
117 | APPLET(deluser, deluser_main, _BB_DIR_BIN) | ||
118 | #endif | ||
107 | #ifdef BB_DF | 119 | #ifdef BB_DF |
108 | APPLET(df, df_main, _BB_DIR_BIN) | 120 | APPLET(df, df_main, _BB_DIR_BIN) |
109 | #endif | 121 | #endif |
@@ -167,6 +179,9 @@ | |||
167 | #ifdef BB_GETOPT | 179 | #ifdef BB_GETOPT |
168 | APPLET(getopt, getopt_main, _BB_DIR_BIN) | 180 | APPLET(getopt, getopt_main, _BB_DIR_BIN) |
169 | #endif | 181 | #endif |
182 | #ifdef BB_GETTY | ||
183 | APPLET(getty, getty_main, _BB_DIR_SBIN) | ||
184 | #endif | ||
170 | #ifdef BB_GREP | 185 | #ifdef BB_GREP |
171 | APPLET(grep, grep_main, _BB_DIR_BIN) | 186 | APPLET(grep, grep_main, _BB_DIR_BIN) |
172 | #endif | 187 | #endif |
@@ -479,3 +494,4 @@ | |||
479 | }; | 494 | }; |
480 | 495 | ||
481 | #endif | 496 | #endif |
497 | |||
diff --git a/applets/usage.h b/applets/usage.h index 13759d23f..ac980bf8c 100644 --- a/applets/usage.h +++ b/applets/usage.h | |||
@@ -1,3 +1,19 @@ | |||
1 | #define addgroup_trivial_usage \ | ||
2 | "[OPTIONS] <group_name>" | ||
3 | #define addgroup_full_usage \ | ||
4 | "Adds a group to the system" \ | ||
5 | "Options:\n" \ | ||
6 | "\t-g\t\tspecify gid\n" | ||
7 | |||
8 | #define adduser_trivial_usage \ | ||
9 | "[OPTIONS] <user_name>" | ||
10 | #define adduser_full_usage \ | ||
11 | "Adds a user to the system" \ | ||
12 | "Options:\n" \ | ||
13 | "\t-h\t\thome directory\n" \ | ||
14 | "\t-s\t\tshell\n" \ | ||
15 | "\t-g\t\tGECOS string\n" | ||
16 | |||
1 | #define adjtimex_trivial_usage \ | 17 | #define adjtimex_trivial_usage \ |
2 | "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" | 18 | "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" |
3 | #define adjtimex_full_usage \ | 19 | #define adjtimex_full_usage \ |
@@ -215,6 +231,15 @@ | |||
215 | #define deallocvt_full_usage \ | 231 | #define deallocvt_full_usage \ |
216 | "Deallocate unused virtual terminal /dev/ttyN" | 232 | "Deallocate unused virtual terminal /dev/ttyN" |
217 | 233 | ||
234 | #define delgroup_trivial_usage \ | ||
235 | "GROUP" | ||
236 | #define delgroup_full_usage \ | ||
237 | "Deletes group GROUP from the system" | ||
238 | |||
239 | #define deluser_trivial_usage \ | ||
240 | "USER" | ||
241 | #define deluser_full_usage \ | ||
242 | "Deletes user USER from the system" | ||
218 | 243 | ||
219 | #ifdef BB_FEATURE_HUMAN_READABLE | 244 | #ifdef BB_FEATURE_HUMAN_READABLE |
220 | #define USAGE_HUMAN_READABLE(a) a | 245 | #define USAGE_HUMAN_READABLE(a) a |
@@ -533,6 +558,22 @@ | |||
533 | " esac\n" \ | 558 | " esac\n" \ |
534 | "done\n" | 559 | "done\n" |
535 | 560 | ||
561 | #define getty_trivial_usage \ | ||
562 | "getty [OPTIONS]... baud_rate,... line [termtype]" | ||
563 | #define getty_full_usage \ | ||
564 | "\nOpens a tty, prompts for a login name, then invokes /bin/login\n\n" \ | ||
565 | "Options:\n" \ | ||
566 | "\t-h\t\tEnable hardware (RTS/CTS) flow control.\n" \ | ||
567 | "\t-i\t\tDo not display /etc/issue before running login.\n" \ | ||
568 | "\t-L\t\tLocal line, so do not do carrier detect.\n" \ | ||
569 | "\t-m\t\tGet baud rate from modem's CONNECT status message.\n" \ | ||
570 | "\t-w\t\tWait for a CR or LF before sending /etc/issue.\n" \ | ||
571 | "\t-l login_app\tInvoke login_app instead of /bin/login.\n" \ | ||
572 | "\t-t timeout\tTerminate after timeout if no username is read.\n" \ | ||
573 | "\t-I initstring\tSets the init string to send before anything else.\n" \ | ||
574 | "\t-H login_host\tLog login_host into the utmp file as the hostname." | ||
575 | |||
576 | |||
536 | #define grep_trivial_usage \ | 577 | #define grep_trivial_usage \ |
537 | "[-ihHnqvs] PATTERN [FILEs...]" | 578 | "[-ihHnqvs] PATTERN [FILEs...]" |
538 | #define grep_full_usage \ | 579 | #define grep_full_usage \ |
diff --git a/deluser.c b/deluser.c new file mode 100644 index 000000000..bb6e10996 --- /dev/null +++ b/deluser.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * deluser (remove lusers from the system ;) for TinyLogin | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 1999 by Lineo, inc. | ||
7 | * Written by John Beppu <beppu@lineo.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <sys/stat.h> | ||
26 | #include <unistd.h> | ||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include "busybox.h" | ||
31 | |||
32 | #define PASSWD_FILE "/etc/passwd" | ||
33 | #define GROUP_FILE "/etc/group" | ||
34 | |||
35 | /* where to start and stop deletion */ | ||
36 | typedef struct { | ||
37 | size_t start; | ||
38 | size_t stop; | ||
39 | } Bounds; | ||
40 | |||
41 | /* An interesting side-effect of boundary()'s | ||
42 | * implementation is that the first user (typically root) | ||
43 | * cannot be removed. Let's call it a feature. */ | ||
44 | static Bounds boundary(const char *buffer, const char *login) | ||
45 | { | ||
46 | char needle[256]; | ||
47 | char *start; | ||
48 | char *stop; | ||
49 | Bounds b; | ||
50 | |||
51 | snprintf(needle, 256, "\n%s", login); | ||
52 | needle[255] = 0; | ||
53 | start = strstr(buffer, needle); | ||
54 | if (!start) { | ||
55 | b.start = 0; | ||
56 | b.stop = 0; | ||
57 | return b; | ||
58 | } | ||
59 | start++; | ||
60 | |||
61 | stop = index(start, '\n'); /* index is a BSD-ism */ | ||
62 | b.start = start - buffer; | ||
63 | b.stop = stop - buffer; | ||
64 | return b; | ||
65 | } | ||
66 | |||
67 | /* grep -v ^login (except it only deletes the first match) */ | ||
68 | /* ...in fact, I think I'm going to simplify this later */ | ||
69 | static int del_line_matching(char *login, char *filename) | ||
70 | { | ||
71 | char *buffer; | ||
72 | FILE *passwd; | ||
73 | size_t len; | ||
74 | Bounds b; | ||
75 | struct stat statbuf; | ||
76 | |||
77 | /* load into buffer */ | ||
78 | passwd = fopen(filename, "r"); | ||
79 | if (!passwd) { | ||
80 | return 1; | ||
81 | } | ||
82 | stat(filename, &statbuf); | ||
83 | len = statbuf.st_size; | ||
84 | buffer = (char *) malloc(len * sizeof(char)); | ||
85 | |||
86 | if (!buffer) { | ||
87 | fclose(passwd); | ||
88 | return 1; | ||
89 | } | ||
90 | fread(buffer, len, sizeof(char), passwd); | ||
91 | |||
92 | fclose(passwd); | ||
93 | |||
94 | /* find the user to remove */ | ||
95 | b = boundary(buffer, login); | ||
96 | if (b.stop == 0) { | ||
97 | free(buffer); | ||
98 | return 1; | ||
99 | } | ||
100 | |||
101 | /* write the file w/o the user */ | ||
102 | passwd = fopen(filename, "w"); | ||
103 | if (!passwd) { | ||
104 | return 1; | ||
105 | } | ||
106 | fwrite(buffer, (b.start - 1), sizeof(char), passwd); | ||
107 | fwrite(&buffer[b.stop], (len - b.stop), sizeof(char), passwd); | ||
108 | |||
109 | fclose(passwd); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | /* ________________________________________________________________________ */ | ||
115 | int delgroup_main(int argc, char **argv) | ||
116 | { | ||
117 | /* int successful; */ | ||
118 | int failure; | ||
119 | |||
120 | if (argc != 2) { | ||
121 | show_usage(); | ||
122 | } else { | ||
123 | |||
124 | failure = del_line_matching(argv[1], GROUP_FILE); | ||
125 | #ifdef TLG_FEATURE_SHADOWPASSWDS | ||
126 | if (access(GSHADOW_FILE, W_OK) == 0) { | ||
127 | /* EDR the |= works if the error is not 0, so he had it wrong */ | ||
128 | failure |= del_line_matching(argv[1], GSHADOW_FILE); | ||
129 | } | ||
130 | #endif /* TLG_FEATURE_SHADOWPASSWDS */ | ||
131 | /* if (!successful) { */ | ||
132 | if (failure) { | ||
133 | error_msg_and_die("%s: Group could not be removed\n", argv[1]); | ||
134 | } | ||
135 | |||
136 | } | ||
137 | return (EXIT_SUCCESS); | ||
138 | } | ||
139 | |||
140 | /* ________________________________________________________________________ */ | ||
141 | int deluser_main(int argc, char **argv) | ||
142 | { | ||
143 | /* int successful; */ | ||
144 | int failure; | ||
145 | |||
146 | if (argc != 2) { | ||
147 | show_usage(); | ||
148 | } else { | ||
149 | |||
150 | failure = del_line_matching(argv[1], PASSWD_FILE); | ||
151 | /* if (!successful) { */ | ||
152 | if (failure) { | ||
153 | error_msg_and_die("%s: User could not be removed from %s\n", | ||
154 | argv[1], PASSWD_FILE); | ||
155 | } | ||
156 | #ifdef TLG_FEATURE_SHADOWPASSWDS | ||
157 | failure = del_line_matching(argv[1], SHADOW_FILE); | ||
158 | /* if (!successful) { */ | ||
159 | if (failure) { | ||
160 | error_msg_and_die("%s: User could not be removed from %s\n", | ||
161 | argv[1], SHADOW_FILE); | ||
162 | } | ||
163 | #endif /* TLG_FEATURE_SHADOWPASSWDS */ | ||
164 | failure = del_line_matching(argv[1], GROUP_FILE); | ||
165 | /* if (!successful) { */ | ||
166 | if (failure) { | ||
167 | error_msg_and_die("%s: User could not be removed from %s\n", | ||
168 | argv[1], GROUP_FILE); | ||
169 | } | ||
170 | |||
171 | } | ||
172 | return (EXIT_SUCCESS); | ||
173 | } | ||
174 | |||
175 | /* $Id: deluser.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */ | ||
diff --git a/getty.c b/getty.c new file mode 100644 index 000000000..a5a0dc717 --- /dev/null +++ b/getty.c | |||
@@ -0,0 +1,1230 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* agetty.c - another getty program for Linux. By W. Z. Venema 1989 | ||
3 | Ported to Linux by Peter Orbaek <poe@daimi.aau.dk> | ||
4 | This program is freely distributable. The entire man-page used to | ||
5 | be here. Now read the real man-page agetty.8 instead. | ||
6 | |||
7 | -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 | ||
8 | |||
9 | 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> | ||
10 | - added Native Language Support | ||
11 | |||
12 | 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> | ||
13 | - enable hardware flow control before displaying /etc/issue | ||
14 | |||
15 | */ | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <unistd.h> | ||
20 | #include <string.h> | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <errno.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <sys/signal.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <stdarg.h> | ||
27 | #include <ctype.h> | ||
28 | #include <utmp.h> | ||
29 | #include <getopt.h> | ||
30 | #include <termios.h> | ||
31 | #include "busybox.h" | ||
32 | |||
33 | #define _PATH_LOGIN "/bin/login" | ||
34 | |||
35 | #ifdef linux | ||
36 | #include <sys/param.h> | ||
37 | #define USE_SYSLOG | ||
38 | #endif | ||
39 | |||
40 | extern void updwtmp(const char *filename, const struct utmp *ut); | ||
41 | |||
42 | /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */ | ||
43 | #ifdef USE_SYSLOG | ||
44 | #include <syslog.h> | ||
45 | #endif | ||
46 | |||
47 | |||
48 | /* | ||
49 | * Some heuristics to find out what environment we are in: if it is not | ||
50 | * System V, assume it is SunOS 4. | ||
51 | */ | ||
52 | |||
53 | #ifdef LOGIN_PROCESS /* defined in System V utmp.h */ | ||
54 | #define SYSV_STYLE /* select System V style getty */ | ||
55 | #endif | ||
56 | |||
57 | /* | ||
58 | * Things you may want to modify. | ||
59 | * | ||
60 | * If ISSUE is not defined, agetty will never display the contents of the | ||
61 | * /etc/issue file. You will not want to spit out large "issue" files at the | ||
62 | * wrong baud rate. Relevant for System V only. | ||
63 | * | ||
64 | * You may disagree with the default line-editing etc. characters defined | ||
65 | * below. Note, however, that DEL cannot be used for interrupt generation | ||
66 | * and for line editing at the same time. | ||
67 | */ | ||
68 | |||
69 | #ifdef SYSV_STYLE | ||
70 | #define ISSUE "/etc/issue" /* displayed before the login prompt */ | ||
71 | #include <sys/utsname.h> | ||
72 | #include <time.h> | ||
73 | #endif | ||
74 | |||
75 | #define LOGIN " login: " /* login prompt */ | ||
76 | |||
77 | /* Some shorthands for control characters. */ | ||
78 | |||
79 | #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */ | ||
80 | #define CR CTL('M') /* carriage return */ | ||
81 | #define NL CTL('J') /* line feed */ | ||
82 | #define BS CTL('H') /* back space */ | ||
83 | #define DEL CTL('?') /* delete */ | ||
84 | |||
85 | /* Defaults for line-editing etc. characters; you may want to change this. */ | ||
86 | |||
87 | #define DEF_ERASE DEL /* default erase character */ | ||
88 | #define DEF_INTR CTL('C') /* default interrupt character */ | ||
89 | #define DEF_QUIT CTL('\\') /* default quit char */ | ||
90 | #define DEF_KILL CTL('U') /* default kill char */ | ||
91 | #define DEF_EOF CTL('D') /* default EOF char */ | ||
92 | #define DEF_EOL 0 | ||
93 | #define DEF_SWITCH 0 /* default switch char */ | ||
94 | |||
95 | /* | ||
96 | * SunOS 4.1.1 termio is broken. We must use the termios stuff instead, | ||
97 | * because the termio -> termios translation does not clear the termios | ||
98 | * CIBAUD bits. Therefore, the tty driver would sometimes report that input | ||
99 | * baud rate != output baud rate. I did not notice that problem with SunOS | ||
100 | * 4.1. We will use termios where available, and termio otherwise. | ||
101 | */ | ||
102 | |||
103 | /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set | ||
104 | properly, but all is well if we use termios?! */ | ||
105 | |||
106 | #ifdef TCGETS | ||
107 | #undef TCGETA | ||
108 | #undef TCSETA | ||
109 | #undef TCSETAW | ||
110 | #define termio termios | ||
111 | #define TCGETA TCGETS | ||
112 | #define TCSETA TCSETS | ||
113 | #define TCSETAW TCSETSW | ||
114 | #endif | ||
115 | |||
116 | /* | ||
117 | * This program tries to not use the standard-i/o library. This keeps the | ||
118 | * executable small on systems that do not have shared libraries (System V | ||
119 | * Release <3). | ||
120 | */ | ||
121 | #ifndef BUFSIZ | ||
122 | #define BUFSIZ 1024 | ||
123 | #endif | ||
124 | |||
125 | /* | ||
126 | * When multiple baud rates are specified on the command line, the first one | ||
127 | * we will try is the first one specified. | ||
128 | */ | ||
129 | |||
130 | #define FIRST_SPEED 0 | ||
131 | |||
132 | /* Storage for command-line options. */ | ||
133 | |||
134 | #define MAX_SPEED 10 /* max. nr. of baud rates */ | ||
135 | |||
136 | struct options { | ||
137 | int flags; /* toggle switches, see below */ | ||
138 | int timeout; /* time-out period */ | ||
139 | char *login; /* login program */ | ||
140 | char *tty; /* name of tty */ | ||
141 | char *initstring; /* modem init string */ | ||
142 | char *issue; /* alternative issue file */ | ||
143 | int numspeed; /* number of baud rates to try */ | ||
144 | int speeds[MAX_SPEED]; /* baud rates to be tried */ | ||
145 | }; | ||
146 | |||
147 | #define F_PARSE (1<<0) /* process modem status messages */ | ||
148 | #define F_ISSUE (1<<1) /* display /etc/issue */ | ||
149 | #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */ | ||
150 | #define F_LOCAL (1<<3) /* force local */ | ||
151 | #define F_INITSTRING (1<<4) /* initstring is set */ | ||
152 | #define F_WAITCRLF (1<<5) /* wait for CR or LF */ | ||
153 | #define F_CUSTISSUE (1<<6) /* give alternative issue file */ | ||
154 | #define F_NOPROMPT (1<<7) /* don't ask for login name! */ | ||
155 | |||
156 | /* Storage for things detected while the login name was read. */ | ||
157 | |||
158 | struct chardata { | ||
159 | int erase; /* erase character */ | ||
160 | int kill; /* kill character */ | ||
161 | int eol; /* end-of-line character */ | ||
162 | int parity; /* what parity did we see */ | ||
163 | int capslock; /* upper case without lower case */ | ||
164 | }; | ||
165 | |||
166 | /* Initial values for the above. */ | ||
167 | |||
168 | struct chardata init_chardata = { | ||
169 | DEF_ERASE, /* default erase character */ | ||
170 | DEF_KILL, /* default kill character */ | ||
171 | 13, /* default eol char */ | ||
172 | 0, /* space parity */ | ||
173 | 0, /* no capslock */ | ||
174 | }; | ||
175 | |||
176 | struct Speedtab { | ||
177 | long speed; | ||
178 | int code; | ||
179 | }; | ||
180 | |||
181 | static struct Speedtab speedtab[] = { | ||
182 | {50, B50}, | ||
183 | {75, B75}, | ||
184 | {110, B110}, | ||
185 | {134, B134}, | ||
186 | {150, B150}, | ||
187 | {200, B200}, | ||
188 | {300, B300}, | ||
189 | {600, B600}, | ||
190 | {1200, B1200}, | ||
191 | {1800, B1800}, | ||
192 | {2400, B2400}, | ||
193 | {4800, B4800}, | ||
194 | {9600, B9600}, | ||
195 | #ifdef B19200 | ||
196 | {19200, B19200}, | ||
197 | #endif | ||
198 | #ifdef B38400 | ||
199 | {38400, B38400}, | ||
200 | #endif | ||
201 | #ifdef EXTA | ||
202 | {19200, EXTA}, | ||
203 | #endif | ||
204 | #ifdef EXTB | ||
205 | {38400, EXTB}, | ||
206 | #endif | ||
207 | #ifdef B57600 | ||
208 | {57600, B57600}, | ||
209 | #endif | ||
210 | #ifdef B115200 | ||
211 | {115200, B115200}, | ||
212 | #endif | ||
213 | #ifdef B230400 | ||
214 | {230400, B230400}, | ||
215 | #endif | ||
216 | {0, 0}, | ||
217 | }; | ||
218 | |||
219 | void parse_args(int argc, char **argv, struct options *op); | ||
220 | void parse_speeds(struct options *op, char *arg); | ||
221 | void update_utmp(char *line); | ||
222 | void open_tty(char *tty, struct termio *tp, int local); | ||
223 | void termio_init(struct termio *tp, int speed, struct options *op); | ||
224 | void auto_baud(struct termio *tp); | ||
225 | void do_prompt(struct options *op, struct termio *tp); | ||
226 | void next_speed(struct termio *tp, struct options *op); | ||
227 | char *get_logname(struct options *op, struct chardata *cp, | ||
228 | |||
229 | struct termio *tp); | ||
230 | void termio_final(struct options *op, struct termio *tp, | ||
231 | |||
232 | struct chardata *cp); | ||
233 | int caps_lock(char *s); | ||
234 | int bcode(char *s); | ||
235 | static void error(const char *fmt, ...); | ||
236 | |||
237 | /* The following is used for understandable diagnostics. */ | ||
238 | |||
239 | char *progname; | ||
240 | |||
241 | /* Fake hostname for ut_host specified on command line. */ | ||
242 | char *fakehost = NULL; | ||
243 | |||
244 | /* ... */ | ||
245 | #ifdef DEBUGGING | ||
246 | #define debug(s) fprintf(dbf,s); fflush(dbf) | ||
247 | #define DEBUGTERM "/dev/ttyp0" | ||
248 | FILE *dbf; | ||
249 | #else | ||
250 | #define debug(s) /* nothing */ | ||
251 | #endif | ||
252 | |||
253 | int getty_main(int argc, char **argv) | ||
254 | { | ||
255 | char *logname = NULL; /* login name, given to /bin/login */ | ||
256 | struct chardata chardata; /* set by get_logname() */ | ||
257 | struct termio termio; /* terminal mode bits */ | ||
258 | static struct options options = { | ||
259 | F_ISSUE, /* show /etc/issue (SYSV_STYLE) */ | ||
260 | 0, /* no timeout */ | ||
261 | _PATH_LOGIN, /* default login program */ | ||
262 | "tty1", /* default tty line */ | ||
263 | "", /* modem init string */ | ||
264 | ISSUE, /* default issue file */ | ||
265 | 0, /* no baud rates known yet */ | ||
266 | }; | ||
267 | |||
268 | /* The BSD-style init command passes us a useless process name. */ | ||
269 | |||
270 | #ifdef SYSV_STYLE | ||
271 | progname = argv[0]; | ||
272 | #else | ||
273 | progname = "getty"; | ||
274 | #endif | ||
275 | |||
276 | #ifdef DEBUGGING | ||
277 | dbf = xfopen(DEBUGTERM, "w"); | ||
278 | |||
279 | { | ||
280 | int i; | ||
281 | |||
282 | for (i = 1; i < argc; i++) { | ||
283 | debug(argv[i]); | ||
284 | debug("\n"); | ||
285 | } | ||
286 | } | ||
287 | #endif | ||
288 | |||
289 | /* Parse command-line arguments. */ | ||
290 | |||
291 | parse_args(argc, argv, &options); | ||
292 | |||
293 | #ifdef __linux__ | ||
294 | setsid(); | ||
295 | #endif | ||
296 | |||
297 | /* Update the utmp file. */ | ||
298 | |||
299 | #ifdef SYSV_STYLE | ||
300 | update_utmp(options.tty); | ||
301 | #endif | ||
302 | |||
303 | debug("calling open_tty\n"); | ||
304 | /* Open the tty as standard { input, output, error }. */ | ||
305 | open_tty(options.tty, &termio, options.flags & F_LOCAL); | ||
306 | |||
307 | #ifdef __linux__ | ||
308 | { | ||
309 | int iv; | ||
310 | |||
311 | iv = getpid(); | ||
312 | if (ioctl(0, TIOCSPGRP, &iv) < 0) | ||
313 | perror_msg("ioctl() TIOCSPGRP call failed"); | ||
314 | } | ||
315 | #endif | ||
316 | /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */ | ||
317 | debug("calling termio_init\n"); | ||
318 | termio_init(&termio, options.speeds[FIRST_SPEED], &options); | ||
319 | |||
320 | /* write the modem init string and DON'T flush the buffers */ | ||
321 | if (options.flags & F_INITSTRING) { | ||
322 | debug("writing init string\n"); | ||
323 | write(1, options.initstring, strlen(options.initstring)); | ||
324 | } | ||
325 | |||
326 | if (!(options.flags & F_LOCAL)) { | ||
327 | /* go to blocking write mode unless -L is specified */ | ||
328 | fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK); | ||
329 | } | ||
330 | |||
331 | /* Optionally detect the baud rate from the modem status message. */ | ||
332 | debug("before autobaud\n"); | ||
333 | if (options.flags & F_PARSE) | ||
334 | auto_baud(&termio); | ||
335 | |||
336 | /* Set the optional timer. */ | ||
337 | if (options.timeout) | ||
338 | (void) alarm((unsigned) options.timeout); | ||
339 | |||
340 | /* optionally wait for CR or LF before writing /etc/issue */ | ||
341 | if (options.flags & F_WAITCRLF) { | ||
342 | char ch; | ||
343 | |||
344 | debug("waiting for cr-lf\n"); | ||
345 | while (read(0, &ch, 1) == 1) { | ||
346 | ch &= 0x7f; /* strip "parity bit" */ | ||
347 | #ifdef DEBUGGING | ||
348 | fprintf(dbf, "read %c\n", ch); | ||
349 | #endif | ||
350 | if (ch == '\n' || ch == '\r') | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | chardata = init_chardata; | ||
356 | if (!(options.flags & F_NOPROMPT)) { | ||
357 | /* Read the login name. */ | ||
358 | debug("reading login name\n"); | ||
359 | /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */ | ||
360 | while ((logname = get_logname(&options, &chardata, &termio)) == | ||
361 | NULL) next_speed(&termio, &options); | ||
362 | } | ||
363 | |||
364 | /* Disable timer. */ | ||
365 | |||
366 | if (options.timeout) | ||
367 | (void) alarm(0); | ||
368 | |||
369 | /* Finalize the termio settings. */ | ||
370 | |||
371 | termio_final(&options, &termio, &chardata); | ||
372 | |||
373 | /* Now the newline character should be properly written. */ | ||
374 | |||
375 | (void) write(1, "\n", 1); | ||
376 | |||
377 | /* Let the login program take care of password validation. */ | ||
378 | |||
379 | (void) execl(options.login, options.login, "--", logname, (char *) 0); | ||
380 | error("%s: can't exec %s: %m", options.tty, options.login); | ||
381 | return (0); /* quiet GCC */ | ||
382 | } | ||
383 | |||
384 | /* parse-args - parse command-line arguments */ | ||
385 | |||
386 | void parse_args(argc, argv, op) | ||
387 | int argc; | ||
388 | char **argv; | ||
389 | struct options *op; | ||
390 | { | ||
391 | extern char *optarg; /* getopt */ | ||
392 | extern int optind; /* getopt */ | ||
393 | int c; | ||
394 | |||
395 | while (isascii(c = getopt(argc, argv, "I:LH:f:hil:mt:wn"))) { | ||
396 | switch (c) { | ||
397 | case 'I': | ||
398 | if (!(op->initstring = malloc(strlen(optarg)))) { | ||
399 | error("can't malloc initstring"); | ||
400 | break; | ||
401 | } | ||
402 | { | ||
403 | char ch, *p, *q; | ||
404 | int i; | ||
405 | |||
406 | /* copy optarg into op->initstring decoding \ddd | ||
407 | octal codes into chars */ | ||
408 | q = op->initstring; | ||
409 | p = optarg; | ||
410 | while (*p) { | ||
411 | if (*p == '\\') { /* know \\ means \ */ | ||
412 | p++; | ||
413 | if (*p == '\\') { | ||
414 | ch = '\\'; | ||
415 | p++; | ||
416 | } else { /* handle \000 - \177 */ | ||
417 | ch = 0; | ||
418 | for (i = 1; i <= 3; i++) { | ||
419 | if (*p >= '0' && *p <= '7') { | ||
420 | ch <<= 3; | ||
421 | ch += *p - '0'; | ||
422 | p++; | ||
423 | } else | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | *q++ = ch; | ||
428 | } else { | ||
429 | *q++ = *p++; | ||
430 | } | ||
431 | } | ||
432 | *q = '\0'; | ||
433 | } | ||
434 | op->flags |= F_INITSTRING; | ||
435 | break; | ||
436 | |||
437 | case 'L': /* force local */ | ||
438 | op->flags |= F_LOCAL; | ||
439 | break; | ||
440 | case 'H': /* fake login host */ | ||
441 | fakehost = optarg; | ||
442 | break; | ||
443 | case 'f': /* custom issue file */ | ||
444 | op->flags |= F_CUSTISSUE; | ||
445 | op->issue = optarg; | ||
446 | break; | ||
447 | case 'h': /* enable h/w flow control */ | ||
448 | op->flags |= F_RTSCTS; | ||
449 | break; | ||
450 | case 'i': /* do not show /etc/issue */ | ||
451 | op->flags &= ~F_ISSUE; | ||
452 | break; | ||
453 | case 'l': | ||
454 | op->login = optarg; /* non-default login program */ | ||
455 | break; | ||
456 | case 'm': /* parse modem status message */ | ||
457 | op->flags |= F_PARSE; | ||
458 | break; | ||
459 | case 'n': | ||
460 | op->flags |= F_NOPROMPT; | ||
461 | break; | ||
462 | case 't': /* time out */ | ||
463 | if ((op->timeout = atoi(optarg)) <= 0) | ||
464 | error("bad timeout value: %s", optarg); | ||
465 | break; | ||
466 | case 'w': | ||
467 | op->flags |= F_WAITCRLF; | ||
468 | break; | ||
469 | default: | ||
470 | show_usage(); | ||
471 | } | ||
472 | } | ||
473 | debug("after getopt loop\n"); | ||
474 | if (argc < optind + 2) /* check parameter count */ | ||
475 | show_usage(); | ||
476 | |||
477 | /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ | ||
478 | if ('0' <= argv[optind][0] && argv[optind][0] <= '9') { | ||
479 | /* a number first, assume it's a speed (BSD style) */ | ||
480 | parse_speeds(op, argv[optind++]); /* baud rate(s) */ | ||
481 | op->tty = argv[optind]; /* tty name */ | ||
482 | } else { | ||
483 | op->tty = argv[optind++]; /* tty name */ | ||
484 | parse_speeds(op, argv[optind]); /* baud rate(s) */ | ||
485 | } | ||
486 | |||
487 | optind++; | ||
488 | if (argc > optind && argv[optind]) | ||
489 | setenv("TERM", argv[optind], 1); | ||
490 | |||
491 | debug("exiting parseargs\n"); | ||
492 | } | ||
493 | |||
494 | /* parse_speeds - parse alternate baud rates */ | ||
495 | |||
496 | void parse_speeds(op, arg) | ||
497 | struct options *op; | ||
498 | char *arg; | ||
499 | { | ||
500 | char *strtok(); | ||
501 | char *cp; | ||
502 | |||
503 | debug("entered parse_speeds\n"); | ||
504 | for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { | ||
505 | if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0) | ||
506 | error("bad speed: %s", cp); | ||
507 | if (op->numspeed > MAX_SPEED) | ||
508 | error("too many alternate speeds"); | ||
509 | } | ||
510 | debug("exiting parsespeeds\n"); | ||
511 | } | ||
512 | |||
513 | #ifdef SYSV_STYLE | ||
514 | |||
515 | /* update_utmp - update our utmp entry */ | ||
516 | void update_utmp(line) | ||
517 | char *line; | ||
518 | { | ||
519 | struct utmp ut; | ||
520 | time_t t; | ||
521 | int mypid = getpid(); | ||
522 | long time(); | ||
523 | long lseek(); | ||
524 | struct utmp *utp; | ||
525 | |||
526 | #if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)) | ||
527 | struct flock lock; | ||
528 | #endif | ||
529 | |||
530 | /* | ||
531 | * The utmp file holds miscellaneous information about things started by | ||
532 | * /sbin/init and other system-related events. Our purpose is to update | ||
533 | * the utmp entry for the current process, in particular the process type | ||
534 | * and the tty line we are listening to. Return successfully only if the | ||
535 | * utmp file can be opened for update, and if we are able to find our | ||
536 | * entry in the utmp file. | ||
537 | */ | ||
538 | |||
539 | #ifdef __linux__ | ||
540 | utmpname(_PATH_UTMP); | ||
541 | setutent(); | ||
542 | while ((utp = getutent()) | ||
543 | && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) /* nothing */ | ||
544 | ; | ||
545 | |||
546 | if (utp) { | ||
547 | memcpy(&ut, utp, sizeof(ut)); | ||
548 | } else { | ||
549 | /* some inits don't initialize utmp... */ | ||
550 | memset(&ut, 0, sizeof(ut)); | ||
551 | strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); | ||
552 | } | ||
553 | /*endutent(); */ | ||
554 | |||
555 | strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user)); | ||
556 | strncpy(ut.ut_line, line, sizeof(ut.ut_line)); | ||
557 | if (fakehost) | ||
558 | strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); | ||
559 | time(&t); | ||
560 | ut.ut_time = t; | ||
561 | ut.ut_type = LOGIN_PROCESS; | ||
562 | ut.ut_pid = mypid; | ||
563 | |||
564 | pututline(&ut); | ||
565 | endutent(); | ||
566 | |||
567 | { | ||
568 | updwtmp(_PATH_WTMP, &ut); | ||
569 | } | ||
570 | #else /* not __linux__ */ | ||
571 | { | ||
572 | int ut_fd; | ||
573 | |||
574 | if ((ut_fd = open(UTMP_FILE, 2)) < 0) { | ||
575 | error("%s: open for update: %m"), UTMP_FILE; | ||
576 | } else { | ||
577 | long ut_size = sizeof(ut); /* avoid nonsense */ | ||
578 | |||
579 | while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) { | ||
580 | if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) { | ||
581 | ut.ut_type = LOGIN_PROCESS; | ||
582 | ut.ut_time = time((long *) 0); | ||
583 | (void) strncpy(ut.ut_name, "LOGIN", sizeof(ut.ut_name)); | ||
584 | (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line)); | ||
585 | if (fakehost) | ||
586 | (void) strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); | ||
587 | (void) lseek(ut_fd, -ut_size, 1); | ||
588 | (void) write(ut_fd, (char *) &ut, sizeof(ut)); | ||
589 | (void) close(ut_fd); | ||
590 | return; | ||
591 | } | ||
592 | } | ||
593 | error("%s: no utmp entry", line); | ||
594 | } | ||
595 | } | ||
596 | #endif /* __linux__ */ | ||
597 | } | ||
598 | |||
599 | #endif | ||
600 | |||
601 | /* open_tty - set up tty as standard { input, output, error } */ | ||
602 | void open_tty(tty, tp, local) | ||
603 | char *tty; | ||
604 | struct termio *tp; | ||
605 | int local; | ||
606 | { | ||
607 | /* Get rid of the present standard { output, error} if any. */ | ||
608 | |||
609 | (void) close(1); | ||
610 | (void) close(2); | ||
611 | errno = 0; /* ignore above errors */ | ||
612 | |||
613 | /* Set up new standard input, unless we are given an already opened port. */ | ||
614 | |||
615 | if (strcmp(tty, "-")) { | ||
616 | struct stat st; | ||
617 | |||
618 | /* Sanity checks... */ | ||
619 | |||
620 | if (chdir("/dev")) | ||
621 | error("/dev: chdir() failed: %m"); | ||
622 | if (stat(tty, &st) < 0) | ||
623 | error("/dev/%s: %m", tty); | ||
624 | if ((st.st_mode & S_IFMT) != S_IFCHR) | ||
625 | error("/dev/%s: not a character device", tty); | ||
626 | |||
627 | /* Open the tty as standard input. */ | ||
628 | |||
629 | (void) close(0); | ||
630 | errno = 0; /* ignore close(2) errors */ | ||
631 | |||
632 | debug("open(2)\n"); | ||
633 | if (open(tty, O_RDWR | O_NONBLOCK, 0) != 0) | ||
634 | error("/dev/%s: cannot open as standard input: %m", tty); | ||
635 | |||
636 | } else { | ||
637 | |||
638 | /* | ||
639 | * Standard input should already be connected to an open port. Make | ||
640 | * sure it is open for read/write. | ||
641 | */ | ||
642 | |||
643 | if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) | ||
644 | error("%s: not open for read/write", tty); | ||
645 | } | ||
646 | |||
647 | /* Set up standard output and standard error file descriptors. */ | ||
648 | debug("duping\n"); | ||
649 | if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */ | ||
650 | error("%s: dup problem: %m", tty); /* we have a problem */ | ||
651 | |||
652 | /* | ||
653 | * The following ioctl will fail if stdin is not a tty, but also when | ||
654 | * there is noise on the modem control lines. In the latter case, the | ||
655 | * common course of action is (1) fix your cables (2) give the modem more | ||
656 | * time to properly reset after hanging up. SunOS users can achieve (2) | ||
657 | * by patching the SunOS kernel variable "zsadtrlow" to a larger value; | ||
658 | * 5 seconds seems to be a good value. | ||
659 | */ | ||
660 | |||
661 | if (ioctl(0, TCGETA, tp) < 0) | ||
662 | error("%s: ioctl: %m", tty); | ||
663 | |||
664 | /* | ||
665 | * It seems to be a terminal. Set proper protections and ownership. Mode | ||
666 | * 0622 is suitable for SYSV <4 because /bin/login does not change | ||
667 | * protections. SunOS 4 login will change the protections to 0620 (write | ||
668 | * access for group tty) after the login has succeeded. | ||
669 | */ | ||
670 | |||
671 | #ifdef DEBIAN | ||
672 | { | ||
673 | /* tty to root.dialout 660 */ | ||
674 | struct group *gr; | ||
675 | int id; | ||
676 | |||
677 | id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0; | ||
678 | chown(tty, 0, id); | ||
679 | chmod(tty, 0660); | ||
680 | |||
681 | /* vcs,vcsa to root.sys 600 */ | ||
682 | if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) { | ||
683 | char *vcs, *vcsa; | ||
684 | |||
685 | if (!(vcs = malloc(strlen(tty)))) | ||
686 | error("Can't malloc for vcs"); | ||
687 | if (!(vcsa = malloc(strlen(tty) + 1))) | ||
688 | error("Can't malloc for vcsa"); | ||
689 | strcpy(vcs, "vcs"); | ||
690 | strcpy(vcs + 3, tty + 3); | ||
691 | strcpy(vcsa, "vcsa"); | ||
692 | strcpy(vcsa + 4, tty + 3); | ||
693 | |||
694 | id = (gr = getgrnam("sys")) ? gr->gr_gid : 0; | ||
695 | chown(vcs, 0, id); | ||
696 | chmod(vcs, 0600); | ||
697 | chown(vcsa, 0, id); | ||
698 | chmod(vcs, 0600); | ||
699 | |||
700 | free(vcs); | ||
701 | free(vcsa); | ||
702 | } | ||
703 | } | ||
704 | #else | ||
705 | (void) chown(tty, 0, 0); /* root, sys */ | ||
706 | (void) chmod(tty, 0622); /* crw--w--w- */ | ||
707 | errno = 0; /* ignore above errors */ | ||
708 | #endif | ||
709 | } | ||
710 | |||
711 | /* termio_init - initialize termio settings */ | ||
712 | |||
713 | char gbuf[1024]; | ||
714 | char area[1024]; | ||
715 | |||
716 | void termio_init(tp, speed, op) | ||
717 | struct termio *tp; | ||
718 | int speed; | ||
719 | struct options *op; | ||
720 | { | ||
721 | |||
722 | /* | ||
723 | * Initial termio settings: 8-bit characters, raw-mode, blocking i/o. | ||
724 | * Special characters are set after we have read the login name; all | ||
725 | * reads will be done in raw mode anyway. Errors will be dealt with | ||
726 | * lateron. | ||
727 | */ | ||
728 | #ifdef __linux__ | ||
729 | /* flush input and output queues, important for modems! */ | ||
730 | (void) ioctl(0, TCFLSH, TCIOFLUSH); | ||
731 | #endif | ||
732 | |||
733 | tp->c_cflag = CS8 | HUPCL | CREAD | speed; | ||
734 | if (op->flags & F_LOCAL) { | ||
735 | tp->c_cflag |= CLOCAL; | ||
736 | } | ||
737 | |||
738 | tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0; | ||
739 | tp->c_cc[VMIN] = 1; | ||
740 | tp->c_cc[VTIME] = 0; | ||
741 | |||
742 | /* Optionally enable hardware flow control */ | ||
743 | |||
744 | #ifdef CRTSCTS | ||
745 | if (op->flags & F_RTSCTS) | ||
746 | tp->c_cflag |= CRTSCTS; | ||
747 | #endif | ||
748 | |||
749 | (void) ioctl(0, TCSETA, tp); | ||
750 | |||
751 | /* go to blocking input even in local mode */ | ||
752 | fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK); | ||
753 | |||
754 | debug("term_io 2\n"); | ||
755 | } | ||
756 | |||
757 | /* auto_baud - extract baud rate from modem status message */ | ||
758 | void auto_baud(tp) | ||
759 | struct termio *tp; | ||
760 | { | ||
761 | int speed; | ||
762 | int vmin; | ||
763 | unsigned iflag; | ||
764 | char buf[BUFSIZ]; | ||
765 | char *bp; | ||
766 | int nread; | ||
767 | |||
768 | /* | ||
769 | * This works only if the modem produces its status code AFTER raising | ||
770 | * the DCD line, and if the computer is fast enough to set the proper | ||
771 | * baud rate before the message has gone by. We expect a message of the | ||
772 | * following format: | ||
773 | * | ||
774 | * <junk><number><junk> | ||
775 | * | ||
776 | * The number is interpreted as the baud rate of the incoming call. If the | ||
777 | * modem does not tell us the baud rate within one second, we will keep | ||
778 | * using the current baud rate. It is advisable to enable BREAK | ||
779 | * processing (comma-separated list of baud rates) if the processing of | ||
780 | * modem status messages is enabled. | ||
781 | */ | ||
782 | |||
783 | /* | ||
784 | * Use 7-bit characters, don't block if input queue is empty. Errors will | ||
785 | * be dealt with lateron. | ||
786 | */ | ||
787 | |||
788 | iflag = tp->c_iflag; | ||
789 | tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ | ||
790 | vmin = tp->c_cc[VMIN]; | ||
791 | tp->c_cc[VMIN] = 0; /* don't block if queue empty */ | ||
792 | (void) ioctl(0, TCSETA, tp); | ||
793 | |||
794 | /* | ||
795 | * Wait for a while, then read everything the modem has said so far and | ||
796 | * try to extract the speed of the dial-in call. | ||
797 | */ | ||
798 | |||
799 | (void) sleep(1); | ||
800 | if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) { | ||
801 | buf[nread] = '\0'; | ||
802 | for (bp = buf; bp < buf + nread; bp++) { | ||
803 | if (isascii(*bp) && isdigit(*bp)) { | ||
804 | if ((speed = bcode(bp))) { | ||
805 | tp->c_cflag &= ~CBAUD; | ||
806 | tp->c_cflag |= speed; | ||
807 | } | ||
808 | break; | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | /* Restore terminal settings. Errors will be dealt with lateron. */ | ||
813 | |||
814 | tp->c_iflag = iflag; | ||
815 | tp->c_cc[VMIN] = vmin; | ||
816 | (void) ioctl(0, TCSETA, tp); | ||
817 | } | ||
818 | |||
819 | /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ | ||
820 | void do_prompt(op, tp) | ||
821 | struct options *op; | ||
822 | struct termio *tp; | ||
823 | { | ||
824 | #ifdef ISSUE | ||
825 | FILE *fd; | ||
826 | int oflag; | ||
827 | int c; | ||
828 | struct utsname uts; | ||
829 | |||
830 | (void) uname(&uts); | ||
831 | #endif | ||
832 | |||
833 | (void) write(1, "\r\n", 2); /* start a new line */ | ||
834 | #ifdef ISSUE /* optional: show /etc/issue */ | ||
835 | if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) { | ||
836 | oflag = tp->c_oflag; /* save current setting */ | ||
837 | tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */ | ||
838 | (void) ioctl(0, TCSETAW, tp); | ||
839 | |||
840 | |||
841 | while ((c = getc(fd)) != EOF) { | ||
842 | if (c == '\\') { | ||
843 | c = getc(fd); | ||
844 | |||
845 | switch (c) { | ||
846 | case 's': | ||
847 | (void) printf("%s", uts.sysname); | ||
848 | break; | ||
849 | |||
850 | case 'n': | ||
851 | (void) printf("%s", uts.nodename); | ||
852 | break; | ||
853 | |||
854 | case 'r': | ||
855 | (void) printf("%s", uts.release); | ||
856 | break; | ||
857 | |||
858 | case 'v': | ||
859 | (void) printf("%s", uts.version); | ||
860 | break; | ||
861 | |||
862 | case 'm': | ||
863 | (void) printf("%s", uts.machine); | ||
864 | break; | ||
865 | |||
866 | case 'o': | ||
867 | { | ||
868 | char domainname[256]; | ||
869 | |||
870 | getdomainname(domainname, sizeof(domainname)); | ||
871 | domainname[sizeof(domainname) - 1] = '\0'; | ||
872 | printf("%s", domainname); | ||
873 | } | ||
874 | break; | ||
875 | |||
876 | case 'd': | ||
877 | case 't': | ||
878 | { | ||
879 | char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", | ||
880 | "Fri", "Sat" | ||
881 | }; | ||
882 | char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", | ||
883 | "Jun", "Jul", "Aug", "Sep", "Oct", | ||
884 | "Nov", "Dec" | ||
885 | }; | ||
886 | time_t now; | ||
887 | struct tm *tm; | ||
888 | |||
889 | (void) time(&now); | ||
890 | tm = localtime(&now); | ||
891 | |||
892 | if (c == 'd') | ||
893 | (void) printf("%s %s %d %d", | ||
894 | weekday[tm->tm_wday], | ||
895 | month[tm->tm_mon], tm->tm_mday, | ||
896 | tm->tm_year < | ||
897 | 70 ? tm->tm_year + | ||
898 | 2000 : tm->tm_year + 1900); | ||
899 | else | ||
900 | (void) printf("%02d:%02d:%02d", tm->tm_hour, | ||
901 | tm->tm_min, tm->tm_sec); | ||
902 | |||
903 | break; | ||
904 | } | ||
905 | |||
906 | case 'l': | ||
907 | (void) printf("%s", op->tty); | ||
908 | break; | ||
909 | |||
910 | case 'b': | ||
911 | { | ||
912 | int i; | ||
913 | |||
914 | for (i = 0; speedtab[i].speed; i++) { | ||
915 | if (speedtab[i].code == (tp->c_cflag & CBAUD)) { | ||
916 | printf("%ld", speedtab[i].speed); | ||
917 | break; | ||
918 | } | ||
919 | } | ||
920 | break; | ||
921 | } | ||
922 | case 'u': | ||
923 | case 'U': | ||
924 | { | ||
925 | int users = 0; | ||
926 | struct utmp *ut; | ||
927 | |||
928 | setutent(); | ||
929 | while ((ut = getutent())) | ||
930 | if (ut->ut_type == USER_PROCESS) | ||
931 | users++; | ||
932 | endutent(); | ||
933 | printf("%d ", users); | ||
934 | if (c == 'U') | ||
935 | printf((users == 1) ? "user" : "users"); | ||
936 | break; | ||
937 | } | ||
938 | default: | ||
939 | (void) putchar(c); | ||
940 | } | ||
941 | } else | ||
942 | (void) putchar(c); | ||
943 | } | ||
944 | fflush(stdout); | ||
945 | |||
946 | tp->c_oflag = oflag; /* restore settings */ | ||
947 | (void) ioctl(0, TCSETAW, tp); /* wait till output is gone */ | ||
948 | (void) fclose(fd); | ||
949 | } | ||
950 | #endif | ||
951 | #ifdef __linux__ | ||
952 | { | ||
953 | char hn[MAXHOSTNAMELEN + 1]; | ||
954 | |||
955 | (void) gethostname(hn, MAXHOSTNAMELEN); | ||
956 | write(1, hn, strlen(hn)); | ||
957 | } | ||
958 | #endif | ||
959 | (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* always show login prompt */ | ||
960 | } | ||
961 | |||
962 | /* next_speed - select next baud rate */ | ||
963 | void next_speed(tp, op) | ||
964 | struct termio *tp; | ||
965 | struct options *op; | ||
966 | { | ||
967 | static int baud_index = FIRST_SPEED; /* current speed index */ | ||
968 | |||
969 | baud_index = (baud_index + 1) % op->numspeed; | ||
970 | tp->c_cflag &= ~CBAUD; | ||
971 | tp->c_cflag |= op->speeds[baud_index]; | ||
972 | (void) ioctl(0, TCSETA, tp); | ||
973 | } | ||
974 | |||
975 | /* get_logname - get user name, establish parity, speed, erase, kill, eol */ | ||
976 | /* return NULL on failure, logname on success */ | ||
977 | char *get_logname(op, cp, tp) | ||
978 | struct options *op; | ||
979 | struct chardata *cp; | ||
980 | struct termio *tp; | ||
981 | { | ||
982 | static char logname[BUFSIZ]; | ||
983 | char *bp; | ||
984 | char c; /* input character, full eight bits */ | ||
985 | char ascval; /* low 7 bits of input character */ | ||
986 | int bits; /* # of "1" bits per character */ | ||
987 | int mask; /* mask with 1 bit up */ | ||
988 | static char *erase[] = { /* backspace-space-backspace */ | ||
989 | "\010\040\010", /* space parity */ | ||
990 | "\010\040\010", /* odd parity */ | ||
991 | "\210\240\210", /* even parity */ | ||
992 | "\210\240\210", /* no parity */ | ||
993 | }; | ||
994 | |||
995 | /* Initialize kill, erase, parity etc. (also after switching speeds). */ | ||
996 | |||
997 | *cp = init_chardata; | ||
998 | |||
999 | /* Flush pending input (esp. after parsing or switching the baud rate). */ | ||
1000 | |||
1001 | (void) sleep(1); | ||
1002 | (void) ioctl(0, TCFLSH, TCIFLUSH); | ||
1003 | |||
1004 | /* Prompt for and read a login name. */ | ||
1005 | |||
1006 | for (*logname = 0; *logname == 0; /* void */ ) { | ||
1007 | |||
1008 | /* Write issue file and prompt, with "parity" bit == 0. */ | ||
1009 | |||
1010 | do_prompt(op, tp); | ||
1011 | |||
1012 | /* Read name, watch for break, parity, erase, kill, end-of-line. */ | ||
1013 | |||
1014 | for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) { | ||
1015 | |||
1016 | /* Do not report trivial EINTR/EIO errors. */ | ||
1017 | |||
1018 | if (read(0, &c, 1) < 1) { | ||
1019 | if (errno == EINTR || errno == EIO) | ||
1020 | exit(0); | ||
1021 | error("%s: read: %m", op->tty); | ||
1022 | } | ||
1023 | /* Do BREAK handling elsewhere. */ | ||
1024 | |||
1025 | if ((c == 0) && op->numspeed > 1) | ||
1026 | /* return (0); */ | ||
1027 | return NULL; | ||
1028 | |||
1029 | /* Do parity bit handling. */ | ||
1030 | |||
1031 | if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */ | ||
1032 | for (bits = 1, mask = 1; mask & 0177; mask <<= 1) | ||
1033 | if (mask & ascval) | ||
1034 | bits++; /* count "1" bits */ | ||
1035 | cp->parity |= ((bits & 1) ? 1 : 2); | ||
1036 | } | ||
1037 | /* Do erase, kill and end-of-line processing. */ | ||
1038 | |||
1039 | switch (ascval) { | ||
1040 | case CR: | ||
1041 | case NL: | ||
1042 | *bp = 0; /* terminate logname */ | ||
1043 | cp->eol = ascval; /* set end-of-line char */ | ||
1044 | break; | ||
1045 | case BS: | ||
1046 | case DEL: | ||
1047 | case '#': | ||
1048 | cp->erase = ascval; /* set erase character */ | ||
1049 | if (bp > logname) { | ||
1050 | (void) write(1, erase[cp->parity], 3); | ||
1051 | bp--; | ||
1052 | } | ||
1053 | break; | ||
1054 | case CTL('U'): | ||
1055 | case '@': | ||
1056 | cp->kill = ascval; /* set kill character */ | ||
1057 | while (bp > logname) { | ||
1058 | (void) write(1, erase[cp->parity], 3); | ||
1059 | bp--; | ||
1060 | } | ||
1061 | break; | ||
1062 | case CTL('D'): | ||
1063 | exit(0); | ||
1064 | default: | ||
1065 | if (!isascii(ascval) || !isprint(ascval)) { | ||
1066 | /* ignore garbage characters */ ; | ||
1067 | } else if (bp - logname >= sizeof(logname) - 1) { | ||
1068 | error("%s: input overrun", op->tty); | ||
1069 | } else { | ||
1070 | (void) write(1, &c, 1); /* echo the character */ | ||
1071 | *bp++ = ascval; /* and store it */ | ||
1072 | } | ||
1073 | break; | ||
1074 | } | ||
1075 | } | ||
1076 | } | ||
1077 | /* Handle names with upper case and no lower case. */ | ||
1078 | |||
1079 | if ((cp->capslock = caps_lock(logname))) { | ||
1080 | for (bp = logname; *bp; bp++) | ||
1081 | if (isupper(*bp)) | ||
1082 | *bp = tolower(*bp); /* map name to lower case */ | ||
1083 | } | ||
1084 | return (logname); | ||
1085 | } | ||
1086 | |||
1087 | /* termio_final - set the final tty mode bits */ | ||
1088 | void termio_final(op, tp, cp) | ||
1089 | struct options *op; | ||
1090 | struct termio *tp; | ||
1091 | struct chardata *cp; | ||
1092 | { | ||
1093 | /* General terminal-independent stuff. */ | ||
1094 | |||
1095 | tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ | ||
1096 | tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; | ||
1097 | /* no longer| ECHOCTL | ECHOPRT */ | ||
1098 | tp->c_oflag |= OPOST; | ||
1099 | /* tp->c_cflag = 0; */ | ||
1100 | tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ | ||
1101 | tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ | ||
1102 | tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ | ||
1103 | tp->c_cc[VEOL] = DEF_EOL; | ||
1104 | #ifdef __linux__ | ||
1105 | tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ | ||
1106 | #else | ||
1107 | tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */ | ||
1108 | #endif | ||
1109 | |||
1110 | /* Account for special characters seen in input. */ | ||
1111 | |||
1112 | if (cp->eol == CR) { | ||
1113 | tp->c_iflag |= ICRNL; /* map CR in input to NL */ | ||
1114 | tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ | ||
1115 | } | ||
1116 | tp->c_cc[VERASE] = cp->erase; /* set erase character */ | ||
1117 | tp->c_cc[VKILL] = cp->kill; /* set kill character */ | ||
1118 | |||
1119 | /* Account for the presence or absence of parity bits in input. */ | ||
1120 | |||
1121 | switch (cp->parity) { | ||
1122 | case 0: /* space (always 0) parity */ | ||
1123 | break; | ||
1124 | case 1: /* odd parity */ | ||
1125 | tp->c_cflag |= PARODD; | ||
1126 | /* FALLTHROUGH */ | ||
1127 | case 2: /* even parity */ | ||
1128 | tp->c_cflag |= PARENB; | ||
1129 | tp->c_iflag |= INPCK | ISTRIP; | ||
1130 | /* FALLTHROUGH */ | ||
1131 | case (1 | 2): /* no parity bit */ | ||
1132 | tp->c_cflag &= ~CSIZE; | ||
1133 | tp->c_cflag |= CS7; | ||
1134 | break; | ||
1135 | } | ||
1136 | /* Account for upper case without lower case. */ | ||
1137 | |||
1138 | if (cp->capslock) { | ||
1139 | tp->c_iflag |= IUCLC; | ||
1140 | tp->c_lflag |= XCASE; | ||
1141 | tp->c_oflag |= OLCUC; | ||
1142 | } | ||
1143 | /* Optionally enable hardware flow control */ | ||
1144 | |||
1145 | #ifdef CRTSCTS | ||
1146 | if (op->flags & F_RTSCTS) | ||
1147 | tp->c_cflag |= CRTSCTS; | ||
1148 | #endif | ||
1149 | |||
1150 | /* Finally, make the new settings effective */ | ||
1151 | |||
1152 | if (ioctl(0, TCSETA, tp) < 0) | ||
1153 | error("%s: ioctl: TCSETA: %m", op->tty); | ||
1154 | } | ||
1155 | |||
1156 | /* caps_lock - string contains upper case without lower case */ | ||
1157 | /* returns 1 if true, 0 if false */ | ||
1158 | int caps_lock(s) | ||
1159 | char *s; | ||
1160 | { | ||
1161 | int capslock; | ||
1162 | |||
1163 | for (capslock = 0; *s; s++) { | ||
1164 | if (islower(*s)) | ||
1165 | return (0); | ||
1166 | if (capslock == 0) | ||
1167 | capslock = isupper(*s); | ||
1168 | } | ||
1169 | return (capslock); | ||
1170 | } | ||
1171 | |||
1172 | /* bcode - convert speed string to speed code; return 0 on failure */ | ||
1173 | int bcode(s) | ||
1174 | char *s; | ||
1175 | { | ||
1176 | struct Speedtab *sp; | ||
1177 | long speed = atol(s); | ||
1178 | |||
1179 | for (sp = speedtab; sp->speed; sp++) | ||
1180 | if (sp->speed == speed) | ||
1181 | return (sp->code); | ||
1182 | return (0); | ||
1183 | } | ||
1184 | |||
1185 | /* error - report errors to console or syslog; only understands %s and %m */ | ||
1186 | |||
1187 | #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2) | ||
1188 | |||
1189 | /* | ||
1190 | * output error messages | ||
1191 | */ | ||
1192 | static void error(const char *fmt, ...) | ||
1193 | { | ||
1194 | va_list va_alist; | ||
1195 | char buf[256], *bp; | ||
1196 | |||
1197 | #ifndef USE_SYSLOG | ||
1198 | int fd; | ||
1199 | #endif | ||
1200 | |||
1201 | #ifdef USE_SYSLOG | ||
1202 | buf[0] = '\0'; | ||
1203 | bp = buf; | ||
1204 | #else | ||
1205 | strncpy(buf, progname, 256); | ||
1206 | strncat(buf, ": ", 256); | ||
1207 | buf[255] = 0; | ||
1208 | bp = buf + strlen(buf); | ||
1209 | #endif | ||
1210 | |||
1211 | va_start(va_alist, fmt); | ||
1212 | vsnprintf(bp, 256 - strlen(buf), fmt, va_alist); | ||
1213 | buf[255] = 0; | ||
1214 | va_end(va_alist); | ||
1215 | |||
1216 | #ifdef USE_SYSLOG | ||
1217 | openlog(progname, LOG_PID, LOG_AUTH); | ||
1218 | syslog(LOG_ERR, buf); | ||
1219 | closelog(); | ||
1220 | #else | ||
1221 | strncat(bp, "\r\n", 256 - strlen(buf)); | ||
1222 | buf[255] = 0; | ||
1223 | if ((fd = open("/dev/console", 1)) >= 0) { | ||
1224 | write(fd, buf, strlen(buf)); | ||
1225 | close(fd); | ||
1226 | } | ||
1227 | #endif | ||
1228 | (void) sleep((unsigned) 10); /* be kind to init(8) */ | ||
1229 | exit(1); | ||
1230 | } | ||
diff --git a/include/applets.h b/include/applets.h index a26a06e21..41b783862 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -46,6 +46,12 @@ | |||
46 | #ifdef BB_TEST | 46 | #ifdef BB_TEST |
47 | APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) | 47 | APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) |
48 | #endif | 48 | #endif |
49 | #ifdef BB_ADDGROUP | ||
50 | APPLET(addgroup, addgroup_main, _BB_DIR_BIN) | ||
51 | #endif | ||
52 | #ifdef BB_ADDUSER | ||
53 | APPLET(adduser, adduser_main, _BB_DIR_BIN) | ||
54 | #endif | ||
49 | #ifdef BB_ADJTIMEX | 55 | #ifdef BB_ADJTIMEX |
50 | APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) | 56 | APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) |
51 | #endif | 57 | #endif |
@@ -104,6 +110,12 @@ | |||
104 | #ifdef BB_DEALLOCVT | 110 | #ifdef BB_DEALLOCVT |
105 | APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) | 111 | APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) |
106 | #endif | 112 | #endif |
113 | #ifdef BB_DELGROUP | ||
114 | APPLET(delgroup, delgroup_main, _BB_DIR_BIN) | ||
115 | #endif | ||
116 | #ifdef BB_DELUSER | ||
117 | APPLET(deluser, deluser_main, _BB_DIR_BIN) | ||
118 | #endif | ||
107 | #ifdef BB_DF | 119 | #ifdef BB_DF |
108 | APPLET(df, df_main, _BB_DIR_BIN) | 120 | APPLET(df, df_main, _BB_DIR_BIN) |
109 | #endif | 121 | #endif |
@@ -167,6 +179,9 @@ | |||
167 | #ifdef BB_GETOPT | 179 | #ifdef BB_GETOPT |
168 | APPLET(getopt, getopt_main, _BB_DIR_BIN) | 180 | APPLET(getopt, getopt_main, _BB_DIR_BIN) |
169 | #endif | 181 | #endif |
182 | #ifdef BB_GETTY | ||
183 | APPLET(getty, getty_main, _BB_DIR_SBIN) | ||
184 | #endif | ||
170 | #ifdef BB_GREP | 185 | #ifdef BB_GREP |
171 | APPLET(grep, grep_main, _BB_DIR_BIN) | 186 | APPLET(grep, grep_main, _BB_DIR_BIN) |
172 | #endif | 187 | #endif |
@@ -479,3 +494,4 @@ | |||
479 | }; | 494 | }; |
480 | 495 | ||
481 | #endif | 496 | #endif |
497 | |||
diff --git a/include/usage.h b/include/usage.h index 13759d23f..ac980bf8c 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -1,3 +1,19 @@ | |||
1 | #define addgroup_trivial_usage \ | ||
2 | "[OPTIONS] <group_name>" | ||
3 | #define addgroup_full_usage \ | ||
4 | "Adds a group to the system" \ | ||
5 | "Options:\n" \ | ||
6 | "\t-g\t\tspecify gid\n" | ||
7 | |||
8 | #define adduser_trivial_usage \ | ||
9 | "[OPTIONS] <user_name>" | ||
10 | #define adduser_full_usage \ | ||
11 | "Adds a user to the system" \ | ||
12 | "Options:\n" \ | ||
13 | "\t-h\t\thome directory\n" \ | ||
14 | "\t-s\t\tshell\n" \ | ||
15 | "\t-g\t\tGECOS string\n" | ||
16 | |||
1 | #define adjtimex_trivial_usage \ | 17 | #define adjtimex_trivial_usage \ |
2 | "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" | 18 | "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" |
3 | #define adjtimex_full_usage \ | 19 | #define adjtimex_full_usage \ |
@@ -215,6 +231,15 @@ | |||
215 | #define deallocvt_full_usage \ | 231 | #define deallocvt_full_usage \ |
216 | "Deallocate unused virtual terminal /dev/ttyN" | 232 | "Deallocate unused virtual terminal /dev/ttyN" |
217 | 233 | ||
234 | #define delgroup_trivial_usage \ | ||
235 | "GROUP" | ||
236 | #define delgroup_full_usage \ | ||
237 | "Deletes group GROUP from the system" | ||
238 | |||
239 | #define deluser_trivial_usage \ | ||
240 | "USER" | ||
241 | #define deluser_full_usage \ | ||
242 | "Deletes user USER from the system" | ||
218 | 243 | ||
219 | #ifdef BB_FEATURE_HUMAN_READABLE | 244 | #ifdef BB_FEATURE_HUMAN_READABLE |
220 | #define USAGE_HUMAN_READABLE(a) a | 245 | #define USAGE_HUMAN_READABLE(a) a |
@@ -533,6 +558,22 @@ | |||
533 | " esac\n" \ | 558 | " esac\n" \ |
534 | "done\n" | 559 | "done\n" |
535 | 560 | ||
561 | #define getty_trivial_usage \ | ||
562 | "getty [OPTIONS]... baud_rate,... line [termtype]" | ||
563 | #define getty_full_usage \ | ||
564 | "\nOpens a tty, prompts for a login name, then invokes /bin/login\n\n" \ | ||
565 | "Options:\n" \ | ||
566 | "\t-h\t\tEnable hardware (RTS/CTS) flow control.\n" \ | ||
567 | "\t-i\t\tDo not display /etc/issue before running login.\n" \ | ||
568 | "\t-L\t\tLocal line, so do not do carrier detect.\n" \ | ||
569 | "\t-m\t\tGet baud rate from modem's CONNECT status message.\n" \ | ||
570 | "\t-w\t\tWait for a CR or LF before sending /etc/issue.\n" \ | ||
571 | "\t-l login_app\tInvoke login_app instead of /bin/login.\n" \ | ||
572 | "\t-t timeout\tTerminate after timeout if no username is read.\n" \ | ||
573 | "\t-I initstring\tSets the init string to send before anything else.\n" \ | ||
574 | "\t-H login_host\tLog login_host into the utmp file as the hostname." | ||
575 | |||
576 | |||
536 | #define grep_trivial_usage \ | 577 | #define grep_trivial_usage \ |
537 | "[-ihHnqvs] PATTERN [FILEs...]" | 578 | "[-ihHnqvs] PATTERN [FILEs...]" |
538 | #define grep_full_usage \ | 579 | #define grep_full_usage \ |
@@ -1,3 +1,19 @@ | |||
1 | #define addgroup_trivial_usage \ | ||
2 | "[OPTIONS] <group_name>" | ||
3 | #define addgroup_full_usage \ | ||
4 | "Adds a group to the system" \ | ||
5 | "Options:\n" \ | ||
6 | "\t-g\t\tspecify gid\n" | ||
7 | |||
8 | #define adduser_trivial_usage \ | ||
9 | "[OPTIONS] <user_name>" | ||
10 | #define adduser_full_usage \ | ||
11 | "Adds a user to the system" \ | ||
12 | "Options:\n" \ | ||
13 | "\t-h\t\thome directory\n" \ | ||
14 | "\t-s\t\tshell\n" \ | ||
15 | "\t-g\t\tGECOS string\n" | ||
16 | |||
1 | #define adjtimex_trivial_usage \ | 17 | #define adjtimex_trivial_usage \ |
2 | "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" | 18 | "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" |
3 | #define adjtimex_full_usage \ | 19 | #define adjtimex_full_usage \ |
@@ -215,6 +231,15 @@ | |||
215 | #define deallocvt_full_usage \ | 231 | #define deallocvt_full_usage \ |
216 | "Deallocate unused virtual terminal /dev/ttyN" | 232 | "Deallocate unused virtual terminal /dev/ttyN" |
217 | 233 | ||
234 | #define delgroup_trivial_usage \ | ||
235 | "GROUP" | ||
236 | #define delgroup_full_usage \ | ||
237 | "Deletes group GROUP from the system" | ||
238 | |||
239 | #define deluser_trivial_usage \ | ||
240 | "USER" | ||
241 | #define deluser_full_usage \ | ||
242 | "Deletes user USER from the system" | ||
218 | 243 | ||
219 | #ifdef BB_FEATURE_HUMAN_READABLE | 244 | #ifdef BB_FEATURE_HUMAN_READABLE |
220 | #define USAGE_HUMAN_READABLE(a) a | 245 | #define USAGE_HUMAN_READABLE(a) a |
@@ -533,6 +558,22 @@ | |||
533 | " esac\n" \ | 558 | " esac\n" \ |
534 | "done\n" | 559 | "done\n" |
535 | 560 | ||
561 | #define getty_trivial_usage \ | ||
562 | "getty [OPTIONS]... baud_rate,... line [termtype]" | ||
563 | #define getty_full_usage \ | ||
564 | "\nOpens a tty, prompts for a login name, then invokes /bin/login\n\n" \ | ||
565 | "Options:\n" \ | ||
566 | "\t-h\t\tEnable hardware (RTS/CTS) flow control.\n" \ | ||
567 | "\t-i\t\tDo not display /etc/issue before running login.\n" \ | ||
568 | "\t-L\t\tLocal line, so do not do carrier detect.\n" \ | ||
569 | "\t-m\t\tGet baud rate from modem's CONNECT status message.\n" \ | ||
570 | "\t-w\t\tWait for a CR or LF before sending /etc/issue.\n" \ | ||
571 | "\t-l login_app\tInvoke login_app instead of /bin/login.\n" \ | ||
572 | "\t-t timeout\tTerminate after timeout if no username is read.\n" \ | ||
573 | "\t-I initstring\tSets the init string to send before anything else.\n" \ | ||
574 | "\t-H login_host\tLog login_host into the utmp file as the hostname." | ||
575 | |||
576 | |||
536 | #define grep_trivial_usage \ | 577 | #define grep_trivial_usage \ |
537 | "[-ihHnqvs] PATTERN [FILEs...]" | 578 | "[-ihHnqvs] PATTERN [FILEs...]" |
538 | #define grep_full_usage \ | 579 | #define grep_full_usage \ |