aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-08-21 16:18:59 +0000
committerEric Andersen <andersen@codepoet.org>2001-08-21 16:18:59 +0000
commitf349e978c43b5061bf9dd3d05b5a30e2da039f60 (patch)
tree9b048f58d1c11600df69323327124425a2f78f63
parenta3e4f455ac0265d9f2477300054f504f563b0c58 (diff)
downloadbusybox-w32-f349e978c43b5061bf9dd3d05b5a30e2da039f60.tar.gz
busybox-w32-f349e978c43b5061bf9dd3d05b5a30e2da039f60.tar.bz2
busybox-w32-f349e978c43b5061bf9dd3d05b5a30e2da039f60.zip
Initial merge of all tinylogin applets that do not require crypt.
There is some optimization that can be done to better use libbb in these applets. There is also redundancy between stty and getty which could be eliminated. -Erik
-rw-r--r--Config.h5
-rw-r--r--addgroup.c178
-rw-r--r--adduser.c366
-rw-r--r--applets.h16
-rw-r--r--applets/usage.h41
-rw-r--r--deluser.c175
-rw-r--r--getty.c1230
-rw-r--r--include/applets.h16
-rw-r--r--include/usage.h41
-rw-r--r--usage.h41
10 files changed, 2109 insertions, 0 deletions
diff --git a/Config.h b/Config.h
index c46e2d282..69ef293c9 100644
--- a/Config.h
+++ b/Config.h
@@ -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? */
48static char *default_passwd = "x";
49
50
51/* make sure gr_name isn't taken, make sure gid is kosher
52 * return 1 on failure */
53static 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 */
94static 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 * ________________________________________________________________________ */
137int 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
51typedef struct {
52 uid_t u;
53 gid_t g;
54} Id;
55
56/* data _____________________________ */
57
58/* defaults : should this be in an external file? */
59static char *default_passwd = "x";
60static char *default_gecos = "Embedix User,,,";
61static char *default_home_prefix = "/home";
62static char *default_shell = "/bin/sh";
63
64/* shadow in use? */
65static int shadow_enabled = 0;
66
67/* I was doing this all over the place */
68static 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 */
81static 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
131static 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
145static 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
161static 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 */
192static 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?) */
275static 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 * ________________________________________________________________________ */
289int 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 $ */
diff --git a/applets.h b/applets.h
index a26a06e21..41b783862 100644
--- a/applets.h
+++ b/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/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 */
36typedef 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. */
44static 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 */
69static 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/* ________________________________________________________________________ */
115int 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/* ________________________________________________________________________ */
141int 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
40extern 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
136struct 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
158struct 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
168struct 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
176struct Speedtab {
177 long speed;
178 int code;
179};
180
181static 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
219void parse_args(int argc, char **argv, struct options *op);
220void parse_speeds(struct options *op, char *arg);
221void update_utmp(char *line);
222void open_tty(char *tty, struct termio *tp, int local);
223void termio_init(struct termio *tp, int speed, struct options *op);
224void auto_baud(struct termio *tp);
225void do_prompt(struct options *op, struct termio *tp);
226void next_speed(struct termio *tp, struct options *op);
227char *get_logname(struct options *op, struct chardata *cp,
228
229 struct termio *tp);
230void termio_final(struct options *op, struct termio *tp,
231
232 struct chardata *cp);
233int caps_lock(char *s);
234int bcode(char *s);
235static void error(const char *fmt, ...);
236
237/* The following is used for understandable diagnostics. */
238
239char *progname;
240
241/* Fake hostname for ut_host specified on command line. */
242char *fakehost = NULL;
243
244/* ... */
245#ifdef DEBUGGING
246#define debug(s) fprintf(dbf,s); fflush(dbf)
247#define DEBUGTERM "/dev/ttyp0"
248FILE *dbf;
249#else
250#define debug(s) /* nothing */
251#endif
252
253int 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
386void parse_args(argc, argv, op)
387int argc;
388char **argv;
389struct 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
496void parse_speeds(op, arg)
497struct options *op;
498char *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 */
516void update_utmp(line)
517char *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 } */
602void open_tty(tty, tp, local)
603char *tty;
604struct termio *tp;
605int 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
713char gbuf[1024];
714char area[1024];
715
716void termio_init(tp, speed, op)
717struct termio *tp;
718int speed;
719struct 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 */
758void auto_baud(tp)
759struct 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 */
820void do_prompt(op, tp)
821struct options *op;
822struct 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 */
963void next_speed(tp, op)
964struct termio *tp;
965struct 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 */
977char *get_logname(op, cp, tp)
978struct options *op;
979struct chardata *cp;
980struct 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 */
1088void termio_final(op, tp, cp)
1089struct options *op;
1090struct termio *tp;
1091struct 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 */
1158int caps_lock(s)
1159char *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 */
1173int bcode(s)
1174char *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 */
1192static 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 \
diff --git a/usage.h b/usage.h
index 13759d23f..ac980bf8c 100644
--- a/usage.h
+++ b/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 \