aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/ChangeLog1152
-rw-r--r--utils/Makefile72
-rw-r--r--utils/addauth.c100
-rw-r--r--utils/devprobe.c29
-rw-r--r--utils/fakeauth.c434
-rw-r--r--utils/fakeroot.sh63
-rw-r--r--utils/frobauth-mod.c162
-rw-r--r--utils/frobauth.c282
-rw-r--r--utils/frobauth.doc83
-rw-r--r--utils/frobauth.h71
-rw-r--r--utils/fsysopts.c18
-rw-r--r--utils/ftpcp.c397
-rw-r--r--utils/ftpdir.c329
-rw-r--r--utils/gcore.c107
-rw-r--r--utils/hurdids.c156
-rw-r--r--utils/ids.c196
-rw-r--r--utils/login.c424
-rw-r--r--utils/mount.c582
-rwxr-xr-xutils/mount.sh73
-rw-r--r--utils/msgport.c661
-rw-r--r--utils/nonsugid.c63
-rw-r--r--utils/old-ps.c183
-rw-r--r--utils/old-settrans.c104
-rw-r--r--utils/parse.c185
-rw-r--r--utils/parse.h63
-rw-r--r--utils/pids.c231
-rw-r--r--utils/pids.h47
-rw-r--r--utils/portinfo.c30
-rw-r--r--utils/ps.c472
-rw-r--r--utils/psout.c42
-rw-r--r--utils/psout.h12
-rw-r--r--utils/rmauth.c121
-rw-r--r--utils/rpctrace.c1238
-rw-r--r--utils/setauth.c134
-rw-r--r--utils/settrans.c171
-rw-r--r--utils/shd.c82
-rw-r--r--utils/showtrans.c34
-rw-r--r--utils/storecat.c73
-rw-r--r--utils/storeinfo.c87
-rw-r--r--utils/storeread.c130
-rw-r--r--utils/su.c481
-rw-r--r--utils/sush.sh91
-rw-r--r--utils/sync.c28
-rw-r--r--utils/syncfs.c80
-rw-r--r--utils/unsu.c90
-rw-r--r--utils/uptime.sh62
-rw-r--r--utils/vminfo.c241
-rw-r--r--utils/vmstat.c332
-rw-r--r--utils/w.c195
-rw-r--r--utils/x.c4
50 files changed, 7357 insertions, 3140 deletions
diff --git a/utils/ChangeLog b/utils/ChangeLog
deleted file mode 100644
index c2222747..00000000
--- a/utils/ChangeLog
+++ /dev/null
@@ -1,1152 +0,0 @@
-Wed Jul 31 14:23:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main/verify_passwd): Use #pragma weak instead of
- __attribute__ ((weak)).
- * su.c (check_password): Likewise.
-
- * login.c (options): Change --inherit-environ to --preserve-environment.
- Change --no-environ to --no-environment-args.
- Change --environ to --envvar and --environ-default to --envvar-default.
- * ps.c (options, main): Change --fmt to --format/-F.
- Change --posix-fmt/-o to --posix-format/-o.
- Change --sort to --sort/-s.
- Change --pgrp to --pgrp/-G.
- Change --login to --login/-L.
- Change --threads/-s to --threads/-T.
- Change --session to --session/-S.
- (OPT_FMT, OPT_SORT, OPT_PGRP, OPT_LOGIN, OPT_SESS): Macros removed.
- * w.c (options, main): Change --fmt to --format/-F.
- Change --sort to --sort/-s.
- (OPT_FMT, OPT_SORT): Macros removed.
-
-Wed Jul 31 14:24:05 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * login.c (main/verify_passwd): Declare crypt weak in a portable
- way.
- * su.c (check_password): Likewise.
-
-Tue Jul 30 14:49:48 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * login.c (main/verify_passwd): If government is broken, don't use
- crypt.
- * su.c (check_password): Likewise.
-
- * login.c (main/verify_passwd): Provide correct prototype for
- crypt.
- * su.c (check_password): Likewise.
-
-Mon Jul 29 03:22:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (val_t): Make `long long'.
-
-Sun Jul 28 21:13:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (main): Correctly parse the -w/--width option.
-
-Fri Jul 26 12:34:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (enum val_display_type): Add `PAGESZ'.
- `SIZES' -> `SIZE'; all uses updated. Remove BYTES, PAGES, and KBYTES.
- (fields): disp_type of "pagesize" and "swap-pagesize" changed to PAGESZ.
- (val_display_type_is_size): Function removed.
- (struct field): `disp_type' field -> `type'; all used updated.
- (print_val): Add TYPE & SIZE_UNITS arguments; remove HOW & PSIZE.
- (main): Variable user_disp_type removed. Variable size_units added.
- Add SIZE_UNITS macro, remove FDISPTYPE macro.
- Calls to print_val now use new PVAL macro.
- (get_vmstats_field): Just test against a type of SIZE, instead of
- using val_display_type_is_size.
-
-Thu Jul 25 22:36:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (INSTALL-vmstat-ops): New variable.
-
- * vmstat.c (options, main): -k/--kilobytes, -v/--pages, and
- -b/--bytes options added.
- (fields): New struct members initialized. `size',
- `cache-hit-ratio', `swap-size', `swap-active', `swap-free', and
- `swap-pagesize' added.
- (val_t, enum val_display_type, enum field_change_type): New types.
- (val_display_type_is_size, print_val, vm_state_refresh,
- vm_state_get_field, get_vmstats_field, get_size,
- ensure_def_pager_info, get_swap_size, get_swap_free,
- get_swap_page_size, get_swap_active): New functions.
- (struct field): CHANGE_TYPE, DISP_TYPE, STANDARD, and COMPUTE
- fields added. CUM field removed.
- (struct vm_state): New type.
- (main): Changed greatly to use vm_state type & functions, use
- print_val, and support CONST display types nicely.
- (argp_program_version): Version changed to 1.1.
-
-Sun Jul 21 03:00:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysopts.c (main): Print an error for no args.
- * portinfo.c (main): For no args, use argp_usage.
- (options): Minor fixes.
-
-Sat Jul 20 15:54:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Deleted var (which was `shd.ChangeLog').
- (shd.ChangeLog): Deleted file.
-
-Fri Jul 19 21:09:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options): Rearrange slightly.
-
-Tue Jul 16 21:38:01 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * login.c (main): If chown fails, print error message using errno,
- not -1.
-
-Fri Jul 12 15:49:09 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (dog): Get rid of `Beware of dog' -- it can't ever happen.
- Rename watch_login calls to check_login; don't use return value.
- (check_login): Renamed from watch_login. Change type to void.
- Exit if there's no such process.
-
- * login.c (main): Only start a watchdog timer if in a new login coll.
-
- * login.c (watch_login): New function.
- (dog): Use watch_login. Get rid of wierd rules for root-gone-away.
-
- * Makefile (INSTALL-ps-ops, INSTALL-w-ops): New variables.
-
-Fri Jul 12 14:20:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (INSTALL-login-ops): New variable.
-
-Sun Jul 7 21:31:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * settrans.c (main): Don't use unsafe MOVE_SEND in call to
- file_set_translator.
-
-Sat Jul 6 18:06:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c, vmstat.c, hurdids.c, fsysopts.c, settrans.c,
- showtrans.c, storeinfo.c, login.c, w.c, ps.c
- (argp_program_version): New variable.
- * vmstat.c <hurd.h>: New include.
-
-Fri Jul 5 22:28:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Pass the the basename of TTY to getutline.
-
-Wed Jul 3 14:00:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Don't fill in ut_line or ut_type
- fields in UTMP.
- Fill in the ut_addr field.
-
- * Makefile (settrans): Depend on ../libports/libports.a.
-
-Tue Jul 2 14:54:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (dog): Include all args in the asprintf.
- Put the ARGV message in parens.
-
-Mon Jul 1 13:05:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (kill_login): Don't kill dog.
- (dog): Take new ARGV argument, and record status in it for ps.
- (main): Pass ARGV to dog.
-
- * w.c (_w_specs): Don't use utmp buffer sizes for field widths, as
- they can be very large.
-
- * login.c (add_utmp_entry): Always fill in UTMP.ut_line.
- Set UTMP.ut_type.
-
-Fri Jun 28 15:44:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Increment TTY_FD while searching for a
- TTY.
-
-Mon Jun 24 16:02:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Fix heuristic to decide whether native booted.
-
-Thu Jun 20 14:41:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * login.c (main): No need for EXEC_NEWTASK or EXEC_SECURE.
-
- * Makefile (getty): Remove rule.
- (targets): Remove `getty'.
- (SRCS): Remove getty.c.
- * getty.c: Removed file to daemons directory.
-
-Wed Jun 19 14:11:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (hurd_file_name_path_lookup): Declaration removed.
- (main: child_lookup): Pass 0 for new LOOKUP arg to
- hurd_file_name_path_lookup.
-
-Mon Jun 17 18:06:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (targets): Add `getty'.
- (SRCS): Add `getty.c'.
- (getty): Depend on -lutil.
-
-Mon Jun 17 10:41:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets): Remove reboot & halt.
- (SRCS): Remove reboot.c & halt.c.
- (login): Depend on -lutil instead of grot.
-
-Tue Jun 11 13:43:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (get_utmp_host): Function removed.
- (add_utmp_entry): Get rid of TTY_FD parameter. Don't search for
- the tty unless we need it to get the old host, since login does it
- for us.
- Also use the `existing host' in the case that a new one isn't specified.
- (main): Update call to add_utmp_entry.
-
- * login.c (dog): Don't print stupid message if login session is empty.
- (add_utmp_entry): Use gettimeofday instead of time to get the time.
-
-Wed May 29 11:01:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Don't use -z flag to login.
-
-Tue May 28 17:48:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Fetch the parent uids before checking their number.
- (dog): Don't kill session if the user logged in!
- Print newline before message.
- (check_owned): Return OWNED, not NOTOWNED.
-
- * ps.c (fmts): Use %sz for vmem format, not %size.
- (spec_abbrevs): Still use `NTH' for field name, just `TH' for title.
- (fmts): Use %nth.
-
-Tue May 21 12:18:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (print_store): Get rid of class-name printing code,
- and use store->class->name. Print all flags.
-
-Tue May 14 09:50:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (dog): Use error to print messages. Use pretty time fmting.
- (main): Fork login timeout watchdog before clearing the process owner.
-
- * login.c (main): Only allow real users to make new login collections.
-
-Mon May 13 18:10:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (options, main): Remove -z/--no-utmp option.
- (main): Only add utmp entry for session leader.
- Clear process owner if no uids.
- Fork self-destruct timer when appropiate.
- (default_args): Add NOAUTH_TIMEOUT entry.
- (check_owned, kill_login, dog): New functions.
-
-Sun May 12 13:38:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.c (psout): When printing result of ps_fmt_creation_error,
- don't pass ERR to error (it should already be in PROBLEM if necessary).
-
-Sat May 11 01:00:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (_parse_strlist, parse_strlist, parse_numlist, lookup_user,
- main): Slather on consts, in a misguided attempt to shut up the
- compiler.
-
-Fri May 10 13:53:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devprobe.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
- * showtrans.c (parse_opt): Likewise.
- * portinfo.c (parse_opt): Likewise.
- * ps.c (parse_opt): Likewise.
- * settrans.c (parse_opt): Likewise.
- * login.c (parse_opt): Likewise.
- * hurdids.c (parse_opt): Likewise.
- * fsysopts.c (parse_opt): Likewise.
-
- * showtrans.c (parse_opt): Print a usage msg with no args.
- (options, main): Add --translated/-t option.
-
- * Makefile (storeinfo): Depend on ../libstore/libstore.a.
-
- * settrans.c (main): Remove const cast from first arg to argz_create.
- * fsysopts.c (main): Likewise.
- * login.c (main): Likewise.
- (main): Remove const from decl of USER & ARG.
- (fail): Remove const from decl of VIA.
-
- * ps.c (parse_strlist): Make DEFAULT_FN return a const char *.
-
- * storeinfo.c (print_store): New function.
- (info): Use store_create to make a store and print_store to print it.
- (parse_opt): Print a usage message for no args.
- (options, parse_opt): Add --children option.
-
-Thu May 9 19:46:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * w.c (uptime): Cast arg to localtime appropriately.
-
- * login.c (add_utmp_entry): Declare HOST `char const *'.
- (main) [fail]: Declare VIA `char const *'.
- (main): Declare USER `char const *'.
- Declare ARG `char const *'.
-
- * login.c (main): Provide new third arg to proc_setowner.
-
- * fsysopts.c (main) [parse_opt]: Cast first arg of argz_create
- appropriately.
- * settrans.c (main) [parse_opt]: Likewise.
- * login.c (main) [parse_opt] [case ARGP_KEY_ARG]: Likewise.
- (main): Likewise.
-
- * ps.c (main) [current_tty_name]: Remove `const' keyword to avoid
- type clash.
-
- * ps.c (main) [proc_stat_has_ctty]: Add parentheses around
- assignment used as truth value.
-
-Mon May 6 17:36:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.c (psout): Take a field, not a spec. Honor PS_FMT_FIELD_KEEP.
-
- * w.c (w_user_getter): New function.
- (w_get_user): New function.
- (w_fetch): Implement W_PSTAT_USER.
- (struct w_hook): Add user field.
- (_w_specs): Add "Name" entry.
- (w_get_uname): Renamed from w_get_user.
- (w_uname_getter): Renamed from w_user_getter.
- * ps.c (fmts): Upcase most format strings.
-
-Sun May 5 01:05:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.h: New file.
- * ps.c (fmts): Use new field syntax.
- (options): Add -o/--posix-fmt option. -A is an alias.
- "psout.h": New include.
- * w.c (_w_specs): Add precision & keep fields.
- (DEFAULT_FMT_STRING): Use new field syntax.
- "psout.h": New include.
- (main): Update call to psout.
- * psout.c (psout): Add posix_fmt arg.
-
-Thu May 2 00:10:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.c (psout): Use ps_fmt_creation_error to find out in detail
- why ps_fmt_create fails.
-
-Wed May 1 19:53:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (main): Default KILL_ACTIVE to 0.
-
-Tue Apr 30 19:04:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (_w_specs): Use ps_emit_past_time to show login times.
-
-Tue Apr 30 09:47:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (all): Remove target.
- (include ../Makeconf): Place before all dependencies.
- ($(targets)): Each separate target should depend on its own .o.
-
-Tue Apr 23 13:49:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Try to intuit whether this is a native-booted hurd
- system, and if so, don't filtered out non-parented processes.
-
-Wed Apr 10 19:47:45 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devprobe.c: New file.
- * Makefile (targets): Add devprobe.
- (SRCS): Add devprobe.c.
-
-Mon Apr 8 17:09:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (options, doc): Change meaning of --translate's
- argument, in preparation for other changes.
- (options, main): Add, but don't really implement, --search option.
-
-Fri Mar 29 14:37:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options): Add --exclusive option, change descriptions.
- (main): Rearrange meanings of arguments somewhat.
-
-Thu Mar 28 13:58:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (main): Use new names for functions, and pass stdout.
- (port_info, ports_info, xlated_port_info, xlated_ports_info,
- name_xlator_create, name_xlator_free, name_xlator_xlate):
- Functions removed (renamed and put in libshouldbeinlibc).
-
- * portinfo.c (parse_task): Use strtoul instead of atoi so pid 0 works.
-
-Mon Mar 25 14:19:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (uptime): Correctly calculate uptime.
- (...various...): Use real types instead of old ps typedefs.
- * ps.c (spec_abbrevs): Make const.
- (ps_specs): Make non-const.
- (...various...): Use real types instead of old ps typedefs.
- * psout.c (psout): Use real types instead of old ps typedefs.
-
-Sat Mar 23 01:02:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (uptime): Add a temporary hack to pretend to show uptime.
-
-Mon Mar 18 18:34:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Pass new arg to argp_parse.
- * w.c (main): Likewise.
- * storeinfo.c (main): Likewise.
- * fsysopts.c (main): Likewise.
- * hurdids.c (main): Likewise.
- * login.c (main): Likewise.
- * vmstat.c (main): Likewise.
- * showtrans.c (main): Likewise.
- * settrans.c (main): Likewise. Also use argp_usage correctly.
- * portinfo.c (main): Likewise.
-
-Tue Mar 5 14:17:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (main): Fix arg order to name_xlator_create.
- (name_xlator_create): Return X in XLATOR.
- (name_xlator_free): Deallocate all ports in X too.
- (main): Use xlated_port_info / xlated_ports_info.
- (xlated_port_info, xlated_ports_info): New functions.
- (struct name_xlator, name_xlator_create, name_xlator_xlate): Don't
- depend on a specified receive/send type for the source being specified.
- (name_xlator_xlate): Take FROM_TYPE arg, & return TO_TYPE.
- (options, main): Get rid of -R/-S options, and add --translate/-t
- option.
-
-Mon Mar 4 15:25:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (struct name_xlator): New structure.
- (name_xlator_create, name_xlator_free, name_xlator_xlate): New funcs.
- (options, main): Add --translate-{receive,send}/-R/-S options.
-
-Fri Mar 1 18:55:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets, SRCS): Add portinfo & portinfo.c.
-
-Tue Feb 27 14:51:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets, SRCS): Remove clri & clri.c.
-
-Mon Feb 26 13:50:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (main): Don't print a newline after `Pausing...' msg.
-
- * ps.c: Include <error.h> instead of "error.h".
- "common.h": Don't include this anymore.
-
-Wed Feb 21 11:47:01 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * w.c (uptime): Use %.2f format for load average numbers.
-
-Mon Feb 19 15:49:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (STRINGIFY): Make work. Is this in a header somewhere?
- (_STRINGIFY): New macro. Ick.
-
- * fsysopts.c (main): Use ARGP_IN_ORDER.
-
-Sat Feb 17 23:47:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * uptime.sh: New file.
- * Makefile (targets, special-targets): Add uptime.
- (SRCS): Add uptime.sh.
-
-Thu Feb 15 15:47:45 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Don't make -a imply -g.
-
- * sush.sh: Change -aBACKUP_SHELL to -aBACKUP_SHELLS.
-
- * login.c (child_lookup): Pass last arg to hurd_file_name_path_lookup.
-
-Wed Feb 14 17:38:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (add_utmp_procs): Correctly add terminal processes using new
- libps functionality.
- (read_utmp_procs): Emit all utmp entries, even the last one.
-
- * ps.c (main): Get rid of totally dead processes/threads.
- (add_pid): Complain about non-existant processes.
- (psout): New declaration.
-
- * ps.c (parse_numlist): Correctly handle NULL hook functions.
- (parse_opt): Deref STATE correctly.
- (main): Update calls to changed proc_stat_list_add_* functions.
-
- * login.c (main): Don't set old SAW_USER_ARG variable.
-
-Tue Feb 13 13:54:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Exec login.
-
- * login.c (main): Deal with the shell args reasonably.
-
- * ps.c (parse_opt): Don't turn quoted args into options.
-
-Mon Feb 12 14:54:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options, main): Add --timeout/-t option.
- (main): Pass ARGP_IN_ORDER to argp_parse (it's no longer the
- default), and deal with the fallout.
-
-Wed Feb 7 23:11:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Allow switches in the login args naturally.
-
-Mon Feb 5 14:18:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (main, args_doc, doc): Add repeat mode.
- (FVAL): New macro.
-
- * vmstat.c (main): Slightly decrease the space for numbers in the
- verbose output format.
- Twiddle the widths of the terse fields to make sure there's room
- for typical numbers.
-
-Sat Feb 3 01:28:20 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (fields, options): Make const.
-
- * vmstat.c: New file.
- * Makefile (targets): Add vmstat.
- (SRCS): Add vmstat.c
-
- * login.c (main): Correctly add gids.
- Avoid duplicating the old real id when keeping the old ids.
- Don't ask for a password unnecessarily.
-
-Thu Feb 1 19:15:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Don't save the parent ids.
-
- * login.c (main): When the user is specified as the first
- argument, always add it as both effective, real, and saved ids,
- even if there are others already.
-
- * login.c (main): Get the ttyname to chown.
- Only do the chown if NO_LOGIN isn't set.
-
- * settrans.c (options, main): Add --pause option.
-
-Thu Feb 1 16:27:24 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * login.c (main): Chown the terminal.
-
-Tue Jan 30 15:25:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Put LOGNAME in the environ even if it was already.
- (copied_args): Add "USER".
-
-Mon Jan 29 09:52:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Get rid of declaration for login().
- (main, default_args): Replace the BACKUP_SHELL param with
- BACKUP_SHELLS, which is a list of things to try. The default
- includes both bash and the /bin/sh.
- (main): Try to set the default path using confstr().
-
-Mon Jan 15 12:29:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options, main): Make -g/--goaway only apply to
- active translators.
- (options): Rearrange a bit.
-
-Sun Jan 14 12:45:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Call setlogin().
-
-Thu Jan 11 19:30:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (options, main): Change the -R/--retry option so that
- the optional argument is an argument to add to those passed to
- login when retrying, and remove all the hardwired arguments
- (except propagating -h/--via).
- (default_args, options, main): Get rid of the -n/--nobody option
- and variables, making it an additional login parameter.
-
- * login.c (default_args): Make the default shell /bin/bash instead of
- _PATH_BSHELL.
- (default_args, default_env): Make the default path just /bin.
-
- * loginpr.sh (user): Pass the appropiate -R options to login.
-
-Wed Jan 10 15:32:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Turn on RETRY when the -h option is specified.
-
-Fri Jan 5 15:21:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_canonical_host): Try harder to get the actual host name.
-
-Thu Jan 4 22:37:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_canonical_host): New function.
- (add_utmp_entry): Use VIA_ADDR instead of VIA in the utmp entry if
- it fits better.
- (add_entry): Function moved out of main.
- (main): Use add_canonical_host() to implement the -h option. Only
- let root specify the login host.
-
- * login.c (main): child_lookup() now takes an additional PATH arg,
- and calls hurd_file_name_path_lookup() instead. Pass a path when
- looking up the shell executable.
-
-Tue Jan 2 01:15:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Instead of giving --su to login, use all the component
- options it stood for. Also use --program-name for nice errors.
-
- * login.c (main): Do all file-name lookups using the target
- authentication, so that login isn't a security hole.
- Rework how password-checking is done somewhat (only ask when necess).
- Call exec_reauth() with SECURE==0 so that it reauths all the ports.
- If setting the real [ug]id, also add it as the `saved id'.
- (cat): Take an io_t port instead of a file descriptor.
- (options, main): Get rid of the -s/--su option, and add -S/--shell-arg.
- (FAILURE_SHELL): Macro deleted.
- (default_args): Add BACKUP_SHELL param.
- (main): Use BACKUP_SHELL instead of FAILURE_SHELL define.
-
-Mon Jan 1 20:51:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Use exec_reauth() instead of our own.
- (options, main): Add -k/--keep & -s/--su options.
- (options, main): Remove -m/--umask option; use UMASK param instead.
- (main): Get rid of various string vars only used once.
-
-Fri Dec 29 12:16:13 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * loginpr.sh: New program.
- * login.c (main): Add optional shell argument for --retry.
- Add --paranoid/-P option.
-
- * login.c (main): Don't ask for password by name if only one user.
-
-Thu Dec 28 17:41:11 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main, options): Add --retry/-R option.
-
- * login.c (main): If -f/--no-passwd is specified, get rid of the
- effect of the login executable being setuid/gid.
- Only set the shell proc's owner to an effective uid.
-
-Sun Dec 24 14:26:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Move a bunch of stuff into psout() in psout.c.
- * psout.c: New file.
-
-Sat Dec 23 20:49:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Allow user to use `-' prefix to invert sort as well.
- (main): Use ps_fmt_set_output_width() to set the output width.
-
- * login.c (add_utmp_entry): Only remove a prefix from the tty name
- if it's _PATH_DEV.
-
-Thu Dec 21 11:15:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (spec_abbrevs, ps_specs): New variables.
- (fmts): Get rid of redundant header specifications.
- (fmt_sortrevs): Variable removed.
- (main): Don't allow sorting on field names any more, just spec
- names (prob ok, since most things ps prints are now spec names).
- (main, options): Rename -o flag to -U for posix compat (ick).
-
- * login.c (options): Add --no-utmp/-z option.
- (add_utmp_entry): New function.
- (main): Call add_utmp_entry().
- (main): Ivec routines are now idvec routines.
- Include <idvec.h> instead of <ivec.h>.
- (options): --host/-h is now --via/-h.
- (main): Store the host were logged in from via in VIA, in the
- login parameters instead of the child environment; optionally copy
- it into the environment too.
- (main): Enable EXEC_SECURE.
- * Makefile (libutil-libsubst): New hack.
- (login): Depend on -lutil.
-
- * ps.c (main): Ivec routines are now idvec routines.
- Include <idvec.h> instead of <ivec.h>.
- Use argz functions to store tty_names instead of our own.
-
-Sun Dec 17 00:24:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main, options): If the specified sort field begins with
- `-', reverse the sort.
-
- * ps.c (main): If there is no current uid, don't try to filter with it.
- (FILTER_NOT_LEADER): Renamed from FILTER_NSESSLDR.
- (main): Rename ps_not_leader_filter from ps_not_sess_leader_filter.
-
- * ps.c (main): Use ivec routines instead of ids.
- (make_ids, ids_add, ids_contains): Routines deleted.
- Include <ivec.h>.
-
-Sat Dec 16 22:13:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (options): Reformat doc string for --tty option.
-
- * ps.c (options): Add argument and doc for 'w' option.
- (main): Implement 'w' option.
-
- * login.c: Zillions of changes.
-
-Tue Dec 12 20:16:22 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c: New file.
- * Makefile (SRCS): Add login.c
- (targets): Add login.
- (login): Depends on ../libshouldbelibc/libshouldbelibc.
-
-Wed Dec 6 15:12:15 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysopts.c (main): Supply the new SEP argument to argz_stringify.
- * showtrans.c (main): Ditto.
-
- * fsysopts.c (main): Change uses of the INDEX field in argp_state
- structures to use NEXT instead.
- * ps.c (main): Ditto.
- * settrans.c (main): Ditto.
- * showtrans.c (main): Ditto. Fix default prefix-printing test.
- * storeinfo.c (main): Ditto.
-
-Mon Dec 4 15:41:06 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (main): Correctly whether to print prefix by default.
- (options): Fix help strings.
-
-Wed Nov 15 19:56:21 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Use new libps stream type.
-
-Tue Nov 14 18:28:20 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Grow TTY_NAMES properly even when it's empty.
-
-Mon Nov 6 12:41:21 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (ids_add): Increase the size of IDS even when 0.
-
- * fsysopts.c (main): Use file_get_fs_options, not fsys_get_options.
- (doc): `filesystem' --> `FILESYS'.
-
-Sat Nov 4 19:56:38 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (print_info): Use the new FLAGS argument to
- file_get_storage_info. Add new storage types.
-
-Wed Nov 1 19:30:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (main): Change to use the new wierd callback
- interface to fshelp_start_translator.
-
- * ps.c (options): Add --not-owner/-O option.
- (id_t, struct ids): New type.
- (make_ids, ids_add, ids_contains): New functions.
- (main): Use a struct ids instead of multiple variables to hold the
- wanted uids list, which renamed to ONLY_UIDS. Add the NOT_UIDS
- list to contain the opposite sense, and use it.
-
- * ps.c (main): Use proc_stat_proc_info instead of proc_stat_info and
- PSTAT_PROC_INFO instead of PSTAT_INFO.
-
-Tue Oct 31 17:57:25 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysopts.c (doc, args_doc): Mention usage without any options.
- (main): If no options are supplied, print existing options.
-
- * ps.c (fmts): Add RPC field to the -l format.
-
-Mon Oct 30 16:24:37 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (options): --all is -e, not -a.
-
-Mon Oct 23 15:17:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options): Change --force/-f to --goaway/-g. Add
- flags for killing translators: --recurse/-r, --force/-f, --nosync/-S.
- (doc): New variable.
- (main): Support new flags. Have some of the options update flag
- words instead of setting variables.
-
- * storeinfo.c (print_info): Calculate total size/blocks correctly.
-
-Fri Oct 20 15:44:45 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (args_doc): New variable.
- (main): Set ARGZ inside of parse_opt.
-
- * fsysopts.c (options): FILE --> FILESYS in help msg.
- (args_doc): OPTION --> FS_OPTION, since the usage message already
- uses OPTION to mean those to fsysopts.
- (doc): New variable; give some common choices for FS_OPTION.
-
-Thu Oct 19 19:07:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (parse_enum): Use argp_error.
-
-Thu Oct 12 15:22:24 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (parse_enum): Use ARGP_HELP_STD_ERR.
-
-Wed Oct 11 19:03:19 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Use realloc on a variable in main instead of
- alloca, since the storage gets used after parse_opt returns.
-
- * fsysopts.c (main): Use argp_help instead of argp_usage.
-
-Tue Oct 10 15:02:17 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * showtrans.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- (arg_doc, doc): New variables.
- Include <argp.h> not <getopt.h>.
- * fsysopts.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- (arg_doc): New variable.
- Include <argp.h> not <getopt.h>.
- * settrans.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- Include <argp.h> not <getopt.h>.
- * ps.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- (arg_doc, doc): New variables.
- Include <argp.h> not <getopt.h>.
-
-Fri Oct 6 17:33:01 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (print_info): Use the new block_size value returned
- from file_get_storage_info.
-
-Wed Oct 4 18:15:59 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * showtrans.c (usage, options, main): Change -h/--no-header options to
- -p/--prefix and -P/--no-prefix.
- (main): Unless overridden by -p/-P, only print a FILE: prefix when
- there are multiple files on the command line.
-
-Mon Oct 2 19:00:27 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets): Add storeinfo.
- (SRCS): Add storeinfo.c.
-
-Fri Sep 1 11:35:12 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * settrans.c (main): Use fshelp_start_translator instead of
- start_translator from ../lib.
- * Makefile: Get rid of rules related to ../lib.
- (settrans): Depend on libfshelp.a instead of starttrans.o.
-
-Thu Aug 24 10:44:17 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (all): New target.
- (ps, settrans, showtrans, fsysopts): Put all dependencies in these
- targets.
- (settrans-HURDLIBS, showtrans-HURDLIBS, ps-HURDLIBS): Removed.
-
-Tue Aug 22 17:56:09 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (settrans-HURDLIBS, showtrans-HURDLIBS, ps-HURDLIBS):
- Add libshouldbeinlibc.
- (settrans, showtrans, fsysopts, ps): Get rid of things that are
- now in libshouldbeinlibc.
- Get rid of rules dealing with error.o.
-
-Sun Jul 23 15:58:06 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): sh.ChangeLog -> shd.ChangeLog.
-
-Fri Jul 7 19:20:21 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * clri.c (copyright, sccsid): Correct syntax.
-
-Fri Jul 7 18:56:45 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * settrans.c (SHORT_OPTIONS): Remove '?' as getopt usurps it.
- (options, main): Use '&' instead of '?' to mean help.
-
-Thu Jul 6 21:04:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * su.c (main, apply_auth_to_loginid, apply_auth_to_pgrp): Remove
- assignments from inside if tests.
-
- * sync.c (main): Declare return type.
-
- * clri.c (copyright, sccsid): Declare unused.
- (main): Correct format for fourth arg in printf call.
-
- * ps.c (lookup_user): Declare return to be `int' to avoid type
- clash in use as 4th parameter to parse_numlist.
-
- * shd.c (run): Remove assignments from inside if tests.
- (command): Likewise.
-
- * Makefile (special-targets): New var.
- (mount): Provide command.
- (OBJS): New var.
- (shd, su, clri, sync, reboot, halt): List object files here.
-
-Thu Jul 6 16:12:22 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * settrans.c (main): Give an error message instead of dying when
- no filename argument is given.
-
-Thu Jul 6 15:43:15 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Wed Jul 5 21:18:42 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (ps-HURDLIBS): Renamed from HURDLIBS.
- (ps): Fix dependencies.
-
-Mon Jun 26 16:13:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (CPPFLAGS): Put -I../lib back in.
- Put back the vpath for %.c to ../lib.
-
-Tue Jun 6 13:22:52 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Added libihash.
- (CPPFLAGS): Deleted addition of -I../lib.
- (vpath): Deleted spec.
- (ps): Deleted ihash.o and primes.o.
-
-Thu Jun 1 11:33:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (ps.o, fsysopts.o, showtrans.o, settrans.o): Add
- dependencies on header files.
- (REMHDRS): Define this variable.
-
-Tue May 30 12:17:33 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (SCRS): Removed update.c.
- (targets): Removed update.
-
-Sat May 20 00:51:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsysopts.c (main): Check for a missing filesystem name.
- (main): Tweak the error msgs a bit.
-
- * fsysopts.c (options, main): Don't use '?' as the --help key.
-
-Mon May 15 20:31:31 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * Makefile (SRCS, targets): Add fsysopts.
-
-Wed May 3 11:37:39 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main, usage, SHORT_OPTIONS, options): Add the -n flag
- (--nominal-fields), which prevents elision of uninteresting fields.
- Also add elision of uninteresting fields...
-
-Tue May 2 17:22:11 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * ps.c (fmts): Add the SC (suspend count) field to various output fmts.
- (usage, main, SHORT_OPTIONS): Add the (ignored) -w flag for BSD compat.
- (main): Use the new name for ps_fmt_squash: ps_fmt_squash_flags.
-
-Tue May 2 14:37:07 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * shd.c (reap): Check for ECHILD, not ESRCH.
-
-Wed Apr 26 21:40:57 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * settrans.c (main): Allow options before and immediately after
- the node name to be rearranged by getopt without affecting those
- following the translator name.
-
-Fri Apr 14 10:18:34 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * mount.sh: Move the test for a valid translator to just before we
- use it. Gratuitously change the "unknown" value for type to "".
- Don't use `--' when invoking settrans, as getopt doesn't seem to
- be handling it correctly. Use `usage' not `USAGE'.
-
-Wed Apr 12 14:38:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Omit ps.ChangeLog.
-
-Tue Apr 11 15:21:46 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (targets): Changed `sh' to `shd'.
- (SRCS): Changed `sh.c' to `shd.c'.
- * shd.c: Renamed from `sh.c'.
-
-Mon Apr 10 20:01:20 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Tweak things so that the -t flag works correctly
- for processes whose tty we can't figure out.
-
-Sun Apr 9 14:00:09 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * su.c (main): Getopt now returns '\001' for non-switch options
- instead of '\0', no doubt to work around an obscure bug in some
- brain-dead system only used by 2 people twice a decade.
-
-Fri Apr 7 11:55:25 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (parse_enum): Renamed from enum_name.
- (main, usage): Add lots of sysvish options, and generalize some
- existing ones to deal with sysvish usage. Make -t & -o work.
-
-Thu Apr 6 11:56:23 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Add the `jobc' (-j) output format from netbsd.
-
-Wed Apr 5 22:10:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): When processes are specified on the command line by PID,
- turn off all filtering so that they don't disappear later. Also
- minor changes in some spec names.
-
-Tue Apr 4 11:32:53 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile: Add showtrans & mount, and uncomment-out su.
-
- * settrans.c (main): Get rid of the `show passive translator'
- functionality, as this is now done by showtrans.
-
- * ps.c (main): Make -a imply -g as well, to be compatible with bsd.
- Add the -M (--no-msg-port) switch, which disables all fields that
- would use any process's message port.
-
- * showtrans.c: New file: Show passive translators.
-
- * su.c (apply_auth): Use msg_add_auth & msg_del_auth instead of
- add_auth & del_auth.
- (apply_auth_to_pids, apply_auth_to_loginid, apply_auth_to_pgrp):
- Don't use the IDS variable, it's no longer around; I think AUTH is
- the right thing to replace it with.
-
-Tue Apr 4 01:47:57 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Treat argument without leading - as if it had one,
- unless it's a number.
-
-Mon Mar 20 20:17:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (ps): Link in ihash.o, error.o, and primes.o too.
- * Makefile (vpath %.c): New decl.
-
- * ps.c: Include <hurd/ps.h> instead of "ps.h".
- Include <unistd.h>.
- (enum_name): Avoid warning.
- (program_name): New variable.
- (main): Don't set program_invocation_short_name (the library does it
- for us). Do set program_name.
-
- * ps.c: Replace with new version by Miles Bader. See ps.ChangeLog
- for some changes made to the new version before the replacement.
- Old ps.c and ps.ChangeLog are now ps.c.old and ps.ChangeLog.old.
- * Makefile (HURDLIBS): Define, for ps.
- (CPPFLAGS): Define, for ps.
- (ps): Add rule to get library.
-
-Sat Jan 28 15:02:08 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * sh.c (main): Only open /dev/tty if stdin is unreadable.
-
-Wed Nov 16 20:28:40 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * reboot.c: Include unistd.h, stdio.h, not hurd/anything.
- (main): If reboot returns, give error message and return 1.
- * halt.c: Likewise.
-
-Sat Nov 12 21:20:07 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * reboot.c (main): Just use the reboot function.
- * halt.c (main): Likewise.
-
-Fri Nov 11 12:05:38 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makefile (targets): Added reboot and halt.
- (SRCS): Added reboot.c and halt.c.
- * reboot.c: New file
- * halt.c: New file.
-
- * ps.c (main): Print in shorter format by default; take -v flag to
- print in longer format.
-
-Wed Nov 9 04:43:54 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * ps.c (time_str): Specify format for decimals correctly.
-
-Wed Nov 9 00:20:09 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ps.c (time_str): Use %.2d instead of %2d to get 0 pads.
-
-Mon Nov 7 14:15:10 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * ps.c (time_str): Don't use floating point conversion;
- it's buggy.
-
-Wed Nov 2 13:34:56 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * sync.c: New file.
- * Makefile (targets): Added sync.
- (SRCS): Added sync.c.
-
-Thu Oct 27 22:19:29 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Also print out a field with the number of threads.
-
-Tue Oct 4 19:40:22 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * clri.c: New file.
- * Makefile (targets): Added clri.
- (SRCS): Added clri.c.
-
-Sat Oct 1 03:44:55 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * update.c: Take optional arg to specify sleep time.
- Use daemon instead of doing its work by hand.
-
-Fri Sep 30 11:53:53 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * update.c: New file.
- * Makefile (SRCS): Added update.c.
- (targets): Added update.
-
-Sat Sep 10 08:22:34 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * settrans.c (main): Give usage message when given no args.
- Use O_NOTRANS in file name lookup.
- Don't use FS_TRANS_EXCL in file_set_translator.
- If given args "FILE -show", get translator and print it out.
-
-Thu Sep 1 11:50:51 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * settrans.c: New file.
- * Makefile (SRCS): Added settrans.c.
- (targets): Added settrans.
-
-Tue Aug 30 16:40:54 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * sh.c (run): Use file_name_lookup instead of path_lookup.
-
-Tue Aug 23 10:44:16 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (targets): Comment out `su' until Roland gets it back
- into a usable state.
-
-Mon Aug 22 12:18:09 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * sh.c (main): Open /dev/tty with O_IGNORE_CTTY and fdopen that
- onto stdin/out/err.
-
-Fri Jul 22 12:26:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten to use new scheme.
-
diff --git a/utils/Makefile b/utils/Makefile
index ebbc8d06..3f3307f4 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994,95,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -18,36 +18,66 @@
dir := utils
makemode := utilities
-targets = shd ps settrans showtrans sync su mount fsysopts \
- storeinfo login w uptime hurdids loginpr sush vmstat portinfo \
- devprobe
-special-targets = mount loginpr sush uptime
-SRCS = shd.c ps.c su.c settrans.c sync.c showtrans.c \
- mount.sh fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
- uptime.sh psout.c hurdids.c vmstat.c portinfo.c devprobe.c
-
-OBJS = $(filter-out loginpr.sh mount.sh sush.sh uptime.sh,$(SRCS:.c=.o))
+targets = shd ps settrans showtrans syncfs fsysopts \
+ storeinfo login w uptime ids loginpr sush vmstat portinfo \
+ devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \
+ storeread msgport rpctrace mount gcore fakeauth fakeroot
+special-targets = loginpr sush uptime fakeroot
+SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
+ fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
+ uptime.sh psout.c ids.c vmstat.c portinfo.c devprobe.c vminfo.c \
+ parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \
+ unsu.c ftpcp.c ftpdir.c storeread.c storecat.c msgport.c \
+ rpctrace.c mount.c gcore.c fakeauth.c fakeroot.sh
+LCLHDRS = psout.h parse.h pids.h frobauth.h
-# This hack to get around ickiness in Makeconf
-libutil-libsubst = -lutil
+OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
+HURDLIBS = ps ihash store fshelp threads ports ftpconn shouldbeinlibc
+login-LDLIBS = -lutil $(LIBCRYPT)
+addauth-LDLIBS = $(LIBCRYPT)
+setauth-LDLIBS = $(LIBCRYPT)
INSTALL-login-ops = -o root -m 4755
+INSTALL-ids-ops = -o root -m 4755
INSTALL-ps-ops = -o root -m 4755
INSTALL-w-ops = -o root -m 4755
-INSTALL-vmstat-ops = -o root -m 4755
include ../Makeconf
-login: -lutil # /gd4/hurdinst/lib/libutil.a # ick ick ick ick
+ps addauth rmauth setauth unsu msgport: parse.o pids.o
+login addauth setauth: nonsugid.o
+addauth rmauth setauth unsu: frobauth.o
+rmauth setauth unsu: frobauth-mod.o
ps w: psout.o ../libps/libps.a ../libihash/libihash.a
-storeinfo: ../libstore/libstore.a
+
+storeinfo storecat storeread: ../libstore/libstore.a
+ftpcp ftpdir: ../libftpconn/libftpconn.a
+
# We must include libthreads because of a bug in the way shared libraries
# work: all libraries that *any* routine in libfshelp uses must be defined.
settrans: ../libfshelp/libfshelp.a ../libports/libports.a ../libthreads/libthreads.a
-ps w hurdids settrans showtrans fsysopts storeinfo login vmstat portinfo \
- devprobe: ../libshouldbeinlibc/libshouldbeinlibc.a
-
-%: %.sh
- cp $< $@
+ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
+ devprobe vminfo addauth rmauth setauth unsu ftpcp ftpdir storeread \
+ storecat msgport mount: \
+ ../libshouldbeinlibc/libshouldbeinlibc.a
$(filter-out $(special-targets), $(targets)): %: %.o
+
+rpctrace: ../libthreads/libthreads.a \
+ ../libports/libports.a ../libihash/libihash.a
+rpctrace-CPPFLAGS = -DDATADIR=\"${datadir}\"
+
+fakeauth: authServer.o auth_requestUser.o interruptServer.o \
+ ../libthreads/libthreads.a \
+ ../libports/libports.a ../libihash/libihash.a \
+ ../libshouldbeinlibc/libshouldbeinlibc.a
+auth-MIGSFLAGS = -imacros $(srcdir)/../auth/authmutations.h
+fakeauth-CPPFLAGS = -I$(srcdir)/../auth
+authServer-CPPFLAGS = -I$(srcdir)/../auth
+auth_requestUser-CPPFLAGS = -I$(srcdir)/../auth
+
+mount: ../sutils/fstab.o ../sutils/clookup.o \
+ $(foreach L,fshelp ports,../lib$L/lib$L.a)
+../sutils/fstab.o ../sutils/clookup.o: FORCE
+ $(MAKE) -C $(@D) $(@F)
+FORCE:
diff --git a/utils/addauth.c b/utils/addauth.c
new file mode 100644
index 00000000..0932a33f
--- /dev/null
+++ b/utils/addauth.c
@@ -0,0 +1,100 @@
+/* Add authentication to selected processes
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <argp.h>
+#include <idvec.h>
+#include <ugids.h>
+#include <error.h>
+#include <hurd.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (addauth);
+
+static struct argp_child child_argps[] = {{ &frobauth_ea_argp }, { 0 }};
+
+static char doc[] =
+ "Add new user/group ids to the authentication of selected processes";
+
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ error_t err;
+ auth_t auth;
+ char *ids_rep = 0;
+ process_t proc_server = getproc();
+ struct frobauth frobauth = FROBAUTH_INIT;
+ struct idvec have_uids = IDVEC_INIT, have_gids = IDVEC_INIT;
+ struct argp argp = { 0, 0, 0, doc, child_argps };
+
+ frobauth.require_ids = 1;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ /* See what the invoking user is authorized to do. */
+ err = get_nonsugid_ids (&have_uids, &have_gids);
+ if (err)
+ error (52, err, "Cannot get invoking authentication");
+
+ /* Check passwords. */
+ err = ugids_verify_make_auth (&frobauth.ugids, &have_uids, &have_gids, 0, 0,
+ 0, 0, &auth);
+ if (err == EACCES)
+ error (15, 0, "Invalid password");
+ else if (err)
+ error (16, err, "Authentication failure");
+
+ if (frobauth.verbose)
+ /* A string showing which ids we will add. */
+ ids_rep = ugids_rep (&frobauth.ugids, 1, 1, 0, 0, 0);
+
+ /* Add the new authentication to each process. */
+ for (i = 0; i < frobauth.num_pids; i++)
+ {
+ mach_port_t msgport;
+ pid_t pid = frobauth.pids[i];
+ error_t err = proc_getmsgport (proc_server, pid, &msgport);
+
+ if (err)
+ error (0, err, "%d: Cannot get message port", pid);
+ else
+ {
+ if (! frobauth.dry_run)
+ err = msg_add_auth (msgport, auth);
+ if (err)
+ error (0, err, "%d: Cannot add authentication", pid);
+ else if (frobauth.verbose)
+ printf ("%d: Added %s\n", pid, ids_rep);
+ mach_port_deallocate (mach_task_self (), msgport);
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/devprobe.c b/utils/devprobe.c
index e29e1e32..d7020322 100644
--- a/utils/devprobe.c
+++ b/utils/devprobe.c
@@ -1,6 +1,6 @@
/* Check the existence of mach devices
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -20,11 +20,13 @@
#include <stdio.h>
#include <argp.h>
-#include <error.h>
#include <hurd.h>
#include <mach.h>
#include <device/device.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (devprobe);
static const struct argp_option options[] = {
{"silent", 's', 0, 0, "Don't print devices found"},
@@ -33,19 +35,19 @@ static const struct argp_option options[] = {
{0}
};
static const char *args_doc = "DEVNAME...";
-static const char *doc = "The exit status is 0 if any devices were found.";
+static const char *doc = "Test for the existence of mach device DEVNAME..."
+ "\vThe exit status is 0 if any devices were found.";
int
main (int argc, char **argv)
{
- error_t err;
- mach_port_t device_master;
/* Print devices found? (otherwise only exit status matters) */
int print = 1;
/* If printing, print all devices on the command line that are found.
Otherwise, just the first one found is printed. */
int all = 1;
int found_one = 0;
+ mach_port_t device_master = MACH_PORT_NULL;
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
@@ -65,10 +67,19 @@ main (int argc, char **argv)
all = 0; break;
case ARGP_KEY_ARG:
- err = device_open (device_master, 0, arg, &device);
+ if (device_master == MACH_PORT_NULL)
+ {
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ argp_failure (state, 3, err, "Can't get device master port");
+ }
+
+ err = device_open (device_master, D_READ, arg, &device);
if (err == 0)
/* Got it. */
{
+ device_close (device);
+
/* Free the device port we got. */
mach_port_deallocate (mach_task_self (), device);
@@ -84,7 +95,7 @@ main (int argc, char **argv)
}
else if (err != ED_NO_SUCH_DEVICE)
/* Complain about unexpected errors. */
- error (0, err, "%s", arg);
+ argp_failure (state, 0, err, "%s", arg);
break;
default:
@@ -94,10 +105,6 @@ main (int argc, char **argv)
}
const struct argp argp = { options, parse_opt, args_doc, doc };
- err = get_privileged_ports (0, &device_master);
- if (err)
- error (3, err, "Can't get device master port");
-
/* Parse our arguments. */
argp_parse (&argp, argc, argv, 0, 0, 0);
diff --git a/utils/fakeauth.c b/utils/fakeauth.c
new file mode 100644
index 00000000..49fa7f1c
--- /dev/null
+++ b/utils/fakeauth.c
@@ -0,0 +1,434 @@
+/* fakeauth -- proxy auth server to lie to users about what their IDs are
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <hurd.h>
+#include <hurd/auth.h>
+#include <hurd/interrupt.h>
+#include <hurd/ports.h>
+#include <idvec.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <argp.h>
+#include <error.h>
+#include "auth_S.h"
+#include "auth_request_U.h"
+#include "interrupt_S.h"
+
+/* Auth handles are server ports with sets of ids. */
+struct authhandle
+ {
+ struct port_info pi;
+ struct idvec euids, egids, auids, agids;
+ };
+
+struct port_bucket *auth_bucket;
+struct port_class *authhandle_portclass;
+
+/* Create a new auth port. */
+
+static error_t
+create_authhandle (struct authhandle **new)
+{
+ error_t err = ports_create_port (authhandle_portclass, auth_bucket,
+ sizeof **new, new);
+ if (! err)
+ bzero (&(*new)->euids, (void *) &(*new)[1] - (void *) &(*new)->euids);
+ return err;
+}
+
+/* Clean up a dead auth port. */
+
+static void
+destroy_authhandle (void *p)
+{
+ struct authhandle *h = p;
+ idvec_free_contents (&h->euids);
+ idvec_free_contents (&h->egids);
+ idvec_free_contents (&h->auids);
+ idvec_free_contents (&h->agids);
+}
+
+/* Called by server stub functions. */
+
+authhandle_t
+auth_port_to_handle (auth_t auth)
+{
+ return ports_lookup_port (auth_bucket, auth, authhandle_portclass);
+}
+
+/* id management. */
+
+static inline void
+idvec_copyout (struct idvec *idvec, uid_t **ids, size_t *nids)
+{
+ if (idvec->num > *nids)
+ *ids = idvec->ids;
+ else
+ memcpy (*ids, idvec->ids, idvec->num * sizeof *ids);
+ *nids = idvec->num;
+}
+
+#define C(auth, ids) idvec_copyout (&auth->ids, ids, n##ids)
+#define OUTIDS(auth) (C (auth, euids), C (auth, egids), \
+ C (auth, auids), C (auth, agids))
+
+/* Implement auth_getids as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_getids (struct authhandle *auth,
+ uid_t **euids,
+ size_t *neuids,
+ uid_t **auids,
+ size_t *nauids,
+ uid_t **egids,
+ size_t *negids,
+ uid_t **agids,
+ size_t *nagids)
+{
+ if (! auth)
+ return EOPNOTSUPP;
+
+ OUTIDS (auth);
+
+ return 0;
+}
+
+/* Implement auth_makeauth as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_makeauth (struct authhandle *auth,
+ mach_port_t *authpts, size_t nauths,
+ uid_t *euids, size_t neuids,
+ uid_t *auids, size_t nauids,
+ uid_t *egids, size_t negids,
+ uid_t *agids, size_t nagids,
+ mach_port_t *newhandle)
+{
+ struct authhandle *newauth, *auths[1 + nauths];
+ int hasroot = 0;
+ error_t err;
+ size_t i, j;
+
+ if (!auth)
+ return EOPNOTSUPP;
+
+ auths[0] = auth;
+
+ /* Fetch the auth structures for all the ports passed in. */
+ for (i = 0; i < nauths; i++)
+ auths[i + 1] = auth_port_to_handle (authpts[i]);
+
+ ++nauths;
+
+ /* Verify that the union of the handles passed in either contains euid 0
+ (root), or contains all the requested ids. */
+
+#define isuid(uid, auth) \
+ (idvec_contains (&(auth)->euids, uid) \
+ || idvec_contains (&(auth)->auids, uid))
+#define groupmember(gid, auth) \
+ (idvec_contains (&(auth)->egids, gid) \
+ || idvec_contains (&(auth)->agids, gid))
+#define isroot(auth) isuid (0, auth)
+
+ for (i = 0; i < nauths; i++)
+ if (auths[i] && isroot (auths[i]))
+ {
+ hasroot = 1;
+ break;
+ }
+
+ if (!hasroot)
+ {
+ int has_it;
+
+ for (i = 0; i < neuids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && isuid (euids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+
+ for (i = 0; i < nauids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && isuid (auids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+
+ for (i = 0; i < negids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && groupmember (egids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+
+ for (i = 0; i < nagids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && groupmember (agids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+ }
+
+ err = create_authhandle (&newauth);
+
+ /* Create a new handle with the specified ids. */
+
+#define MERGE S (euids); S (egids); S (auids); S (agids);
+#define S(uids) if (!err) err = idvec_merge_ids (&newauth->uids, uids, n##uids)
+
+ MERGE;
+
+#undef S
+
+ if (! err)
+ {
+ for (j = 1; j < nauths; ++j)
+ mach_port_deallocate (mach_task_self (), authpts[j - 1]);
+ *newhandle = ports_get_right (newauth);
+ ports_port_deref (newauth);
+ }
+
+ for (j = 1; j < nauths; j++)
+ if (auths[j])
+ ports_port_deref (auths[j]);
+ return err;
+
+ eperm:
+ for (j = 1; j < nauths; j++)
+ if (auths[j])
+ ports_port_deref (auths[j]);
+ return EPERM;
+}
+
+
+/* This is our original auth port, where we will send all proxied
+ authentication requests. */
+static auth_t real_auth_port;
+
+kern_return_t
+S_auth_user_authenticate (struct authhandle *userauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ mach_port_t rendezvous,
+ mach_port_t *newport,
+ mach_msg_type_name_t *newporttype)
+{
+ if (! userauth)
+ return EOPNOTSUPP;
+
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
+
+ return auth_user_authenticate_request (real_auth_port, reply, reply_type,
+ rendezvous, MACH_MSG_TYPE_MOVE_SEND)
+ ? : MIG_NO_REPLY;
+}
+
+kern_return_t
+S_auth_server_authenticate (struct authhandle *serverauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ mach_port_t rendezvous,
+ mach_port_t newport,
+ mach_msg_type_name_t newport_type,
+ uid_t **euids,
+ size_t *neuids,
+ uid_t **auids,
+ size_t *nauids,
+ uid_t **egids,
+ size_t *negids,
+ uid_t **agids,
+ size_t *nagids)
+{
+ if (! serverauth)
+ return EOPNOTSUPP;
+
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
+
+ return auth_server_authenticate_request (real_auth_port,
+ reply, reply_type,
+ rendezvous, MACH_MSG_TYPE_MOVE_SEND,
+ newport, newport_type)
+ ? : MIG_NO_REPLY;
+}
+
+kern_return_t
+S_interrupt_operation (mach_port_t port, mach_port_seqno_t seqno)
+{
+ return interrupt_operation (real_auth_port, 0);
+}
+
+static int
+auth_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int auth_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ extern int interrupt_server (mach_msg_header_t *inp, mach_msg_header_t *);
+ return (auth_server (inp, outp) ||
+ interrupt_server (inp, outp) ||
+ ports_notify_server (inp, outp));
+}
+
+
+static any_t
+handle_auth_requests (any_t ignored)
+{
+ while (1)
+ ports_manage_port_operations_multithread (auth_bucket, auth_demuxer,
+ 30 * 1000, 0, 0);
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct authhandle *firstauth;
+ auth_t authport;
+ pid_t child;
+ int status;
+ int argi;
+
+ /* Parse our options. */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = { 0, parse_opt, "COMMAND...", "\
+Run COMMAND with a fake authentication handle that claims to be root or \
+any arbitrary identity derived from that handle, but in fact is always just \
+a proxy for your real authentication handle. This means that all processes \
+created by the COMMAND will have your privileges, even though it may \
+believe it has restricted them to different identities or no identity at all.\
+" };
+
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &argi, 0);
+
+ auth_bucket = ports_create_bucket ();
+ authhandle_portclass = ports_create_class (&destroy_authhandle, 0);
+
+ /* Create the initial root auth handle. */
+ err = create_authhandle (&firstauth);
+ assert_perror (err);
+ idvec_add (&firstauth->euids, 0);
+ idvec_add (&firstauth->auids, 0);
+ idvec_add (&firstauth->auids, 0);
+ idvec_merge (&firstauth->egids, &firstauth->euids);
+ idvec_merge (&firstauth->agids, &firstauth->auids);
+
+ /* Get a send right for it. */
+ authport = ports_get_right (firstauth);
+ err = mach_port_insert_right (mach_task_self (), authport, authport,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ ports_port_deref (firstauth);
+
+ /* Stash our original auth port for later use. */
+ real_auth_port = getauth ();
+
+ /* Start handling auth requests on our fake handles. */
+ cthread_detach (cthread_fork (&handle_auth_requests, (any_t)0));
+
+ /* Now we start faking ourselves out. This will immediately
+ reauthenticate all our descriptors through our proxy auth port.
+ The POSIXoid calls we make below will continue to use the fake
+ port and pass it on to the child. */
+ if (setauth (authport))
+ error (2, errno, "Cannot switch to fake auth handle");
+ mach_port_deallocate (mach_task_self (), authport);
+
+ /* We cannot use fork because it doesn't do the right thing with our send
+ rights that point to our own receive rights, i.e. the new auth port.
+ Since posix_spawn might be implemented with fork (prior to glibc 2.3),
+ we cannot use that simple interface either. We use _hurd_exec
+ directly to effect what posix_spawn does in the simple case. */
+ {
+ task_t newtask;
+ process_t proc;
+ file_t execfile = file_name_lookup (argv[argi], O_EXEC, 0);
+ if (execfile == MACH_PORT_NULL)
+ error (3, errno, "%s", argv[argi]);
+
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &newtask);
+ if (err)
+ error (3, err, "cannot create child task");
+ child = task2pid (newtask);
+ if (child < 0)
+ error (3, errno, "task2pid");
+ proc = getproc ();
+ err = proc_child (proc, newtask);
+ mach_port_deallocate (mach_task_self (), proc);
+ if (err)
+ error (3, err, "proc_child");
+
+ err = _hurd_exec (newtask, execfile, &argv[argi], environ);
+ mach_port_deallocate (mach_task_self (), newtask);
+ mach_port_deallocate (mach_task_self (), execfile);
+ if (err)
+ error (3, err, "cannot execute %s", argv[argi]);
+ }
+
+ if (waitpid (child, &status, 0) != child)
+ error (4, errno, "waitpid on %d", child);
+
+ if (WIFSIGNALED (status))
+ error (WTERMSIG (status) + 128, 0,
+ "%s for child %d", strsignal (WTERMSIG (status)), child);
+ if (WEXITSTATUS (status) != 0)
+ error (WEXITSTATUS (status), 0,
+ "Error %d for child %d", WEXITSTATUS (status), child);
+
+ return 0;
+}
diff --git a/utils/fakeroot.sh b/utils/fakeroot.sh
new file mode 100644
index 00000000..1ace1cf7
--- /dev/null
+++ b/utils/fakeroot.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Execute a command in an environment where it appears to be root.
+#
+# Copyright (C) 2002 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+USAGE="Usage: $0 [OPTION...] [COMMAND...]"
+DOC="Execute COMMAND in an environment where it appears to be root."
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "$USAGE"
+ echo "$DOC"
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ exit 0;;
+ --usage)
+ echo "Usage: $0 [-V?] [--help] [--usage] [--version]"
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_fakeroot_"; exit 0;;
+ --)
+ shift
+ break;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+if [ $# -eq 0 ]; then
+ set -- ${SHELL:-/bin/sh}
+fi
+
+# We exec settrans, which execs the "fakeauth" command in the chroot context.
+# The `pwd` is evaluated here and now, and that result interpreted inside
+# the shell running under fakeauth to chdir there inside the chroot world.
+# That shell then execs our arguments as a command line.
+exec /bin/settrans --chroot \
+ /bin/fakeauth /bin/sh -c "cd `pwd`; $*" \
+ -- / /hurd/fakeroot
diff --git a/utils/frobauth-mod.c b/utils/frobauth-mod.c
new file mode 100644
index 00000000..4464c18c
--- /dev/null
+++ b/utils/frobauth-mod.c
@@ -0,0 +1,162 @@
+/* Modify the current authentication selected processes
+
+ Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <hurd.h>
+#include <error.h>
+
+#include "frobauth.h"
+
+/* For every pid in FROBAUTH, call MODIFY to change its argument UGIDS from
+ the current authentication to what it should be; CHANGE is whatever ids
+ the user specified. AUTHS, of length NUM_AUTHS, should be a vector of
+ auth ports giving whatever additional authentication is needed (besides
+ the process's current authentication). If the user specifies the
+ --verbose flags, PRINT_INFO is called after successfully installing the
+ new authentication in each process, to print a message about what
+ happened. True is returned if no errors occur, although most errors do
+ not cause termination, and error messages are printed for them. */
+error_t
+frobauth_modify (struct frobauth *frobauth,
+ const auth_t *auths, size_t num_auths,
+ error_t (*modify) (struct ugids *ugids,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void (*print_info) (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void *hook)
+{
+ int i;
+ int ok = 1;
+ size_t num_all_auths = num_auths + 1;
+ auth_t all_auths[num_all_auths];
+ pid_t cur_pid = getpid ();
+ process_t proc_server = getproc ();
+
+ bcopy (auths, all_auths, num_auths * sizeof *auths);
+
+ /* Map MODIFY over all pids. */
+ for (i = 0; i < frobauth->num_pids; i++)
+ if (frobauth->pids[i] != cur_pid)
+ {
+ mach_port_t msgport;
+ pid_t pid = frobauth->pids[i];
+ error_t err = proc_getmsgport (proc_server, pid, &msgport);
+
+ if (err)
+ error (0, err, "%d: Cannot get message port", pid);
+ else
+ {
+ task_t task;
+
+ err = proc_pid2task (proc_server, pid, &task);
+ if (err)
+ error (0, err, "%d", pid);
+ else
+ {
+ auth_t old_auth;
+
+ err = msg_get_init_port (msgport, task, INIT_PORT_AUTH,
+ &old_auth);
+ if (err)
+ error (0, err, "%d: Cannot get auth port", pid);
+ else
+ {
+ struct ugids old = UGIDS_INIT;
+
+ err = ugids_merge_auth (&old, old_auth);
+
+ if (err)
+ error (0, err, "%d: Cannot get auth port ids", pid);
+ else
+ {
+ struct ugids new = UGIDS_INIT;
+
+ /* Assume all gids that can be implied by some uid are
+ only present for that reason. */
+ ugids_imply_all (&old);
+
+ err = ugids_set (&new, &old);
+
+ err = (*modify) (&new, &frobauth->ugids, pid, hook);
+ if (err)
+ error (99, err, "%d: Cannot modify ids", pid);
+ else if (! ugids_equal (&new, &old))
+ {
+ if (! frobauth->dry_run)
+ {
+ auth_t new_auth;
+
+ /* Add the PID's old authentication to that
+ supplied by the calller. */
+ all_auths[num_all_auths - 1] = old_auth;
+
+ err = ugids_make_auth (&new,
+ all_auths,
+ num_all_auths,
+ &new_auth);
+ if (err)
+ error (0, err,
+ "%d: Authentication failure", pid);
+ else
+ {
+ err =
+ msg_set_init_port (msgport, task,
+ INIT_PORT_AUTH,
+ new_auth,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (),
+ new_auth);
+ if (err)
+ error (0, err, "%d", pid);
+ }
+
+ }
+
+ if (frobauth->verbose && !err)
+ (*print_info) (&new, &old, &frobauth->ugids,
+ pid, hook);
+
+ }
+ else if (frobauth->verbose)
+ printf ("%d: Nothing changed\n", pid);
+
+ ugids_fini (&new);
+ }
+
+ ugids_fini (&old);
+ mach_port_deallocate (mach_task_self (), old_auth);
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ }
+ mach_port_deallocate (mach_task_self (), msgport);
+ }
+
+ if (err)
+ ok = 0; /* Something didn't work. */
+ }
+
+ return ok;
+}
diff --git a/utils/frobauth.c b/utils/frobauth.c
new file mode 100644
index 00000000..ccb7c3bb
--- /dev/null
+++ b/utils/frobauth.c
@@ -0,0 +1,282 @@
+/* Common interface for auth frobbing utilities
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file is rather a mess of intertwined argps; it shoud be redone as a
+ single level once argp can handle dynamic option frobbing. XXX */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/process.h>
+
+#include "frobauth.h"
+#include "ugids.h"
+#include "pids.h"
+
+static struct argp common_argp;
+static struct argp fr_ugids_argp;
+
+static const struct argp_option common_options[] =
+{
+ {"verbose", 'v', 0, 0, "Print informational messages"},
+ {"dry-run", 'n', 0, 0, "Don't do anything, just print what would be done"},
+ { 0 }
+};
+static struct argp_child common_child_argps[] =
+{
+ { &pids_argp, 0, "Process selection:" },
+ { 0 }
+};
+
+static const char common_args_doc[] = "USER...";
+static const char common_doc[] =
+ "\vBy default, all processes in the current login collection are selected";
+
+static struct argp_child ugids_child_argps[] =
+{
+ { &ugids_argp, 0, "User/group ids:" },
+ { 0 }
+};
+
+/* An argp on top of the base frobauth argp that provides switchable
+ effective/available ids (XXX this junk should be moved into a single argp
+ [indeed, into ugids_argp] once argp can deal with the init routine
+ frobbing the argp source). */
+static const struct argp_option ea_options[] =
+{
+ {"available", 'a', 0, 0, "USER... specifies available ids"},
+ {"effective", 'e', 0, 0, "USER... specifies effective ids"},
+ { 0 }
+};
+
+static struct argp_child ea_posix_child_argps[] =
+{
+ { &common_argp },
+ { &fr_ugids_argp },
+ { 0 }
+};
+
+static struct argp_child no_ugids_child_argps[] =
+{
+ { &common_argp },
+ { 0 }
+};
+
+/* This holds state information that's only active during parsing. */
+struct frobauth_argp_state
+{
+ struct frobauth *frobauth;
+ struct pids_argp_params pids_argp_params;
+ struct ugids_argp_params ugids_argp_params;
+};
+
+static error_t
+common_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->input;
+ struct frobauth *frobauth = fs->frobauth;
+
+ switch (key)
+ {
+ case 'v':
+ frobauth->verbose = 1; break;
+ case 'n':
+ frobauth->dry_run = 1; break;
+
+ case ARGP_KEY_END:
+ if (frobauth->num_pids == 0)
+ /* No pids specified! By default, do the current login collection. */
+ {
+ pid_t lid;
+ error_t err = proc_getloginid (getproc (), getpid (), &lid);
+
+ if (err)
+ argp_failure (state, 2, err,
+ "Couldn't get current login collection");
+
+ err = add_fn_pids (&frobauth->pids, &frobauth->num_pids,
+ lid, proc_getloginpids);
+ if (err)
+ argp_failure (state, 3, err,
+ "%d: Couldn't get login collection pids", lid);
+
+ return err;
+ }
+ break;
+
+ case ARGP_KEY_INIT:
+ bzero (fs, sizeof *fs);
+ fs->frobauth = frobauth;
+ fs->pids_argp_params.pids = &frobauth->pids;
+ fs->pids_argp_params.num_pids = &frobauth->num_pids;
+ state->child_inputs[0] = &fs->pids_argp_params;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ free (fs);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+ugids_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->input;
+ struct frobauth *frobauth = fs->frobauth;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ fs->ugids_argp_params.ugids = &frobauth->ugids;
+ fs->ugids_argp_params.parse_user_args = 1;
+ fs->ugids_argp_params.default_user = frobauth->default_user;
+ fs->ugids_argp_params.require_ids = frobauth->require_ids;
+ fs->pids_argp_params.pids = &frobauth->pids;
+ fs->pids_argp_params.num_pids = &frobauth->num_pids;
+
+ state->child_inputs[0] = &fs->ugids_argp_params;
+
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+ea_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case 'a':
+ fs->ugids_argp_params.user_args_are_available = 1;
+ break;
+ case 'e':
+ fs->ugids_argp_params.user_args_are_effective = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (!fs->ugids_argp_params.user_args_are_effective
+ && !fs->ugids_argp_params.user_args_are_available)
+ /* Default to effective. */
+ fs->ugids_argp_params.user_args_are_effective = 1;
+
+ /* Let someone else parse the arg. */
+ return ARGP_ERR_UNKNOWN;
+
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ state->child_inputs[1] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+posix_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ state->child_inputs[1] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+no_ugids_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp common_argp =
+{
+ common_options, common_parse_opt, 0, common_doc, common_child_argps
+};
+static struct argp fr_ugids_argp =
+{
+ 0, ugids_parse_opt, 0, 0, ugids_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as single ids to
+ either the effective or available ids. */
+struct argp frobauth_ea_argp =
+{
+ ea_options, ea_parse_opt, 0, 0, ea_posix_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+struct argp frobauth_posix_argp =
+{
+ 0, posix_parse_opt, 0, 0, ea_posix_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+struct argp frobauth_no_ugids_argp =
+{
+ 0, no_ugids_parse_opt, 0, 0, no_ugids_child_argps
+};
diff --git a/utils/frobauth.doc b/utils/frobauth.doc
new file mode 100644
index 00000000..e4d1358f
--- /dev/null
+++ b/utils/frobauth.doc
@@ -0,0 +1,83 @@
+ -- Hurd process authentication frobbing commands --
+
+addauth -- Adds additional authority to selected processes, without changing
+ their identity (unless they previously had none)
+rmauth -- Removes authority
+setauth -- Changes the identity and authority of selected processes
+su -- Changes the identity and authority of selected processes, saving enough
+ authority to later undo the change
+unsu -- Attempts to undo the results of a previous su command
+
+Examples:
+
+As these commands effective existing processes rather than creating
+subshells, the following are all typed to the same shell.
+
+Starting with the ids I get from logging in as miles (the `ids' command shows
+all the ids in the process it was invoked from):
+
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles agids=10,10
+
+Note that first euid/egids is the traditional unix effective uid/gid, and,
+for instance, determines what identity files are created with; the 1st and
+2nd auids/agids are the posix `real' and `saved' ids. Now I add root
+authority:
+
+ (utils) addauth root
+ Password:
+ (utils) ids -tn
+ euids=miles,root egids=10,wheel auids=miles,miles agids=10,10
+
+The main id is still miles, but an effective root id is also present, meaning
+that the process has root privileges. The traditional `id' command hasn't
+yet been changed to print extended hurd ids, so it only knows about the
+additional group:
+
+ (utils) id
+ uid=9427(miles) gid=10 groups=10,0(wheel)
+
+Removing root puts us back where we started:
+
+ (utils) rmauth root
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles agids=10,10
+
+Now if we use su instead, it actually changes our process's identity (but
+note that the old ids are still around as available ids -- this means they
+the only privilege they grant is to become effective ids):
+
+ (utils) su
+ Password:
+ (utils) ids -tn
+ euids=root egids=wheel auids=root,root,miles,miles agids=wheel,wheel,10,10
+ (utils) id
+ uid=0(root) gid=0(wheel) groups=0(wheel)
+
+We can undo the su with unsu:
+
+ (utils) unsu
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles agids=10,10
+
+Now lets su again, to a different user:
+
+ (utils) su thomas
+ Password:
+ (utils) ids -tn
+ euids=thomas egids=11 auids=thomas,thomas,miles,miles agids=11,11,10,10
+
+If we now use another su command, instead of su, we can swap our identity;
+we don't need a password to do this, since the old ids are still there as
+available ids.
+
+ (utils) su miles
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles,thomas,thomas agids=10,10,11,11
+
+Now if we give unsu, we'll become thomas for good (this same effect may be
+had in one step with the `su --no-save' or `setauth' commands):
+
+ (utils) unsu
+ (utils) ids -tn
+ euids=thomas egids=11 auids=thomas,thomas agids=11,11
diff --git a/utils/frobauth.h b/utils/frobauth.h
new file mode 100644
index 00000000..2b9c78f1
--- /dev/null
+++ b/utils/frobauth.h
@@ -0,0 +1,71 @@
+/* Common interface for auth frobbing utilities
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __FROBAUTH_H__
+#define __FROBAUTH_H__
+
+#include <sys/types.h>
+#include <ugids.h>
+#include <argp.h>
+
+/* Structure describing which processes to frob, and how to frob them. */
+struct frobauth
+{
+ struct ugids ugids;
+ pid_t *pids;
+ size_t num_pids;
+ int verbose, dry_run; /* User options */
+ uid_t default_user; /* If none specified; -1 means none. */
+ int require_ids; /* If true, require some ids be specified. */
+};
+
+#define FROBAUTH_INIT { UGIDS_INIT, 0, 0, 0, 0, -1 }
+
+/* For every pid in FROBAUTH, call MODIFY to change its argument UGIDS from
+ the current authentication to what it should be; CHANGE is whatever ids
+ the user specified. AUTHS, of length NUM_AUTHS, should be a vector of
+ auth ports giving whatever additional authentication is needed (besides
+ the process's current authentication). If the user specifies the
+ --verbose flags, PRINT_INFO is called after successfully installing the
+ new authentication in each process, to print a message about what
+ happened. True is returned if no errors occur, although most errors do
+ not cause termination, and error messages are printed for them. */
+error_t frobauth_modify (struct frobauth *frobauth,
+ const auth_t *auths, size_t num_auths,
+ error_t (*modify) (struct ugids *ugids,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void (*print_info) (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void *hook);
+
+/* Parse frobauth args/options, where user args are added as single ids to
+ either the effective or available ids. */
+extern struct argp frobauth_ea_argp;
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+extern struct argp frobauth_posix_argp;
+
+/* Parse frobauth args/options, with no user specifications. */
+extern struct argp frobauth_no_ugids_argp;
+
+#endif /* __FROBAUTH_H__ */
diff --git a/utils/fsysopts.c b/utils/fsysopts.c
index 076e2a87..f3458a03 100644
--- a/utils/fsysopts.c
+++ b/utils/fsysopts.c
@@ -1,8 +1,8 @@
/* Set options in a running filesystem
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,2002,2004 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -28,10 +28,11 @@
#include <error.h>
#include <argz.h>
+#include <version.h>
#include <hurd/fsys.h>
-char *argp_program_version = "fsysopts 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (fsysopts);
static struct argp_option options[] =
{
@@ -40,14 +41,15 @@ static struct argp_option options[] =
{0, 0, 0, 0}
};
static char *args_doc = "FILESYS [FS_OPTION...]";
-static char *doc = "The legal values for FS_OPTION depends on FILESYS, but\
- some common ones are: --readonly, --writable, --remount, --sync[=INTERVAL],\
+static char *doc = "Get or set command line options for running translator FILESYS."
+"\vThe legal values for FS_OPTION depends on FILESYS, but\
+ some common ones are: --readonly, --writable, --update, --sync[=INTERVAL],\
and --nosync.\n\nIf no options are supplied, FILESYS's existing options\
are printed";
/* ---------------------------------------------------------------- */
-void
+int
main(int argc, char *argv[])
{
error_t err;
@@ -58,7 +60,7 @@ main(int argc, char *argv[])
/* The filesystem options vector, in '\0' separated format. */
char *argz = 0;
- int argz_len = 0;
+ size_t argz_len = 0;
int deref = 0, recursive = 0;
@@ -122,5 +124,5 @@ main(int argc, char *argv[])
puts (argz);
}
- exit(0);
+ return 0;
}
diff --git a/utils/ftpcp.c b/utils/ftpcp.c
new file mode 100644
index 00000000..67ccb1a0
--- /dev/null
+++ b/utils/ftpcp.c
@@ -0,0 +1,397 @@
+/* Copy a file using the ftp protocol
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <error.h>
+#include <argp.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#include <version.h>
+
+#include <ftpconn.h>
+
+#define COPY_SZ 65536
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpcp);
+
+#define OPT_SRC_U -3
+#define OPT_SRC_A -4
+#define OPT_SRC_P -5
+#define OPT_DST_U -6
+#define OPT_DST_A -7
+#define OPT_DST_P -8
+
+
+static struct argp_option options[] =
+{
+ {"user", 'u', "USER",0, "User to login as on both ftp servers"},
+ {"password", 'p', "PWD", 0, "USER's password"},
+ {"account", 'a', "ACCT",0, "Account to login as"},
+ {"src-user", OPT_SRC_U, "USER",0, "User to login as on the src ftp server"},
+ {"src-password",OPT_SRC_P, "PWD", 0, "The src USER's password"},
+ {"src-account", OPT_SRC_A, "ACCT",0, "Account to login as on the source server"},
+ {"dst-user", OPT_DST_U, "USER",0, "User to login as on the dst ftp server"},
+ {"dst-password",OPT_DST_P, "PWD", 0, "The dst USER's password"},
+ {"dst-account", OPT_DST_A, "ACCT",0, "Account to login as on the source server"},
+ {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
+ {0, 0}
+};
+static char *args_doc = "SRC [DST]";
+static char *doc = "Copy file SRC over ftp to DST."
+"\vBoth SRC and DST may have the form HOST:FILE, FILE, or -, where - is"
+" standard input for SRC or standard output for DST, and FILE is a local"
+" file. DST may be a directory, in which case the basename of SRC is"
+" appended to make the actual destination filename.";
+
+/* customization hooks. */
+static struct ftp_conn_hooks conn_hooks = { 0 };
+
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = ">"; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ fprintf (stderr, "%s%s%s\n", (char *)conn->hook ?: "", type_str, txt);
+}
+
+/* Return an ftp connection for the host NAME using PARAMS. If an error
+ occurrs, a message is printed the program exits. If CNAME is non-zero,
+ the host's canonical name, in mallocated storage, is returned in it. */
+struct ftp_conn *
+get_host_conn (char *name, struct ftp_conn_params *params, char **cname)
+{
+ error_t err;
+ struct hostent *he;
+ struct ftp_conn *conn;
+
+ he = gethostbyname (name);
+ if (! he)
+ error (10, 0, "%s: %s", name, hstrerror (h_errno));
+
+ params->addr = malloc (he->h_length);
+ if (! params->addr)
+ error (11, ENOMEM, "%s", name);
+
+ bcopy (he->h_addr_list[0], params->addr, he->h_length);
+ params->addr_len = he->h_length;
+ params->addr_type = he->h_addrtype;
+
+ err = ftp_conn_create (params, &conn_hooks, &conn);
+ if (err)
+ error (12, err, "%s", he->h_name);
+
+ if (cname)
+ *cname = strdup (he->h_name);
+
+ return conn;
+}
+
+static void
+cp (int src, const char *src_name, int dst, const char *dst_name)
+{
+ ssize_t rd;
+ static void *copy_buf = 0;
+
+ if (! copy_buf)
+ {
+ copy_buf = valloc (COPY_SZ);
+ if (! copy_buf)
+ error (13, ENOMEM, "Cannot allocate copy buffer");
+ }
+
+ while ((rd = read (src, copy_buf, COPY_SZ)) > 0)
+ do
+ {
+ int wr = write (dst, copy_buf, rd);
+ if (wr < 0)
+ error (14, errno, "%s", dst_name);
+ rd -= wr;
+ }
+ while (rd > 0);
+
+ if (rd != 0)
+ error (15, errno, "%s", src_name);
+}
+
+struct epoint
+{
+ char *name; /* Name, of the form HOST:FILE, FILE, or -. */
+ char *file; /* If remote, the FILE portion, or 0. */
+ int fd; /* A file descriptor to use. */
+ struct ftp_conn *conn; /* An ftp connection to use. */
+ struct ftp_conn_params params;
+};
+
+static void
+econnect (struct epoint *e, struct ftp_conn_params *def_params, char *name)
+{
+ char *rmt;
+
+ if (! e->name)
+ e->name = "-";
+
+ rmt = strchr (e->name, ':');
+ if (rmt)
+ {
+ error_t err;
+
+ *rmt++ = 0;
+
+ if (! e->params.user)
+ e->params.user = def_params->user;
+ if (! e->params.pass)
+ e->params.pass = def_params->pass;
+ if (! e->params.acct)
+ e->params.acct = def_params->acct;
+
+ e->conn = get_host_conn (e->name, &e->params, &e->name);
+ e->name = realloc (e->name, strlen (e->name) + 1 + strlen (rmt) + 1);
+ if (! e->name)
+ error (22, ENOMEM, "Cannot allocate name storage");
+
+ e->conn->hook = name;
+
+ err = ftp_conn_set_type (e->conn, "I");
+ if (err)
+ error (23, err, "%s: Cannot set connection type to binary",
+ e->name);
+
+ strcat (e->name, ":");
+ strcat (e->name, rmt);
+
+ e->file = rmt;
+ }
+ else if (e->params.user || e->params.pass || e->params.acct)
+ error (20, 0,
+ "%s: Ftp login parameter specified for a local endpoint (%s,%s,%s)",
+ e->name, e->params.user, e->params.pass, e->params.acct);
+ else
+ e->file = strdup (e->name);
+}
+
+static error_t
+eopen_wr (struct epoint *e, int *fd)
+{
+ if (e->conn)
+ return ftp_conn_start_store (e->conn, e->file, fd);
+ else if (strcmp (e->name, "-") == 0)
+ *fd = 1;
+ else
+ {
+ *fd = open (e->name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (*fd < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static error_t
+eopen_rd (struct epoint *e, int *fd)
+{
+ if (e->conn)
+ return ftp_conn_start_retrieve (e->conn, e->file, fd);
+ else if (strcmp (e->name, "-") == 0)
+ *fd = 0;
+ else
+ {
+ *fd = open (e->name, O_RDONLY, 0666);
+ if (*fd < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static void
+efinish (struct epoint *e)
+{
+ if (e->conn)
+ {
+ error_t err = ftp_conn_finish_transfer (e->conn);
+ if (err)
+ error (31, err, "%s", e->name);
+ }
+}
+
+/* Give a name which refers to a directory file, and a name in that
+ directory, this should return in COMPOSITE the composite name referring to
+ that name in that directory, in malloced storage. */
+error_t
+eappend (struct epoint *e,
+ const char *dir, const char *name,
+ char **composite)
+{
+ if (e->conn)
+ return ftp_conn_append_name (e->conn, dir, name, composite);
+ else
+ {
+ char *rval = malloc (strlen (dir) + 1 + strlen (name) + 1);
+
+ if (! rval)
+ return ENOMEM;
+
+ if (dir[0] == '/' && dir[1] == '\0')
+ stpcpy (stpcpy (rval, dir), name);
+ else
+ stpcpy (stpcpy (stpcpy (rval, dir), "/"), name);
+
+ *composite = rval;
+
+ return 0;
+ }
+}
+
+/* If the name of a file COMPOSITE is a composite name (containing both a
+ filename and a directory name), this function will return the name
+ component only in BASE, in malloced storage, otherwise it simply returns a
+ newly malloced copy of COMPOSITE in BASE. */
+error_t
+ebasename (struct epoint *e, const char *composite, char **base)
+{
+ if (e->conn)
+ return ftp_conn_basename (e->conn, composite, base);
+ else
+ {
+ *base = strdup (basename (composite));
+ return 0;
+ }
+}
+
+static void
+append_basename (struct epoint *dst, struct epoint *src)
+{
+ char *bname;
+ error_t err = ebasename (src, src->file, &bname);
+
+ if (err)
+ error (33, err, "%s: Cannot find basename", src->name);
+
+ err = eappend (dst, dst->file, bname, &dst->file);
+ if (err)
+ error (34, err, "%s: Cannot append name component", dst->name);
+
+ err = eappend (dst, dst->name, bname, &dst->name);
+ if (err)
+ error (35, err, "%s: Cannot append name component", dst->name);
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct epoint rd = { 0 }, wr = { 0 };
+ struct ftp_conn_params def_params = { 0 }; /* default params */
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ switch (state->arg_num)
+ {
+ case 0: rd.name = arg; break;
+ case 1: wr.name = arg; break;
+ default: return ARGP_ERR_UNKNOWN;
+ }
+ break;
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+
+ case 'u': def_params.user = arg; break;
+ case 'p': def_params.pass = arg; break;
+ case 'a': def_params.acct = arg; break;
+
+ case OPT_SRC_U: rd.params.user = arg; break;
+ case OPT_SRC_P: rd.params.pass = arg; break;
+ case OPT_SRC_A: rd.params.acct = arg; break;
+
+ case OPT_DST_U: wr.params.user = arg; break;
+ case OPT_DST_P: wr.params.pass = arg; break;
+ case OPT_DST_A: wr.params.acct = arg; break;
+
+ case 'D': conn_hooks.cntl_debug = cntl_debug; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ econnect (&rd, &def_params, "SRC");
+ econnect (&wr, &def_params, "DST");
+
+ if (rd.conn && wr.conn)
+ /* Both endpoints are remote; directly copy between ftp servers. */
+ {
+ err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
+ if (err == EISDIR)
+ /* The destination name is a directory; try again with the source
+ basename appended. */
+ {
+ append_basename (&wr, &rd);
+ err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
+ }
+ if (err)
+ error (30, err, "Remote copy");
+ }
+ else
+ /* One endpoint is local, so do the copying ourself. */
+ {
+ int rd_fd, wr_fd;
+
+ err = eopen_rd (&rd, &rd_fd);
+ if (err)
+ error (31, err, "%s", rd.name);
+
+ err = eopen_wr (&wr, &wr_fd);
+ if (err == EISDIR)
+ /* The destination name is a directory; try again with the source
+ basename appended. */
+ {
+ append_basename (&wr, &rd);
+ err = eopen_wr (&wr, &wr_fd);
+ }
+ if (err)
+ error (32, err, "%s", wr.name);
+
+ cp (rd_fd, rd.name, wr_fd, wr.name);
+
+ close (rd_fd);
+ close (wr_fd);
+
+ efinish (&rd);
+ efinish (&wr);
+ }
+
+ exit (0);
+}
diff --git a/utils/ftpdir.c b/utils/ftpdir.c
new file mode 100644
index 00000000..4ccb821d
--- /dev/null
+++ b/utils/ftpdir.c
@@ -0,0 +1,329 @@
+/* Get a directory listing using the ftp protocol
+
+ Copyright (C) 1997,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <error.h>
+#include <argp.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <version.h>
+
+#include <ftpconn.h>
+
+#define COPY_SZ 65536
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpdir);
+
+static struct argp_option options[] =
+{
+ {"user", 'u', "USER",0, "User to login as on ftp server"},
+ {"password", 'p', "PWD", 0, "USER's password"},
+ {"account", 'a', "ACCT",0, "Account to login as"},
+ {"separator",'S', "SEP", 0, "String to separate multiple listings"},
+ {"prefix", 'P', "PFX", 0, "String to proceed listings; the first and second"
+ " occurrences of %s are replace by HOST and DIR"},
+ {"host", 'h', "HOST",0, "Use HOST as a default host"},
+ {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
+ {"intepret", 'i', 0, 0, "Parse the directory output"},
+ {0, 0}
+};
+static char *args_doc = "[([HOST:]DIR | HOST:)...]";
+static char *doc = "Get a directory listing over ftp from HOST:DIR."
+"\vIf HOST is not supplied in an argument any default value set by --host is"
+" used; if DIR is not supplied, the default directory of HOST is used."
+"\nIf multiple DIRs are supplied on the command line, each listing is"
+" prefixed by a newline (or SEP) and a line containing HOST:DIR: (or PFX).";
+
+/* customization hooks. */
+static struct ftp_conn_hooks conn_hooks = { 0 };
+
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = "."; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ fprintf (stderr, "%s%s\n", type_str, txt);
+}
+
+struct ftpdir_host
+{
+ char *name;
+ struct ftp_conn_params params;
+ struct ftp_conn *conn;
+ struct ftpdir_host *next;
+};
+
+/* Return an ftp connection for the host NAME using PARAMS, and add an entry
+ for it to *HOSTS. If a connection already exists in HOSTS, it is returned
+ instead of making a new one. If an error occurrs, a message is printed and
+ 0 is returned. */
+static struct ftpdir_host *
+get_host_conn (char *name, struct ftp_conn_params *params,
+ struct ftpdir_host **hosts)
+{
+ error_t err;
+ struct ftpdir_host *h;
+ struct hostent *he;
+
+ for (h = *hosts; h; h = h->next)
+ if (strcmp (h->name, name) == 0)
+ return h;
+
+ he = gethostbyname (name);
+ if (! he)
+ {
+ error (0, 0, "%s: %s", name, hstrerror (h_errno));
+ return 0;
+ }
+
+ for (h = *hosts; h; h = h->next)
+ if (he->h_addrtype == h->params.addr_type
+ && he->h_length == h->params.addr_len
+ && bcmp (he->h_addr_list[0], h->params.addr, he->h_length) == 0)
+ return h;
+
+ h = malloc (sizeof (struct ftpdir_host));
+ if (! h)
+ {
+ error (0, ENOMEM, "%s", name);
+ return 0;
+ }
+
+ h->params = *params;
+ h->params.addr = malloc (he->h_length);
+ h->name = strdup (he->h_name);
+
+ if (!h->name || !h->params.addr)
+ err = ENOMEM;
+ else
+ {
+ bcopy (he->h_addr_list[0], h->params.addr, he->h_length);
+ h->params.addr_len = he->h_length;
+ h->params.addr_type = he->h_addrtype;
+ err = ftp_conn_create (&h->params, &conn_hooks, &h->conn);
+ }
+
+ if (err)
+ {
+ error (0, err, "%s", he->h_name);
+ if (h->name)
+ free (h->name);
+ if (h->params.addr)
+ free (h->params.addr);
+ free (h);
+ return 0;
+ }
+
+ h->next = *hosts;
+ *hosts = h;
+
+ return h;
+}
+
+static int
+ftpdir (char *dir, struct ftpdir_host *host)
+{
+ int data;
+ int rd;
+ error_t err;
+ static void *copy_buf = 0;
+ struct ftp_conn *conn = host->conn;
+ char *host_name = host->name;
+
+ err = ftp_conn_start_dir (conn, dir, &data);
+ if (err)
+ {
+ error (0, err, "%s:%s", host_name, dir);
+ return err;
+ }
+
+ if (! copy_buf)
+ {
+ copy_buf = valloc (COPY_SZ);
+ if (! copy_buf)
+ error (12, ENOMEM, "Cannot allocate copy buffer");
+ }
+
+ while ((rd = read (data, copy_buf, COPY_SZ)) > 0)
+ do
+ {
+ int wr = write (1, copy_buf, rd);
+ if (wr < 0)
+ error (13, errno, "stdout");
+ rd -= wr;
+ }
+ while (rd > 0);
+ if (rd != 0)
+ {
+ error (0, errno, "%s:%s", host_name, dir);
+ return errno;
+ }
+
+ close (data);
+
+ err = ftp_conn_finish_transfer (conn);
+ if (err)
+ {
+ error (0, err, "%s:%s", host_name, dir);
+ return err;
+ }
+
+ return 0;
+}
+
+static error_t
+pdirent (const char *name, const struct stat *st, const char *symlink_target,
+ void *hook)
+{
+ char timebuf[20];
+ strftime (timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime (&st->st_mtime));
+ printf ("%6o %2d %5d %5d %6lld %s %s\n",
+ st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
+ timebuf, name);
+ if (symlink_target)
+ printf (" -> %s\n",
+ symlink_target);
+ return 0;
+}
+
+static error_t
+ftpdir2 (char *dir, struct ftpdir_host *host)
+{
+ error_t err = ftp_conn_get_stats (host->conn, dir, 1, pdirent, 0);
+ if (err == ENOTDIR)
+ err = ftp_conn_get_stats (host->conn, dir, 0, pdirent, 0);
+ if (err)
+ error (0, err, "%s:%s", host->name, dir);
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct ftpdir_host *hosts = 0;
+ char *default_host = 0;
+ int interpret = 0;
+ struct ftp_conn_params params = { 0 };
+ char *sep = "\n";
+ char *pfx = "%s:%s:\n";
+ int use_pfx = 0;
+ int errs = 0;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ {
+ char *host, *dir;
+
+ if (state->next < state->argc)
+ use_pfx = 1; /* Multiple arguments. */
+
+ dir = index (arg, ':');
+ if (dir)
+ {
+ host = arg;
+ *dir++ = '\0';
+ if (*host == '\0')
+ /* An argument of `:' */
+ host = default_host;
+ }
+ else
+ {
+ host = default_host;
+ dir = arg;
+ }
+
+ if (host)
+ {
+ struct ftpdir_host *h = get_host_conn (host, &params, &hosts);
+ if (h)
+ {
+ if (state->arg_num > 0)
+ fputs (sep, stdout);
+ if (use_pfx)
+ printf (pfx, h->name, dir);
+ if ((use_pfx && *pfx) || (state->arg_num > 0 && *sep))
+ fflush (stdout);
+ if (interpret)
+ errs |= ftpdir2 (dir, h);
+ else
+ errs |= ftpdir (dir, h);
+ }
+ errs = 1;
+ }
+ else
+ {
+ error (0, 0, "%s: No default host", arg);
+ errs = 1;
+ }
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (default_host)
+ {
+ struct ftpdir_host *h =
+ get_host_conn (default_host, &params, &hosts);
+ if (h)
+ errs |= ftpdir (0, h);
+ }
+ else
+ {
+ error (0, 0, "No default host");
+ errs = 1;
+ }
+ break;
+
+ return EINVAL;
+
+ case 'u': params.user = arg; break;
+ case 'p': params.pass = arg; break;
+ case 'a': params.acct = arg; break;
+ case 'h': default_host = arg; break;
+ case 'D': conn_hooks.cntl_debug = cntl_debug; break;
+ case 'P': pfx = arg; use_pfx = 1; break;
+ case 'S': sep = arg; break;
+ case 'i': interpret = 1; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (errs)
+ exit (10);
+ else
+ exit (0);
+}
diff --git a/utils/gcore.c b/utils/gcore.c
new file mode 100644
index 00000000..3d72492c
--- /dev/null
+++ b/utils/gcore.c
@@ -0,0 +1,107 @@
+/* `gcore' program for GNU Hurd: write a core dump from a running process.
+ Copyright (C) 1992,2001,2002 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <hurd.h>
+#include <hurd/crash.h>
+#include <hurd/paths.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (gcore);
+
+static const struct argp argp =
+{
+ NULL, NULL,
+ "PID...",
+ "Generate a core dump file from a running process"
+ "\vFor each PID, a core dump file \"core.PID\" is written."
+};
+
+int
+main (int argc, char **argv)
+{
+ int status = 0;
+ file_t crashserv;
+ int argi;
+
+ argp_parse (&argp, argc, argv, 0, &argi, 0);
+
+ crashserv = file_name_lookup (_SERVERS_CRASH, 0, 0);
+ if (crashserv == MACH_PORT_NULL)
+ error (1, errno, "cannot reach crash server: %s", _SERVERS_CRASH);
+
+ for (; argi < argc; ++argi)
+ {
+ char *end;
+ pid_t pid;
+ task_t task;
+
+ pid = strtol (argv[argi], &end, 10);
+ if (end == argv[argi] || *end != '\0')
+ {
+ error (0, 0, "cannot parse process ID: %s", argv[argi]);
+ status = 1;
+ continue;
+ }
+
+ task = pid2task ((pid_t) pid);
+ if (task == MACH_PORT_NULL)
+ {
+ error (0, errno, "pid2task: %d", pid);
+ status = 1;
+ }
+ else
+ {
+ file_t file;
+ char *name = 0;
+ asprintf (&name, "core.%d", pid);
+
+ file = file_name_lookup (name, O_WRONLY|O_CREAT,
+ 0600 &~ getumask ());
+ if (file == MACH_PORT_NULL)
+ {
+ error (0, errno, "cannot create %s", name);
+ status = 1;
+ }
+ else
+ {
+ error_t err = crash_dump_task (crashserv, task, file,
+ 0, 0, 0, 0, 0, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), file);
+ if (err)
+ {
+ (void) remove (name);
+ error (0, err, "crash_dump_task on %d to %s", pid, name);
+ status = 1;
+ }
+ free (name);
+ }
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ }
+
+ return status;
+}
diff --git a/utils/hurdids.c b/utils/hurdids.c
deleted file mode 100644
index 18eb3c41..00000000
--- a/utils/hurdids.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* Show all hurd ids
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <argp.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include <error.h>
-#include <hurd/id.h>
-
-char *argp_program_version = "hurdids 1.0 (GNU " HURD_RELEASE ")";
-
-static struct argp_option options[] =
-{
- {"effective", 'e', 0, 0, "Show effective ids"},
- {"available", 'a', 0, 0, "Show available ids"},
- {"uids", 'u', 0, 0, "Show user ids"},
- {"gids", 'g', 0, 0, "Show group ids"},
- {"names", 'n', 0, 0, "Show names of uids/gids"},
- {"ids", 'i', 0, 0, "Show numeric uids/gids"},
- {0}
-};
-static char *args_doc = 0;
-static char *doc = 0;
-
-/* ---------------------------------------------------------------- */
-
-void
-main(int argc, char *argv[])
-{
- error_t err;
- int show_eff = 0, show_avail = 0, show_uids = 0, show_gids = 0;
- int show_names = 0, show_ids = 0;
-
- /* Parse a command line option. */
- error_t parse_opt (int key, char *arg, struct argp_state *state)
- {
- switch (key)
- {
- case 'e': show_eff = 1; break;
- case 'a': show_avail = 1; break;
- case 'u': show_uids = 1; break;
- case 'g': show_gids = 1; break;
- case 'n': show_names = 1; break;
- case 'i': show_ids = 1; break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
-
- struct argp argp = {options, parse_opt, args_doc, doc};
-
- argp_parse (&argp, argc, argv, 0, 0, 0);
-
- if (! show_eff && ! show_avail)
- show_eff = show_avail = 1;
- if (! show_uids && ! show_gids)
- show_uids = show_gids = 1;
- if (! show_names && ! show_ids)
- show_names = show_ids = 1;
-
- mutex_lock (&_hurd_id.lock);
- err = _hurd_check_ids ();
- mutex_unlock (&_hurd_id.lock);
-
- if (err)
- error (2, err, "Can't update ids");
- else
- {
- typedef typeof (_hurd_id.gen) *ids_t;
- void print_ids (ids_t ids, char *name)
- {
- int i;
-
- if (show_uids)
- {
- if (name && show_gids)
- printf ("%s uids: ", name);
- else if (show_gids)
- printf ("uids: ");
- else if (name)
- printf ("%s: ", name);
-
- for (i = 0; i < ids->nuids; i++)
- {
- uid_t uid = ids->uids[i];
- struct passwd *pw = show_names ? getpwuid (uid) : 0;
- if (i > 0)
- putchar (' ');
- if (pw)
- if (show_ids)
- printf ("%d(%s)", uid, pw->pw_name);
- else
- printf ("%s", pw->pw_name);
- else
- printf ("%d", uid);
- }
- putchar ('\n');
- }
- if (show_gids)
- {
- if (name && show_uids)
- printf ("%s gids: ", name);
- else if (show_uids)
- printf ("gids: ");
- else if (name)
- printf ("%s: ", name);
-
- for (i = 0; i < ids->ngids; i++)
- {
- gid_t gid = ids->gids[i];
- struct group *gr = show_names ? getgrgid (gid) : 0;
- if (i > 0)
- putchar (' ');
- if (gr)
- if (show_ids)
- printf ("%d(%s)", gid, gr->gr_name);
- else
- printf ("%s", gr->gr_name);
- else
- printf ("%d", gid);
- }
- putchar ('\n');
- }
- }
- if (show_eff)
- print_ids (&_hurd_id.gen, show_avail ? "effective" : 0);
- if (show_avail)
- print_ids (&_hurd_id.aux, show_eff ? "available" : 0);
- }
-
- exit(0);
-}
diff --git a/utils/ids.c b/utils/ids.c
new file mode 100644
index 00000000..f8ad22c5
--- /dev/null
+++ b/utils/ids.c
@@ -0,0 +1,196 @@
+/* Show all hurd ids
+
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <argp.h>
+#include <unistd.h>
+#include <error.h>
+#include <ugids.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ids);
+
+static struct argp_option options[] =
+{
+ {"terse", 't', 0, 0, "Use a shorter one-line output format"},
+ {"effective", 'e', 0, 0, "Show effective ids"},
+ {"available", 'a', 0, 0, "Show available ids"},
+ {"uids", 'u', 0, 0, "Show user ids"},
+ {"gids", 'g', 0, 0, "Show group ids"},
+ {"names", 'n', 0, 0, "Show names of uids/gids"},
+ {"values", 'v', 0, 0, "Show numeric uids/gids"},
+ {0}
+};
+static char *args_doc = "[PID]";
+static char *doc = "Show hurd uids/gids."
+"\vIf PID is suppplied, show ids in that process.";
+
+/* ---------------------------------------------------------------- */
+
+int
+main(int argc, char *argv[])
+{
+ error_t err;
+ task_t task;
+ mach_port_t msgport;
+ int pid = -1;
+ auth_t auth = getauth ();
+ process_t proc = getproc ();
+ struct ugids ugids = UGIDS_INIT;
+ int show_eff = 0, show_avail = 0, show_uids = 0, show_gids = 0, terse = 0;
+ int show_names = 0, show_values = 0;
+
+ /* Print the given id vectors, using NAME for the prompt. */
+ void print_ids (struct idvec *uids, struct idvec *gids, char *name)
+ {
+ if (show_uids)
+ {
+ if (name && show_gids)
+ printf ("%s uids: ", name);
+ else if (show_gids)
+ printf ("uids: ");
+ else if (name)
+ printf ("%s: ", name);
+ printf ("%s\n",
+ idvec_uids_rep (uids, show_values, show_names, " "));
+ }
+ if (show_gids)
+ {
+ if (name && show_uids)
+ printf ("%s gids: ", name);
+ else if (show_uids)
+ printf ("gids: ");
+ else if (name)
+ printf ("%s: ", name);
+ printf ("%s\n", idvec_gids_rep (gids, show_values, show_names, " "));
+ }
+ }
+
+ /* Parse a command line option. */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'e': show_eff = 1; break;
+ case 'a': show_avail = 1; break;
+ case 'u': show_uids = 1; break;
+ case 'g': show_gids = 1; break;
+ case 'n': show_names = 1; break;
+ case 'v': show_values = 1; break;
+ case 't': terse = 1; break;
+ case ARGP_KEY_ARG:
+ if (state->arg_num == 0)
+ {
+ pid = atoi (arg);
+ break;
+ }
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (!show_eff && !show_avail)
+ show_eff = show_avail = 1;
+ if (!show_uids && !show_gids)
+ show_uids = show_gids = 1;
+ if (!show_names && !show_values)
+ show_names = show_values = 1;
+
+ if (pid < 0)
+ /* We get our parent's authentication instead of our own because this
+ program is usually installed setuid. This should work even if it's
+ not installed setuid, using the auth port as authentication to the
+ msg_get_init_port rpc. */
+ pid = getppid ();
+
+ /* Get a msgport for PID, to which we can send requests. */
+ err = proc_getmsgport (proc, pid, &msgport);
+ if (err)
+ error (5, err, "%d: Cannot get process msgport", pid);
+
+ /* Try to get the task port to use as authentication. */
+ err = proc_pid2task (proc, pid, &task);
+
+ /* Now fetch the auth port; if we couldn't get the task port to use for
+ authentication, we try the (old) auth port instead. */
+ if (err)
+ err = msg_get_init_port (msgport, auth, INIT_PORT_AUTH, &auth);
+ else
+ err = msg_get_init_port (msgport, task, INIT_PORT_AUTH, &auth);
+ if (err)
+ error (6, err, "%d: Cannot get process authentication", pid);
+
+ mach_port_deallocate (mach_task_self (), msgport);
+ mach_port_deallocate (mach_task_self (), task);
+
+ /* Get the ids that AUTH represents. */
+ err = ugids_merge_auth (&ugids, auth);
+ if (err)
+ error (10, err, "Cannot get authentication ids");
+
+ /* Print them. */
+ if (terse)
+ /* Short output format. */
+ {
+ /* Since we use ugids_rep to format the output, just clear any fields
+ we don't want to show. */
+ if (! show_eff)
+ {
+ idvec_clear (&ugids.eff_uids);
+ idvec_clear (&ugids.eff_gids);
+ }
+ if (! show_avail)
+ {
+ idvec_clear (&ugids.avail_uids);
+ idvec_clear (&ugids.avail_gids);
+ }
+ if (! show_uids)
+ {
+ idvec_clear (&ugids.eff_uids);
+ idvec_clear (&ugids.avail_uids);
+ }
+ if (! show_gids)
+ {
+ idvec_clear (&ugids.eff_gids);
+ idvec_clear (&ugids.avail_gids);
+ }
+ printf ("%s\n", ugids_rep (&ugids, show_values, show_names, 0, " ","="));
+ }
+ else
+ /* Long output format */
+ {
+ if (show_eff)
+ print_ids (&ugids.eff_uids, &ugids.eff_gids,
+ show_avail ? "effective" : 0);
+ if (show_avail)
+ print_ids (&ugids.avail_uids, &ugids.avail_gids,
+ show_eff ? "available" : 0);
+ }
+
+ return 0;
+}
diff --git a/utils/login.c b/utils/login.c
index 46f9629b..cad3b1ed 100644
--- a/utils/login.c
+++ b/utils/login.c
@@ -1,8 +1,8 @@
/* Hurdish login
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2002 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -31,6 +31,8 @@
#include <netdb.h>
#include <time.h>
#include <assert.h>
+#include <version.h>
+#include <sys/mman.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -44,13 +46,16 @@
#include <error.h>
#include <timefmt.h>
#include <hurd/lookup.h>
+#include <ugids.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (login);
extern error_t
exec_reauth (auth_t auth, int secure, int must_reauth,
mach_port_t *ports, unsigned num_ports,
mach_port_t *fds, unsigned num_fds);
-
-char *argp_program_version = "login 1.0 (GNU " HURD_RELEASE ")";
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
/* Defaults for various login parameters. */
char *default_args[] = {
@@ -88,26 +93,28 @@ static struct argp_option options[] =
{"arg", 'a', "ARG", 0, "Add login parameter ARG"},
{"arg-default", 'A', "ARG", 0, "Use ARG as a default login parameter"},
{"no-environment-args", 'X', 0, 0, "Don't add the parent environment as default login params"},
- {"user", 'u', "USER", 0, "Add USER to the effective uids"},
- {"avail-user",'U', "USER", 0, "Add USER to the available uids"},
- {"group", 'g', "GROUP", 0, "Add GROUP to the effective groups"},
- {"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
{"no-login", 'L', 0, 0, "Don't modify the shells argv[0] to look"
" like a login shell"},
{"preserve-environment", 'p', 0, 0, "Inherit the parent's environment"},
{"via", 'h', "HOST", 0, "This login is from HOST"},
{"no-passwd", 'f', 0, 0, "Don't ask for passwords"},
{"paranoid", 'P', 0, 0, "Don't admit that a user doesn't exist"},
- {"keep", 'k', 0, 0, "Keep the old available ids, and save the old"
- "effective ids as available ids"},
+ {"save", 's', 0, 0, "Keep the old available ids, and save the old"
+ " effective ids as available ids"},
{"shell-from-args", 'S', 0, 0, "Use the first shell arg as the shell to invoke"},
{"retry", 'R', "ARG", OPTION_ARG_OPTIONAL,
"Re-exec login with no users after non-fatal errors; if ARG is supplied,"
"add it to the list of args passed to login when retrying"},
{0, 0}
};
+static struct argp_child child_argps[] =
+{
+ { &ugids_argp, 0, "Adding individual user/group ids:" },
+ { 0 }
+};
static char *args_doc = "[USER [ARG...]]";
static char *doc =
+"Exec a program with uids and/or the environment changed appropriately.\v"
"To give args to the shell without specifying a user, use - for USER.\n"
"Current login parameters include HOME, SHELL, USER, NAME, and ROOT.";
@@ -133,7 +140,7 @@ cat (mach_port_t node, char *str)
{
write (0, data, data_len);
if (data != buf)
- vm_deallocate (mach_task_self (), (vm_address_t)data, data_len);
+ munmap (data, data_len);
}
}
if (err)
@@ -181,7 +188,9 @@ add_utmp_entry (char *args, unsigned args_len, int inherit_host)
{
struct utmp *old_utmp;
strncpy (utmp.ut_line, basename (tty), sizeof (utmp.ut_line));
+ setutent ();
old_utmp = getutline (&utmp);
+ endutent ();
if (old_utmp)
{
if (! host)
@@ -201,7 +210,7 @@ add_utmp_entry (char *args, unsigned args_len, int inherit_host)
/* Lookup the host HOST, and add entries for VIA (the host name), and
VIA_ADDR (the dotted decimal address) to ARGS & ARGS_LEN. */
static error_t
-add_canonical_host (char **args, unsigned *args_len, char *host)
+add_canonical_host (char **args, size_t *args_len, char *host)
{
struct hostent *he = gethostbyname (host);
@@ -238,7 +247,7 @@ add_canonical_host (char **args, unsigned *args_len, char *host)
/* Add the `=' separated environment entry ENTRY to ENV & ENV_LEN, exiting
with an error message if we can't. */
static void
-add_entry (char **env, unsigned *env_len, char *entry)
+add_entry (char **env, size_t *env_len, char *entry)
{
char *name = strsep (&entry, "=");
error_t err = envz_add (env, env_len, name, entry);
@@ -263,7 +272,7 @@ check_owned (process_t proc_server, pid_t pid, int *owned)
{
*owned = !(pi->state & PI_NOTOWNED);
if (pi != &_pi)
- vm_deallocate (mach_task_self (), (vm_address_t)pi, pi_size);
+ munmap (pi, pi_size);
}
return err;
@@ -288,7 +297,7 @@ kill_login (process_t proc_server, pid_t pid, int sig)
if (pids[i] != self)
kill (pids[i], sig);
if (pids != _pids)
- vm_deallocate (mach_task_self (), (vm_address_t)pids, num_pids);
+ munmap (pids, num_pids);
}
}
while (!err && num_pids > 0);
@@ -359,7 +368,7 @@ dog (time_t timeout, pid_t pid, char **argv)
}
}
-void
+int
main(int argc, char *argv[])
{
int i;
@@ -368,17 +377,15 @@ main(int argc, char *argv[])
char *path;
error_t err = 0;
char *args = 0; /* The login parameters */
- unsigned args_len = 0;
- char *passwd = 0; /* Login parameters from /etc/passwd */
- unsigned passwd_len = 0;
+ size_t args_len = 0;
char *args_defs = 0; /* Defaults for login parameters. */
- unsigned args_defs_len = 0;
+ size_t args_defs_len = 0;
char *env = 0; /* The new environment. */
- unsigned env_len = 0;
+ size_t env_len = 0;
char *env_defs = 0; /* Defaults for the environment. */
- unsigned env_defs_len = 0;
+ size_t env_defs_len = 0;
char *parent_env = 0; /* The environment we got from our parent */
- unsigned parent_env_len = 0;
+ size_t parent_env_len = 0;
int no_environ = 0; /* If false, use the env as default params. */
int no_args = 0; /* If false, put login params in the env. */
int inherit_environ = 0; /* True if we shouldn't clear our env. */
@@ -387,28 +394,24 @@ main(int argc, char *argv[])
int paranoid = 0; /* Admit no knowledge. */
int retry = 0; /* For some failures, exec a login shell. */
char *retry_args = 0; /* Args passed when retrying. */
- unsigned retry_args_len = 0;
+ size_t retry_args_len = 0;
char *shell = 0; /* The shell program to run. */
char *sh_arg0 = 0; /* The shell's argv[0]. */
char *sh_args = 0; /* The args to the shell. */
- unsigned sh_args_len = 0;
+ size_t sh_args_len = 0;
int shell_arg = 0; /* If there are shell args, use the first as
the shell name. */
- struct idvec *eff_uids = make_idvec (); /* The UIDs of the new shell. */
- struct idvec *eff_gids = make_idvec (); /* The EFF_GIDs. */
- struct idvec *avail_uids = make_idvec (); /* The aux UIDs of the new shell. */
- struct idvec *avail_gids = make_idvec (); /* The aux EFF_GIDs. */
- struct idvec *parent_uids = make_idvec (); /* Parent uids, -SETUID. */
- struct idvec *parent_gids = make_idvec (); /* Parent gids, -SETGID. */
+ struct ugids ugids = UGIDS_INIT; /* Authorization of the new shell. */
+ struct ugids_argp_params ugids_argp_params = { &ugids, 0, 0, 0, -1, 0 };
+ struct idvec parent_uids = IDVEC_INIT; /* Parent uids, -SETUID. */
+ struct idvec parent_gids = IDVEC_INIT; /* Parent gids, -SETGID. */
mach_port_t exec; /* The shell executable. */
- mach_port_t cwd; /* The child's CWD. */
mach_port_t root; /* The child's root directory. */
mach_port_t ports[INIT_PORT_MAX]; /* Init ports for the new process. */
int ints[INIT_INT_MAX]; /* Init ints for it. */
mach_port_t fds[3]; /* File descriptors passed. */
mach_port_t auth; /* The new shell's authentication. */
mach_port_t proc_server = getproc ();
- mach_port_t parent_auth = getauth ();
pid_t pid = getpid (), sid;
/* These three functions are to do child-authenticated lookups. See
@@ -437,9 +440,11 @@ main(int argc, char *argv[])
int retry_argc;
char **retry_argv;
char *via = envz_get (args, args_len, "VIA");
- extern void _argp_unlock_xxx (); /* Secret unknown function. */
- error (retry ? 0 : code, err, fmt, str); /* May exit... */
+ if (fmt)
+ error (retry ? 0 : code, err, fmt, str); /* May exit... */
+ else if (! retry)
+ exit (code);
if (via)
envz_add (&retry_args, &retry_args_len, "--via", via);
@@ -450,104 +455,10 @@ main(int argc, char *argv[])
argz_extract (retry_args, retry_args_len, retry_argv);
/* Reinvoke ourselves with no userids or anything; shouldn't return. */
- _argp_unlock_xxx (); /* Hack to get around problems with getopt. */
main (retry_argc, retry_argv);
exit (code); /* But if it does... */
}
- /* Make sure that the parent_[ug]ids are filled in. To make them useful
- for su'ing, each is the avail ids with all effective ids but the first
- appended; this gets rid of the effect of login being suid, and is useful
- as the new process's avail id list (e.g., the real id is right). */
- void need_parent_ids ()
- {
- if (parent_uids->num == 0 && parent_gids->num == 0)
- {
- struct idvec *p_eff_uids = make_idvec ();
- struct idvec *p_eff_gids = make_idvec ();
- if (!p_eff_uids || !p_eff_gids)
- err = ENOMEM;
- if (! err)
- err = idvec_merge_auth (p_eff_uids, parent_uids,
- p_eff_gids, parent_gids,
- parent_auth);
- if (! err)
- {
- idvec_delete (p_eff_uids, 0); /* Counteract setuid. */
- idvec_delete (p_eff_gids, 0);
- err = idvec_merge (parent_uids, p_eff_uids);
- if (! err)
- err = idvec_merge (parent_gids, p_eff_gids);
- }
- if (err)
- error (39, err, "Can't get uids");
- }
- }
-
- /* Returns true if the *caller* of this login program has UID. */
- int parent_has_uid (uid_t uid)
- {
- need_parent_ids ();
- return idvec_contains (parent_uids, uid);
- }
- /* Returns true if the *caller* of this login program has GID. */
- int parent_has_gid (gid_t gid)
- {
- need_parent_ids ();
- return idvec_contains (parent_gids, gid);
- }
- /* Returns the number of parent uids. */
- int count_parent_uids ()
- {
- need_parent_ids ();
- return parent_uids->num;
- }
- /* Returns the number of parent gids. */
- int count_parent_gids ()
- {
- need_parent_ids ();
- return parent_gids->num;
- }
-
- /* Make sure the user should be allowed to do this. */
- void verify_passwd (const char *name, const char *password,
- uid_t id, int is_group)
- {
- extern char *crypt (const char *string, const char salt[2]);
-#pragma weak crypt
- char *prompt, *unencrypted, *encrypted;
-
- if (!password || !*password
- || idvec_contains (is_group ? eff_gids : eff_uids, id)
- || idvec_contains (is_group ? avail_gids : avail_uids, id)
- || (no_passwd
- && (parent_has_uid (0)
- || (is_group ? parent_has_uid (id) : parent_has_gid (id)))))
- return; /* Already got this one. */
-
- if (name)
- asprintf (&prompt, "Password for %s%s:",
- is_group ? "group " : "", name);
- else
- prompt = "Password:";
-
- unencrypted = getpass (prompt);
- if (crypt)
- {
- encrypted = crypt (unencrypted, password);
- /* Paranoia may destroya. */
- memset (unencrypted, 0, strlen (unencrypted));
- }
- else
- encrypted = unencrypted;
-
- if (name)
- free (prompt);
-
- if (strcmp (encrypted, password) != 0)
- fail (50, 0, "Incorrect password", 0);
- }
-
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -581,14 +492,14 @@ main(int argc, char *argv[])
retry = 1;
break;
- case 'k':
- need_parent_ids ();
- idvec_merge (avail_uids, parent_uids);
- idvec_merge (avail_gids, parent_gids);
+ case 's':
+ idvec_merge (&ugids.avail_uids, &parent_uids);
+ idvec_merge (&ugids.avail_gids, &parent_gids);
break;
case ARGP_KEY_ARG:
if (state->arg_num > 0)
+ /* Program arguments. */
{
err = argz_create (state->argv + state->next - 1,
&sh_args, &sh_args_len);
@@ -599,105 +510,32 @@ main(int argc, char *argv[])
}
if (strcmp (arg, "-") == 0)
- arg = 0; /* Just like there weren't any args at all. */
- /* Fall through to deal with adding the user. */
+ /* An explicit no-user-specified (so remaining args can be used
+ to set the program args). */
+ break;
- case 'u':
- case 'U':
- case ARGP_KEY_NO_ARGS:
- {
- /* USER is whom to look up. If it's 0, then we hit the end of
- the sh_args without seeing a user, so we want to add defaults
- values for `nobody'. */
- char *user = arg ?: envz_get (args, args_len, "NOBODY");
- struct passwd *pw =
- isdigit (*user) ? getpwuid (atoi (user)) : getpwnam (user);
- /* True if this is the user arg and there were no user options. */
- int only_user =
- (key == ARGP_KEY_ARG
- && eff_uids->num == 0 && avail_uids->num <= count_parent_uids ()
- && eff_gids->num == 0 && avail_gids->num <= count_parent_gids ());
-
- if (! pw)
- if (! arg)
- /* It was nobody anyway. Just use the defaults. */
- break;
+ if (isdigit (*arg))
+ err = ugids_set_posix_user (&ugids, atoi (arg));
+ else
+ {
+ struct passwd *pw = getpwnam (arg);
+ if (pw)
+ err = ugids_set_posix_user (&ugids, pw->pw_uid);
else if (paranoid)
- /* In paranoid mode, we don't admit we don't know about a
- user, so we just ask for a password we we know the user
- can't supply. */
- verify_passwd (only_user ? 0 : user, "*", -1, 0);
+ /* Add a bogus uid so that password verification will
+ fail. */
+ idvec_add (&ugids.eff_uids, -1);
else
- fail (10, 0, "%s: Unknown user", user);
-
- if (arg)
- /* If it's not nobody, make sure we're authorized. */
- verify_passwd (only_user ? 0 : pw->pw_name, pw->pw_passwd,
- pw->pw_uid, 0);
-
- if (key == 'U')
- /* Add available ids instead of effective ones. */
- {
- idvec_add_new (avail_uids, pw->pw_uid);
- idvec_add_new (avail_gids, pw->pw_gid);
- }
- else
- {
- if (key == ARGP_KEY_ARG || eff_uids->num == 0)
- /* If it's the argument (as opposed to option) specifying a
- user, or the first option user, then we get defaults for
- various things from the password entry. */
- {
- envz_add (&passwd, &passwd_len, "HOME", pw->pw_dir);
- envz_add (&passwd, &passwd_len, "SHELL", pw->pw_shell);
- envz_add (&passwd, &passwd_len, "NAME", pw->pw_gecos);
- envz_add (&passwd, &passwd_len, "USER", pw->pw_name);
- }
- if (arg) /* A real user. */
- if (key == ARGP_KEY_ARG)
- /* The main user arg; add both effective and available
- ids (the available ids twice, for posix compatibility
- -- once for the real id, and again for the saved). */
- {
- /* Updates the real id in IDS to be ID. */
- void update_real (struct idvec *ids, uid_t id)
- {
- if (ids->num == 0
- || !idvec_tail_contains (ids, 1, ids->ids[0]))
- idvec_insert (ids, 0, id);
- else
- ids->ids[0] = id;
- }
-
- /* Effective */
- idvec_insert_only (eff_uids, 0, pw->pw_uid);
- idvec_insert_only (eff_gids, 0, pw->pw_gid);
- /* Real */
- update_real (avail_uids, pw->pw_uid);
- update_real (avail_gids, pw->pw_gid);
- /* Saved */
- idvec_insert_only (avail_uids, 1, pw->pw_uid);
- idvec_insert_only (avail_gids, 1, pw->pw_gid);
- }
- else
- {
- idvec_add_new (eff_uids, pw->pw_uid);
- idvec_add_new (eff_gids, pw->pw_gid);
- }
- }
- }
+ fail (10, 0, "%s: Unknown user", arg);
+ }
+
+ if (err)
+ fail (11, err, "%s: Can't set user!", arg);
+
break;
- case 'g':
- case 'G':
- {
- struct group *gr =
- isdigit (*arg) ? getgrgid (atoi (arg)) : getgrnam (arg);
- if (! gr)
- fail (11, 0, "%s: Unknown group", arg);
- verify_passwd (gr->gr_name, gr->gr_passwd, gr->gr_gid, 1);
- idvec_add_new (key == 'g' ? eff_gids : avail_gids, gr->gr_gid);
- }
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = &ugids_argp_params;
break;
default:
@@ -705,7 +543,7 @@ main(int argc, char *argv[])
}
return 0;
}
- struct argp argp = {options, parse_opt, args_doc, doc};
+ struct argp argp = { options, parse_opt, args_doc, doc, child_argps };
/* Don't allow logins if the nologin file exists. */
node = file_name_lookup (_PATH_NOLOGIN, O_RDONLY, 0);
@@ -736,9 +574,24 @@ main(int argc, char *argv[])
err = argz_create (environ, &parent_env, &parent_env_len);
+ /* Get authentication of our parent, minus any setuid. */
+ get_nonsugid_ids (&parent_uids, &parent_gids);
+
/* Parse our options. */
argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+ /* Check passwords where necessary. If no_passwd is set, then our parent
+ guarantees identity itself (where it is allowed), but otherwise
+ we want every UID fully checked. */
+ err = ugids_verify_make_auth (&ugids,
+ no_passwd ? &parent_uids : 0,
+ no_passwd ? &parent_gids : 0,
+ 0, 0, 0, 0, &auth);
+ if (err == EACCES)
+ fail (5, 0, "Invalid password", 0);
+ else if (err)
+ error (5, err, "Authentication failure");
+
/* Now that we've parsed the command line, put together all these
environments we've gotten from various places. There are two targets:
(1) the login parameters, and (2) the child environment.
@@ -750,37 +603,56 @@ main(int argc, char *argv[])
d) From the user-specified defaults (--arg-default)
e) From last-ditch defaults given by the DEFAULT_* defines above
- The child environment is from:
+ The child environment (constructed later) is from:
a) User specified (--environ)
b) From the login parameters (if --no-args wasn't specified)
c) From the parent environment, if --inherit-environ was specified
d) From the user-specified default env values (--environ-default)
e) From last-ditch defaults given by the DEFAULT_* defines above
*/
-
- /* Merge the login parameters. */
- err = envz_merge (&args, &args_len, passwd, passwd_len, 0);
- if (! err && ! no_environ)
- err = envz_merge (&args, &args_len, parent_env, parent_env_len, 0);
- if (! err)
- err = envz_merge (&args, &args_len, args_defs, args_defs_len, 0);
- if (err)
- error (24, err, "merging parameters");
-
- err =
- auth_makeauth (getauth (), 0, MACH_MSG_TYPE_COPY_SEND, 0,
- eff_uids->ids, eff_uids->num,
- avail_uids->ids, avail_uids->num,
- eff_gids->ids, eff_gids->num,
- avail_gids->ids, avail_gids->num,
- &auth);
- if (err)
- fail (3, err, "Authentication failure", 0);
+ {
+ struct passwd *pw;
+ char *passwd = 0; /* Login parameters from /etc/passwd */
+ size_t passwd_len = 0;
+
+ /* Decide which password entry to get parameters from. */
+ if (ugids.eff_uids.num > 0)
+ pw = getpwuid (ugids.eff_uids.ids[0]); /* Effective uid */
+ else if (ugids.avail_uids.num > 0)
+ pw = getpwuid (ugids.avail_uids.ids[0]); /* Auxiliary uid */
+ else
+ /* No user! Try to used the `not-logged-in' user to set various
+ parameters. */
+ pw = getpwnam (envz_get (args, args_len, "NOBODY")
+ ?: envz_get (args_defs, args_defs_len, "NOBODY")
+ ?: "login");
+
+ if (pw)
+ {
+ envz_add (&passwd, &passwd_len, "HOME", pw->pw_dir);
+ envz_add (&passwd, &passwd_len, "SHELL", pw->pw_shell);
+ envz_add (&passwd, &passwd_len, "NAME", pw->pw_gecos);
+ envz_add (&passwd, &passwd_len, "USER", pw->pw_name);
+ }
+
+ /* Merge the login parameters. */
+ err = envz_merge (&args, &args_len, passwd, passwd_len, 0);
+ if (! err && ! no_environ)
+ err = envz_merge (&args, &args_len, parent_env, parent_env_len, 0);
+ if (! err)
+ err = envz_merge (&args, &args_len, args_defs, args_defs_len, 0);
+ if (err)
+ error (24, err, "merging parameters");
+
+ free (passwd);
+ }
err = proc_getsid (proc_server, pid, &sid);
assert_perror (err); /* This should never fail. */
- if (!no_login && count_parent_uids () != 0)
+ if (!no_login
+ && (parent_uids.num != 0
+ || ugids.eff_uids.num + ugids.avail_uids.num > 0))
/* Make a new login collection (but only for real users). */
{
char *user = envz_get (args, args_len, "USER");
@@ -788,10 +660,10 @@ main(int argc, char *argv[])
setlogin (user);
proc_make_login_coll (proc_server);
- if (eff_uids->num + avail_uids->num == 0)
+ if (ugids.eff_uids.num + ugids.avail_uids.num == 0)
/* We're transiting from having some uids to having none, which means
this is probably a new login session. Unless specified otherwise,
- set a timer to kill this session if it hasn't aquired any ids by
+ set a timer to kill this session if it hasn't acquired any ids by
then. Note that we fork off the timer process before clearing the
process owner: because we're interested in killing unowned
processes, proc's in-same-login-session rule should apply to us
@@ -805,8 +677,8 @@ main(int argc, char *argv[])
}
}
- if (eff_uids->num > 0)
- proc_setowner (proc_server, eff_uids->ids[0], 0);
+ if (ugids.eff_uids.num > 0)
+ proc_setowner (proc_server, ugids.eff_uids.ids[0], 0);
else
proc_setowner (proc_server, 0, 1); /* Clear the owner. */
@@ -821,6 +693,7 @@ main(int argc, char *argv[])
for (i = 0; i < INIT_PORT_MAX; i++)
ports[i] = MACH_PORT_NULL;
ports[INIT_PORT_PROC] = getproc ();
+ ports[INIT_PORT_CTTYID] = getcttyid ();
ports[INIT_PORT_CRDIR] = getcrdir (); /* May be replaced below. */
ports[INIT_PORT_CWDIR] = getcwdir (); /* " */
@@ -829,11 +702,10 @@ main(int argc, char *argv[])
if (err)
error (40, err, "Port reauth failure");
- /* These are the default values for the child's root/cwd. We don't want to
+ /* These are the default values for the child's root. We don't want to
modify PORTS just yet, because we use it to do child-authenticated
lookups. */
root = ports[INIT_PORT_CRDIR];
- cwd = ports[INIT_PORT_CWDIR];
/* Find the shell executable (we copy the name, as ARGS may be changed). */
if (shell_arg && sh_args && *sh_args)
@@ -888,13 +760,15 @@ main(int argc, char *argv[])
arg = envz_get (args, args_len, "HOME");
if (arg && *arg)
{
- cwd = child_lookup (arg, 0, O_RDONLY);
+ mach_port_t cwd = child_lookup (arg, 0, O_RDONLY);
if (cwd == MACH_PORT_NULL)
{
error (0, errno, "%s", arg);
error (0, 0, "Using HOME=/");
envz_add (&args, &args_len, "HOME", "/");
}
+ else
+ ports[INIT_PORT_CWDIR] = cwd;
}
arg = envz_get (args, args_len, "ROOT");
@@ -944,25 +818,24 @@ main(int argc, char *argv[])
if (no_login)
sh_arg0 = shell_base;
+ else if (ugids.eff_uids.num + ugids.avail_uids.num == 0)
+ /* Use a special format for the argv[0] of a login prompt shell,
+ so that `ps' shows something informative in the COMMAND field.
+ This string must begin with a `-', the convention to tell the
+ shell to be a login shell (i.e. run .profile and the like). */
+ err = (asprintf (&sh_arg0, "-login prompt (%s)", shell_base) == -1
+ ? ENOMEM : 0);
else
- {
- sh_arg0 = malloc (strlen (shell_base) + 2);
- if (! sh_arg0)
- err = ENOMEM;
- else
- /* Prepend the name with a `-', as is the odd custom. */
- {
- sh_arg0[0] = '-';
- strcpy (sh_arg0 + 1, shell_base);
- }
- }
+ /* Prepend a `-' to the name, which is the ancient canonical
+ way to tell the shell that it's a login shell. */
+ err = asprintf (&sh_arg0, "-%s", shell_base) == -1 ? ENOMEM : 0;
}
if (! err)
err = argz_insert (&sh_args, &sh_args_len, sh_args, sh_arg0);
if (err)
error (21, err, "Error building shell args");
- /* Maybe output the message of the day. Note that we we the child's
+ /* Maybe output the message of the day. Note that we use the child's
authentication to do it, so that this program can't be used to read
arbitrary files! */
arg = envz_get (args, args_len, "MOTD");
@@ -982,29 +855,28 @@ main(int argc, char *argv[])
}
/* Now that we don't need to use PORTS for lookups anymore, put the correct
- ROOT and CWD in. */
+ ROOT in. */
ports[INIT_PORT_CRDIR] = root;
- ports[INIT_PORT_CWDIR] = cwd;
/* Get rid of any accumulated null entries in env. */
envz_strip (&env, &env_len);
/* No more authentications to fail, so cross our fingers and add our utmp
entry. */
-
+
if (pid == sid)
/* Only add utmp entries for the session leader. */
- add_utmp_entry (args, args_len, !parent_has_uid (0));
+ add_utmp_entry (args, args_len, !idvec_contains (&parent_uids, 0));
- if ((eff_uids->num | eff_gids->num) && !no_login)
+ if ((ugids.eff_uids.num | ugids.eff_gids.num) && !no_login)
{
char *tty = ttyname (0);
if (tty)
{
/* Change the terminal to be owned by the user. */
err = chown (tty,
- eff_uids->num ? eff_uids->ids[0] : -1,
- eff_gids->num ? eff_gids->ids[0] : -1);
+ ugids.eff_uids.num ? ugids.eff_uids.ids[0] : -1,
+ ugids.eff_gids.num ? ugids.eff_gids.ids[0] : -1);
if (err)
error (0, errno, "chown: %s", tty);
}
@@ -1019,5 +891,5 @@ main(int argc, char *argv[])
if (err)
error(5, err, "%s", shell);
- exit(0);
+ return 0;
}
diff --git a/utils/mount.c b/utils/mount.c
new file mode 100644
index 00000000..8b059c23
--- /dev/null
+++ b/utils/mount.c
@@ -0,0 +1,582 @@
+/* Roughly Unix/Linux-compatible `mount' frontend for Hurd translators.
+
+ Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../sutils/fstab.h"
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <hurd/fsys.h>
+#include <hurd/fshelp.h>
+#include <hurd/paths.h>
+
+#define SEARCH_FMTS _HURD "%sfs\0" _HURD "%s"
+#define DEFAULT_FSTYPE "ext2"
+
+static char *fstype = DEFAULT_FSTYPE;
+static char *device, *mountpoint;
+static int verbose;
+static char *options;
+static size_t options_len;
+static mach_msg_timeout_t timeout;
+
+static enum { mount, query } mode;
+static enum { qf_standard, qf_fstab, qf_translator } query_format;
+static struct fstab_argp_params fstab_params;
+
+
+static const struct argp_option argp_opts[] =
+{
+ {"timeout", 'T', "MILLISECONDS", 0, "Timeout for translator startup"},
+ {"format", 'p', "mount|fstab|translator", OPTION_ARG_OPTIONAL,
+ "Output format for query (no filesystem arguments)"},
+ {"options", 'o', "OPTIONS", 0, "A `,' separated list of options"},
+ {"readonly", 'r', 0, 0, "Never write to disk or allow opens for writing"},
+ {"writable", 'w', 0, 0, "Use normal read/write behavior"},
+ {"update", 'u', 0, 0, "Flush any meta-data cached in core"},
+ {"remount", 0, 0, OPTION_ALIAS},
+ {"verbose", 'v', 0, 0, "Give more detailed information"},
+ {0, 0}
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct fstab_argp_params *params = state->input;
+ error_t err;
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = params; /* pass down to fstab_argp parser */
+ break;
+
+#define ARGZ(call) \
+ err = argz_##call; \
+ if (err) \
+ argp_failure (state, 100, ENOMEM, "%s", arg); \
+ break
+ case 'r': ARGZ (add (&options, &options_len, "ro"));
+ case 'w': ARGZ (add (&options, &options_len, "rw"));
+ case 'u': ARGZ (add (&options, &options_len, "update"));
+ case 'o': ARGZ (add_sep (&options, &options_len, arg, ','));
+ case 'v': ++verbose; break;
+#undef ARGZ
+
+ case 'T':
+ {
+ char *end;
+ unsigned long int ms = strtoul (arg, &end, 10);
+ if (end && *end == '\0')
+ timeout = ms;
+ else
+ {
+ argp_error (state,
+ "--timeout needs a numeric argument (milliseconds)");
+ return EINVAL;
+ }
+ }
+ break;
+
+ case 'p':
+ if (arg == 0 || !strcasecmp (arg, "fstab"))
+ query_format = qf_fstab;
+ else if (!strcasecmp (arg, "mount"))
+ query_format = qf_standard;
+ else if (!strcasecmp (arg, "translator")
+ || !strcasecmp (arg, "showtrans"))
+ query_format = qf_translator;
+ else
+ {
+ argp_error (state, "invalid argument to --format");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_ARG:
+ if (mountpoint == 0) /* One arg: mountpoint */
+ mountpoint = arg;
+ else if (device == 0) /* Two args: device, mountpoint */
+ {
+ device = mountpoint;
+ mountpoint = arg;
+ }
+ else /* More than two args. */
+ {
+ argp_error (state, "too many arguments");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (! params->do_all)
+ {
+ params->do_all = 1;
+ mode = query;
+ }
+ break;
+
+ case ARGP_KEY_END:
+ if (params->do_all && mountpoint)
+ {
+ argp_error (state, "filesystem argument not allowed with --all");
+ return EINVAL;
+ }
+ if (mode == query && options_len != 0)
+ {
+ argp_error (state,
+ "mount options not allowed without filesystem argument");
+ return EINVAL;
+ }
+ if (mountpoint)
+ switch (argz_count (params->types, params->types_len))
+ {
+ default:
+ argp_error (state,
+ "multiple types not allowed with filesystem argument");
+ return EINVAL;
+ case 1:
+ fstype = params->types;
+ params->types = 0;
+ params->types_len = 0;
+ break;
+ case 0:
+ break;
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static const char doc[] = "Start active filesystem translators";
+static const char args_doc[] = "\
+DEVICE\t(in " _PATH_MNTTAB ")\n\
+DIRECTORY\t(in " _PATH_MNTTAB ")\n\
+[-t TYPE] DEVICE DIRECTORY\n\
+-a";
+static const struct argp_child argp_kids[] =
+{ { &fstab_argp, 0,
+ "Filesystem selection (if no explicit filesystem arguments given):", 2 },
+ { 0 } };
+static struct argp argp = { argp_opts, parse_opt, args_doc, doc, argp_kids };
+
+/* Mount one filesystem. */
+static error_t
+do_mount (struct fs *fs, int remount)
+{
+ error_t err;
+ char *fsopts, *o;
+ size_t fsopts_len;
+ char *mntopts;
+ size_t mntopts_len;
+ fsys_t mounted;
+
+ inline void explain (const char *command)
+ {
+ if (verbose)
+ {
+ const char *o;
+ printf ("%s %s", command, fs->mntent.mnt_dir);
+ for (o = fsopts; o; o = argz_next (fsopts, fsopts_len, o))
+ printf (" %s", o);
+ putchar ('\n');
+ }
+ }
+
+ err = fs_fsys (fs, &mounted);
+ if (err)
+ {
+ error (0, err, "cannot determine if %s is already mounted",
+ fs->mntent.mnt_fsname);
+ return err;
+ }
+
+
+ /* Produce an argz of translator option arguments from the
+ given FS's options and the command-line options. */
+
+#define ARGZ(call) \
+ err = argz_##call; \
+ if (err) \
+ error (3, ENOMEM, "collecting mount options"); \
+
+ if (fs->mntent.mnt_opts)
+ {
+ /* Append the fstab options to any specified on the command line. */
+ ARGZ (create_sep (fs->mntent.mnt_opts, ',', &mntopts, &mntopts_len));
+
+ /* Remove the `noauto' option, since it's for us not the filesystem. */
+ for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o))
+ if (!strcmp (o, MNTOPT_NOAUTO))
+ break;
+ if (o)
+ argz_delete (&mntopts, &mntopts_len, o);
+
+ ARGZ (append (&mntopts, &mntopts_len, options, options_len));
+ }
+ else
+ {
+ mntopts = options;
+ mntopts_len = options_len;
+ }
+
+ /* Convert the list of options into a list of switch arguments. */
+ fsopts = 0;
+ fsopts_len = 0;
+ for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o))
+ if (*o == '-') /* Allow letter opts `-o -r,-E', BSD style. */
+ {
+ ARGZ (add (&fsopts, &fsopts_len, o));
+ }
+ else if (strcmp (o, "defaults") != 0)
+ {
+ /* Prepend `--' to the option to make a long option switch,
+ e.g. `--ro' or `--rsize=1024'. */
+ char arg[2 + strlen (o) + 1];
+ arg[0] = arg[1] = '-';
+ memcpy (&arg[2], o, sizeof arg - 2);
+ ARGZ (add (&fsopts, &fsopts_len, arg));
+ }
+
+ if (mntopts != options)
+ free (mntopts);
+#undef ARGZ
+
+ if (remount)
+ {
+ if (mounted == MACH_PORT_NULL)
+ {
+ error (0, 0, "%s not already mounted", fs->mntent.mnt_fsname);
+ return EBUSY;
+ }
+
+ /* Send an RPC to request the new options, including --update. */
+ explain ("fsysopts");
+ err = fsys_set_options (mounted, fsopts, fsopts_len, 0);
+ if (err)
+ error (0, err, "cannot remount %s", fs->mntent.mnt_fsname);
+ return err;
+ }
+ else
+ {
+ /* Error during file lookup; we use this to avoid duplicating error
+ messages. */
+ error_t open_err = 0;
+ /* The control port for any active translator we start up. */
+ fsys_t active_control;
+ file_t node; /* Port to the underlying node. */
+ struct fstype *type;
+
+ /* The callback to start_translator opens NODE as a side effect. */
+ error_t open_node (int flags,
+ mach_port_t *underlying,
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
+ {
+ node = file_name_lookup (fs->mntent.mnt_dir,
+ flags | O_NOTRANS, 0666);
+ if (node == MACH_PORT_NULL)
+ {
+ open_err = errno;
+ return open_err;
+ }
+
+ *underlying = node;
+ *underlying_type = MACH_MSG_TYPE_COPY_SEND;
+
+ return 0;
+ }
+
+ if (mounted != MACH_PORT_NULL)
+ {
+ error (0, 0, "%s already mounted", fs->mntent.mnt_fsname);
+ return EBUSY;
+ }
+
+ err = fs_type (fs, &type);
+ if (err)
+ {
+ error (0, err, "%s: cannot determine filesystem type",
+ fs->mntent.mnt_fsname);
+ return err;
+ }
+ if (type->program == 0)
+ {
+ error (0, 0, "%s: filesystem type `%s' unknown",
+ fs->mntent.mnt_fsname, type->name);
+ return EFTYPE;
+ }
+
+ /* Stick the translator program name in front of the option switches. */
+ err = argz_insert (&fsopts, &fsopts_len, fsopts, type->program);
+ /* Now stick the device name on the end as the last argument. */
+ if (!err)
+ err = argz_add (&fsopts, &fsopts_len, fs->mntent.mnt_fsname);
+ if (err)
+ error (3, ENOMEM, "collecting mount options");
+
+ /* Now we have a translator command line argz in FSOPTS. */
+
+ explain ("settrans -a");
+ err = fshelp_start_translator (open_node, NULL, fsopts,
+ fsopts, fsopts_len, timeout,
+ &active_control);
+ /* If ERR is due to a problem opening the translated node, we print
+ that name, otherwise, the name of the translator. */
+ if (open_err)
+ error (0, open_err, "cannot mount on %s", fs->mntent.mnt_dir);
+ else if (err)
+ error (0, err, "cannot start translator %s", fsopts);
+ else
+ {
+ err = file_set_translator (node, 0, FS_TRANS_SET|FS_TRANS_EXCL, 0,
+ 0, 0,
+ active_control, MACH_MSG_TYPE_COPY_SEND);
+ if (err == EBUSY)
+ error (0, 0, "%s already mounted on", fs->mntent.mnt_dir);
+ else if (err)
+ error (0, err, "cannot set translator on %s", fs->mntent.mnt_dir);
+ if (err)
+ fsys_goaway (active_control, FSYS_GOAWAY_FORCE);
+ mach_port_deallocate (mach_task_self (), active_control);
+ }
+
+ return err;
+ }
+}
+
+/* Report the state of one filesystem to stdout. */
+static error_t
+do_query (struct fs *fs)
+{
+ error_t err;
+ fsys_t fsys;
+ char _opts[200], *opts = _opts;
+ size_t opts_len = sizeof opts;
+ size_t nopts;
+
+ err = fs_fsys (fs, &fsys);
+ if (err)
+ return err;
+
+ if (fsys == MACH_PORT_NULL)
+ /* This filesystem is not mounted. Nothing to report. */
+ return 0;
+
+ err = fsys_get_options (fsys, &opts, &opts_len);
+ if (err)
+ {
+ error (0, err, "%s: cannot get filesystem options",
+ fs->mntent.mnt_fsname);
+ return err;
+ }
+
+ nopts = argz_count (opts, opts_len);
+ if (nopts == 0)
+ {
+ error (0, 0, "%s: fsys_get_options returned empty string",
+ fs->mntent.mnt_dir);
+ return EGRATUITOUS;
+ }
+
+ if (query_format == qf_translator)
+ {
+ argz_stringify (opts, opts_len, ' ');
+ printf ("%s: %s\n", fs->mntent.mnt_dir, opts);
+ }
+ else
+ {
+ char *argv[nopts];
+ const char *prog, *device;
+
+ inline const char *fsopt_string (const char *opt) /* canonicalize */
+ {
+ if (opt[0] == '-' && opt[1] == '-')
+ {
+ opt += 2;
+ if (!strcmp (opt, "readonly"))
+ return "ro";
+ if (!strcmp (opt, "writable"))
+ return "rw";
+ }
+ else
+ {
+ if (!strcmp (opt, "-r"))
+ return "ro";
+ if (!strcmp (opt, "-w"))
+ return "rw";
+ }
+ return opt;
+ }
+ inline void print_prog (const char *sfx)
+ {
+ if (!strncmp (_HURD, prog, sizeof _HURD - 1))
+ {
+ const char *type = &prog[sizeof _HURD - 1];
+ size_t len = strlen (type);
+ if (!strcmp (&type[len - 2], "fs"))
+ printf ("%.*s%s", (int) (len - 2), type, sfx);
+ else
+ printf ("%s%s", type, sfx);
+ }
+ else
+ printf ("%s%s", prog, sfx);
+ }
+ inline int print_opts (char sep)
+ {
+ char *opt = argz_next (opts, opts_len, prog);
+ if (opt == 0)
+ return 0;
+ fputs (fsopt_string (opt), stdout);
+ while ((opt = argz_next (opts, opts_len, opt)) != 0)
+ printf ("%c%s", sep, fsopt_string (opt));
+ return 1;
+ }
+
+ argz_extract (opts, opts_len, argv);
+ prog = argv[0];
+
+ if (nopts < 2)
+ device = fs->mntent.mnt_fsname;
+ else
+ {
+ static const char type_opt[] = "--store-type=";
+ device = argv[--nopts];
+ opts_len -= strlen (device) + 1;
+ if (!strncmp (type_opt, argv[nopts - 1], sizeof type_opt - 1))
+ {
+ asprintf ((char **) &device, "%s:%s",
+ &argv[nopts - 1][sizeof type_opt - 1], device);
+ opts_len -= strlen (argv[nopts - 1]) + 1;
+ }
+ }
+
+ switch (query_format)
+ {
+ case qf_standard:
+ printf ("%s on %s type ", device, fs->mntent.mnt_dir);
+ print_prog (" (");
+ if (print_opts (','))
+ puts (")");
+ else
+ puts ("defaults)");
+ break;
+
+ case qf_fstab:
+ printf ("%s\t%s\t", device, fs->mntent.mnt_dir);
+ print_prog ("\t");
+ printf ("%s\t%d %d\n",
+ print_opts (',') ? "" : "defaults",
+ fs->mntent.mnt_freq, fs->mntent.mnt_passno);
+ break;
+
+ case qf_translator: /* impossible */
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ unsigned int remount;
+ struct fstab *fstab;
+ struct fs *fs;
+ error_t err;
+
+ argp_parse (&argp, argc, argv, 0, 0, &fstab_params);
+
+ if (!mountpoint && (fstab_params.types == 0
+
+ || !strncasecmp (fstab_params.types, "no", 2)))
+ {
+ /* Always add the type "swap" to the list of types to exclude. */
+ err = argz_add (&fstab_params.types, &fstab_params.types_len,
+ "no"MNTTYPE_SWAP);
+ if (err)
+ error (3, ENOMEM, "parsing arguments");
+ }
+
+ fstab = fstab_argp_create (&fstab_params, SEARCH_FMTS, sizeof SEARCH_FMTS);
+
+ if (device) /* two-argument form */
+ {
+ struct mntent m =
+ {
+ mnt_fsname: device,
+ mnt_dir: mountpoint,
+ mnt_type: fstype,
+ mnt_opts: 0,
+ mnt_freq: 0, mnt_passno: 0
+ };
+ struct fstype *fst;
+
+ err = fstypes_get (fstab->types, fstype, &fst);
+ if (err)
+ error (106, err, "cannot initialize type %s", fstype);
+ if (fst->program == 0)
+ error (2, 0, "filesystem type %s not recognized", fstype);
+
+ err = fstab_add_mntent (fstab, &m, &fs);
+ if (err)
+ error (2, err, "%s", mountpoint);
+ }
+ else if (mountpoint) /* one-argument form */
+ {
+ fs = fstab_find (fstab, mountpoint);
+ if (!fs)
+ error (2, 0, "%s: Unknown device or filesystem", mountpoint);
+ }
+ else
+ fs = 0;
+
+ /* This is a convenient way of checking for any `remount' options. */
+ remount = 0;
+ err = argz_replace (&options, &options_len, "remount", "update", &remount);
+ if (err)
+ error (3, ENOMEM, "collecting mount options");
+
+ if (fs != 0)
+ err = do_mount (fs, remount);
+ else
+ switch (mode)
+ {
+ case mount:
+ for (fs = fstab->entries; fs; fs = fs->next)
+ {
+ if (fstab_params.do_all && hasmntopt (&fs->mntent, MNTOPT_NOAUTO))
+ continue;
+ err |= do_mount (fs, remount);
+ }
+ break;
+
+ case query:
+ for (fs = fstab->entries; fs; fs = fs->next)
+ err |= do_query (fs);
+ break;
+ }
+
+ return err ? 1 : 0;
+}
diff --git a/utils/mount.sh b/utils/mount.sh
deleted file mode 100755
index a403b8d8..00000000
--- a/utils/mount.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/sh
-#
-# A simple version of mount for the hurd
-#
-
-usage="Usage: $0: [ -rnv | -o DEVOPTS | -t TYPE | -f FSTAB ] ( DEVICE NODE | DEVICE | NODE )"
-
-PATH=/bin
-
-default_type=ufs
-type=""
-fstab=/etc/fstab
-exec=true
-echo=false
-
-while :; do
- case $1 in
- -v) echo=true; margs="$margs -v"; shift;;
- -n) exec=false; margs="$margs -n"; shift;;
- -r) targs="$targs -r"; shift;;
- -t) case "$type" in
- ""|"$2") type="$2"; shift 2; margs="$margs -t $type";;
- *) echo 1>&2 $0: "$2": Filesystem type inconsistent with "$type"
- exit 7;;
- esac;;
- -f) fstab=$2; shift 2;;
- -o) targs="$targs $2"; shift 2;;
- -*) echo 1>&2 $0: $1: unknown flag; echo 1>&2 "$usage"; exit 1;;
- *) break;;
- esac
-done
-
-case "$targs" in ?*)
- # We embed quotes so that spaces are preserved in targs later on
- margs="$margs -o \"$targs\""
-esac
-
-case $# in
- 1)
- # Lookup the given single arg in /etc/fstab for the rest of the args
- args=`gawk -f - $fstab <<END
-\\$1 == "$1" || \\$2 == "$1" {
- for (i = 4; i <= NF; i++)
- printf("%s ", \\$i);
- printf("-t %s %s %s", \\$3, \\$1, \\$2);
- exit(0);
-}
-END
-`
- case "$args" in
- "") echo 1>&2 $0: $1: not found in $fstab; exit 3;;
- *) eval $0 $margs $args;;
- esac
- ;;
-
- 2)
- # Do the mount, by putting an active translator on the node
-
- case "$type" in "") type="$default_type";; esac
-
- if [ ! -x /hurd/$type ]; then
- echo 1>&2 $0: $type: unknown filesystem type
- exit 1
- fi
-
- $echo && echo settrans -a $2 /hurd/$type $targs $1
- $exec && settrans -a $2 /hurd/$type $targs $1
- ;;
-
- *)
- echo 1>&2 "$usage"; exit 1
- ;;
-esac
diff --git a/utils/msgport.c b/utils/msgport.c
new file mode 100644
index 00000000..06b7dc37
--- /dev/null
+++ b/utils/msgport.c
@@ -0,0 +1,661 @@
+/* Send messages to selected processes
+
+ Copyright (C) 1998,99,2000,02 Free Software Foundation, Inc.
+ Written by Jose M. Moya <josem@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+#include "pids.h"
+#include <sys/mman.h>
+
+/* From libc (not in hurd.h) */
+char *
+_hurd_canonicalize_directory_name_internal (file_t thisdir,
+ char *buf,
+ size_t size);
+
+const char *argp_program_version = STANDARD_HURD_VERSION (msgport);
+
+static const struct argp_option options[] =
+{
+ {0, 0}
+};
+
+static const char doc[] =
+"Send messages to selected processes";
+
+static const char args_doc[] =
+"";
+
+
+
+/* All command functions match this prototype. */
+typedef error_t (*cmd_func_t) (pid_t pid, mach_port_t msgport,
+ int argc, char *argv[]);
+
+/* One of these is created for each command given in the command line. */
+typedef struct cmd {
+ /* Function to execute for this command */
+ cmd_func_t f;
+
+ /* Array of arguments that will be passed to function F */
+ char **args;
+ size_t num_args;
+} cmd_t;
+
+
+/* Execute command CMD on process PID */
+error_t
+do_cmd (pid_t pid, cmd_t cmd)
+{
+ error_t err;
+ mach_port_t msgport;
+ process_t proc = getproc ();
+
+ /* Get a msgport for PID, to which we can send requests. */
+ err = proc_getmsgport (proc, pid, &msgport);
+ if (err)
+ error (1, err, "%d: Cannot get process msgport", pid);
+
+ err = (*cmd.f) (pid, msgport, cmd.num_args, cmd.args);
+ if (err)
+ error (2, err, "%d: Cannot execute command", pid);
+
+ mach_port_deallocate (mach_task_self (), msgport);
+ return 0;
+}
+
+
+/* All these functions, whose name start with cmd_, execute some
+ commands on the process PID, by sending messages (see msg.defs) to
+ its message port, which is MSGPORT. ARGC and ARGV are as in main.
+ They return zero iff successful. */
+
+/* Print the name and value of the environment variable ARGV[0].
+ Without arguments (ARGC==0), print the names and values of all
+ environment variables. */
+error_t
+cmd_getenv (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+
+ /* Memory will be vm_allocated by msg_get_* if the result does not
+ fit in buf. */
+ char buf[1024], *data = buf;
+ mach_msg_type_number_t len = sizeof (buf);
+
+ if (argc)
+ {
+ err = msg_get_env_variable (msgport, argv[0], &data, &len);
+ if (err)
+ return err;
+ printf ("%d: %s=%s\n", pid, argv[0], data);
+ }
+ else /* get the whole environment */
+ {
+ char *p;
+ err = msg_get_environment (msgport, &data, &len);
+ if (err)
+ return err;
+ for (p=data; p < data + len; p = strchr (p, '\0') + 1)
+ printf ("%d: %s\n", pid, p);
+ }
+ if (data != buf)
+ munmap (data, len);
+ return err;
+}
+
+/* Set environment variable ARGV[0] to the value ARGV[1]. */
+error_t
+cmd_setenv (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_set_env_variable (msgport, task, argv[0], argv[1], 1);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Clear environment. */
+error_t
+cmd_clearenv (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_set_environment (msgport, task, 0, 0);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Convert string STR in flags for file access modes. STR should be a
+ combination of `r', `w' and `x' (for read, write and execute modes
+ respectively). Other chars are ignored. */
+static inline int
+str2flags (const char *str)
+{
+ int flags = 0;
+ while (*str)
+ {
+ switch (*str)
+ {
+ case 'r': flags |= O_RDONLY; break;
+ case 'w': flags |= O_WRONLY|O_CREAT; break;
+ case 'x': flags |= O_EXEC; break;
+ case 'a': flags |= O_APPEND; break;
+ default:
+ /* ignore */
+ break;
+ }
+ ++str;
+ }
+ return flags;
+}
+
+/* Set port associated to file descriptor FD of process PID, whose
+ message port is MSGPORT, to FILE. Used by
+ cmd_{setfd,stdin,stdout,stderr}. */
+error_t
+do_setfd (pid_t pid, mach_port_t msgport, size_t fd, file_t file)
+{
+ error_t err;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_set_fd (msgport, task, fd, file, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), file);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Set port associated to file descriptor ARGV[0] to the file ARGV[1].
+ File access mode is given by ARGV[2] (see str2flags). If no access
+ mode is given, the default is O_RDONLY. */
+error_t
+cmd_setfd (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "r");
+ file_t file = file_name_lookup (argv[1], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, atoi (argv[0]), file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Set standard input to ARGV[0]. Optionally, ARGV[1] may specify the
+ file access mode (see str2flags). The default is O_RDONLY */
+error_t
+cmd_stdin (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "r");
+ file_t file = file_name_lookup (argv[0], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, STDIN_FILENO, file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Set standard output to ARGV[0]. Optionally, ARGV[1] may specify the
+ file access mode (see str2flags). The default is O_WRONLY */
+error_t
+cmd_stdout (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "w");
+ file_t file = file_name_lookup (argv[0], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, STDOUT_FILENO, file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Set standard error to ARGV[0]. Optionally, ARGV[1] may specify the
+ file access mode (see str2flags). The default is O_RDONLY */
+error_t
+cmd_stderr (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "w");
+ file_t file = file_name_lookup (argv[0], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, STDERR_FILENO, file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Change current working directory to ARGV[0]. */
+error_t
+cmd_chcwdir (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ dir = file_name_lookup (argv[0], 0, 0);
+ if (dir == MACH_PORT_NULL)
+ return errno;
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), dir);
+ return err;
+ }
+ err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Change current working directory to current root directory. */
+error_t
+cmd_cdroot (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+ }
+ err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Change current root directory to ARGV[0]. */
+error_t
+cmd_chcrdir (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ dir = file_name_lookup (argv[0], 0, 0);
+ if (dir == MACH_PORT_NULL)
+ return errno;
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), dir);
+ return err;
+ }
+ err = msg_set_init_port (msgport, task, INIT_PORT_CRDIR, dir,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Print current working directory. */
+error_t
+cmd_pwd (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_get_init_port (msgport, task, INIT_PORT_CWDIR, &dir);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+ }
+ printf ("%d: %s\n", pid,
+ _hurd_canonicalize_directory_name_internal(dir, NULL, 0));
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return 0;
+}
+
+/* Print current root directory */
+error_t
+cmd_getroot (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+ }
+ printf ("%d: %s\n", pid,
+ _hurd_canonicalize_directory_name_internal(dir, NULL, 0));
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return 0;
+}
+
+/* Change umask to ARGV[0] (octal value). Without arguments, print
+ the value of current umask. */
+error_t
+cmd_umask (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ mode_t umask;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ if (argc)
+ {
+ umask = strtol(argv[0], 0, 8);
+ err = msg_set_init_int (msgport, task, INIT_UMASK, umask);
+ }
+ else
+ {
+ err = msg_get_init_int (msgport, task, INIT_UMASK, &umask);
+ if (!err)
+ printf ("%d: %03o\n", pid, umask);
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+
+#define OA OPTION_ARG_OPTIONAL
+
+#define CMD_GETENV 1000
+#define CMD_SETENV 1001
+#define CMD_CLRENV 1002
+#define CMD_CHCWDIR 1003
+#define CMD_CHCRDIR 1004
+#define CMD_CDROOT 1005
+#define CMD_UMASK 1006
+#define CMD_SETFD 1007
+#define CMD_STDIN 1008
+#define CMD_STDOUT 1009
+#define CMD_STDERR 1010
+#define CMD_PWD 1011
+#define CMD_GETROOT 1012
+
+/* Params to be passed as the input when parsing CMDS_ARGP. */
+struct cmds_argp_params
+{
+ /* Array to be extended with parsed cmds. */
+ cmd_t **cmds;
+ size_t *num_cmds;
+};
+
+static const struct argp_option cmd_options[] =
+{
+ {"getenv", CMD_GETENV, "VAR", OA, "Get environment variable"},
+ {"printenv", 0, 0, OPTION_ALIAS},
+ {"setenv", CMD_SETENV, "VAR VALUE", 0, "Set environment variable"},
+ {"clearenv", CMD_CLRENV, 0, 0, "Clear environment"},
+ {"pwd", CMD_PWD, 0, 0, "Print current working directory"},
+ {"getcwd", 0, 0, OPTION_ALIAS},
+ {"getroot", CMD_GETROOT,0, 0, "Print current root directory"},
+ {"setfd", CMD_SETFD, "FD FILE [rwxa]", 0, "Change file descriptor"},
+ {"stdin", CMD_STDIN, "FILE [rwxa]", 0, "Change standard input"},
+ {"stdout", CMD_STDOUT, "FILE [rwxa]", 0, "Change standard output"},
+ {"stderr", CMD_STDERR, "FILE [rwxa]", 0, "Change standard error"},
+ {"chdir", CMD_CHCWDIR,"DIR", 0, "Change current working directory"},
+ {"cd", 0, 0, OPTION_ALIAS},
+ {"chroot", CMD_CHCRDIR,"DIR", 0, "Change current root directory"},
+ {"cdroot", CMD_CDROOT, 0, 0, "Change cwd to root directory"},
+ {"umask", CMD_UMASK, "MASK", OA, "Change umask"},
+ {0, 0}
+};
+
+/* Add a new command to the array of commands already parsed
+ reallocating it in malloced memory. FUNC is the command function.
+ MINARGS and MAXARGS are the minimum and maximum number of arguments
+ the parser will accept for this command. Further checking of the
+ arguments should be done in FUNC. ARG is the next argument in the
+ command line (probably the first argument for this command). STATE
+ is the argp parser state as used in parse_cmd_opt. */
+static error_t
+add_cmd (cmd_func_t func, size_t minargs, size_t maxargs,
+ char *arg, struct argp_state *state)
+{
+ cmd_t *cmd;
+ size_t i = 0;
+
+ struct cmds_argp_params *params = state->input;
+ size_t num_cmds = *params->num_cmds + 1;
+ cmd_t *cmds = realloc (*params->cmds, num_cmds * sizeof(cmd_t));
+
+ *params->cmds = cmds;
+ *params->num_cmds = num_cmds;
+
+ cmd = &cmds[num_cmds-1];
+ cmd->f = func;
+ cmd->args = 0;
+ if (maxargs)
+ {
+ cmd->args = malloc (maxargs * sizeof (char *));
+ if (arg)
+ cmd->args[i++] = arg;
+ while (i < maxargs
+ && state->argv[state->next]
+ && state->argv[state->next][0] != '-')
+ cmd->args[i++] = state->argv[state->next++];
+ }
+ if (i < minargs || i > maxargs)
+ argp_usage(state);
+ cmd->num_args = i;
+ return 0;
+}
+
+/* Parse one option/arg for the argp parser cmds_argp (see argp.h). */
+static error_t
+parse_cmd_opt (int key, char *arg, struct argp_state *state)
+{
+ /* A buffer used for rewriting command line arguments without dashes
+ for the parser to understand them. It gets realloced for each
+ successive arg that needs it, on the assumption that args don't
+ get parsed multiple times. */
+ static char *arg_hack_buf = 0;
+ switch (key)
+ {
+ case ARGP_KEY_ARG: /* Non-option argument. */
+ if (!isdigit (*arg) && !state->quoted)
+ {
+ /* Make state->next point to the just parsed argument to
+ re-parse it with 2 dashes prepended. */
+ size_t len = strlen (arg) + 1;
+ arg_hack_buf = realloc (arg_hack_buf, 2 + len);
+ state->argv[--state->next] = arg_hack_buf;
+ state->argv[state->next][0] = '-';
+ state->argv[state->next][1] = '-';
+ memcpy (&state->argv[state->next][2], arg, len);
+ break;
+ }
+ else
+ return ARGP_ERR_UNKNOWN;
+ case CMD_CHCWDIR:
+ add_cmd (&cmd_chcwdir, 0, 1, arg, state);
+ break;
+ case CMD_CHCRDIR:
+ add_cmd (&cmd_chcrdir, 1, 1, arg, state);
+ break;
+ case CMD_CDROOT:
+ add_cmd (&cmd_cdroot, 0, 0, arg, state);
+ break;
+ case CMD_PWD:
+ add_cmd (&cmd_pwd, 0, 0, arg, state);
+ break;
+ case CMD_GETROOT:
+ add_cmd (&cmd_getroot, 0, 0, arg, state);
+ break;
+ case CMD_UMASK:
+ add_cmd (&cmd_umask, 0, 1, arg, state);
+ break;
+ case CMD_GETENV:
+ add_cmd (&cmd_getenv, 0, 1, arg, state);
+ break;
+ case CMD_SETENV:
+ add_cmd (&cmd_setenv, 2, 2, arg, state);
+ break;
+ case CMD_CLRENV:
+ add_cmd (&cmd_clearenv, 0, 0, arg, state);
+ break;
+ case CMD_SETFD:
+ add_cmd (&cmd_setfd, 2, 3, arg, state);
+ break;
+ case CMD_STDIN:
+ add_cmd (&cmd_stdin, 1, 2, arg, state);
+ break;
+ case CMD_STDOUT:
+ add_cmd (&cmd_stdout, 1, 2, arg, state);
+ break;
+ case CMD_STDERR:
+ add_cmd (&cmd_stderr, 1, 2, arg, state);
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Filtering of help output strings for cmds_argp parser. Return a
+ malloced replacement for TEXT as the arguments doc string. See
+ argp.h for details. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ if (key == ARGP_KEY_HELP_ARGS_DOC)
+ return strdup ("CMD [ARG...]");
+
+ return (char *)text;
+}
+
+/* An argp parser for selecting a command (see argp.h). */
+struct argp cmds_argp = { cmd_options, parse_cmd_opt, 0, 0, 0, help_filter };
+
+
+
+int
+main(int argc, char *argv[])
+{
+ cmd_t *cmds = 0;
+ size_t num_cmds = 0;
+ struct cmds_argp_params cmds_argp_params = { &cmds, &num_cmds };
+ pid_t *pids = 0; /* User-specified pids. */
+ size_t num_pids = 0;
+ struct pids_argp_params pids_argp_params = { &pids, &num_pids, 0 };
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ state->child_inputs[0] = &cmds_argp_params;
+ state->child_inputs[1] = &pids_argp_params;
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (!num_cmds || !num_pids)
+ argp_usage (state);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+
+ struct argp_child argp_kids[] =
+ { { &cmds_argp, 0,
+ "Commands:", 2},
+ { &pids_argp, 0,
+ "Process selection:", 3},
+ {0} };
+
+ struct argp argp = { options, parse_opt, args_doc, doc, argp_kids };
+
+ error_t err;
+ pid_t cur_pid = getpid ();
+ pid_t pid;
+ cmd_t cmd;
+ size_t i, j;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ for (i = 0; i < num_pids; ++i)
+ {
+ pid = pids[i];
+ if (pid != cur_pid)
+ for (j = 0; j < num_cmds; ++j)
+ {
+ cmd = cmds[j];
+ if ((err = do_cmd (pid, cmd)))
+ error (2, err, "%d: Cannot execute command", pid);
+ }
+ }
+
+ exit (0);
+}
diff --git a/utils/nonsugid.c b/utils/nonsugid.c
new file mode 100644
index 00000000..71cd3d71
--- /dev/null
+++ b/utils/nonsugid.c
@@ -0,0 +1,63 @@
+/* Get our ids, minus any setuid result
+
+ Copyright (C) 1995,96,97,2000 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <errno.h>
+#include <idvec.h>
+#include <hurd.h>
+
+/* Make sure that the [UG]IDS are filled in. To make them useful for
+ su'ing, each is the avail ids with the saved set-ID removed, and all
+ effective ids but the first appended; this gets rid of the effect of
+ being suid, and is useful as a new process's avail id list (e.g., the
+ real id is right). */
+error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids)
+{
+ if (uids->num == 0 && gids->num == 0)
+ {
+ error_t err = 0;
+ static auth_t auth = MACH_PORT_NULL;
+ struct idvec *p_eff_uids = make_idvec ();
+ struct idvec *p_eff_gids = make_idvec ();
+
+ if (!p_eff_uids || !p_eff_gids)
+ err = ENOMEM;
+
+ if (auth == MACH_PORT_NULL)
+ auth = getauth ();
+
+ if (! err)
+ err = idvec_merge_auth (p_eff_uids, uids, p_eff_gids, gids, auth);
+ if (! err)
+ {
+ idvec_delete (p_eff_uids, 0); /* Remove effective ID from setuid. */
+ idvec_delete (p_eff_gids, 0);
+ idvec_delete (uids, 1); /* Remove saved set-ID from setuid. */
+ idvec_delete (gids, 1);
+ if (! err)
+ err = idvec_merge (uids, p_eff_uids);
+ if (! err)
+ err = idvec_merge (gids, p_eff_gids);
+ }
+
+ return err;
+ }
+ else
+ return 0;
+}
diff --git a/utils/old-ps.c b/utils/old-ps.c
deleted file mode 100644
index 5dac7854..00000000
--- a/utils/old-ps.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- Copyright (C) 1994 Free Software Foundation
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-
-/* return a string describing the amount of memory SIZE represents. */
-char *
-mem_str (vm_size_t size)
-{
- char *ret = malloc (10);
- char *spec=" KMG";
- int dec = 0;
-
- while (size > 1000)
- {
- dec = size % 1000;
- size /= 1000;
- spec++;
- }
-
- if (size >= 100)
- sprintf (ret, "%d%c", size, *spec);
- else if (size >= 10)
- sprintf (ret, "%d.%d%c", size, dec / 100, *spec);
- else
- sprintf (ret, "%d.%d%c", size, dec / 10, *spec);
-
- return ret;
-}
-
-/* Return a string representing time T. */
-char *
-time_str (time_value_t *t)
-{
- char *ret = malloc (20);
- int centiseconds;
-
- if (t->microseconds >= 1000000)
- {
- t->seconds += t->microseconds / 1000000;
- t->microseconds %= 1000000;
- }
- centiseconds = t->microseconds / (1000000 / 100);
-
- sprintf (ret, "%d:%02d.%02d",
- t->seconds / 60, /* minutes */
- t->seconds % 60, /* seconds */
- centiseconds);
- return ret;
-}
-
-/* Print a string describing the args of proc PID */
-void
-print_args_str (process_t proc, pid_t pid)
-{
- char *args;
- u_int nargs = 0;
- char *p;
- error_t err;
-
- err = proc_getprocargs (proc, pid, &args, &nargs);
- if (err)
- return;
- p = args;
- while (p - args < nargs)
- {
- printf ("%s ", p);
- p = strchr (p, '\0') + 1;
- }
- vm_deallocate (mach_task_self (), (vm_address_t) args, nargs);
-}
-
-/* Very simple PS */
-int
-main (int argc, char **argv)
-{
- process_t proc;
- pid_t pids[20];
- pid_t *pp = pids;
- u_int npids = 20;
- int ind;
- struct thread_basic_info tbi;
- struct thread_sched_info tsi;
- int verbose;
-
-#if 0
- stdout = mach_open_devstream (getdport (1), "w");
-#endif
-
- if (argc > 2 ||
- (argc == 2 && (argv[1][0] != '-' || argv[1][1] != 'v' || argv[1][2])))
- {
- fprintf (stderr, "Usage: %s [-v]\n", argv[0]);
- exit (1);
- }
- verbose = argc == 2;
-
- if (verbose)
- puts ("PID\tUSER\tPP\tPG\tSS\tThds\tVMem\tRSS\tPRI\t%CPU\tUser\tSystem\tArgs");
- else
- puts ("PID\tUSER\tThds\tVMem\tRSS\tUser\tSystem\tArgs");
- proc = getproc ();
- proc_getallpids (proc, &pp, &npids);
- for (ind = 0; ind < npids; ind++)
- {
- int procinfobuf[0];
- struct procinfo *pi = (struct procinfo *) procinfobuf;
- u_int pisize = 0;
- int i;
-
- proc_getprocinfo (proc, pp[ind], (int **)&pi, &pisize);
-
- if (pi->state & PI_NOPARENT)
- continue;
-
- bzero (&tbi, sizeof tbi);
- bzero (&tsi, sizeof tsi);
- for (i = 0; i < pi->nthreads; i++)
- {
- tsi.base_priority += pi->threadinfos[i].pis_si.base_priority;
- tsi.cur_priority += pi->threadinfos[i].pis_si.cur_priority;
- tbi.cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;
- tbi.user_time.seconds += pi->threadinfos[i].pis_bi.user_time.seconds;
- tbi.user_time.microseconds
- += pi->threadinfos[i].pis_bi.user_time.microseconds;
- tbi.system_time.seconds
- += pi->threadinfos[i].pis_bi.system_time.seconds;
- tbi.system_time.microseconds
- += pi->threadinfos[i].pis_bi.system_time.microseconds;
- }
- tsi.base_priority /= pi->nthreads;
- tsi.cur_priority /= pi->nthreads;
- tbi.user_time.seconds += tbi.user_time.microseconds / 1000000;
- tbi.user_time.microseconds %= 1000000;
- tbi.system_time.seconds += tbi.system_time.microseconds / 1000000;
- tbi.system_time.microseconds %= 1000000;
- if (verbose)
- printf ("%d\t%d\t%d\t%d\t%d\t%d\t%s\t%s\t%d/%d\t%d\t%s\t%s\t",
- pp[ind],
- (pi->state & PI_NOTOWNED) ? -1 : pi->owner,
- pi->ppid,
- pi->pgrp,
- pi->session,
- pi->nthreads,
- mem_str (pi->taskinfo.virtual_size),
- mem_str (pi->taskinfo.resident_size),
- tsi.base_priority,
- tsi.cur_priority,
- tbi.cpu_usage,
- time_str (&tbi.user_time),
- time_str (&tbi.system_time));
- else
- printf ("%d\t%d\t%d\t%s\t%s\t%s\t%s\t",
- pp[ind],
- (pi->state & PI_NOTOWNED) ? -1 : pi->owner,
- pi->nthreads,
- mem_str (pi->taskinfo.virtual_size),
- mem_str (pi->taskinfo.resident_size),
- time_str (&tbi.user_time),
- time_str (&tbi.system_time));
- print_args_str (proc, pp[ind]);
- putchar ('\n');
- }
- return 0;
-}
diff --git a/utils/old-settrans.c b/utils/old-settrans.c
deleted file mode 100644
index 4d1ba167..00000000
--- a/utils/old-settrans.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Set a passive translator on a file
- Copyright (C) 1994 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <fcntl.h>
-
-int
-main (int argc, char **argv)
-{
- /* This is pretty kludgy for now. */
- mach_port_t file;
-
- char *buf, *bp;
- int buflen;
- int i;
-
- if (argc < 2)
- {
- fprintf (stderr, "\
-Usage: %s FILE TRANSLATOR [ARG ...]\n\
- or: %s FILE -show\n", argv[0], argv[0]);
- exit (1);
- }
-
- /* Use the O_NOTRANS flag so that we replace any existing
- translator rather than piggybacking on top of it. */
- file = file_name_lookup (argv[1], O_NOTRANS, 0);
- if (file == MACH_PORT_NULL)
- {
- perror (argv[1]);
- exit (1);
- }
-
- if (argc == 3 && !strcmp (argv[2], "-show"))
- {
- char buf[1024], *trans = buf;
- unsigned int len = sizeof buf;
- errno = file_get_translator (file, &trans, &len);
- if (errno)
- {
- perror ("file_get_translator");
- exit (1);
- }
- printf ("%s translated by:", argv[1]);
- do
- {
- char *next;
- printf (" %.*s", (int) len, trans);
- next = memchr (trans, '\0', len);
- if (! next)
- {
- printf ("<unterminated>");
- break;
- }
- len -= ++next - trans;
- trans = next;
- } while (len > 0);
- putchar ('\n');
- exit (0);
- }
-
- buflen = 0;
- for (i = 2; i < argc; i++)
- buflen += strlen (argv[i]) + 1;
-
- bp = buf = alloca (buflen);
-
- for (i = 2; i < argc; i++)
- bp = stpcpy (bp, argv[i]) + 1;
-
- errno = file_set_translator (file, FS_TRANS_SET, 0, 0,
- buf, buflen, MACH_PORT_NULL,
- MACH_MSG_TYPE_COPY_SEND);
- if (errno != 0)
- {
- perror ("Setting translator");
- exit (1);
- }
-
- exit (0);
-}
-
-
-
diff --git a/utils/parse.c b/utils/parse.c
new file mode 100644
index 00000000..5334dbda
--- /dev/null
+++ b/utils/parse.c
@@ -0,0 +1,185 @@
+/* Random helpful option parsing functions
+
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <error.h>
+
+#include "parse.h"
+
+/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
+ empty and DEFAULT_ADD_FN isn't NULL, then call DEFAULT_ADD_FN instead. */
+error_t
+_parse_strlist (char *arg,
+ error_t (*add_fn)(const char *str, struct argp_state *state),
+ error_t (*default_add_fn)(struct argp_state *state),
+ const char *type_name, struct argp_state *state)
+{
+ if (arg)
+ while (isspace(*arg))
+ arg++;
+
+ if (arg == NULL || *arg == '\0')
+ if (default_add_fn)
+ return (*default_add_fn)(state);
+ else
+ {
+ argp_error (state, "Empty %s list", type_name);
+ return EINVAL;
+ }
+ else
+ {
+ error_t err = 0;
+ char *end = arg;
+
+ void mark_end()
+ {
+ *end++ = '\0';
+ while (isspace(*end))
+ end++;
+ }
+ error_t parse_element()
+ {
+ char *cur = arg;
+ if (*cur == '\0')
+ {
+ argp_error (state, "Empty element in %s list", type_name);
+ return EINVAL;
+ }
+ arg = end;
+ return (*add_fn)(cur, state);
+ }
+
+ while (*end != '\0' && !err)
+ switch (*end)
+ {
+ case ' ': case '\t':
+ mark_end();
+ if (*end == ',')
+ mark_end();
+ err = parse_element();
+ break;
+ case ',':
+ mark_end();
+ err = parse_element();
+ break;
+ default:
+ end++;
+ }
+
+ if (! err)
+ err = parse_element();
+
+ return err;
+ }
+}
+
+/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
+ empty and DEFAULT_FN isn't NULL, then call ADD_FN on the resutl of calling
+ DEFAULT_FN instead, otherwise signal an error. */
+error_t
+parse_strlist (char *arg,
+ error_t (*add_fn)(const char *str, struct argp_state *state),
+ const char *(*default_fn)(struct argp_state *state),
+ const char *type_name, struct argp_state *state)
+{
+ error_t default_str_add (struct argp_state *state)
+ { return (*add_fn)((*default_fn)(state), state); }
+ return _parse_strlist (arg, add_fn, default_str_add, type_name, state);
+}
+
+/* For each numeric string in the comma-separated list in ARG, call ADD_FN;
+ if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number,
+ and call ADD_FN on that, otherwise signal an error. If any member of the
+ list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return
+ an integer for the string. LOOKUP_FN should signal an error itself it
+ there's some problem parsing the string. */
+error_t
+parse_numlist (char *arg,
+ error_t (*add_fn)(unsigned num, struct argp_state *state),
+ int (*default_fn)(struct argp_state *state),
+ int (*lookup_fn)(const char *str, struct argp_state *state),
+ const char *type_name, struct argp_state *state)
+{
+ error_t default_num_add() { return (*add_fn)((*default_fn)(state), state); }
+ error_t add_num_str(const char *str, struct argp_state *state)
+ {
+ const char *p;
+ for (p = str; *p != '\0'; p++)
+ if (!isdigit(*p))
+ {
+ if (lookup_fn)
+ return (*add_fn)((*lookup_fn)(str, state), state);
+ else
+ {
+ argp_error (state, "%s: Invalid %s", p, type_name);
+ return EINVAL;
+ }
+ return 0;
+ }
+ return (*add_fn) (atoi (str), state);
+ }
+ return _parse_strlist(arg, add_num_str, default_fn ? default_num_add : 0,
+ type_name, state);
+}
+
+/* Return the index of which of a set of strings ARG matches, including
+ non-ambiguous partial matches. CHOICE_FN should be a function that
+ returns the name of the Nth option, or 0 if N is out of range, and KIND
+ should be a string that describes what's being matched, for use in error
+ messages. If ALLOW_MISMATCHES is true, then -1 is returned in the event
+ that ARG matches no entry , otherwise, an error message is printed and the
+ program exits in this event. If ARG is an ambiguous match, an error
+ message is printed and the program exits. */
+int
+parse_enum (const char *arg,
+ const char *(*choice_fn)(unsigned n),
+ const char *kind, int allow_mismatches,
+ struct argp_state *state)
+{
+ const char *choice;
+ int arglen = strlen (arg);
+ int n = 0;
+ int partial_match = -1;
+
+ while ((choice = (*choice_fn)(n)) != NULL)
+ if (strcasecmp (choice, arg) == 0)
+ return n;
+ else
+ {
+ if (strncasecmp (choice, arg, arglen) == 0)
+ {
+ if (partial_match >= 0)
+ {
+ argp_error (state, "%s: Ambiguous %s", arg, kind);
+ return -1;
+ }
+ else
+ partial_match = n;
+ }
+ n++;
+ }
+
+ if (partial_match < 0 && !allow_mismatches)
+ argp_error (state, "%s: Invalid %s", arg, kind);
+
+ return partial_match;
+}
diff --git a/utils/parse.h b/utils/parse.h
new file mode 100644
index 00000000..9b6f31f9
--- /dev/null
+++ b/utils/parse.h
@@ -0,0 +1,63 @@
+/* Random helpful option parsing functions
+
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __PARSE_H__
+#define __PARSE_H__
+
+#include <errno.h>
+#include <argp.h>
+
+/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
+ empty and DEFAULT_FN isn't NULL, then call ADD_FN on the resutl of calling
+ DEFAULT_FN instead, otherwise signal an error. */
+extern error_t
+parse_strlist (char *arg,
+ error_t (*add_fn)(const char *str, struct argp_state *state),
+ const char *(*default_fn)(struct argp_state *state),
+ const char *type_name, struct argp_state *state);
+
+/* For each numeric string in the comma-separated list in ARG, call ADD_FN;
+ if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number,
+ and call ADD_FN on that, otherwise signal an error. If any member of the
+ list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return
+ an integer for the string. LOOKUP_FN should signal an error itself it
+ there's some problem parsing the string. */
+extern error_t
+parse_numlist (char *arg,
+ error_t (*add_fn)(unsigned num, struct argp_state *state),
+ int (*default_fn)(struct argp_state *state),
+ int (*lookup_fn)(const char *str, struct argp_state *state),
+ const char *type_name, struct argp_state *state);
+
+/* Return the index of which of a set of strings ARG matches, including
+ non-ambiguous partial matches. CHOICE_FN should be a function that
+ returns the name of the Nth option, or 0 if N is out of range, and KIND
+ should be a string that describes what's being matched, for use in error
+ messages. If ALLOW_MISMATCHES is true, then -1 is returned in the event
+ that ARG matches no entry , otherwise, an error message is printed and the
+ program exits in this event. If ARG is an ambiguous match, an error
+ message is printed and the program exits. */
+extern int
+parse_enum (const char *arg,
+ const char *(*choice_fn)(unsigned n),
+ const char *kind, int allow_mismatches,
+ struct argp_state *state);
+
+#endif /* __PARSE_H__ */
diff --git a/utils/pids.c b/utils/pids.c
new file mode 100644
index 00000000..44cd0b44
--- /dev/null
+++ b/utils/pids.c
@@ -0,0 +1,231 @@
+/* Pid parsing/frobbing
+
+ Copyright (C) 1997,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <argp.h>
+#include <hurd.h>
+#include <hurd/process.h>
+#include <mach.h>
+#include <sys/mman.h>
+
+#include "parse.h"
+#include "pids.h"
+
+static process_t _proc_server = MACH_PORT_NULL;
+
+/* Return this process's proc server. */
+static inline process_t
+proc_server ()
+{
+ if (_proc_server == MACH_PORT_NULL)
+ _proc_server = getproc ();
+ return _proc_server;
+}
+
+/* Add the pids returned in vm_allocated memory by calling PIDS_FN with ID as
+ an argument to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+error_t
+add_fn_pids (pid_t **pids, size_t *num_pids, unsigned id,
+ error_t (*pids_fn)(process_t proc, pid_t id,
+ pid_t **pids, size_t *num_pids))
+{
+ size_t num_new_pids = 25;
+ pid_t _new_pids[num_new_pids], *new_pids = _new_pids;
+ error_t err = (*pids_fn)(proc_server (), id, &new_pids, &num_new_pids);
+
+ if (! err)
+ {
+ size_t new_sz = *num_pids + num_new_pids;
+ pid_t *new = realloc (*pids, new_sz * sizeof (pid_t));
+ if (new)
+ {
+ bcopy (new_pids, new + (*num_pids * sizeof (pid_t)),
+ num_new_pids * sizeof (pid_t));
+ *pids = new;
+ *num_pids = new_sz;
+ }
+ else
+ err = ENOMEM;
+ if (new_pids != _new_pids)
+ munmap (new_pids, num_new_pids * sizeof (pid_t));
+ }
+
+ return err;
+}
+
+/* Add PID to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+error_t
+add_pid (pid_t **pids, size_t *num_pids, pid_t pid)
+{
+ size_t new_sz = *num_pids + 1;
+ pid_t *new = realloc (*pids, new_sz * sizeof (pid_t));
+
+ if (new)
+ {
+ new[new_sz - 1] = pid;
+ *pids = new;
+ *num_pids = new_sz;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+struct pids_parse_state
+{
+ struct pids_argp_params *params;
+ struct argp_state *state;
+};
+
+/* Returns our session id. */
+static pid_t
+current_sid (struct argp_state *state)
+{
+ pid_t sid = -1;
+ error_t err = proc_getsid (proc_server (), getpid (), &sid);
+ if (err)
+ argp_failure (state, 2, err, "Couldn't get current session id");
+ return sid;
+}
+
+/* Returns our login collection id. */
+static pid_t
+current_lid (struct argp_state *state)
+{
+ pid_t lid = -1;
+ error_t err = proc_getloginid (proc_server (), getpid (), &lid);
+ if (err)
+ argp_failure (state, 2, err, "Couldn't get current login collection");
+ return lid;
+}
+
+/* Add a specific process to be printed out. */
+static error_t
+parse_pid (unsigned pid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err = add_pid (params->pids, params->num_pids, pid);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add process", pid);
+ return err;
+}
+
+/* Print out all process from the given session. */
+static error_t
+parse_sid (unsigned sid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, sid, proc_getsessionpids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add session", sid);
+ return err;
+}
+
+/* Print out all process from the given login collection. */
+static error_t
+parse_lid (unsigned lid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, lid, proc_getloginpids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add login collection", lid);
+ return err;
+}
+
+/* Print out all process from the given process group. */
+static error_t
+parse_pgrp (unsigned pgrp, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, pgrp, proc_getpgrppids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add process group", pgrp);
+ return err;
+}
+
+#define OA OPTION_ARG_OPTIONAL
+
+/* Options for PIDS_ARGP. */
+static const struct argp_option options[] =
+{
+ {"login", 'L', "LID", OA, "Processes from the login"
+ " collection LID (which defaults that of"
+ " the current process)"},
+ {"lid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"pid", 'p', "PID", 0, "The process PID"},
+ {"pgrp", 'P', "PGRP", 0, "Processes in process group PGRP"},
+ {"session", 'S', "SID", OA, "Processes from the session SID"
+ " (which defaults to that of the"
+ " current process)"},
+ {"sid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {0, 0}
+};
+
+/* Parse one option/arg for PIDS_ARGP. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+
+ switch (key)
+ {
+ case 'p':
+ return
+ parse_numlist (arg, parse_pid, NULL, NULL, "process id", state);
+ case 'S':
+ return
+ parse_numlist (arg, parse_sid, current_sid, NULL, "session id", state);
+ case 'L':
+ return
+ parse_numlist (arg, parse_lid, current_lid, NULL, "login collection",
+ state);
+ case 'P':
+ return
+ parse_numlist (arg, parse_pgrp, NULL, NULL, "process group", state);
+
+ case ARGP_KEY_ARG:
+ if (params->parse_pid_args)
+ return parse_numlist (arg, parse_pid, NULL, NULL, "process id", state);
+ /* Else fall through */
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+}
+
+/* Filtering of help output strings for PIDS_ARGP. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ struct pids_argp_params *params = input;
+
+ /* Describe the optional behavior of parsing normal args as pids. */
+ if (key == ARGP_KEY_HELP_ARGS_DOC && params->parse_pid_args)
+ return strdup ("[PID...]");
+
+ return (char *)text;
+}
+
+/* A parser for selecting a set of pids. */
+struct argp pids_argp = { options, parse_opt, 0, 0, 0, help_filter };
diff --git a/utils/pids.h b/utils/pids.h
new file mode 100644
index 00000000..dcf87e81
--- /dev/null
+++ b/utils/pids.h
@@ -0,0 +1,47 @@
+/* Pid parsing/frobbing
+
+ Copyright (C) 1997,2001 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __PIDS_H__
+#define __PIDS_H__
+
+/* Add the pids returned in vm_allocated memory by calling PIDS_FN with ID as
+ an argument to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+extern error_t add_fn_pids (pid_t **pids, size_t *num_pids, unsigned id,
+ error_t (*pids_fn)(process_t proc, pid_t id,
+ pid_t **pids, size_t *num_pids));
+
+/* Add PID to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+extern error_t add_pid (pid_t **pids, size_t *num_pids, pid_t pid);
+
+/* Params to be passed as the input when parsing PIDS_ARGP. */
+struct pids_argp_params
+{
+ /* Array to be extended with parsed pids. */
+ pid_t **pids;
+ size_t *num_pids;
+
+ /* If true, parse non-option arguments as pids. */
+ int parse_pid_args;
+};
+
+/* A parser for selecting a set of pids. */
+extern struct argp pids_argp;
+
+#endif /* __PIDS_H__ */
diff --git a/utils/portinfo.c b/utils/portinfo.c
index 10f5fe8f..e78c77df 100644
--- a/utils/portinfo.c
+++ b/utils/portinfo.c
@@ -1,6 +1,6 @@
/* Print information about a task's ports
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,98,99, 2000 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -25,6 +25,7 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <version.h>
#include <mach.h>
@@ -34,15 +35,17 @@
#include <portinfo.h>
#include <portxlate.h>
-char *argp_program_version = "portinfo 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (portinfo);
static const struct argp_option options[] = {
{0,0,0,0,0, 1},
{"verbose", 'v', 0, 0, "Give more detailed information"},
{"members", 'm', 0, 0, "Show members of port-sets"},
{"hex-names", 'x', 0, 0, "Show port names in hexadecimal"},
+#if 0 /* XXX implement this */
{"query-process", 'q', 0, 0, "Query the process itself for the identity of"
" the ports in question -- requires the process be in a sane state"},
+#endif
{"hold", '*', 0, OPTION_HIDDEN},
{0,0,0,0, "Selecting which names to show:", 2},
@@ -54,8 +57,10 @@ static const struct argp_option options[] = {
{0,0,0,0, "Translating port names between tasks:", 3},
{"translate", 't', "PID", 0, "Translate port names to process PID"},
+#if 0
{"show-targets", 'h', 0, 0,
"Print a header describing the target process" },
+#endif
{"no-translation-errors", 'E', 0, 0,
"Don't display an error if a specified port can't be translated" },
#if 0
@@ -63,16 +68,18 @@ static const struct argp_option options[] = {
{"target-receive", 'R', 0, 0,
"Only show ports that translate into receive rights"},
{"target-send", 'S', 0, 0,
- "Only show ports that translate into receive rights"},
+ "Only show ports that translate into send rights"},
{"target-send-once",'O', 0, 0,
- "Only show ports that translate into receive rights"},
+ "Only show ports that translate into send-once rights"},
+ "Only show ports that translate into send once rights"},
#endif
{0}
};
static const char *args_doc = "PID [NAME...]";
static const char *doc =
-"If no port NAMEs are given, all ports in process PID are reported (if"
+"Show information about mach ports NAME... (default all ports) in process PID."
+"\vIf no port NAMEs are given, all ports in process PID are reported (if"
" translation is used, then only those common to both processes). NAMEs"
" may be specified in hexadecimal or octal by using a 0x or 0 prefix.";
@@ -96,11 +103,13 @@ parse_task (char *arg)
err = proc_pid2task (proc, pid, &task);
if (err)
error (11, err, "%s", arg);
+ else if (task == MACH_PORT_NULL)
+ error (11, 0, "%s: Process %d is dead and has no task", arg, (int) pid);
return task;
}
-static volatile hold = 0;
+static volatile int hold = 0;
int
main (int argc, char **argv)
@@ -111,6 +120,7 @@ main (int argc, char **argv)
unsigned show = 0; /* what info we print */
mach_port_type_t only = 0, target_only = 0; /* Which names to show */
task_t xlate_task = MACH_PORT_NULL;
+ int no_translation_errors = 0; /* inhibit complaints about bad names */
struct port_name_xlator *xlator = 0;
/* Parse our options... */
@@ -134,6 +144,7 @@ main (int argc, char **argv)
case 't': xlate_task = parse_task (arg); break;
case 'a': search = 1; break;
+ case 'E': no_translation_errors = 1; break;
case '*':
hold = 1;
@@ -189,7 +200,12 @@ main (int argc, char **argv)
else
{
if (xlator)
- err = print_xlated_port_info (name, 0, xlator, show, stdout);
+ {
+ err = print_xlated_port_info (name, 0, xlator,
+ show, stdout);
+ if (err && no_translation_errors)
+ break;
+ }
else
err = print_port_info (name, 0, task, show, stdout);
if (err)
diff --git a/utils/ps.c b/utils/ps.c
index de913f74..992b467d 100644
--- a/utils/ps.c
+++ b/utils/ps.c
@@ -1,8 +1,8 @@
/* Show process information.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2002,2006 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -30,96 +30,78 @@
#include <idvec.h>
#include <ps.h>
#include <error.h>
+#include <version.h>
+
#include "psout.h"
+#include "parse.h"
+#include "pids.h"
-char *argp_program_version = "ps 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (ps);
#define OA OPTION_ARG_OPTIONAL
static const struct argp_option options[] =
{
- {"all-users", 'a', 0, 0, "List other users' processes"},
+ {0,0,0,0, "Output format selection:", 1},
{"format", 'F', "FMT", 0, "Use the output-format FMT; FMT may be"
" `default', `user', `vmem', `long',"
" `jobc', `full', `hurd', `hurd-long',"
" or a custom format-string"},
{"posix-format",'o', "FMT", 0, "Use the posix-style output-format FMT"},
+ {0, 'f', 0, 0, "Use the `full' output-format"},
+ {0, 'j', 0, 0, "Use the `jobc' output-format"},
+ {0, 'l', 0, 0, "Use the `long' output-format"},
+ {0, 'u', 0, 0, "Use the `user' output-format"},
+ {0, 'v', 0, 0, "Use the `vmem' output-format"},
+
+ {0,0,0,0, "Process filtering (by default, other users'"
+ " processes, threads, and process-group leaders are not shown):", 2},
+ {"all-users", 'a', 0, 0, "List other users' processes"},
{0, 'd', 0, 0, "List all processes except process group"
" leaders"},
{"all", 'e', 0, 0, "List all processes"},
{0, 'A', 0, OPTION_ALIAS}, /* Posix option meaning -e */
- {0, 'f', 0, 0, "Use the `full' output-format"},
{0, 'g', 0, 0, "Include session and login leaders"},
- {"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
- {0, 'j', 0, 0, "Use the `jobc' output-format"},
- {0, 'l', 0, 0, "Use the `long' output-format"},
- {"login", 'L', "LID", OA, "Add the processes from the login"
- " collection LID (which defaults that of"
- " the current process)"},
- {"lid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"owner", 'U', "USER", 0, "Show only processes owned by USER"},
+ {"not-owner", 'O', "USER", 0, "Show only processes not owned by USER"},
+ {"no-parent", 'P', 0, 0, "Include processes without parents"},
+ {"threads", 'T', 0, 0, "Show the threads for each process"},
+ {"tty", 't', "TTY", OA, "Only show processes with controlling"
+ " terminal TTY"},
+ {0, 'x', 0, 0, "Include orphaned processes"},
+
+ {0,0,0,0, "Elision of output fields:", 4},
{"no-msg-port",'M', 0, 0, "Don't show info that uses a process's"
" msg port"},
{"nominal-fields",'n', 0, 0, "Don't elide fields containing"
" `uninteresting' data"},
- {"owner", 'U', "USER", 0, "Show only processes owned by USER"},
- {"not-owner", 'O', "USER", 0, "Show only processes not owned by USER"},
- {"pid", 'p', "PID", 0, "List the process PID"},
- {"pgrp", 'G', "PGRP", 0, "List processes in process group PGRP"},
- {"no-parent", 'P', 0, 0, "Include processes without parents"},
{"all-fields", 'Q', 0, 0, "Don't elide unusable fields (normally"
" if there's some reason ps can't print"
" a field for any process, it's removed"
" from the output entirely)"},
+
+ {0,0,0,0, "Output attributes:"},
+ {"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
{"reverse", 'r', 0, 0, "Reverse the order of any sort"},
- {"session", 'S', "SID", OA, "Add the processes from the session SID"
- " (which defaults to the sid of the"
- " current process)"},
- {"sid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
- {"sort", 'S', "FIELD",0, "Sort the output with respect to FIELD,"
+ {"sort", 's', "FIELD",0, "Sort the output with respect to FIELD,"
" backwards if FIELD is prefixed by `-'"},
- {"threads", 'T', 0, 0, "Show the threads for each process"},
- {"tty", 't', "TTY", OA, "Only show processes with controlling"
- " terminal TTY"},
- {0, 'u', 0, 0, "Use the `user' output-format"},
- {0, 'v', 0, 0, "Use the `vmem' output-format"},
+ {"top", 'h', "ENTRIES", OA, "Show the top ENTRIES processes"
+ " (default 10), or if ENTRIES is"
+ " negative, the bottom -ENTRIES"},
+ {"head", 0, 0, OPTION_ALIAS},
+ {"bottom", 'b', "ENTRIES", OA, "Show the bottom ENTRIES processes"
+ " (default 10)"},
+ {"tail", 0, 0, OPTION_ALIAS},
{"width", 'w', "WIDTH",OA, "If WIDTH is given, try to format the"
" output for WIDTH columns, otherwise,"
- " remove the default limit"},
- {0, 'x', 0, 0, "Include orphaned processes"},
+ " remove the default limit"},
{0, 0}
};
-char *args_doc = "[PID...]";
-
-char *doc = "The USER, LID, PID, PGRP, and SID arguments may also be comma \
-separated lists. The System V options -u and -g may be accessed with -O and \
---pgrp.";
-
-int
-parse_enum(char *arg, char **choices, char *kind, int allow_mismatches)
-{
- int arglen = strlen(arg);
- char **p = choices;
- int partial_match = -1;
-
- while (*p != NULL)
- if (strcmp(*p, arg) == 0)
- return p - choices;
- else
- {
- if (strncmp(*p, arg, arglen) == 0)
- if (partial_match >= 0)
- argp_error (0, "%s: Ambiguous %s", arg, kind);
- else
- partial_match = p - choices;
- p++;
- }
-
- if (partial_match < 0 && !allow_mismatches)
- argp_error (0, "%s: Invalid %s", arg, kind);
-
- return partial_match;
-}
+static const char doc[] =
+"Show information about processes PID... (default all `interesting' processes)"
+"\vThe USER, LID, PID, PGRP, and SID arguments may also be comma separated"
+" lists. The System V options -u and -g may be accessed with -O and -G.";
#define FILTER_OWNER 0x01
#define FILTER_NOT_LEADER 0x02
@@ -127,38 +109,36 @@ parse_enum(char *arg, char **choices, char *kind, int allow_mismatches)
#define FILTER_UNORPHANED 0x08
#define FILTER_PARENTED 0x10
-enum procsets
+/* A particular predefined output format. */
+struct output_fmt
{
- PROCSET_ALL, PROCSET_SESSION, PROCSET_LOGIN
+ const char *name;
+ const char *sort_key; /* How this format should be sorted. */
+ const char *fmt; /* The format string. */
};
-char *procset_names[] =
-{"all", "session", "login", 0};
-
-/* The names of various predefined output formats. */
-char *fmt_names[] =
- {"default", "user", "vmem", "long", "jobc", "full", "hurd", "hurd-long",0};
-/* How each of those formats should be sorted; */
-char *fmt_sortkeys[] =
- {"pid", "-cpu","-mem", "pid", "pid", "pid", "pid", "pid"};
-/* and the actual format strings. */
-char *fmts[] =
+
+/* The predefined output formats. */
+struct output_fmt output_fmts[] =
{
- /* default */
- "%^%?user %pid %th %tt %sc %stat %time %command",
- /* user (-u) */
- "%^%user %pid %th %cpu %mem %sz %rss %tt %sc %stat %command",
- /* vmem (-v) */
- "%^%pid %th %stat %sl %pgins %pgflts %cowflts %zfills %sz %rss %cpu %mem %command",
- /* long (-l) */
- "%^%uid %pid %th %ppid %pri %ni %nth %msgi %msgo %sz %rss %sc %wait %stat %tt %time %command",
- /* jobc (-j) */
- "%^%user %pid %th %ppid %pgrp %sess %lcoll %sc %stat %tt %time %command",
- /* full (-f) (from sysv) */
- "%^%-user %pid %ppid %tty %time %command",
- /* hurd */
- "%pid %th %uid %nth %{vsize:Vmem} %rss %{utime:User} %{stime:System} %args",
- /* hurd-long */
- "%pid %th %uid %ppid %pgrp %sess %nth %{vsize:Vmem} %rss %cpu %{utime:User} %{stime:System} %args"
+ { "default", "pid",
+ "%^%?user %pid %th %tt %sc %stat %time %command" },
+ { "user", "-cpu",
+ "%^%user %pid %th %cpu %mem %sz %rss %tt %sc %stat %start %time %command" },
+ { "vmem", "-mem",
+ "%^%pid %th %stat %sl %pgins %pgflts %cowflts %zfills %sz %rss %cpu %mem %command"
+ },
+ { "long", "pid",
+ "%^%uid %pid %th %ppid %pri %ni %nth %msgi %msgo %sz %rss %sc %wait %stat %tt %time %command" },
+ { "jobc", "pid",
+ "%^%user %pid %th %ppid %pgrp %sess %lcoll %sc %stat %tt %time %command" },
+ { "full", "pid",
+ "%^%-user %pid %ppid %tty %time %command" },
+ { "hurd", "pid",
+ "%pid %th %uid %nth %{vsize:Vmem} %rss %{utime:User} %{stime:System} %args"
+ },
+ { "hurd-long", "pid",
+ "%pid %th %uid %ppid %pgrp %sess %nth %{vsize:Vmem} %rss %cpu %{utime:User} %{stime:System} %args"
+ }
};
/* Augment the standard specs with our own abbrevs. */
@@ -172,141 +152,17 @@ spec_abbrevs[] = {
static struct ps_fmt_specs ps_specs =
{ spec_abbrevs, &ps_std_fmt_specs };
-/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
- empty and DEFAULT_ADD_FN isn't NULL, then call DEFAULT_ADD_FN instead. */
-static void
-_parse_strlist (char *arg,
- void (*add_fn)(const char *str), void (*default_add_fn)(),
- const char *type_name)
-{
- if (arg)
- while (isspace(*arg))
- arg++;
-
- if (arg == NULL || *arg == '\0')
- if (default_add_fn)
- (*default_add_fn)();
- else
- error(7, 0, "Empty %s list", type_name);
- else
- {
- char *end = arg;
-
- void mark_end()
- {
- *end++ = '\0';
- while (isspace(*end))
- end++;
- }
- void parse_element()
- {
- if (*arg == '\0')
- error(7, 0, "Empty element in %s list", type_name);
- (*add_fn)(arg);
- arg = end;
- }
-
- while (*end != '\0')
- switch (*end)
- {
- case ' ': case '\t':
- mark_end();
- if (*end == ',')
- mark_end();
- parse_element();
- break;
- case ',':
- mark_end();
- parse_element();
- break;
- default:
- end++;
- }
-
- parse_element();
- }
-}
-
-/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
- empty and DEFAULT_FN isn't NULL, then call ADD_FN on the resutl of calling
- DEFAULT_FN instead, otherwise signal an error. */
-static void
-parse_strlist (char *arg,
- void (*add_fn)(const char *str),
- const char *(*default_fn)(),
- const char *type_name)
-{
- void default_str_add() { (*add_fn)((*default_fn)()); }
- _parse_strlist(arg, add_fn, default_str_add, type_name);
-}
-
-/* For each numeric string in the comma-separated list in ARG, call ADD_FN;
- if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number,
- and call ADD_FN on that, otherwise signal an error. If any member of the
- list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return
- an integer for the string. LOOKUP_FN should signal an error itself it
- there's some problem parsing the string. */
-static void
-parse_numlist (char *arg,
- void (*add_fn)(unsigned num),
- int (*default_fn)(),
- int (*lookup_fn)(const char *str),
- const char *type_name)
-{
- void default_num_add() { (*add_fn)((*default_fn)()); }
- void add_num_str(const char *str)
- {
- const char *p;
- for (p = str; *p != '\0'; p++)
- if (!isdigit(*p))
- {
- if (lookup_fn)
- (*add_fn)((*lookup_fn)(str));
- else
- error (7, 0, "%s: Invalid %s", p, type_name);
- return;
- }
- (*add_fn)(atoi(str));
- }
- _parse_strlist(arg, add_num_str, default_fn ? default_num_add : 0,
- type_name);
-}
-
-static process_t proc_server;
-
-/* Returns our session id. */
-static pid_t
-current_sid()
-{
- pid_t sid;
- error_t err = proc_getsid(proc_server, getpid(), &sid);
- if (err)
- error(2, err, "Couldn't get current session id");
- return sid;
-}
-
-/* Returns our login collection id. */
-static pid_t
-current_lid()
-{
- pid_t lid;
- error_t err = proc_getloginid(proc_server, getpid(), &lid);
- if (err)
- error(2, err, "Couldn't get current login collection") ;
- return lid;
-}
-
/* Returns the UID for the user called NAME. */
static int
-lookup_user(const char *name)
+lookup_user (const char *name, struct argp_state *state)
{
struct passwd *pw = getpwnam(name);
if (pw == NULL)
- error(2, 0, "%s: Unknown user", name);
+ argp_failure (state, 2, 0, "%s: Unknown user", name);
return pw->pw_uid;
}
-void
+int
main(int argc, char *argv[])
{
error_t err;
@@ -317,10 +173,10 @@ main(int argc, char *argv[])
char *arg_hack_buf = 0;
struct idvec *only_uids = make_idvec (), *not_uids = make_idvec ();
char *tty_names = 0;
- unsigned num_tty_names = 0;
+ size_t num_tty_names = 0;
struct proc_stat_list *procset;
struct ps_context *context;
- char *fmt_string = "default", *sort_key_name = NULL;
+ const char *fmt_string = "default", *sort_key_name = NULL;
unsigned filter_mask =
FILTER_OWNER | FILTER_NOT_LEADER | FILTER_UNORPHANED | FILTER_PARENTED;
int sort_reverse = FALSE, print_heading = TRUE;
@@ -329,65 +185,26 @@ main(int argc, char *argv[])
int output_width = -1; /* Desired max output size. */
int show_non_hurd_procs = 1; /* Show non-hurd processes. */
int posix_fmt = 0; /* Use a posix_fmt-style format string. */
+ int top = 0; /* Number of entries to output. */
+ pid_t *pids = 0; /* User-specified pids. */
+ size_t num_pids = 0;
+ struct pids_argp_params pids_argp_params = { &pids, &num_pids, 1 };
- /* Add a specific process to be printed out. */
- void add_pid (unsigned pid)
- {
- struct proc_stat *ps;
-
- err = proc_stat_list_add_pid (procset, pid, &ps);
- if (err)
- error (0, err, "%d: Can't add process", pid);
-
- /* See if this process actually exists. */
- proc_stat_set_flags (ps, PSTAT_PROC_INFO);
- if (! proc_stat_has (ps, PSTAT_PROC_INFO))
- /* Give an error message; using ps_alive_filter below will delete the
- entry so it doesn't get output. */
- error (0, 0, "%d: Unknown process", pid);
-
- /* If explicit processes are specified, we probably don't want to
- filter them out later. This implicit turning off of filtering might
- be confusing in the case where a login-collection or session is
- specified along with some pids, but it's probably not worth worrying
- about. */
- filter_mask = 0;
- }
- /* Print out all process from the given session. */
- void add_sid(unsigned sid)
- {
- err = proc_stat_list_add_session (procset, sid, 0, 0);
- if (err)
- error(2, err, "%u: Can't add session", sid);
- }
- /* Print out all process from the given login collection. */
- void add_lid(unsigned lid)
- {
- error_t err = proc_stat_list_add_login_coll (procset, lid, 0, 0);
- if (err)
- error(2, err, "%u: Can't add login collection", lid);
- }
- /* Print out all process from the given process group. */
- void add_pgrp(unsigned pgrp)
- {
- error_t err = proc_stat_list_add_pgrp (procset, pgrp, 0, 0);
- if (err)
- error(2, err, "%u: Can't add process group", pgrp);
- }
-
/* Add a user who's processes should be printed out. */
- void add_uid (uid_t uid)
+ error_t add_uid (uid_t uid, struct argp_state *state)
{
error_t err = idvec_add (only_uids, uid);
if (err)
- error (23, err, "Can't add uid");
+ argp_failure (state, 23, err, "Can't add uid");
+ return err;
}
/* Add a user who's processes should not be printed out. */
- void add_not_uid (uid_t uid)
+ error_t add_not_uid (uid_t uid, struct argp_state *state)
{
error_t err = idvec_add (not_uids, uid);
if (err)
- error (23, err, "Can't add uid");
+ argp_failure (state, 23, err, "Can't add uid");
+ return err;
}
/* Returns TRUE if PS is owned by any of the users in ONLY_UIDS, and none
in NOT_UIDS. */
@@ -403,11 +220,12 @@ main(int argc, char *argv[])
/* Add TTY_NAME to the list for which processes with those controlling
terminals will be printed. */
- void add_tty_name (const char *tty_name)
+ error_t add_tty_name (const char *tty_name, struct argp_state *state)
{
error_t err = argz_add (&tty_names, &num_tty_names, tty_name);
if (err)
- error (8, err, "%s: Can't add tty", tty_name);
+ argp_failure (state, 8, err, "%s: Can't add tty", tty_name);
+ return err;
}
int proc_stat_has_ctty(struct proc_stat *ps)
{
@@ -431,7 +249,7 @@ main(int argc, char *argv[])
}
/* Returns the name of the current controlling terminal. */
- static const char *current_tty_name()
+ const char *current_tty_name()
{
error_t err;
struct ps_tty *tty;
@@ -463,10 +281,9 @@ main(int argc, char *argv[])
memcpy (&state->argv[state->next][1], arg, len);
break;
}
- /* Otherwise, fall through and treat the arg as a process id. */
- case 'p':
- parse_numlist(arg, add_pid, NULL, NULL, "process id");
- break;
+ else
+ /* Let PIDS_ARGP handle it. */
+ return ARGP_ERR_UNKNOWN;
case 'a': filter_mask &= ~FILTER_OWNER; break;
case 'd': filter_mask &= ~(FILTER_OWNER | FILTER_UNORPHANED); break;
@@ -486,6 +303,8 @@ main(int argc, char *argv[])
case 'T': show_threads = TRUE; break;
case 's': sort_key_name = arg; break;
case 'r': sort_reverse = TRUE; break;
+ case 'h': top = arg ? atoi (arg) : 10; break;
+ case 'b': top = -(arg ? atoi (arg) : 10); break;
case 'F': fmt_string = arg; posix_fmt = 0; break;
case 'o': fmt_string = arg; posix_fmt = 1; break;
@@ -494,22 +313,37 @@ main(int argc, char *argv[])
break;
case 't':
- parse_strlist (arg, add_tty_name, current_tty_name, "tty");
- break;
+ return parse_strlist (arg, add_tty_name, current_tty_name, "tty", state);
case 'U':
- parse_numlist (arg, add_uid, NULL, lookup_user, "user");
- break;
+ return parse_numlist (arg, add_uid, NULL, lookup_user, "user", state);
case 'O':
- parse_numlist (arg, add_not_uid, NULL, lookup_user, "user");
- break;
- case 'S':
- parse_numlist(arg, add_sid, current_sid, NULL, "session id");
- break;
- case 'L':
- parse_numlist(arg, add_lid, current_lid, NULL, "login collection");
+ return parse_numlist (arg, add_not_uid, NULL, lookup_user, "user", state);
+
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ state->child_inputs[0] = &pids_argp_params;
break;
- case 'G':
- parse_numlist(arg, add_pgrp, NULL, NULL, "process group");
+
+ case ARGP_KEY_SUCCESS:
+ /* Select an explicit format string if FMT_STRING is a format
+ name. This is done here because parse_enum needs STATE. */
+ {
+ const char *fmt_name (unsigned n)
+ {
+ return
+ n >= (sizeof output_fmts / sizeof *output_fmts)
+ ? 0
+ : output_fmts[n].name;
+ }
+ int fmt_index = parse_enum (fmt_string, fmt_name,
+ "format type", 1, state);
+ if (fmt_index >= 0)
+ {
+ fmt_string = output_fmts[fmt_index].fmt;
+ if (sort_key_name == NULL)
+ sort_key_name = output_fmts[fmt_index].sort_key;
+ }
+ }
break;
default:
@@ -518,46 +352,27 @@ main(int argc, char *argv[])
return 0;
}
- struct argp argp = { options, parse_opt, args_doc, doc};
-
- proc_server = getproc();
+ struct argp_child argp_kids[] =
+ { { &pids_argp, 0,
+ "Process selection (before filtering; default is all processes):", 3},
+ {0} };
+ struct argp argp = { options, parse_opt, 0, doc, argp_kids };
- err = ps_context_create (proc_server, &context);
+ err = ps_context_create (getproc (), &context);
if (err)
error(1, err, "ps_context_create");
- err = proc_stat_list_create(context, &procset);
- if (err)
- error(1, err, "proc_stat_list_create");
-
/* Parse our command line. This shouldn't ever return an error. */
argp_parse (&argp, argc, argv, 0, 0, 0);
- if (only_uids->num == 0 && (filter_mask & FILTER_OWNER))
- /* Restrict the output to only our own processes. */
- {
- int uid = getuid ();
- if (uid >= 0)
- add_uid (uid);
- else
- filter_mask &= ~FILTER_OWNER; /* Must be an anonymous process. */
- }
-
- {
- int fmt_index = parse_enum(fmt_string, fmt_names, "format type", 1);
- if (fmt_index >= 0)
- {
- fmt_string = fmts[fmt_index];
- if (sort_key_name == NULL)
- sort_key_name = fmt_sortkeys[fmt_index];
- }
- }
+ err = proc_stat_list_create(context, &procset);
+ if (err)
+ error(1, err, "proc_stat_list_create");
- if (proc_stat_list_num_procs (procset) == 0)
+ if (num_pids == 0)
+ /* No explicit processes specified. */
{
err = proc_stat_list_add_all (procset, 0, 0);
- if (err)
- error(2, err, "Can't get process list");
/* Try to avoid showing non-hurd processes if this isn't a native-booted
hurd system (because there would be lots of them). Here we use a
@@ -576,10 +391,29 @@ main(int argc, char *argv[])
show_non_hurd_procs = 1;
}
}
+ else
+ /* User-specified processes. */
+ {
+ err = proc_stat_list_add_pids (procset, pids, num_pids, 0);
+ filter_mask = 0; /* Don't mess with them. */
+ }
+
+ if (err)
+ error(2, err, "Can't get process list");
if (no_msg_port)
proc_stat_list_set_flags(procset, PSTAT_NO_MSGPORT);
+ if (only_uids->num == 0 && (filter_mask & FILTER_OWNER))
+ /* Restrict the output to only our own processes. */
+ {
+ int uid = getuid ();
+ if (uid >= 0)
+ add_uid (uid, 0);
+ else
+ filter_mask &= ~FILTER_OWNER; /* Must be an anonymous process. */
+ }
+
/* Filter out any processes that we don't want to show. */
if (only_uids->num || not_uids->num)
proc_stat_list_filter1 (procset, proc_stat_owner_ok,
@@ -606,7 +440,7 @@ main(int argc, char *argv[])
psout (procset, fmt_string, posix_fmt, &ps_specs,
sort_key_name, sort_reverse,
output_width, print_heading,
- squash_bogus_fields, squash_nominal_fields);
+ squash_bogus_fields, squash_nominal_fields, top);
- exit (0);
+ return 0;
}
diff --git a/utils/psout.c b/utils/psout.c
index 7f2b0591..93667b28 100644
--- a/utils/psout.c
+++ b/utils/psout.c
@@ -1,6 +1,6 @@
/* Common output function for ps & w
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -31,7 +31,8 @@ psout (struct proc_stat_list *procs,
char *fmt_string, int posix_fmt, struct ps_fmt_specs *specs,
char *sort_key_name, int sort_reverse,
int output_width, int print_heading,
- int squash_bogus_fields, int squash_nominal_fields)
+ int squash_bogus_fields, int squash_nominal_fields,
+ int top)
{
error_t err;
struct ps_stream *output;
@@ -96,15 +97,17 @@ psout (struct proc_stat_list *procs,
error (5, err, "Can't make output stream");
if (print_heading)
- if (proc_stat_list_num_procs (procs) > 0)
- {
- err = ps_fmt_write_titles (fmt, output);
- if (err)
- error (0, err, "Can't print titles");
- ps_stream_newline (output);
- }
- else
- error (0, 0, "No applicable processes");
+ {
+ if (procs->num_procs > 0)
+ {
+ err = ps_fmt_write_titles (fmt, output);
+ if (err)
+ error (0, err, "Can't print titles");
+ ps_stream_newline (output);
+ }
+ else
+ error (1, 0, "No applicable processes");
+ }
if (output_width)
/* Try and restrict the number of output columns. */
@@ -117,6 +120,23 @@ psout (struct proc_stat_list *procs,
ps_fmt_set_output_width (fmt, output_width);
}
+ if (top)
+ /* Restrict output to the top TOP entries, if TOP is positive, or the
+ bottom -TOP entries, if it is negative. */
+ {
+ int filter (struct proc_stat *ps)
+ {
+ return --top >= 0;
+ }
+ if (top < 0)
+ {
+ top += procs->num_procs;
+ proc_stat_list_filter1 (procs, filter, 0, 1);
+ }
+ else
+ proc_stat_list_filter1 (procs, filter, 0, 0);
+ }
+
/* Finally, output all the processes! */
err = proc_stat_list_fmt (procs, fmt, output);
if (err)
diff --git a/utils/psout.h b/utils/psout.h
index f9c44484..f4469ac4 100644
--- a/utils/psout.h
+++ b/utils/psout.h
@@ -1,6 +1,6 @@
/* Common output function for ps & w
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -23,10 +23,12 @@
#include <ps.h>
-void psout (struct proc_stat_list *procs,
- char *fmt_string, int posix_fmt, struct ps_fmt_specs *specs,
- char *sort_key_name, int sort_reverse,
+void psout (const struct proc_stat_list *procs,
+ const char *fmt_string, int posix_fmt,
+ const struct ps_fmt_specs *specs,
+ const char *sort_key_name, int sort_reverse,
int output_width, int print_heading,
- int squash_bogus_fields, int squash_nominal_fields);
+ int squash_bogus_fields, int squash_nominal_fields,
+ int top);
#endif /* __PSOUT_H__ */
diff --git a/utils/rmauth.c b/utils/rmauth.c
new file mode 100644
index 00000000..4c68cd18
--- /dev/null
+++ b/utils/rmauth.c
@@ -0,0 +1,121 @@
+/* Remove authentication from selected processes
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rmauth);
+
+static const struct argp_option options[] =
+{
+#ifndef UNSU
+ {"save", 's', 0, 0, "Save removed effective ids as available ids"},
+#endif
+ { 0 }
+};
+
+#ifdef UNSU
+static struct argp_child child_argps[] = {{ &frobauth_posix_argp }, { 0 }};
+#else
+static struct argp_child child_argps[] = {{ &frobauth_ea_argp }, { 0 }};
+#endif
+
+static char doc[] =
+ "Remove user/group ids from the authentication of selected processes";
+
+int
+main (int argc, char *argv[])
+{
+ int save = 0; /* save effective ids */
+ struct frobauth frobauth = FROBAUTH_INIT;
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 's': save = 1; break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ /* Modify UGIDS, to be what PID's new authentication should be, UGIDS is
+ what the user specified. */
+ error_t modify (struct ugids *ugids, const struct ugids *remove,
+ pid_t pid, void *hook)
+ {
+ error_t err = 0;
+ struct ugids saved = UGIDS_INIT;
+
+ if (save)
+ ugids_set (&saved, ugids);
+
+ err = ugids_subtract (ugids, remove);
+
+ if (save)
+ {
+ ugids_subtract (&saved, ugids);
+ ugids_save (&saved);
+ ugids_merge (ugids, &saved);
+ }
+
+ return err;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *removed,
+ pid_t pid, void *hook)
+ {
+ char *delta_rep;
+ struct ugids delta = UGIDS_INIT;
+
+ ugids_set (&delta, old);
+ ugids_subtract (&delta, new);
+
+ delta_rep = ugids_rep (&delta, 1, 1, 0, 0, 0);
+ printf ("%d: Removed %s\n", pid, delta_rep);
+
+ free (delta_rep);
+ ugids_fini (&delta);
+ }
+ struct argp argp = { options, parse_opt, 0, doc, child_argps };
+
+#ifdef UNSU
+ frobauth.default_user = 0;
+#endif
+ frobauth.require_ids = 1;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ if (frobauth_modify (&frobauth, 0, 0, modify, print_info, 0))
+ return 0;
+ else
+ return 1;
+}
diff --git a/utils/rpctrace.c b/utils/rpctrace.c
new file mode 100644
index 00000000..996d4bae
--- /dev/null
+++ b/utils/rpctrace.c
@@ -0,0 +1,1238 @@
+/* Trace RPCs sent to selected ports
+
+ Copyright (C) 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2009, 2011
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/ihash.h>
+#include <mach/message.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <argp.h>
+#include <error.h>
+#include <string.h>
+#include <version.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <argz.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace);
+
+#define STD_MSGIDS_DIR DATADIR "/msgids/"
+
+static unsigned strsize = 80;
+
+#define OPT_NOSTDINC -1
+static const struct argp_option options[] =
+{
+ {"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."},
+ {"nostdinc", OPT_NOSTDINC, 0, 0,
+ "Do not search inside the standard system directory, `" STD_MSGIDS_DIR
+ "', for `.msgids' files."},
+ {"rpc-list", 'i', "FILE", 0,
+ "Read FILE for assocations of message ID numbers to names."},
+ {0, 'I', "DIR", 0,
+ "Add the directory DIR to the list of directories to be searched for files "
+ "containing message ID numbers."},
+ {0, 's', "SIZE", 0, "Specify the maximum string size to print (the default is 80)."},
+ {0}
+};
+
+static const char args_doc[] = "COMMAND [ARG...]";
+static const char doc[] = "Trace Mach Remote Procedure Calls.";
+
+/* The msgid_ihash table maps msgh_id values to names. */
+
+struct msgid_info
+{
+ char *name;
+ char *subsystem;
+};
+
+static void
+msgid_ihash_cleanup (void *element, void *arg)
+{
+ struct msgid_info *info = element;
+ free (info->name);
+ free (info->subsystem);
+ free (info);
+}
+
+static struct hurd_ihash msgid_ihash
+ = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
+
+/* Parse a file of RPC names and message IDs as output by mig's -list
+ option: "subsystem base-id routine n request-id reply-id". Put each
+ request-id value into `msgid_ihash' with the routine name as its value. */
+static void
+parse_msgid_list (const char *filename)
+{
+ FILE *fp;
+ char *buffer = NULL;
+ size_t bufsize = 0;
+ unsigned int lineno = 0;
+ char *name, *subsystem;
+ unsigned int msgid;
+ error_t err;
+
+ fp = fopen (filename, "r");
+ if (fp == 0)
+ {
+ error (2, errno, "%s", filename);
+ return;
+ }
+
+ while (getline (&buffer, &bufsize, fp) > 0)
+ {
+ ++lineno;
+ if (buffer[0] == '#' || buffer[0] == '\0')
+ continue;
+ if (sscanf (buffer, "%as %*u %as %*u %u %*u\n",
+ &subsystem, &name, &msgid) != 3)
+ error (0, 0, "%s:%u: invalid format in RPC list file",
+ filename, lineno);
+ else
+ {
+ struct msgid_info *info = malloc (sizeof *info);
+ if (info == 0)
+ error (1, errno, "malloc");
+ info->name = name;
+ info->subsystem = subsystem;
+ err = hurd_ihash_add (&msgid_ihash, msgid, info);
+ if (err)
+ error (1, err, "hurd_ihash_add");
+ }
+ }
+
+ free (buffer);
+ fclose (fp);
+}
+
+/* Look for a name describing MSGID. We check the table directly, and
+ also check if this looks like the ID of a reply message whose request
+ ID is already in the table. */
+static const struct msgid_info *
+msgid_info (mach_msg_id_t msgid)
+{
+ const struct msgid_info *info = hurd_ihash_find (&msgid_ihash, msgid);
+ if (info == 0 && (msgid / 100) % 2 == 1)
+ {
+ /* This message ID is not in the table, and its number makes it
+ what should be an RPC reply message ID. So look up the message
+ ID of the corresponding RPC request and synthesize a name from
+ that. Then stash that name in the table so the next time the
+ lookup will match directly. */
+ info = hurd_ihash_find (&msgid_ihash, msgid - 100);
+ if (info != 0)
+ {
+ struct msgid_info *reply_info = malloc (sizeof *info);
+ if (reply_info != 0)
+ {
+ reply_info->subsystem = strdup (info->subsystem);
+ reply_info->name = 0;
+ asprintf (&reply_info->name, "%s-reply", info->name);
+ hurd_ihash_add (&msgid_ihash, msgid, reply_info);
+ info = reply_info;
+ }
+ else
+ info = 0;
+ }
+ }
+ return info;
+}
+
+static const char *
+msgid_name (mach_msg_id_t msgid)
+{
+ const struct msgid_info *info = msgid_info (msgid);
+ return info ? info->name : 0;
+}
+
+/* Return true if this message's data should be printed out.
+ For a request message, that means the in parameters.
+ For a reply messages, that means the return code and out parameters. */
+static int
+msgid_display (const struct msgid_info *info)
+{
+ return 1;
+}
+
+/* Return true if we should interpose on this RPC's reply port. If this
+ returns false, we will pass the caller's original reply port through so
+ we never see the reply message at all. */
+static int
+msgid_trace_replies (const struct msgid_info *info)
+{
+ return 1;
+}
+
+/* We keep one of these structures for each port right we are tracing. */
+struct traced_info
+{
+ struct port_info pi;
+
+ mach_port_t forward; /* real port */
+ mach_msg_type_name_t type;
+
+ char *name; /* null or a string describing this */
+
+ union
+ {
+ struct traced_info *nextfree; /* Link when on free list. */
+
+ struct /* For a send right wrapper. */
+ {
+ hurd_ihash_locp_t locp; /* position in the traced_names hash table */
+ } send;
+
+ struct /* For a send-once right wrapper. */
+ {
+ /* We keep track of the send right to which the message containing
+ this send-once right as its reply port was sent, and the msgid of
+ that request. We don't hold a reference to the send right; it is
+ just a hint to indicate a match with a send right on which we just
+ forwarded a message. */
+ mach_port_t sent_to;
+ mach_msg_id_t sent_msgid;
+ } send_once;
+ } u;
+};
+#define INFO_SEND_ONCE(info) ((info)->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+
+static struct traced_info *freelist;
+
+struct hurd_ihash traced_names
+ = HURD_IHASH_INITIALIZER (offsetof (struct traced_info, u.send.locp));
+struct port_class *traced_class;
+struct port_bucket *traced_bucket;
+FILE *ostream;
+
+/* These are the calls made from the tracing engine into
+ the output formatting code. */
+
+/* Called for a message that does not look like an RPC reply.
+ The header has already been swapped into the sender's view
+ with interposed ports. */
+static void print_request_header (struct traced_info *info,
+ mach_msg_header_t *header);
+
+/* Called for a message that looks like an RPC reply. */
+static void print_reply_header (struct traced_info *info,
+ mig_reply_header_t *header);
+
+/* Called for each data item (which might be an array).
+ Always called after one of the above two. */
+static void print_data (mach_msg_type_name_t type,
+ const void *data,
+ mach_msg_type_number_t nelt,
+ mach_msg_type_number_t eltsize);
+
+/*** Mechanics of tracing messages and interposing on ports ***/
+
+
+/* Create a new wrapper port and do `ports_get_right' on it. */
+static struct traced_info *
+new_send_wrapper (mach_port_t right, mach_port_t *wrapper_right)
+{
+ error_t err;
+ struct traced_info *info;
+
+ /* Use a free send-once wrapper port if we have one. */
+ if (freelist)
+ {
+ info = freelist;
+ freelist = info->u.nextfree;
+ }
+ else
+ {
+ /* Create a new wrapper port that forwards to *RIGHT. */
+ err = ports_create_port (traced_class, traced_bucket,
+ sizeof *info, &info);
+ assert_perror (err);
+ info->name = 0;
+ }
+
+ info->forward = right;
+ info->type = MACH_MSG_TYPE_MOVE_SEND;
+
+ /* Store it in the reverse-lookup hash table, so we can
+ look up this same right again to find the wrapper port.
+ The entry in the hash table holds a weak ref on INFO. */
+ err = hurd_ihash_add (&traced_names, info->forward, info);
+ assert_perror (err);
+ ports_port_ref_weak (info);
+ assert (info->u.send.locp != 0);
+
+ *wrapper_right = ports_get_right (info);
+ ports_port_deref (info);
+
+ return info;
+}
+
+/* Create a new wrapper port and do `ports_get_right' on it. */
+static struct traced_info *
+new_send_once_wrapper (mach_port_t right, mach_port_t *wrapper_right)
+{
+ error_t err;
+ struct traced_info *info;
+
+ /* Use a free send-once wrapper port if we have one. */
+ if (freelist)
+ {
+ info = freelist;
+ freelist = info->u.nextfree;
+ }
+ else
+ {
+ /* Create a new wrapper port that forwards to *RIGHT. */
+ err = ports_create_port (traced_class, traced_bucket,
+ sizeof *info, &info);
+ assert_perror (err);
+ info->name = 0;
+ }
+
+ info->forward = right;
+ info->type = MACH_MSG_TYPE_MOVE_SEND_ONCE;
+
+ /* Send-once rights never compare equal to any other right (even
+ another send-once right), so there is no point in putting them
+ in the reverse-lookup table.
+
+ Since we never make send rights to this port, we don't want to
+ use the normal libports mechanisms (ports_get_right) that are
+ designed for send rights and no-senders notifications.
+ Instead, we hold on to the initial hard ref to INFO until we
+ receive a message on it. The kernel automatically sends a
+ MACH_NOTIFY_SEND_ONCE message if the send-once right dies. */
+
+ *wrapper_right = info->pi.port_right;
+ memset (&info->u.send_once, 0, sizeof info->u.send_once);
+
+ return info;
+}
+
+
+/* This gets called when a wrapper port has no hard refs (send rights),
+ only weak refs. The only weak ref is the one held in the reverse-lookup
+ hash table. */
+static void
+traced_dropweak (void *pi)
+{
+ struct traced_info *const info = pi;
+
+ assert (info->type == MACH_MSG_TYPE_MOVE_SEND);
+ assert (info->u.send.locp);
+
+ /* Remove INFO from the hash table. */
+ hurd_ihash_locp_remove (&traced_names, info->u.send.locp);
+ ports_port_deref_weak (info);
+
+ /* Deallocate the forward port, so the real port also sees no-senders. */
+ mach_port_deallocate (mach_task_self (), info->forward);
+
+ /* There are no rights to this port, so we can reuse it.
+ Add a hard ref and put INFO on the free list. */
+ ports_port_ref (info);
+
+ free (info->name);
+ info->name = 0;
+
+ info->u.nextfree = freelist;
+ freelist = info;
+}
+
+
+/* Rewrite a port right in a message with an appropriate wrapper port. */
+static struct traced_info *
+rewrite_right (mach_port_t *right, mach_msg_type_name_t *type)
+{
+ error_t err;
+ struct traced_info *info;
+
+ /* We can never do anything special with a null or dead port right. */
+ if (!MACH_PORT_VALID (*right))
+ return 0;
+
+ switch (*type)
+ {
+ case MACH_MSG_TYPE_PORT_SEND:
+ /* See if we are already tracing this port. */
+ info = hurd_ihash_find (&traced_names, *right);
+ if (info)
+ {
+ /* We are already tracing this port. We will pass on a right
+ to our existing wrapper port. */
+ *right = ports_get_right (info);
+ *type = MACH_MSG_TYPE_MAKE_SEND;
+ return info;
+ }
+
+ /* See if this is already one of our own wrapper ports. */
+ info = ports_lookup_port (traced_bucket, *right, 0);
+ if (info)
+ {
+ /* This is a send right to one of our own wrapper ports.
+ Instead, send along the original send right. */
+ mach_port_deallocate (mach_task_self (), *right); /* eat msg ref */
+ *right = info->forward;
+ err = mach_port_mod_refs (mach_task_self (), *right,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ ports_port_deref (info);
+ return info;
+ }
+
+ /* We have never seen this port before. Create a new wrapper port
+ and replace the right in the message with a right to it. */
+ *type = MACH_MSG_TYPE_MAKE_SEND;
+ return new_send_wrapper (*right, right);
+
+ case MACH_MSG_TYPE_PORT_SEND_ONCE:
+ /* There is no way to know if this send-once right is to the same
+ receive right as any other send-once or send right we have seen.
+ Fortunately, it doesn't matter, since the recipient of the
+ send-once right we pass along can't tell either. We always just
+ make a new send-once wrapper object, that will trace the one
+ message it receives, and then die. */
+ *type = MACH_MSG_TYPE_MAKE_SEND_ONCE;
+ return new_send_once_wrapper (*right, right);
+
+ case MACH_MSG_TYPE_PORT_RECEIVE:
+ /* We have got a receive right, call it A. We will pass along a
+ different receive right of our own, call it B. We ourselves will
+ receive messages on A, trace them, and forward them on to B.
+
+ If A is the receive right to a send right that we have wrapped,
+ then B must be that wrapper receive right, moved from us to the
+ intended receiver of A--that way it matches previous send rights
+ to A that were sent through and replaced with our wrapper (B).
+ If not, we create a new receive right. */
+ {
+ mach_port_t rr; /* B */
+ char *name;
+
+ info = hurd_ihash_find (&traced_names, *right);
+ if (info)
+ {
+ /* This is a receive right that we have been tracing sends to. */
+ name = info->name;
+ rr = ports_claim_right (info);
+ /* That released the refs on INFO, so it's been freed now. */
+ }
+ else
+ {
+ /* This is a port we know nothing about. */
+ rr = mach_reply_port ();
+ name = 0;
+ }
+
+ /* Create a new wrapper object that receives on this port. */
+ err = ports_import_port (traced_class, traced_bucket,
+ *right, sizeof *info, &info);
+ assert_perror (err);
+ info->name = name;
+ info->type = MACH_MSG_TYPE_MOVE_SEND; /* XXX ? */
+
+ /* Get us a send right that we will forward on. */
+ err = mach_port_insert_right (mach_task_self (), rr, rr,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ info->forward = rr;
+
+ err = hurd_ihash_add (&traced_names, info->forward, info);
+ assert_perror (err);
+ ports_port_ref_weak (info);
+
+ /* If there are no extant send rights to this port, then INFO will
+ die right here and release its send right to RR.
+ XXX what to do?
+ */
+ ports_port_deref (info);
+
+ *right = rr;
+ return info;
+ }
+
+ default:
+ assert (!"??? bogus port type from kernel!");
+ }
+ return 0;
+}
+
+static void
+print_contents (mach_msg_header_t *inp,
+ void *msg_buf_ptr)
+{
+ error_t err;
+
+ int first = 1;
+
+ /* Process the message data, wrapping ports and printing data. */
+ while (msg_buf_ptr < (void *) inp + inp->msgh_size)
+ {
+ mach_msg_type_t *const type = msg_buf_ptr;
+ mach_msg_type_long_t *const lt = (void *) type;
+ void *data;
+ mach_msg_type_number_t nelt; /* Number of data items. */
+ mach_msg_type_size_t eltsize; /* Bytes per item. */
+ mach_msg_type_name_t name; /* MACH_MSG_TYPE_* code */
+
+ if (!type->msgt_longform)
+ {
+ name = type->msgt_name;
+ nelt = type->msgt_number;
+ eltsize = type->msgt_size / 8;
+ data = msg_buf_ptr = type + 1;
+ }
+ else
+ {
+ name = lt->msgtl_name;
+ nelt = lt->msgtl_number;
+ eltsize = lt->msgtl_size / 8;
+ data = msg_buf_ptr = lt + 1;
+ }
+
+ if (!type->msgt_inline)
+ {
+ /* This datum is out-of-line, meaning the message actually
+ contains a pointer to a vm_allocate'd region of data. */
+ data = *(void **) data;
+ msg_buf_ptr += sizeof (void *);
+ }
+ else
+ msg_buf_ptr += ((nelt * eltsize + sizeof(natural_t) - 1)
+ & ~(sizeof(natural_t) - 1));
+
+ if (first)
+ first = 0;
+ else
+ putc (' ', ostream);
+
+ /* Note that MACH_MSG_TYPE_PORT_NAME does not indicate a port right.
+ It indicates a port name, i.e. just an integer--and we don't know
+ what task that port name is meaningful in. If it's meaningful in
+ a traced task, then it refers to our intercepting port rather than
+ the original port anyway. */
+ if (MACH_MSG_TYPE_PORT_ANY_RIGHT (name))
+ {
+ /* These are port rights. Translate them into wrappers. */
+ mach_port_t *const portnames = data;
+ mach_msg_type_number_t i;
+ mach_msg_type_name_t newtypes[nelt];
+ int poly;
+ struct traced_info *ti;
+
+ assert (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+ assert (eltsize == sizeof (mach_port_t));
+
+ poly = 0;
+ for (i = 0; i < nelt; ++i)
+ {
+ newtypes[i] = name;
+
+ if (inp->msgh_id == 3215) /* mach_port_insert_right */
+ {
+ /* XXX
+ */
+ fprintf (ostream,
+ "\t\t[%d] = pass through port %d, type %d\n",
+ i, portnames[i], name);
+ continue;
+ }
+
+ ti = rewrite_right (&portnames[i], &newtypes[i]);
+
+ putc ((i == 0 && nelt > 1) ? '{' : ' ', ostream);
+
+ if (portnames[i] == MACH_PORT_NULL)
+ fprintf (ostream, "(null)");
+ else if (portnames[i] == MACH_PORT_DEAD)
+ fprintf (ostream, "(dead)");
+ else
+ {
+ assert (ti);
+ if (ti->name != 0)
+ fprintf (ostream, "%s", ti->name);
+ else
+ fprintf (ostream, "%3u", (unsigned int) portnames[i]);
+ }
+ if (i > 0 && newtypes[i] != newtypes[0])
+ poly = 1;
+ }
+ if (nelt > 1)
+ putc ('}', ostream);
+
+ if (poly)
+ {
+ if (name == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ /* Some of the new rights are MAKE_SEND_ONCE.
+ Turn them all into MOVE_SEND_ONCE. */
+ for (i = 0; i < nelt; ++i)
+ if (newtypes[i] == MACH_MSG_TYPE_MAKE_SEND_ONCE)
+ {
+ err = mach_port_insert_right (mach_task_self (),
+ portnames[i],
+ portnames[i],
+ newtypes[i]);
+ assert_perror (err);
+ }
+ else
+ assert (newtypes[i] == MACH_MSG_TYPE_MOVE_SEND_ONCE);
+ }
+ else
+ {
+ for (i = 0; i < nelt; ++i)
+ switch (newtypes[i])
+ {
+ case MACH_MSG_TYPE_COPY_SEND:
+ err = mach_port_mod_refs (mach_task_self (),
+ portnames[i],
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ break;
+ case MACH_MSG_TYPE_MAKE_SEND:
+ err = mach_port_insert_right (mach_task_self (),
+ portnames[i],
+ portnames[i],
+ newtypes[i]);
+ assert_perror (err);
+ break;
+ default:
+ assert (newtypes[i] == MACH_MSG_TYPE_MOVE_SEND);
+ break;
+ }
+
+ name = MACH_MSG_TYPE_MOVE_SEND;
+ }
+ if (type->msgt_longform)
+ lt->msgtl_name = name;
+ else
+ type->msgt_name = name;
+ }
+ else if (nelt > 0 && newtypes[0] != name)
+ {
+ if (type->msgt_longform)
+ lt->msgtl_name = newtypes[0];
+ else
+ type->msgt_name = newtypes[0];
+ }
+ }
+ else
+ print_data (name, data, nelt, eltsize);
+ }
+}
+
+int
+trace_and_forward (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ const mach_msg_type_t RetCodeType =
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+
+ error_t err;
+ const struct msgid_info *msgid;
+ struct traced_info *info;
+ mach_msg_bits_t complex;
+
+ /* Look up our record for the receiving port. There is no need to check
+ the class, because our port bucket only ever contains one class of
+ ports (traced_class). */
+ info = ports_lookup_port (traced_bucket, inp->msgh_local_port, 0);
+ assert (info);
+
+ /* A notification message from the kernel appears to have been sent
+ with a send-once right, even if there have never really been any. */
+ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ if (inp->msgh_id == MACH_NOTIFY_DEAD_NAME)
+ {
+ /* If INFO is a send-once wrapper, this could be a forged
+ notification; oh well. XXX */
+
+ const mach_dead_name_notification_t *const n = (void *) inp;
+
+ assert (n->not_port == info->forward);
+ /* Deallocate extra ref allocated by the notification. */
+ mach_port_deallocate (mach_task_self (), n->not_port);
+ ports_destroy_right (info);
+ ports_port_deref (info);
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+ return 1;
+ }
+ else if (inp->msgh_id == MACH_NOTIFY_NO_SENDERS
+ && !INFO_SEND_ONCE (info))
+ {
+ /* No more senders for a send right we are tracing. Now INFO
+ will die, and we will release the tracee send right so it too
+ can see a no-senders notification. */
+ mach_no_senders_notification_t *n = (void *) inp;
+ ports_no_senders (info, n->not_count);
+ ports_port_deref (info);
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+ return 1;
+ }
+ }
+
+ assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == info->type);
+
+ complex = inp->msgh_bits & MACH_MSGH_BITS_COMPLEX;
+
+ msgid = msgid_info (inp->msgh_id);
+
+ /* Swap the header data like a crossover cable. */
+ {
+ mach_msg_type_name_t this_type = MACH_MSGH_BITS_LOCAL (inp->msgh_bits);
+ mach_msg_type_name_t reply_type = MACH_MSGH_BITS_REMOTE (inp->msgh_bits);
+
+ inp->msgh_local_port = inp->msgh_remote_port;
+ if (reply_type && msgid_trace_replies (msgid))
+ {
+ struct traced_info *info;
+ info = rewrite_right (&inp->msgh_local_port, &reply_type);
+ assert (info);
+ if (info->name == 0)
+ {
+ if (msgid == 0)
+ asprintf (&info->name, "reply(%u:%u)",
+ (unsigned int) info->pi.port_right,
+ (unsigned int) inp->msgh_id);
+ else
+ asprintf (&info->name, "reply(%u:%s)",
+ (unsigned int) info->pi.port_right, msgid->name);
+ }
+ if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ info->u.send_once.sent_to = info->pi.port_right;
+ info->u.send_once.sent_msgid = inp->msgh_id;
+ }
+ }
+
+ inp->msgh_remote_port = info->forward;
+ if (this_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ /* We have a message to forward for a send-once wrapper object.
+ Since each wrapper object only lives for a single message, this
+ one can be reclaimed now. We continue to hold a hard ref to the
+ ports object, but we know that nothing else refers to it now, and
+ we are consuming its `forward' right in the message we send. */
+ free (info->name);
+ info->name = 0;
+ info->u.nextfree = freelist;
+ freelist = info;
+ }
+ else
+ this_type = MACH_MSG_TYPE_COPY_SEND;
+
+ inp->msgh_bits = complex | MACH_MSGH_BITS (this_type, reply_type);
+ }
+
+ /* The message now appears as it would if we were the sender.
+ It is ready to be resent. */
+
+ if (msgid_display (msgid))
+ {
+ if (inp->msgh_local_port == MACH_PORT_NULL
+ && info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE
+ && inp->msgh_size >= sizeof (mig_reply_header_t)
+ && (*(int *) &((mig_reply_header_t *) inp)->RetCodeType
+ == *(int *)&RetCodeType))
+ {
+ /* This sure looks like an RPC reply message. */
+ mig_reply_header_t *rh = (void *) inp;
+ print_reply_header (info, rh);
+ putc (' ', ostream);
+ print_contents (&rh->Head, rh + 1);
+ putc ('\n', ostream);
+ }
+ else
+ {
+ /* Print something about the message header. */
+ print_request_header (info, inp);
+ print_contents (inp, inp + 1);
+ if (inp->msgh_local_port == MACH_PORT_NULL) /* simpleroutine */
+ fprintf (ostream, ");\n");
+ else
+ /* Leave a partial line that will be finished later. */
+ fprintf (ostream, ")");
+ }
+ }
+
+ /* Resend the message to the tracee. */
+ err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ /* The tracee port died. No doubt we are about to receive the dead-name
+ notification. */
+ /* XXX MAKE_SEND, MAKE_SEND_ONCE rights in msg not handled */
+ mach_msg_destroy (inp);
+ }
+ else
+ assert_perror (err);
+
+ ports_port_deref (info);
+
+ /* We already sent the message, so the server loop shouldn't do it again. */
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+
+ return 1;
+}
+
+/* This function runs in the tracing thread and drives all the tracing. */
+static any_t
+trace_thread_function (void *arg)
+{
+ struct port_bucket *const bucket = arg;
+ ports_manage_port_operations_one_thread (bucket, trace_and_forward, 0);
+ return 0;
+}
+
+/*** Output formatting ***/
+
+#if 0
+struct msg_type
+{
+ const char *name;
+ const char *letter;
+};
+
+static const char *const msg_types[] =
+{
+ [MACH_MSG_TYPE_BIT] = {"bool", "b"},
+ [MACH_MSG_TYPE_INTEGER_16] = {"int16", "h"},
+ [MACH_MSG_TYPE_INTEGER_32] = {"int32", "i"},
+ [MACH_MSG_TYPE_CHAR] = {"char", "c"},
+ [MACH_MSG_TYPE_INTEGER_8] = {"int8", "B"},
+ [MACH_MSG_TYPE_REAL] = {"float", "f"},
+ [MACH_MSG_TYPE_INTEGER_64] = {"int64", "q"},
+ [MACH_MSG_TYPE_STRING] = {"string", "s"},
+ [MACH_MSG_TYPE_MOVE_RECEIVE] = {"move-receive", "R"},
+ [MACH_MSG_TYPE_MOVE_SEND] = {"move-send", "S"},
+ [MACH_MSG_TYPE_MOVE_SEND_ONCE]= {"move-send-once", "O"},
+ [MACH_MSG_TYPE_COPY_SEND] = {"copy-send", "s"},
+ [MACH_MSG_TYPE_MAKE_SEND] = {"make-send", ""},
+ [MACH_MSG_TYPE_MAKE_SEND_ONCE]= {"make-send-once", ""},
+ [MACH_MSG_TYPE_PORT_NAME] = {"port-name", "n"},
+};
+#endif
+
+static mach_port_t expected_reply_port;
+
+static void
+print_request_header (struct traced_info *receiver, mach_msg_header_t *msg)
+{
+ const char *msgname = msgid_name (msg->msgh_id);
+
+ expected_reply_port = msg->msgh_local_port;
+
+ if (receiver->name != 0)
+ fprintf (ostream, "%4s->", receiver->name);
+ else
+ fprintf (ostream, "%4u->", (unsigned int) receiver->pi.port_right);
+
+ if (msgname != 0)
+ fprintf (ostream, "%5s (", msgname);
+ else
+ fprintf (ostream, "%5u (", (unsigned int) msg->msgh_id);
+}
+
+static void
+unfinished_line (void)
+{
+ /* A partial line was printed by print_request_header, but
+ cannot be finished before we print something else.
+ Finish this line with the name of the reply port that
+ will appear in the disconnected reply later on. */
+ fprintf (ostream, " > %4u ...\n", expected_reply_port);
+}
+
+static void
+print_reply_header (struct traced_info *info, mig_reply_header_t *reply)
+{
+ if (info->pi.port_right == expected_reply_port)
+ {
+ /* We have printed a partial line for the request message,
+ and now we have the corresponding reply. */
+ if (reply->Head.msgh_id == info->u.send_once.sent_msgid + 100)
+ fprintf (ostream, " = "); /* normal case */
+ else
+ /* This is not the proper reply message ID. */
+ fprintf (ostream, " =(%u != %u) ",
+ reply->Head.msgh_id,
+ info->u.send_once.sent_msgid + 100);
+ }
+ else
+ {
+ /* This does not match up with the last thing printed. */
+ if (expected_reply_port != MACH_PORT_NULL)
+ /* We don't print anything if the last call was a simpleroutine. */
+ unfinished_line ();
+ if (info->name == 0)
+ /* This was not a reply port in previous message sent
+ through our wrappers. */
+ fprintf (ostream, "reply?%4u",
+ (unsigned int) info->pi.port_right);
+ else
+ fprintf (ostream, "%s%4u",
+ info->name, (unsigned int) info->pi.port_right);
+ if (reply->Head.msgh_id == info->u.send_once.sent_msgid + 100)
+ /* This is a normal reply to a previous request. */
+ fprintf (ostream, " > ");
+ else
+ {
+ /* Weirdo. */
+ const char *msgname = msgid_name (reply->Head.msgh_id);
+ if (msgname == 0)
+ fprintf (ostream, " >(%u) ", reply->Head.msgh_id);
+ else
+ fprintf (ostream, " >(%s) ", msgname);
+ }
+ }
+
+ if (reply->RetCode == 0)
+ fprintf (ostream, "0");
+ else
+ {
+ const char *str = strerror (reply->RetCode);
+ if (str == 0)
+ fprintf (ostream, "%#x", reply->RetCode);
+ else
+ fprintf (ostream, "%#x (%s)", reply->RetCode, str);
+ }
+
+ expected_reply_port = MACH_PORT_NULL;
+}
+
+
+static void
+print_data (mach_msg_type_name_t type,
+ const void *data,
+ mach_msg_type_number_t nelt,
+ mach_msg_type_number_t eltsize)
+{
+ switch (type)
+ {
+ case MACH_MSG_TYPE_PORT_NAME:
+ assert (eltsize == sizeof (mach_port_t));
+ {
+ mach_msg_type_number_t i;
+ fprintf (ostream, "pn{");
+ for (i = 0; i < nelt; ++i)
+ {
+ fprintf (ostream, "%*u", (i > 0) ? 4 : 3,
+ (unsigned int) ((mach_port_t *) data)[i]);
+ }
+ fprintf (ostream, "}");
+ return;
+ }
+
+ case MACH_MSG_TYPE_STRING:
+ case MACH_MSG_TYPE_CHAR:
+ if (nelt > strsize)
+ nelt = strsize;
+ fprintf (ostream, "\"%.*s\"",
+ (int) (nelt * eltsize), (const char *) data);
+ return;
+
+#if 0
+ case MACH_MSG_TYPE_CHAR:
+ if (eltsize == 1)
+ FMT ("'%c'", unsigned char);
+ break;
+#endif
+
+#define FMT(fmt, ctype) do { \
+ mach_msg_type_number_t i; \
+ for (i = 0; i < nelt; ++i) \
+ { \
+ fprintf (ostream, "%s" fmt, \
+ (i == 0 && nelt > 1) ? "{" : i > 0 ? " " : "", \
+ *(const ctype *) data); \
+ data += eltsize; \
+ } \
+ if (nelt > 1) \
+ putc ('}', ostream); \
+ return; \
+ } while (0)
+
+ case MACH_MSG_TYPE_BIT:
+ case MACH_MSG_TYPE_INTEGER_8:
+ case MACH_MSG_TYPE_INTEGER_16:
+ case MACH_MSG_TYPE_INTEGER_32:
+ case MACH_MSG_TYPE_INTEGER_64:
+ switch (eltsize)
+ {
+ case 1: FMT ("%"PRId8, int8_t);
+ case 2: FMT ("%"PRId16, int16_t);
+ case 4: FMT ("%"PRId32, int32_t);
+ case 8: FMT ("%"PRId64, int64_t);
+ }
+ break;
+
+ case MACH_MSG_TYPE_REAL:
+ if (eltsize == sizeof (float))
+ FMT ("%g", float);
+ else if (eltsize == sizeof (double))
+ FMT ("%g", double);
+ else if (eltsize == sizeof (long double))
+ FMT ("%Lg", long double);
+ else
+ abort ();
+ break;
+ }
+
+ /* XXX */
+ fprintf (ostream, "\t%#x (type %d, %d*%d)\n", *(const int *)data, type,
+ nelt, eltsize);
+}
+
+
+/*** Main program and child startup ***/
+
+task_t traced_task;
+
+
+/* Run a child and have it do more or else `execvpe (argv, envp);'. */
+pid_t
+traced_spawn (char **argv, char **envp)
+{
+ error_t err;
+ pid_t pid;
+ mach_port_t task_wrapper;
+ struct traced_info *ti;
+ file_t file = file_name_path_lookup (argv[0], getenv ("PATH"),
+ O_EXEC, 0, 0);
+
+ if (file == MACH_PORT_NULL)
+ error (1, errno, "command not found: %s", argv[0]);
+
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &traced_task);
+ assert_perror (err);
+
+ /* Declare the new task to be our child. This is what a fork does. */
+ err = proc_child (getproc (), traced_task);
+ if (err)
+ error (2, err, "proc_child");
+ pid = task2pid (traced_task);
+ if (pid < 0)
+ error (2, errno, "task2pid");
+
+ /* Create a trace wrapper for the task port. */
+ ti = new_send_wrapper (traced_task, &task_wrapper);/* consumes ref */
+ asprintf (&ti->name, "task%d", (int) pid);
+
+ /* Replace the task's kernel port with the wrapper. When this task calls
+ `mach_task_self ()', it will get our wrapper send right instead of its
+ own real task port. */
+ err = mach_port_insert_right (mach_task_self (), task_wrapper,
+ task_wrapper, MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ err = task_set_special_port (traced_task, TASK_KERNEL_PORT, task_wrapper);
+ assert_perror (err);
+
+ /* Now actually run the command they told us to trace. We do the exec on
+ the actual task, so the RPCs to map in the program itself do not get
+ traced. Could have an option to use TASK_WRAPPER here instead. */
+ err = _hurd_exec (traced_task, file, argv, envp);
+ if (err)
+ error (2, err, "cannot exec `%s'", argv[0]);
+
+ /* We were keeping this send right alive so that the wrapper object
+ cannot die and hence our TRACED_TASK ref cannot have been released. */
+ mach_port_deallocate (mach_task_self (), task_wrapper);
+
+ return pid;
+}
+
+
+static void
+scan_msgids_dir (char **argz, size_t *argz_len, char *dir, bool append)
+{
+ struct dirent **eps;
+ int n;
+
+ int
+ msgids_file_p (const struct dirent *eps)
+ {
+ if (fnmatch ("*.msgids", eps->d_name, 0) != FNM_NOMATCH)
+ return 1;
+ return 0;
+ }
+
+ n = scandir (dir, &eps, msgids_file_p, NULL);
+ if (n >= 0)
+ {
+ for (int cnt = 0; cnt < n; ++cnt)
+ {
+ char *msgids_file;
+
+ if (asprintf (&msgids_file, "%s/%s", dir, eps[cnt]->d_name) < 0)
+ error (1, errno, "asprintf");
+
+ if (append == TRUE)
+ {
+ if (argz_add (argz, argz_len, msgids_file) != 0)
+ error (1, errno, "argz_add");
+ }
+ else
+ {
+ if (argz_insert (argz, argz_len, *argz, msgids_file) != 0)
+ error (1, errno, "argz_insert");
+ }
+ free (msgids_file);
+ }
+ }
+
+ /* If the directory couldn't be scanned for whatever reason, just ignore
+ it. */
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+ char *msgids_files_argz = NULL;
+ size_t msgids_files_argz_len = 0;
+ bool nostdinc = FALSE;
+ const char *outfile = 0;
+ char **cmd_argv = 0;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'o':
+ outfile = arg;
+ break;
+
+ case OPT_NOSTDINC:
+ nostdinc = TRUE;
+ break;
+
+ case 'i':
+ if (argz_add (&msgids_files_argz, &msgids_files_argz_len,
+ arg) != 0)
+ error (1, errno, "argz_add");
+ break;
+
+ case 'I':
+ scan_msgids_dir (&msgids_files_argz, &msgids_files_argz_len,
+ arg, TRUE);
+ break;
+
+ case 's':
+ strsize = atoi (arg);
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_ARG:
+ cmd_argv = &state->argv[state->next - 1];
+ state->next = state->argc;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ /* Insert the files from STD_MSGIDS_DIR at the beginning of the list, so that
+ their content can be overridden by subsequently parsed files. */
+ if (nostdinc == FALSE)
+ scan_msgids_dir (&msgids_files_argz, &msgids_files_argz_len,
+ STD_MSGIDS_DIR, FALSE);
+
+ if (msgids_files_argz != NULL)
+ {
+ char *msgids_file = NULL;
+
+ while ((msgids_file = argz_next (msgids_files_argz,
+ msgids_files_argz_len, msgids_file)))
+ parse_msgid_list (msgids_file);
+
+ free (msgids_files_argz);
+ }
+
+ if (outfile)
+ {
+ ostream = fopen (outfile, "w");
+ if (!ostream)
+ error (1, errno, "%s", outfile);
+ }
+ else
+ ostream = stderr;
+ setlinebuf (ostream);
+
+ traced_bucket = ports_create_bucket ();
+ traced_class = ports_create_class (0, &traced_dropweak);
+
+ hurd_ihash_set_cleanup (&msgid_ihash, msgid_ihash_cleanup, 0);
+
+ /* Spawn a single thread that will receive intercepted messages, print
+ them, and interpose on the ports they carry. The access to the
+ `traced_info' and ihash data structures is all single-threaded,
+ happening only in this new thread. */
+ cthread_detach (cthread_fork (trace_thread_function, traced_bucket));
+
+ /* Run the program on the command line and wait for it to die.
+ The other thread does all the tracing and interposing. */
+ {
+ pid_t child, pid;
+ int status;
+ child = traced_spawn (cmd_argv, envp);
+ pid = waitpid (child, &status, 0);
+ sleep (1); /* XXX gives other thread time to print */
+ if (pid != child)
+ error (1, errno, "waitpid");
+ if (WIFEXITED (status))
+ fprintf (ostream, "Child %d exited with %d\n",
+ pid, WEXITSTATUS (status));
+ else
+ fprintf (ostream, "Child %d %s\n", pid, strsignal (WTERMSIG (status)));
+ }
+
+ return 0;
+}
diff --git a/utils/setauth.c b/utils/setauth.c
new file mode 100644
index 00000000..73f221a0
--- /dev/null
+++ b/utils/setauth.c
@@ -0,0 +1,134 @@
+/* Change the authentication of selected processes
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (setauth);
+
+#define OPT_NO_SAVE 1
+
+static const struct argp_option options[] =
+{
+#ifdef SU
+ {"no-save", OPT_NO_SAVE, 0, 0, "Don't save removed effective ids as available ids"},
+#else
+ {"save", 's', 0, 0, "Save removed effective ids as available ids"},
+#endif
+ {"keep", 'k', 0, 0, "Keep old ids in addition to the new ones"},
+ { 0 }
+};
+
+static struct argp_child child_argps[] = {{ &frobauth_posix_argp }, { 0 }};
+
+static char doc[] =
+ "Change the authentication of selected processes";
+
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ auth_t auth; /* Authority to make changes. */
+ int save = 0, keep = 0;
+ struct idvec have_uids = IDVEC_INIT, have_gids = IDVEC_INIT;
+ struct frobauth frobauth = FROBAUTH_INIT;
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 's': save = 1; break;
+ case 'k': keep = 1; break;
+ case OPT_NO_SAVE: save = 0; break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ /* Modify UGIDS, to be what PID's new authentication should be, UGIDS is
+ what the user specified. */
+ error_t modify (struct ugids *ugids, const struct ugids *new,
+ pid_t pid, void *hook)
+ {
+ struct ugids old = UGIDS_INIT;
+ ugids_set (&old, ugids);
+
+ ugids_set (ugids, new);
+
+ if (keep)
+ ugids_merge (ugids, &old);
+ if (save)
+ {
+ ugids_save (&old);
+ ugids_merge (ugids, &old);
+ }
+
+ return 0;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *user,
+ pid_t pid, void *hook)
+ {
+ char *new_rep = ugids_rep (new, 1, 1, 0, 0, 0);
+ printf ("%d: Changed auth to %s\n", pid, new_rep);
+ free (new_rep);
+ }
+ struct argp argp = { options, parse_opt, 0, doc, child_argps };
+
+#ifdef SU
+ frobauth.default_user = 0;
+ save = 1; /* Default to saving ids */
+#endif
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ /* See what the invoking user is authorized to do. */
+ err = get_nonsugid_ids (&have_uids, &have_gids);
+ if (err)
+ error (52, err, "Cannot get invoking authentication");
+
+ /* Check passwords. */
+ err = ugids_verify_make_auth (&frobauth.ugids, &have_uids, &have_gids, 0, 0,
+ 0, 0, &auth);
+ if (err == EACCES)
+ error (15, 0, "Invalid password");
+ else if (err)
+ error (16, err, "Authentication failure");
+
+ if (frobauth_modify (&frobauth, &auth, 1, modify, print_info, 0))
+ return 0;
+ else
+ return 1;
+}
diff --git a/utils/settrans.c b/utils/settrans.c
index ff264a5b..a8814016 100644
--- a/utils/settrans.c
+++ b/utils/settrans.c
@@ -1,8 +1,7 @@
/* Set a file's translator.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,14 +22,21 @@
#include <stdlib.h>
#include <string.h>
#include <argp.h>
+#include <error.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
#include <argz.h>
#include <hurd/fshelp.h>
+#include <hurd/process.h>
+#include <version.h>
+
+#include <hurd/lookup.h>
+#include <hurd/fsys.h>
+
-char *argp_program_version = "settrans 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (settrans);
#define DEFAULT_TIMEOUT 60
@@ -39,33 +45,41 @@ char *argp_program_version = "settrans 1.0 (GNU " HURD_RELEASE ")";
static struct argp_option options[] =
{
- {"active", 'a', 0, 0, "Set NODE's active translator", 1},
- {"passive", 'p', 0, 0, "Set NODE's passive translator"},
- {"create", 'c', 0, 0, "Create NODE if it doesn't exist"},
+ {"active", 'a', 0, 0, "Start TRANSLATOR and set it as NODE's active translator" },
+ {"passive", 'p', 0, 0, "Change NODE's passive translator record (default)" },
+ {"create", 'c', 0, 0, "Create NODE if it doesn't exist" },
{"dereference", 'L', 0, 0, "If a translator exists, put the new one on top"},
{"pause", 'P', 0, 0, "When starting an active translator, prompt and"
" wait for a newline on stdin before completing the startup handshake"},
{"timeout", 't',"SEC",0, "Timeout for translator startup, in seconds"
" (default " STRINGIFY (DEFAULT_TIMEOUT) "); 0 means no timeout"},
- {"exclusive", 'x', 0, 0, "Only set the translator if there is none already"},
+ {"exclusive", 'x', 0, 0, "Only set the translator if there is not one already"},
+ {"orphan", 'o', 0, 0, "Disconnect old translator from the filesystem "
+ "(do not ask it to go away)"},
+
+ {"chroot", 'C', 0, 0,
+ "Instead of setting the node's translator, take following arguments up to"
+ " `--' and run that command chroot'd to the translated node."},
{0,0,0,0, "When setting the passive translator, if there's an active translator:"},
- {"goaway", 'g', 0, 0, "Make the active translator go away"},
- {"keep-active", 'k', 0, 0, "Leave the existing active translator running"},
+ {"goaway", 'g', 0, 0, "Ask the active translator to go away"},
+ {"keep-active", 'k', 0, 0, "Leave any existing active translator running"},
- {0,0,0,0, "When an active translator is told to go away:", 2},
+ {0,0,0,0, "When an active translator is told to go away:"},
{"recursive", 'R', 0, 0, "Shutdown its children too"},
- {"force", 'f', 0, 0, "If it doesn't want to die, force it"},
+ {"force", 'f', 0, 0, "Ask it to ignore current users and shutdown "
+ "anyway." },
{"nosync", 'S', 0, 0, "Don't sync it before killing it"},
{0, 0}
};
static char *args_doc = "NODE [TRANSLATOR ARG...]";
-static char *doc = "By default the passive translator is set.";
+static char *doc = "Set the passive/active translator on NODE."
+"\vBy default the passive translator is set.";
/* ---------------------------------------------------------------- */
-void
+int
main(int argc, char *argv[])
{
error_t err;
@@ -76,7 +90,7 @@ main(int argc, char *argv[])
/* The translator's arg vector, in '\0' separated format. */
char *argz = 0;
- int argz_len = 0;
+ size_t argz_len = 0;
/* The control port for any active translator we start up. */
fsys_t active_control = MACH_PORT_NULL;
@@ -88,9 +102,11 @@ main(int argc, char *argv[])
int goaway_flags = 0;
/* Various option flags. */
- int passive = 0, active = 0, keep_active = 0, pause = 0, kill_active = 0;
+ int passive = 0, active = 0, keep_active = 0, pause = 0, kill_active = 0,
+ orphan = 0;
int excl = 0;
int timeout = DEFAULT_TIMEOUT * 1000; /* ms */
+ char **chroot_command = 0;
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
@@ -120,6 +136,32 @@ main(int argc, char *argv[])
case 'g': kill_active = 1; break;
case 'x': excl = 1; break;
case 'P': pause = 1; break;
+ case 'o': orphan = 1; break;
+
+ case 'C':
+ if (chroot_command)
+ {
+ argp_error (state, "--chroot given twice");
+ return EINVAL;
+ }
+ chroot_command = &state->argv[state->next];
+ while (state->next < state->argc)
+ {
+ if (!strcmp (state->argv[state->next], "--"))
+ {
+ state->argv[state->next++] = 0;
+ if (chroot_command[0] == 0)
+ {
+ argp_error (state,
+ "--chroot must be followed by a command");
+ return EINVAL;
+ }
+ return 0;
+ }
+ ++state->next;
+ }
+ argp_error (state, "--chroot command must be terminated with `--'");
+ return EINVAL;
case 'c': lookup_flags |= O_CREAT; break;
case 'L': lookup_flags &= ~O_NOTRANS; break;
@@ -140,49 +182,63 @@ main(int argc, char *argv[])
argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
- if (!active && !passive)
+ if (!active && !passive && !chroot_command)
passive = 1; /* By default, set the passive translator. */
if (passive)
passive_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0);
if (active)
- active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0);
+ active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0)
+ | (orphan ? FS_TRANS_ORPHAN : 0);
if (passive && !active)
- /* When setting just the passive, decide what to do with any active. */
- if (kill_active)
- /* Make it go away. */
- active_flags = FS_TRANS_SET;
- else if (! keep_active)
- /* Ensure that there isn't one. */
- active_flags = FS_TRANS_SET | FS_TRANS_EXCL;
-
- if (active && argz_len > 0)
{
+ /* When setting just the passive, decide what to do with any active. */
+ if (kill_active)
+ /* Make it go away. */
+ active_flags = FS_TRANS_SET;
+ else if (! keep_active)
+ /* Ensure that there isn't one. */
+ active_flags = FS_TRANS_SET | FS_TRANS_EXCL;
+ }
+
+ if ((active || chroot_command) && argz_len > 0)
+ {
+ /* Error during file lookup; we use this to avoid duplicating error
+ messages. */
+ error_t open_err = 0;
+
/* The callback to start_translator opens NODE as a side effect. */
error_t open_node (int flags,
mach_port_t *underlying,
- mach_msg_type_name_t *underlying_type)
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
{
if (pause)
{
- fprintf (stderr, "Pausing...");
+ fprintf (stderr, "Translator pid: %d\nPausing...",
+ task2pid (task));
getchar ();
}
node = file_name_lookup (node_name, flags | lookup_flags, 0666);
if (node == MACH_PORT_NULL)
- return errno;
+ {
+ open_err = errno;
+ return open_err;
+ }
*underlying = node;
*underlying_type = MACH_MSG_TYPE_COPY_SEND;
return 0;
}
- err = fshelp_start_translator (open_node, argz, argz, argz_len, timeout,
- &active_control);
+ err = fshelp_start_translator (open_node, NULL, argz, argz, argz_len,
+ timeout, &active_control);
if (err)
- error(4, err, "%s", argz);
+ /* If ERR is due to a problem opening the translated node, we print
+ that name, otherwise, the name of the translator. */
+ error(4, err, "%s", (err == open_err) ? node_name : argz);
}
else
{
@@ -191,13 +247,46 @@ main(int argc, char *argv[])
error(1, errno, "%s", node_name);
}
- err =
- file_set_translator(node,
- passive_flags, active_flags, goaway_flags,
- argz, argz_len,
- active_control, MACH_MSG_TYPE_COPY_SEND);
- if (err)
- error(5, err, "%s", node_name);
+ if (active || passive)
+ {
+ err = file_set_translator (node,
+ passive_flags, active_flags, goaway_flags,
+ argz, argz_len,
+ active_control, MACH_MSG_TYPE_COPY_SEND);
+ if (err)
+ error (5, err, "%s", node_name);
+ }
+
+ if (chroot_command)
+ {
+ /* We will act as the parent filesystem would for a lookup
+ of the active translator's root node, then use this port
+ as our root directory while we exec the command. */
+
+ char retry_name[1024]; /* XXX */
+ retry_type do_retry;
+ mach_port_t root;
+ err = fsys_getroot (active_control,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND,
+ NULL, 0, NULL, 0, 0, &do_retry, retry_name, &root);
+ mach_port_deallocate (mach_task_self (), active_control);
+ if (err)
+ error (6, err, "fsys_getroot");
+ err = hurd_file_name_lookup_retry (&_hurd_ports_use, &getdport, 0,
+ do_retry, retry_name, 0, 0,
+ &root);
+ if (err)
+ error (6, err, "cannot resolve root port");
+
+ if (setcrdir (root))
+ error (7, errno, "cannot install root port");
+ mach_port_deallocate (mach_task_self (), root);
+ if (chdir ("/"))
+ error (8, errno, "cannot chdir to new root");
+
+ execvp (chroot_command[0], chroot_command);
+ error (8, errno, "cannot execute %s", chroot_command[0]);
+ }
- exit(0);
+ return 0;
}
diff --git a/utils/shd.c b/utils/shd.c
index cb4b0ad0..a1a4b26b 100644
--- a/utils/shd.c
+++ b/utils/shd.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995 Free Software Foundation
+/*
+ Copyright (C) 1994,95,99,2002 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,6 +23,7 @@
#include <device/device.h>
#include <unistd.h>
#include <errno.h>
+#include <error.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -44,7 +45,7 @@ reap (pid_t waitfor)
if (pid == -1)
{
if (errno != ECHILD && errno != EWOULDBLOCK)
- perror ("waitpid");
+ error (0, errno, "waitpid");
return;
}
else if (WIFEXITED (status))
@@ -54,7 +55,7 @@ reap (pid_t waitfor)
printf ("PID %d %s\n",
pid, strsignal (WTERMSIG (status)));
else if (WIFSTOPPED (status))
- printf ("PID %d stopped: %s\n",
+ printf ("PID %d stopped: %s\n",
pid, strsignal (WSTOPSIG (status)));
else
printf ("PID %d bizarre status %#x\n", pid, status);
@@ -69,6 +70,7 @@ run (char **argv, int fd0, int fd1)
{
file_t file;
char *program;
+ error_t err;
if (strchr (argv[0], '/') != NULL)
program = argv[0];
@@ -84,18 +86,22 @@ run (char **argv, int fd0, int fd1)
file = file_name_lookup (program, O_EXEC, 0);
if (file == MACH_PORT_NULL)
{
- perror (program);
+ error (0, errno, "%s", program);
return -1;
}
else
{
task_t task;
pid_t pid;
-
- errno = task_create (mach_task_self (), 0, &task);
- if (errno)
+
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &task);
+ if (err)
{
- perror ("task_create");
+ error (0, err, "task_create");
pid = -1;
}
else
@@ -109,12 +115,12 @@ run (char **argv, int fd0, int fd1)
*save = dup (to);
if (*save < 0)
{
- perror ("dup");
+ error (0, errno, "dup");
return -1;
}
if (dup2 (from, to) != to)
{
- perror ("dup2");
+ error (0, errno, "dup2");
return -1;
}
close (from);
@@ -126,7 +132,7 @@ run (char **argv, int fd0, int fd1)
return 0;
if (dup2 (*save, to) != to)
{
- perror ("dup2");
+ error (0, errno, "dup2");
return -1;
}
close (*save);
@@ -135,13 +141,16 @@ run (char **argv, int fd0, int fd1)
pid = task2pid (task);
if (pid == -1)
- perror ("task2pid"), pid = 0;
- errno = proc_child (proc, task);
- if (errno)
- perror ("proc_child");
+ {
+ error (0, errno, "task2pid");
+ pid = 0;
+ }
+ err = proc_child (proc, task);
+ if (err)
+ error (0, err, "proc_child");
if (pause_startup)
{
- printf ("Pausing...");
+ printf ("Pausing (child PID %d)...", pid);
fflush (stdout);
getchar ();
}
@@ -149,25 +158,26 @@ run (char **argv, int fd0, int fd1)
if (movefd (fd0, 0, &save0) ||
movefd (fd1, 1, &save1))
return -1;
-
- errno = _hurd_exec (task, file, argv, environ);
+
+ err = _hurd_exec (task, file, argv, environ);
if (restorefd (fd0, 0, &save0) ||
restorefd (fd1, 1, &save1))
return -1;
- if (errno)
+ if (err)
{
- perror ("_hurd_exec");
- errno = task_terminate (task);
- if (errno)
- perror ("task_terminate");
+ error (0, err, "_hurd_exec");
+ err = task_terminate (task);
+ if (err)
+ error (0, err, "task_terminate");
}
mach_port_deallocate (mach_task_self (), task);
}
mach_port_deallocate (mach_task_self (), file);
+ errno = err;
return pid;
}
}
@@ -183,7 +193,7 @@ command (int argc, char **argv)
bg = !strcmp (argv[argc - 1], "&");
if (bg)
argv[--argc] = NULL;
-
+
start = 0;
for (i = 1; i < argc; ++i)
if (! strcmp (argv[i], "|"))
@@ -192,7 +202,7 @@ command (int argc, char **argv)
argv[i] = NULL;
if (pipe (fds))
{
- perror ("pipe");
+ error (0, errno, "pipe");
return;
}
pid = run (argv + start, fd0, fds[1]);
@@ -213,7 +223,7 @@ command (int argc, char **argv)
int
-main ()
+main (int argc, char *argv[])
{
char *linebuf = NULL;
size_t linebufsize = 0;
@@ -228,15 +238,15 @@ main ()
mach_port_t hostp, masterd;
err = proc_getprivports (proc, &hostp, &masterd);
assert (!err);
-
+
err = device_open (masterd, D_WRITE|D_READ, "console", &outp);
assert (!err);
-
+
stdin = mach_open_devstream (outp, "r");
stdout = stderr = mach_open_devstream (outp, "w+");
}
#endif
-
+
/* Kludge to give boot a port to the auth server. */
exec_init (getdport (0), getauth (),
MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
@@ -266,7 +276,7 @@ main ()
{
if (feof (stdin))
return 0;
- perror ("getline");
+ error (0, errno, "getline");
continue;
}
@@ -321,7 +331,7 @@ main ()
if (argc != 2)
fprintf (stderr, "Usage: cd DIRECTORY\n");
else if (chdir (argv[1]))
- perror ("chdir");
+ error (0, errno, "chdir");
}
else if (!strcmp (argv[0], "exec"))
{
@@ -343,7 +353,7 @@ main ()
if (execv (program, &argv[1]) == 0)
fprintf (stderr, "execv (%s) returned 0!\n", program);
else
- perror ("execv");
+ error (0, errno, "execv");
}
}
else if (!strcmp (argv[0], "setenv"))
@@ -351,7 +361,7 @@ main ()
if (argc != 3)
fprintf (stderr, "Usage: setenv VAR VALUE\n");
else if (setenv (argv[1], argv[2], 1))
- perror ("setenv");
+ error (0, errno, "setenv");
}
else if (!strcmp (argv[0], "fork"))
{
@@ -359,7 +369,7 @@ main ()
switch (pid)
{
case -1:
- perror ("fork");
+ error (0, errno, "fork");
break;
case 0:
printf ("I am the child, PID %d.\n", (int) getpid ());
@@ -377,5 +387,3 @@ main ()
fflush (stderr);
}
}
-
-
diff --git a/utils/showtrans.c b/utils/showtrans.c
index d6acfd9d..aa55f14d 100644
--- a/utils/showtrans.c
+++ b/utils/showtrans.c
@@ -1,8 +1,7 @@
/* Show files' passive translators.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,11 +24,13 @@
#include <argp.h>
#include <fcntl.h>
#include <unistd.h>
+#include <version.h>
+#include <sys/mman.h>
#include <error.h>
#include <argz.h>
-char *argp_program_version = "showtrans 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (showtrans);
static struct argp_option options[] =
{
@@ -42,13 +43,13 @@ static struct argp_option options[] =
};
static char *args_doc = "FILE...";
-
-static char *doc = "A FILE argument of `-' prints the translator on the node \
-attached to standard input.";
+static char *doc = "Show the passive translator of FILE..."
+"\vA FILE argument of `-' prints the translator on the node"
+" attached to standard input.";
/* ---------------------------------------------------------------- */
-void
+int
main (int argc, char *argv[])
{
/* The default exit status -- changed to 0 if we find any translators. */
@@ -66,7 +67,7 @@ main (int argc, char *argv[])
else
{
char buf[1024], *trans = buf;
- int trans_len = sizeof (buf);
+ size_t trans_len = sizeof (buf);
error_t err = file_get_translator (node, &trans, &trans_len);
switch (err)
@@ -76,14 +77,15 @@ main (int argc, char *argv[])
argz_stringify (trans, trans_len, ' ');
if (!silent)
- if (print_prefix)
- printf ("%s: %s\n", name, trans);
- else
- puts (trans);
+ {
+ if (print_prefix)
+ printf ("%s: %.*s\n", name, (int) trans_len, trans);
+ else
+ printf ("%.*s\n", (int) trans_len, trans);
+ }
if (trans != buf)
- vm_deallocate (mach_task_self (),
- (vm_address_t)trans, trans_len);
+ munmap (trans, trans_len);
status = 0;
@@ -138,5 +140,5 @@ main (int argc, char *argv[])
argp_parse (&argp, argc, argv, 0, 0, 0);
- exit (status);
+ return status;
}
diff --git a/utils/storecat.c b/utils/storecat.c
new file mode 100644
index 00000000..7f9de491
--- /dev/null
+++ b/utils/storecat.c
@@ -0,0 +1,73 @@
+/* Write a store to stdout
+
+ Copyright (C) 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <error.h>
+
+#include <hurd/store.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (storecat);
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct store *s;
+ char *name;
+ store_offset_t addr;
+ store_offset_t left;
+ const struct argp_child kids[] = { { &store_argp }, { 0 }};
+ struct argp argp =
+ { 0, 0, 0, "Write the contents of a store to stdout", kids };
+ struct store_argp_params p = { 0 };
+
+ argp_parse (&argp, argc, argv, 0, 0, &p);
+ err = store_parsed_name (p.result, &name);
+ if (err)
+ error (2, err, "store_parsed_name");
+
+ err = store_parsed_open (p.result, STORE_READONLY, &s);
+ if (err)
+ error (4, err, "%s", name);
+
+ addr = 0;
+ left = s->size;
+ while (left > 0)
+ {
+ size_t read = left > 1024*1024 ? 1024*1024 : left;
+ char buf[4096];
+ void *data = buf;
+ size_t data_len = sizeof (buf);
+
+ err = store_read (s, addr, read, &data, &data_len);
+ if (err)
+ error (5, err, "%s", name);
+ if (write (1, data, data_len) < 0)
+ error (6, errno, "stdout");
+
+ addr += data_len >> s->log2_block_size;
+ left -= data_len;
+ }
+
+ exit (0);
+}
diff --git a/utils/storeinfo.c b/utils/storeinfo.c
index ba6d0654..a738d50d 100644
--- a/utils/storeinfo.c
+++ b/utils/storeinfo.c
@@ -1,8 +1,8 @@
/* Show where a file exists
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,22 +25,24 @@
#include <argp.h>
#include <unistd.h>
#include <sys/fcntl.h>
+#include <version.h>
#include <error.h>
#include <hurd/fs.h>
#include <hurd/store.h>
-char *argp_program_version = "storeinfo 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (storeinfo);
static struct argp_option options[] =
{
- {"kind", 'k', 0, 0, "Print the type of store behind FILE"},
+ {"type", 't', 0, 0, "Print the type of store behind FILE"},
+ {"flags", 'f', 0, 0, "Print the flags associated with FILE's store"},
{"name", 'n', 0, 0, "Print the name of the store behind FILE"},
{"blocks", 'b', 0, 0, "Print the number of blocks in FILE"},
{"block-size", 'B', 0, 0, "Print the block size of FILE's store"},
{"size", 's', 0, 0, "Print the size, in bytes, of FILE"},
- {"runs", 'r', 0, 0, "Print the runs of blocks in FILE"},
+ {"block-list", 'l', 0, 0, "Print the blocks that are in FILE"},
{"children", 'c', 0, 0, "If the store has children, show them too"},
{"dereference", 'L', 0, 0, "If FILE is a symbolic link, follow it"},
{"prefix", 'p', 0, 0, "Always print `FILE: ' before info"},
@@ -48,26 +50,28 @@ static struct argp_option options[] =
{0, 0}
};
static char *args_doc = "FILE...";
-static char *doc = "With no FILE arguments, the file attached to standard \
-input is used. The fields to be printed are separated by colons, in this \
-order: PREFIX: KIND: NAME: BLOCK-SIZE: BLOCKS: SIZE: RUNS. If the store is a \
-composite one and --children is specified, children are printed on lines \
-following the main store, indented accordingly. By default, all \
-fields, and children, are printed.";
+static char *doc = "Show information about storage used by FILE..."
+"\vWith no FILE arguments, the file attached to standard"
+" input is used. The fields to be printed are separated by colons, in this"
+" order: PREFIX: TYPE (FLAGS): NAME: BLOCK-SIZE: BLOCKS: SIZE: BLOCK-LIST."
+" If the store is a composite one and --children is specified, children"
+" are printed on lines following the main store, indented accordingly."
+" By default, all fields, and children, are printed.";
/* ---------------------------------------------------------------- */
/* Things we can print about a file's storage. */
#define W_SOURCE 0x01
-#define W_KIND 0x02
+#define W_TYPE 0x02
#define W_NAME 0x04
#define W_BLOCKS 0x08
#define W_BLOCK_SIZE 0x10
#define W_SIZE 0x20
#define W_RUNS 0x40
#define W_CHILDREN 0x80
+#define W_FLAGS 0x100
-#define W_ALL 0xFF
+#define W_ALL 0x1FF
/* Print a line of information (exactly what is determinted by WHAT)
about store to stdout. LEVEL is the desired indentation level. */
@@ -87,7 +91,7 @@ print_store (struct store *store, int level, unsigned what)
putchar (' ');
}
}
- void pstr (char *str, unsigned mask)
+ void pstr (const char *str, unsigned mask)
{
if ((what & mask) == mask)
{
@@ -95,12 +99,20 @@ print_store (struct store *store, int level, unsigned what)
fputs (str ?: "-", stdout);
}
}
- void pint (off_t val, unsigned mask)
+ void psiz (size_t val, unsigned mask)
{
if ((what & mask) == mask)
{
psep ();
- printf ("%ld", val);
+ printf ("%zu", val);
+ }
+ }
+ void poff (store_offset_t val, unsigned mask)
+ {
+ if ((what & mask) == mask)
+ {
+ psep ();
+ printf ("%Ld", val);
}
}
@@ -111,9 +123,9 @@ print_store (struct store *store, int level, unsigned what)
putchar (' ');
}
- pstr (store->class->name,W_KIND);
+ pstr (store->class->name,W_TYPE);
- if (store->flags && (what & W_KIND))
+ if ((store->flags & ~STORE_INACTIVE) && (what & W_FLAGS))
{
int t = 0; /* flags tested */
int f = 1;
@@ -140,20 +152,20 @@ print_store (struct store *store, int level, unsigned what)
pf (STORE_ENFORCED, "enf");
pf (STORAGE_MUTATED, "mut");
- if (store->flags & ~t)
+ if (store->flags & ~(t | STORE_INACTIVE))
/* Leftover flags. */
{
if (! f)
putchar (';');
- printf ("0x%x", store->flags);
+ printf ("0x%x", store->flags & ~(t | STORE_INACTIVE));
}
- putchar ('(');
+ putchar (')');
}
pstr (store->name, W_NAME);
- pint (store->block_size, W_BLOCK_SIZE);
- pint (store->blocks, W_BLOCKS);
- pint (store->size, W_SIZE);
+ psiz (store->block_size, W_BLOCK_SIZE);
+ poff (store->blocks, W_BLOCKS);
+ poff (store->size, W_SIZE);
if (what & W_RUNS)
{
@@ -163,9 +175,10 @@ print_store (struct store *store, int level, unsigned what)
if (i > 0)
putchar (',');
if (store->runs[i].start < 0)
- printf ("[%ld]", store->runs[i].length);
+ /* A hole */
+ printf ("@+%Ld", store->runs[i].length);
else
- printf ("%ld[%ld]", store->runs[i].start, store->runs[i].length);
+ printf ("%Ld+%Ld", store->runs[i].start, store->runs[i].length);
}
}
@@ -177,8 +190,8 @@ print_store (struct store *store, int level, unsigned what)
print_store (store->children[i], level + 1, what);
}
-void
-main(int argc, char *argv[])
+int
+main (int argc, char *argv[])
{
int deref = 0, print_prefix = -1;
unsigned what = 0;
@@ -191,7 +204,7 @@ main(int argc, char *argv[])
struct store *store;
if (file == MACH_PORT_NULL)
- error (3, err, source);
+ error (3, err, "%s", source);
if (print_prefix < 0)
/* By default, only print filename prefixes for multiple files. */
@@ -200,9 +213,14 @@ main(int argc, char *argv[])
if (what == 0)
what = W_ALL;
- err = store_create (file, 0, 0, &store);
+ /* The STORE_NO_FILEIO flag tells it to give us the special
+ "unknown" class instead of an error if it cannot parse the
+ file_get_storage_info results. That will allow us to display
+ what we can from them, i.e. the name that shows at least some
+ of what the unknown data looked like. */
+ err = store_create (file, STORE_INACTIVE|STORE_NO_FILEIO, 0, &store);
if (err)
- error (4, err, source);
+ error (4, err, "%s", source);
print_store (store, 0, what);
store_free (store);
@@ -214,12 +232,13 @@ main(int argc, char *argv[])
case 'p': print_prefix = 1; break;
case 'P': print_prefix = 0; break;
- case 'k': what |= W_KIND; break;
+ case 't': what |= W_TYPE; break;
+ case 'f': what |= W_FLAGS; break;
case 'n': what |= W_NAME; break;
case 'b': what |= W_BLOCKS; break;
case 'B': what |= W_BLOCK_SIZE; break;
case 's': what |= W_SIZE; break;
- case 'r': what |= W_RUNS; break;
+ case 'l': what |= W_RUNS; break;
case 'c': what |= W_CHILDREN; break;
case ARGP_KEY_NO_ARGS:
@@ -245,5 +264,5 @@ main(int argc, char *argv[])
argp_parse (&argp, argc, argv, 0, 0, 0);
- exit(0);
+ return 0;
}
diff --git a/utils/storeread.c b/utils/storeread.c
new file mode 100644
index 00000000..df381bec
--- /dev/null
+++ b/utils/storeread.c
@@ -0,0 +1,130 @@
+/* Write portions of a store to stdout
+
+ Copyright (C) 1996,97,99,2001,02,03,04 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <argp.h>
+#include <error.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+
+#include <hurd/store.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (storeread);
+
+struct argp_option options[] = {
+ {"file", 'f', 0, 0, "Use file IO instead of the raw device"},
+ {"block-size", 'b', "BYTES", 0, "Set the file block size"},
+ {0, 0}
+};
+const char arg_doc[] = "FILE [ADDR [LENGTH]]...";
+const char doc[] = "Write portions of the contents of a store to stdout"
+"\vADDR is in blocks, and defaults to 0;"
+" LENGTH is in bytes, and defaults to the remainder of FILE.";
+
+int
+main (int argc, char **argv)
+{
+ struct store *store = 0;
+ store_offset_t addr = -1;
+ int dumped = 0, use_file_io = 0, block_size = 0;
+
+ void dump (store_offset_t addr, ssize_t len)
+ {
+ char buf[4096];
+ void *data = buf;
+ size_t data_len = sizeof (buf);
+
+ /* XXX: store->size can be too big for len. */
+ error_t err =
+ store_read (store, addr, len < 0 ? store->size : len,
+ &data, &data_len);
+ if (err)
+ error (5, err, store->name ? "%s" : "<store>", store->name);
+ if (write (1, data, data_len) < 0)
+ error (6, errno, "stdout");
+ if (data != buf)
+ munmap (data, data_len);
+ }
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'f': use_file_io = 1; break;
+ case 'b': block_size = atoi (arg); break;
+
+ case ARGP_KEY_ARG:
+ if (! store)
+ {
+ error_t err;
+ file_t source = file_name_lookup (arg, O_READ, 0);
+ if (errno)
+ error (2, errno, "%s", arg);
+ if (use_file_io)
+ if (block_size)
+ {
+ struct stat stat;
+ err = io_stat (source, &stat);
+ if (! err)
+ {
+ struct store_run run = {0, stat.st_size / block_size};
+ err = _store_file_create (source, 0, block_size, &run, 1,
+ &store);
+ }
+ }
+ else
+ err = store_file_create (source, 0, &store);
+ else
+ err = store_create (source, 0, 0, &store);
+ if (err)
+ error (3, err, "%s", arg);
+ }
+ else if (addr < 0)
+ addr = atoll (arg);
+ else
+ {
+ dump (addr, atoi (arg));
+ dumped = 1;
+ addr = -1;
+ }
+ break;
+
+ case ARGP_KEY_END:
+ if (!store)
+ argp_usage (state);
+
+ if (addr >= 0)
+ dump (addr, -1);
+ else if (! dumped)
+ dump (0, -1);
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, arg_doc, doc};
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+ exit (0);
+}
diff --git a/utils/su.c b/utils/su.c
deleted file mode 100644
index de12917e..00000000
--- a/utils/su.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/* `su' for GNU Hurd.
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
- Written by Roland McGrath.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Unlike Unix su, this program does not spawn a subshell. Instead, it
- adds or removes (with the -r flag) auth rights to all the processes in
- the current login. Note that the addition and removal of rights to a
- particular process is voluntary; the process doesn't get them unless
- it's listening for the right rpc (which the C library normally does),
- and it doesn't have to release any of the rights it has when requested
- (though the C library does this automatically in most programs).
-
- The -r flag allows you to easily be authorized or not authorized for any
- number of users (uids and gid sets). This program is not intelligent,
- however. The -r flag always removes whatever gids the specified user
- has. If some other user you have obtained authorization for has some of
- the same gids, it will remove them. The C library could be intelligent
- enough to look up the groups of all the uids it has, and make sure it
- has at least those. */
-
-#include <stdlib.h>
-#include <hurd.h>
-#include <pwd.h>
-#include <grp.h>
-#include <termios.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <hurd/msg.h>
-#include <assert.h>
-
-process_t proc; /* Our proc server port. */
-
-/* Command line flags. */
-int remove_ids = 0; /* -r: Remove ids instead of adding them. */
-
-const struct option longopts[] =
- {
- { "remove", 0, 0, 'r' },
- { "uid", 0, 0, 'u' },
- { "gid", 0, 0, 'g' },
- { "loginuser", 0, 0, 'l' },
- { "pid", 0, 0, 'p' },
- { "pgrp", 0, 0, 'G' },
- { "loginid", 0, 0, 'i' },
- { 0, }
- };
-
-struct auth
- {
- unsigned int *ids;
- auth_t authport;
- };
-
-/* These functions return a malloc'd array of ids that can be passed to
- make_auth_handle or used in del_auth messages. They check authorization
- and return NULL on failure. */
-unsigned int *get_uid (const char *user); /* From a named user or UID. */
-unsigned int *get_gid (const char *user); /* From a named group or GID. */
-unsigned int *get_user (const char *user); /* All ids for a named user. */
-
-int apply_auth (struct auth *auth, pid_t, int);
-int apply_auth_to_pids (struct auth *auth, unsigned int, pid_t *, int);
-int apply_auth_to_pgrp (struct auth *auth, pid_t);
-int apply_auth_to_loginid (struct auth *auth, int);
-
-int check_password (const char *name, const char *password);
-
-
-int
-main (int argc, char **argv)
-{
- int c;
- int status;
- enum { user, group, loginuser, loginid, pid, pgrp } mode = loginuser;
- struct auth auth[argc];
- unsigned int authidx = 0, loginidx = 0, pididx = 0, pgrpidx = 0;
- int loginids[argc];
- pid_t pids[argc], pgrps[argc];
- unsigned int i, j;
-
- proc = getproc (); /* Used often. */
-
- while ((c = getopt_long (argc, argv, "--rgulpiG", longopts, NULL)) != EOF)
- switch (c)
- {
- case 'r':
- remove_ids = 1;
- break;
-
- case 'u':
- mode = user;
- break;
- case 'g':
- mode = group;
- break;
- case 'l':
- mode = loginuser;
- break;
- case 'p':
- mode = pid;
- break;
- case 'i':
- mode = loginid;
- break;
- case 'G':
- mode = pgrp;
- break;
-
- case 1: /* Non-option argument. */
- switch (mode)
- {
- case user:
- auth[authidx++].ids = get_uid (optarg);
- break;
- case group:
- auth[authidx++].ids = get_gid (optarg);
- break;
- case loginuser:
- auth[authidx++].ids = get_user (optarg);
- break;
-
- case pid:
- pids[pididx++] = atoi (optarg);
- break;
- case loginid:
- loginids[loginidx++] = atoi (optarg);
- break;
- case pgrp:
- pgrps[pgrpidx++] = atoi (optarg);
- break;
- }
- break;
-
- case '?':
- default:
- fprintf (stderr, "Usage: %s [-r|--remove]\n\
- [-u|--uid UID...] [-g|--gid GID...] [-l|--loginuser USER...]\n\
- [-p|--pid PID...] [-i|--loginid ID...] [-G|--pgrp PGRP...]\n",
- program_invocation_short_name);
- exit (1);
- }
-
- if (authidx == 0)
- /* No ids specified; default is "su root". */
- auth[authidx++].ids = get_user ("root");
-
- if (pididx == 0 && loginidx == 0 && pgrpidx == 0)
- {
- /* No processes specified; default is current login collection. */
- errno = proc_getloginid (proc, getpid (), &loginids[loginidx++]);
- if (errno)
- {
- perror ("proc_getloginid");
- return 1;
- }
- }
-
- status = 0;
-
- if (! remove_ids)
- for (i = 0; i < authidx; ++i)
- {
- struct auth *a = &auth[i];
- errno = auth_makeauth (getauth (), NULL, MACH_MSG_TYPE_COPY_SEND, 0,
- &a->ids[1], a->ids[0], NULL, 0,
- &a->ids[1 + a->ids[0] + 1],
- a->ids[1 + a->ids[0]], NULL, 0, &a->authport);
- if (errno)
- {
- perror ("auth_makeauth");
- status = 1;
- }
- }
-
- for (j = 0; j < authidx; ++j)
- status |= apply_auth_to_pids (&auth[j], pididx, pids, 0);
-
- for (i = 0; i < loginidx; ++i)
- {
- for (j = 0; j < authidx; ++j)
- status |= apply_auth_to_loginid (&auth[j], loginids[i]);
- }
-
- for (i = 0; i < pgrpidx; ++i)
- {
- for (j = 0; j < authidx; ++j)
- status |= apply_auth_to_loginid (&auth[j], pgrps[i]);
- }
-
-
- return status;
-}
-
-/* Turn USER into a list of ids, giving USER's primary uid and gid from the
- passwd file and all the groups that USER appears in in the group file. */
-
-unsigned int *
-get_user (const char *user)
-{
- struct passwd *p;
- unsigned int ngids, *ids;
-
- p = getpwnam (user);
- if (p == NULL)
- {
- fprintf (stderr, "%s: User `%s' not found\n",
- program_invocation_short_name, user);
- return NULL;
- }
-
- if (! check_password (user, p->pw_passwd))
- return NULL;
-
- /* We don't need to change our own gids, but it doesn't really hurt,
- and initgroups does all the work for us. */
- if (initgroups (user, p->pw_gid) < 0)
- {
- perror ("initgroups");
- return NULL;
- }
- ngids = getgroups (0, NULL);
- if ((int) ngids < 0)
- {
- getgroups_lost:
- perror ("getgroups");
- return NULL;
- }
- assert (sizeof (*ids) == sizeof (gid_t));
- ids = malloc ((3 + ngids) * sizeof (*ids));
- ids[0] = 1;
- ids[1] = p->pw_uid;
- ids[2] = getgroups (ngids, &ids[3]);
- if ((int) ids[2] < 0)
- goto getgroups_lost;
-
- return ids;
-}
-
-/* Return an id list containing just the uid of USER. */
-
-unsigned int *
-get_uid (const char *user)
-{
- struct passwd *p;
- unsigned int *ids;
- uid_t uid;
- char *uend;
-
- uid = strtoul (user, &uend, 10);
- if (uend && *uend == '\0')
- {
- if (remove_ids || getuid () == 0)
- /* No need to verify. */
- p = NULL;
- else
- {
- p = getpwuid (uid);
- if (p == NULL)
- {
- fprintf (stderr, "%s: UID %u not found\n",
- program_invocation_short_name, uid);
- return NULL;
- }
- }
- }
- else
- {
- p = getpwnam (user);
- if (p == NULL)
- {
- fprintf (stderr, "%s: User `%s' not found\n",
- program_invocation_short_name, user);
- return NULL;
- }
- }
-
- if (p != NULL && ! check_password (user, p->pw_passwd))
- return NULL;
-
- ids = malloc (3 * sizeof (*ids));
- ids[0] = 1;
- ids[1] = p->pw_uid;
- ids[2] = 0;
-
- return ids;
-}
-
-/* Return an id list containing just the gid of GROUP. */
-
-unsigned int *
-get_gid (const char *group)
-{
- struct group *g;
- unsigned int *ids;
- gid_t gid;
- char *gend;
-
- gid = strtoul (group, &gend, 10);
- if (gend && *gend == '\0')
- {
- if (remove_ids || getuid () == 0)
- /* No need to verify. */
- g = NULL;
- else
- {
- g = getgrgid (gid);
- if (g == NULL)
- {
- fprintf (stderr, "%s: GID %u not found\n",
- program_invocation_short_name, gid);
- return NULL;
- }
- }
- }
- else
- {
- g = getgrnam (group);
- if (g == NULL)
- {
- fprintf (stderr, "%s: Group `%s' not found\n",
- program_invocation_short_name, group);
- return NULL;
- }
- }
-
- if (g != NULL && ! check_password (group, g->gr_passwd))
- return NULL;
-
- ids = malloc (3 * sizeof (*ids));
- ids[0] = 0;
- ids[1] = 1;
- ids[2] = g->gr_gid;
-
- return ids;
-}
-
-/* Add or delete (under -r) the ids indicated by AUTH to/from PID. If
- IGNORE_BAD_PID is nonzero, return success if PID does not exist.
- Returns zero if successful, nonzero on error (after printing message). */
-
-int
-apply_auth (struct auth *auth, pid_t pid, int ignore_bad_pid)
-{
- error_t err;
-
- if (! auth->ids)
- return 0;
-
- err = HURD_MSGPORT_RPC (proc_getmsgport (proc, pid, &msgport),
- proc_pid2task (proc, pid, &refport), 1,
- remove_ids ?
- msg_del_auth (msgport, refport,
- &auth->ids[1], auth->ids[0],
- &auth->ids[1 + auth->ids[0] + 1],
- auth->ids[1 + auth->ids[0]]) :
- msg_add_auth (msgport, auth->authport));
- if (err &&
- (!ignore_bad_pid || (err != ESRCH && err != MIG_SERVER_DIED)))
- {
- fprintf (stderr, "%s: error in %s_auth from PID %d: %s\n",
- program_invocation_short_name,
- remove_ids ? "del" : "add", pid, strerror (err));
- return 1;
- }
- else
- return 0;
-}
-
-int
-apply_auth_to_pids (struct auth *auth, unsigned int npids, pid_t pids[],
- int ignore_bad_pid)
-{
- int status = 0;
- unsigned int i;
-
- for (i = 0; i < npids; ++i)
- status |= apply_auth (auth, pids[i], ignore_bad_pid);
-
- return status;
-}
-
-int
-apply_auth_to_loginid (struct auth *auth, int loginid)
-{
- unsigned int npids = 20;
- pid_t pidbuf[20], *pids = pidbuf;
- int status;
- error_t err;
-
- err = proc_getloginpids (proc, loginid, &pids, &npids);
- if (err)
- {
- fprintf (stderr, "%s: proc_getloginpids failed for loginid %d: %s\n",
- program_invocation_short_name, loginid, strerror (err));
- return 1;
- }
-
- status = apply_auth_to_pids (auth, npids, pids, 1);
-
- if (pids != pidbuf)
- vm_deallocate (mach_task_self (),
- (vm_address_t) pids, npids * sizeof (pid_t));
-
- return status;
-}
-
-int
-apply_auth_to_pgrp (struct auth *auth, pid_t pgrp)
-{
- unsigned int npids = 20;
- pid_t pidbuf[20], *pids = pidbuf;
- int status;
- error_t err;
-
- err = proc_getpgrppids (proc, pgrp, &pids, &npids);
- if (err)
- {
- fprintf (stderr, "%s: proc_getpgrppids failed for pgrp %d: %s\n",
- program_invocation_short_name, pgrp, strerror (err));
- return 1;
- }
-
- status = apply_auth_to_pids (auth, npids, pids, 1);
-
- if (pids != pidbuf)
- vm_deallocate (mach_task_self (),
- (vm_address_t) pids, npids * sizeof (pid_t));
-
- return status;
-}
-
-/* Return 1 if the user gives the correct password matching the encrypted
- string PASSWORD, 0 if not. Return 1 without asking for a password if
- run by uid 0 or if PASSWORD is an empty password, and always under -r.
- Always prints a message before returning 0. */
-int
-check_password (const char *name, const char *password)
-{
- extern char *crypt (const char *string, const char salt[2]);
-#pragma weak crypt
- char *unencrypted, *encrypted;
- static char *prompt = NULL;
-
- if (remove_ids || getuid () == 0 || password == NULL || password[0] == '\0')
- return 1;
-
- asprintf (&prompt, "%s's Password:", name);
- unencrypted = getpass (prompt);
- if (crypt)
- {
- encrypted = crypt (unencrypted, password);
- memset (unencrypted, 0, strlen (unencrypted)); /* Paranoia may destroya. */
- }
- else
- encrypted = unencrypted;
-
- if (!strcmp (encrypted, password))
- return 1;
-
- fprintf (stderr, "%s: Access denied for `%s'\n",
- program_invocation_short_name, name);
- return 0;
-}
diff --git a/utils/sush.sh b/utils/sush.sh
index 034fb6ad..4fccd75e 100644
--- a/utils/sush.sh
+++ b/utils/sush.sh
@@ -1,3 +1,90 @@
#!/bin/sh
-# A unix-like su (one which invokes a sub-shell).
-exec /bin/login --program-name="$0" -pxSLf -aHOME -aMOTD -aUMASK -aBACKUP_SHELLS "$@"
+# A unix-like su (one which invokes a sub-shell).
+#
+# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+ARGS_DOC="[USER|- [COMMAND [ARG...]]]"
+USAGE="Usage: $0 $ARGS_DOC"
+DOC="Start a new shell, or COMMAND, as USER"
+
+LOGIN=${LOGIN-/bin/login}
+FMT=${FMT-/bin/fmt}
+
+needs_arg=""
+for I; do
+ case $needs_arg in
+ ?*) needs_arg="";;
+ "")
+ case "$I" in
+ -e|-E|-g|-G|-u|-U|--envar|--envva|--env|--en|--e|--envvar-default|--envvar-defaul|--envvar-defau|--envvar-defa|--envvar-def|--envvar-def|--envvar-de|--envvar-d|--envvar-|--group|--grou|--gro|--gr|--g|--avail-group|--avail-grou|--avail-gro|--avail-gr|--avail-g|--user|--use|--us|--u|--avail-user|--avail-use|--avail-us|--avail-u)
+ needs_arg="$I";;
+ -e*|-E*|-g*|-G*|-u*|-U*|--envar=*|--envva=*|--env=*|--en=*|--e=*|--envvar-default=*|--envvar-defaul=*|--envvar-defau=*|--envvar-defa=*|--envvar-def=*|--envvar-def=*|--envvar-de=*|--envvar-d=*|--envvar-=*|--group=*|--grou=*|--gro=*|--gr=*|--g=*|--avail-group=*|--avail-grou=*|--avail-gro=*|--avail-gr=*|--avail-g=*|--user=*|--use=*|--us=*|--u=*|--avail-user=*|--avail-use=*|--avail-us=*|--avail-u=*)
+ :;;
+ --avail-|--avail|--avai|--ava|--av|--a|--avail-=*|--avail=*|--avai=*|--ava=*|--av=*|--a=*)
+ echo 1>&2 "$0: option \`$1' is ambiguous"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ --help|"-?" |--hel|--he|--h)
+ echo "$USAGE"
+ echo "$DOC"
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " -e ENTRY, --envvar=ENTRY Add ENTRY to the environment"
+ echo " -E ENTRY, --envvar-default=ENTRY"
+ echo " Use ENTRY as a default environment variable"
+ echo " -g GROUP, --group=GROUP Add GROUP to the effective groups"
+ echo " -G GROUP, --avail-group=GROUP Add GROUP to the available groups"
+ echo " -u USER, --user=USER Add USER to the effective uids"
+ echo " -U USER, --avail-user=USER Add USER to the available uids"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ echo ""
+ echo "Unlike the traditional unix \`su' command, if USER is not specified,"
+ echo "then the result is *no* user-ids, not uid 0."
+ exit 0;;
+ --usage |--usag|--usa|--us|--u)
+ (echo "Usage: $0 [-V?]"
+ echo " [-e ENTRY] [-E ENTRY] [-g GROUP] [-G GROUP] [-u USER] [-U USER] [--envvar=ENTRY] [--envvar-default=ENTRY] [--group=GROUP] [--avail-group=GROUP][--group=GROUP] [--avail-group=GROUP] [--user=USER] [--avail-user=USER] [--help] [--usage] [--version] $ARGS_DOC") |$FMT -t
+ exit 0;;
+ --version|-V |--versio|--versi|--vers|--ver|--ve|--v)
+ echo "STANDARD_HURD_VERSION_sush_"; exit 0;;
+ -)
+ : ;;
+ --)
+ break;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac;;
+ esac
+done
+
+case "$needs_arg" in ?*)
+ echo 1>&2 "$0: option \`$1' requires an argument"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+esac
+
+exec $LOGIN --program-name="$0" -pxSLf -aHOME -aMOTD -aUMASK -aBACKUP_SHELLS "$@"
diff --git a/utils/sync.c b/utils/sync.c
deleted file mode 100644
index bce972e8..00000000
--- a/utils/sync.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Call sync synchronously.
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-
-int
-main ()
-{
- __USEPORT (CRDIR, __file_syncfs (port, 1, 1));
- return 0;
-}
diff --git a/utils/syncfs.c b/utils/syncfs.c
new file mode 100644
index 00000000..3434f5c6
--- /dev/null
+++ b/utils/syncfs.c
@@ -0,0 +1,80 @@
+/* syncfs -- User interface to file_syncfs, synchronize filesystems.
+ Copyright (C) 1994, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (sync);
+
+static int synchronous = 0, do_children = 1;
+
+static void
+sync_one (const char *name, file_t port)
+{
+ error_t err = (port == MACH_PORT_NULL ? errno
+ : file_syncfs (port, synchronous, do_children));
+ if (err)
+ error (1, err, "%s", name);
+}
+
+static error_t
+parser (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 's': synchronous = 1; break;
+ case 'c': do_children = 0; break;
+
+ case ARGP_KEY_NO_ARGS:
+ sync_one ("/", getcrdir ());
+ break;
+
+ case ARGP_KEY_ARG:
+ sync_one (arg, file_name_lookup (arg, 0, 0));
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ static struct argp_option options[] =
+ {
+ {"synchronous", 's', 0, 0, "Wait for completion of all disk writes"},
+ {"no-children", 'c', 0, 0, "Do not synchronize child filesystems"},
+ {0}
+ };
+ struct argp argp =
+ {options, parser,
+ "[FILE...]", "Force all pending disk writes to be done immediately"
+ "\vThe filesystem containing each FILE is synchronized, and its child"
+ " filesystems unless --no-children is specified. With no FILE argument"
+ " synchronizes the root filesystem."};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ return 0;
+}
diff --git a/utils/unsu.c b/utils/unsu.c
new file mode 100644
index 00000000..467cf46f
--- /dev/null
+++ b/utils/unsu.c
@@ -0,0 +1,90 @@
+/* Attempt to undo a previous su
+
+ Copyright (C) 1997,98,2000 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+#include "pids.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (unsu);
+
+static struct argp_child child_argps[] = {{ &frobauth_no_ugids_argp }, { 0 }};
+
+static char doc[] =
+ "Attempt to undo a previous setauth --save"
+ "\vThis command is convenient, but will only correctly undo a limited"
+ " subset of possible setauth commands. It works by simply deleting all"
+ " current effective ids and the first two available ids, and then"
+ " making the first remaining available id the current effective id.";
+
+int
+main (int argc, char *argv[])
+{
+ struct frobauth frobauth = FROBAUTH_INIT;
+
+ /* Modify UGIDS, to be what PID's new authentication should be, NOISE is
+ ignored. */
+ error_t modify (struct ugids *ugids, const struct ugids *noise,
+ pid_t pid, void *hook)
+ {
+ error_t err = 0;
+
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+
+ idvec_delete (&ugids->avail_uids, 0);
+ idvec_delete (&ugids->avail_uids, 0);
+
+ idvec_delete (&ugids->avail_gids, 0);
+ idvec_delete (&ugids->avail_gids, 0);
+ idvec_keep (&ugids->imp_avail_gids, &ugids->avail_gids);
+
+ if (ugids->avail_uids.num > 0)
+ err = ugids_set_posix_user (ugids, ugids->avail_uids.ids[0]);
+
+ return err;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *removed,
+ pid_t pid, void *hook)
+ {
+ char *new_rep = ugids_rep (new, 1, 1, 0, 0, 0);
+ printf ("%d: Changed auth to %s\n", pid, new_rep);
+ free (new_rep);
+ }
+ struct argp argp = { 0, 0, 0, doc, child_argps };
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ if (frobauth_modify (&frobauth, 0, 0, modify, print_info, 0))
+ return 0;
+ else
+ return 1;
+}
diff --git a/utils/uptime.sh b/utils/uptime.sh
index 541996b3..8e52c81b 100644
--- a/utils/uptime.sh
+++ b/utils/uptime.sh
@@ -1,2 +1,62 @@
#!/bin/sh
-/bin/w -u
+# Show system uptime, number of users, and load
+#
+# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+USAGE="Usage: $0 [OPTION...]"
+DOC="Show system uptime, number of users, and load"
+
+W=${W-/bin/w}
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "$USAGE"
+ echo "$DOC"
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ exit 0;;
+ --usage)
+ echo "Usage: $0 [-V?] [--help] [--usage] [--version]"
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_uptime_"; exit 0;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+case "$#" in
+ 0) :;;
+ *)
+ echo 1>&2 "$0: too many arguments"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+esac
+
+$W -u
diff --git a/utils/vminfo.c b/utils/vminfo.c
new file mode 100644
index 00000000..6ead677e
--- /dev/null
+++ b/utils/vminfo.c
@@ -0,0 +1,241 @@
+/* Print task vm information
+
+ Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <argp.h>
+#include <error.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <version.h>
+
+#include <mach.h>
+#include <mach/vm_statistics.h>
+#include <mach/default_pager.h>
+#include <hurd.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (vminfo);
+
+static const struct argp_option options[] = {
+ {"verbose", 'v', 0, 0, "Give more detailed information"},
+ {"addresses", 'a', 0, 0, "Print region start addresses"},
+ {"sizes", 's', 0, 0, "Print region sizes"},
+ {"decimal", 'd', 0, 0, "Show number is decimal"},
+ {"holes", 'h', 0, 0, "Show holes between regions explicitly"},
+ {0}
+};
+static const char *args_doc = "PID [ADDR [SIZE]]]";
+static const char *doc = "Show virtual memory regions for process PID"
+"\vIf ADDR, and possibly SIZE, are given only regions enclosing the range"
+" ADDR to ADDR+SIZE are shown (SIZE defaults to 0)."
+"\nIf neither --addresses nor --sizes is specified, both are assumed.";
+
+/* Possible things to show about regions. */
+#define W_ADDRS 0x1
+#define W_SIZES 0x2
+#define W_DETAILS 0x4
+
+static char *
+prot_rep (vm_prot_t prot)
+{
+ if (prot == 0)
+ return "0";
+ else
+ {
+ static char buf[20];
+ char *p = buf;
+ if (prot & VM_PROT_READ)
+ *p++ = 'R';
+ if (prot & VM_PROT_WRITE)
+ *p++ = 'W';
+ if (prot & VM_PROT_EXECUTE)
+ *p++ = 'X';
+ if (prot & ~VM_PROT_ALL)
+ sprintf (p, "+%#x", (prot & ~VM_PROT_ALL));
+ else
+ *p = '\0';
+ return buf;
+ }
+}
+
+static char *
+inh_rep (vm_inherit_t inh)
+{
+ static char buf[20];
+ switch (inh)
+ {
+ case VM_INHERIT_SHARE: return "share";
+ case VM_INHERIT_COPY: return "copy";
+ case VM_INHERIT_NONE: return "none";
+ default:
+ sprintf (buf, "%d", inh);
+ return buf;
+ }
+}
+
+static unsigned
+parse_num (char *arg, unsigned base, struct argp_state *state, char *what)
+{
+ char *arg_end;
+ unsigned long num = strtoul (arg, &arg_end, base);
+ if (*arg == '\0' || *arg_end != '\0')
+ argp_error (state, "%s: Invalid %s", arg, what);
+ return num;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int what = 0, hex = 1, holes = 0;
+ vm_offset_t addr = 0, max_addr = ~addr;
+ task_t task;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ pid_t pid;
+ process_t proc;
+
+ case 'a': what |= W_ADDRS; break;
+ case 's': what |= W_SIZES; break;
+ case 'v': what |= W_DETAILS; break;
+ case 'd': hex = 0; break;
+ case 'h': holes = 1; break;
+
+ case ARGP_KEY_ARG:
+ switch (state->arg_num)
+ {
+ case 0: /* PID */
+ pid = parse_num (arg, 10, state, "PID");
+ proc = getproc ();
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ argp_failure (state, 11, err, "%s", arg);
+ break;
+ case 1: /* ADDR */
+ addr = max_addr = parse_num (arg, 0, state, "address"); break;
+ case 2: /* SIZE */
+ max_addr = addr + parse_num (arg, 0, state, "size"); break;
+ default:
+ argp_usage (state);
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if ((what & ~W_DETAILS) == 0)
+ what = W_ADDRS | W_SIZES | W_DETAILS;
+
+ while (addr <= max_addr)
+ {
+ vm_size_t size;
+ vm_prot_t prot, max_prot;
+ mach_port_t obj;
+ vm_offset_t offs;
+ vm_inherit_t inh;
+ int shared;
+ vm_offset_t hole_addr = addr;
+
+ err =
+ vm_region (task, &addr, &size, &prot, &max_prot, &inh, &shared,
+ &obj, &offs);
+ if (err)
+ {
+ if (err != EKERN_NO_SPACE)
+ error (12, err, "vm_region");
+ break;
+ }
+
+ if (holes && hole_addr != addr)
+ {
+ if ((what & (W_ADDRS|W_SIZES)) == (W_ADDRS|W_SIZES))
+ {
+ if (hex)
+ printf (" [%#zx] (hole)\n", addr - hole_addr);
+ else
+ printf (" [%zd] (hole)\n", addr - hole_addr);
+ }
+ else if ((what & (W_ADDRS|W_SIZES)) == W_SIZES)
+ {
+ if (hex)
+ printf ("%#10zx (hole)\n", addr - hole_addr);
+ else
+ printf ("%10zu (hole)\n", addr - hole_addr);
+ }
+ }
+
+ if ((what & (W_ADDRS|W_SIZES)) == (W_ADDRS|W_SIZES))
+ if (hex)
+ printf ("%#10zx[%#zx]", addr, size);
+ else
+ printf ("%10zu[%zd]", addr, size);
+ else if ((what & (W_ADDRS|W_SIZES)) == W_ADDRS)
+ if (hex)
+ printf ("%#10zx", addr);
+ else
+ printf ("%10zu", addr);
+ else if ((what & (W_ADDRS|W_SIZES)) == W_SIZES)
+ {
+ if (hex)
+ printf ("%#10zx", size);
+ else
+ printf ("%10zu", size);
+ }
+ if (what & W_DETAILS)
+ {
+ printf (" (prot=%s", prot_rep (prot));
+ if (max_prot != prot)
+ printf (", max_prot=%s", prot_rep (max_prot));
+ if (inh != VM_INHERIT_DEFAULT)
+ printf (", inherit=%s", inh_rep (inh));
+ if (shared)
+ printf (", shared");
+ if (obj != MACH_PORT_NULL)
+ printf (", mem_obj=%d", obj);
+ if (offs != 0)
+ {
+ if (hex)
+ printf (", offs=%#zx", offs);
+ else
+ printf (", offs=%zd", offs);
+ }
+ putchar (')');
+ }
+ putchar ('\n');
+
+ addr += size;
+ }
+
+ exit (0);
+}
diff --git a/utils/vmstat.c b/utils/vmstat.c
index c7f7a7af..7d852992 100644
--- a/utils/vmstat.c
+++ b/utils/vmstat.c
@@ -1,8 +1,7 @@
/* Print vm statistics
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1996,97,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,30 +24,30 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <fcntl.h>
+#include <version.h>
#include <mach.h>
#include <mach/vm_statistics.h>
#include <mach/default_pager.h>
#include <hurd.h>
+#include <hurd/paths.h>
-char *argp_program_version = "vmstat 1.1 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (vmstat);
static const struct argp_option options[] = {
- {"terse", 't', 0, 0, "Use short one-line output format", 1 },
+ {"terse", 't', 0, 0, "Use short one-line output format"},
{"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
{"prefix", 'p', 0, 0, "Always display a description before stats"},
{"no-prefix", 'P', 0, 0, "Never display a description before stats"},
{"pages", 'v', 0, 0, "Display sizes in pages"},
{"kilobytes", 'k', 0, 0, "Display sizes in 1024 byte blocks"},
{"bytes", 'b', 0, 0, "Display sizes in bytes"},
-
- /* A header for all the individual field options. */
- { 0,0,0,0, "Selecting which statistics to show:", 2},
-
{0}
};
static const char *args_doc = "[PERIOD [COUNT [HEADER_INTERVAL]]]";
-static const char *doc = "If PERIOD is supplied, then terse mode is"
+static const char *doc = "Show system virtual memory statistics"
+"\vIf PERIOD is supplied, then terse mode is"
" selected, and the output repeated every PERIOD seconds, with cumulative"
" fields given the difference from the last output. If COUNT is given"
" and non-zero, only that many lines are output. HEADER_INTERVAL"
@@ -61,6 +60,7 @@ static const char *doc = "If PERIOD is supplied, then terse mode is"
than what the system returns values in, as we represent some quantities as
bytes instead of pages)! */
typedef long long val_t;
+#define BADVAL ((val_t) -1LL) /* a good generic value for "couldn't get" */
/* What a given number describes. */
enum val_type
@@ -71,6 +71,31 @@ enum val_type
PCENT, /* Append `%'. */
};
+/* Return the `nominal' width of a field of type TYPE, in units of SIZE_UNITS. */
+static size_t
+val_width (val_t val, enum val_type type, size_t size_units)
+{
+ size_t vwidth (val_t val)
+ {
+ size_t w = 1;
+ if (val < 0)
+ w++, val = -val;
+ while (val > 9)
+ w++, val /= 10;
+ return w;
+ }
+ if (type == PCENT)
+ return vwidth (val) + 1;
+ else if ((type == SIZE || type == PAGESZ) && size_units == 0)
+ return val > 1000 ? 5 : vwidth (val) + 1;
+ else
+ {
+ if ((type == SIZE || type == PAGESZ) && size_units > 0)
+ val /= size_units;
+ return vwidth (val);
+ }
+}
+
/* Print a number of type TYPE. If SIZE_UNITS is non-zero, then values of
type SIZE are divided by that amount and printed without a suffix. FWIDTH
is the width of the field to print it in, right-justified. If SIGN is
@@ -80,13 +105,13 @@ print_val (val_t val, enum val_type type,
size_t size_units, int fwidth, int sign)
{
if (type == PCENT)
- printf (sign ? "%+*d%%" : "%*d%%", fwidth - 1, val);
+ printf (sign ? "%+*lld%%" : "%*lld%%", fwidth - 1, val);
else if ((type == SIZE || type == PAGESZ) && size_units == 0)
{
float fval = val;
char *units = " KMGT", *u = units;
- while (fval > 1024)
+ while (fval >= 10000)
{
fval /= 1024;
u++;
@@ -101,10 +126,14 @@ print_val (val_t val, enum val_type type,
{
if ((type == SIZE || type == PAGESZ) && size_units > 0)
val /= size_units;
- printf (sign ? "%+*d" : "%*d", fwidth, val);
+ printf (sign ? "%+*lld" : "%*lld", fwidth, val);
}
}
+/* Special values for val_t ranges. */
+#define VAL_MAX_MEM -1 /* up to the system memory size */
+#define VAL_MAX_SWAP -2 /* up to the system swap size */
+
/* How this field changes with time. */
enum field_change_type
{
@@ -117,15 +146,15 @@ struct vm_state; /* fwd */
struct field
{
- /* Name of the field; used for the option name. */
+ /* Name of the field. */
char *name;
- /* A descriptive title used for long output format. */
- char *desc;
-
/* Terse header used for the columnar style output. */
char *hdr;
+ /* A description of this field (for user help). */
+ char *doc;
+
/* Type of this field. */
enum field_change_type change_type;
@@ -134,6 +163,9 @@ struct field
user. */
enum val_type type;
+ /* The `maximum value' this field can have -- used for field widths. */
+ val_t max;
+
/* True if we display this field by default (user can always override). */
int standard :1;
@@ -148,7 +180,7 @@ struct field
};
/* State about system vm from which we compute the above defined fields. */
-struct vm_state
+struct vm_state
{
/* General vm statistics. */
struct vm_statistics vmstats;
@@ -167,7 +199,7 @@ vm_state_refresh (struct vm_state *state)
return err;
/* Mark the info as invalid, but leave DEF_PAGER alone. */
- bzero (&state->def_pager_info, sizeof state->def_pager_info);
+ memset (&state->def_pager_info, 0, sizeof state->def_pager_info);
return 0;
}
@@ -198,7 +230,7 @@ vm_state_get_field (struct vm_state *state, const struct field *field)
}
static val_t
-get_cache_hit_ratio (struct vm_state *state, const struct field *field)
+get_memobj_hit_ratio (struct vm_state *state, const struct field *field)
{
return state->vmstats.hits * 100 / state->vmstats.lookups;
}
@@ -215,89 +247,125 @@ ensure_def_pager_info (struct vm_state *state)
mach_port_t host;
err = get_privileged_ports (&host, 0);
- if (err)
+ if (err == EPERM)
{
- error (0, err, "get_privileged_ports");
- return 0;
+ /* We are not root, so try opening the /servers file. */
+ state->def_pager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0);
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ error (0, errno, _SERVERS_DEFPAGER);
+ return 0;
+ }
}
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ if (err)
+ {
+ error (0, err, "get_privileged_ports");
+ return 0;
+ }
- err = vm_set_default_memory_manager (host, &state->def_pager);
- mach_port_deallocate (mach_task_self (), host);
+ err = vm_set_default_memory_manager (host, &state->def_pager);
+ mach_port_deallocate (mach_task_self (), host);
+
+ if (err)
+ {
+ error (0, err, "vm_set_default_memory_manager");
+ return 0;
+ }
+ }
+ }
- if (err)
+ if (!MACH_PORT_VALID (state->def_pager))
+ {
+ if (state->def_pager == MACH_PORT_NULL)
{
- error (0, err, "vm_set_default_memory_manager");
- return 0;
+ error (0, 0,
+ "No default pager running, so no swap information available");
+ state->def_pager = MACH_PORT_DEAD; /* so we don't try again */
}
+ return 0;
}
err = default_pager_info (state->def_pager, &state->def_pager_info);
if (err)
error (0, err, "default_pager_info");
-
return (err == 0);
}
-static val_t
-get_swap_size (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_total_space : -1;
-}
+#define SWAP_FIELD(getter, expr) \
+ static val_t getter (struct vm_state *state, const struct field *field) \
+ { return ensure_def_pager_info (state) ? (val_t) (expr) : BADVAL; }
-static val_t
-get_swap_free (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_free_space : -1;
-}
-
-static val_t
-get_swap_page_size (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_page_size : -1;
-}
-
-static val_t
-get_swap_active (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state)
- ? (state->def_pager_info.dpi_total_space
- - state->def_pager_info.dpi_free_space)
- : -1;
-}
+SWAP_FIELD (get_swap_size, state->def_pager_info.dpi_total_space)
+SWAP_FIELD (get_swap_free, state->def_pager_info.dpi_free_space)
+SWAP_FIELD (get_swap_page_size, state->def_pager_info.dpi_page_size)
+SWAP_FIELD (get_swap_active, (state->def_pager_info.dpi_total_space
+ - state->def_pager_info.dpi_free_space))
/* Returns the byte offset of the field FIELD in a vm_statistics structure. */
#define _F(field_name) offsetof (struct vm_statistics, field_name)
+#define K 1024
+#define M (1024*K)
+#define G (1024LL*M)
+
/* vm_statistics fields we know about. */
static const struct field fields[] =
{
- {"pagesize", "Pagesize", " pgsz", CONST,PAGESZ, 1,_F(pagesize)},
- {"size", "Size", " size", CONST,SIZE, 1,0,get_size},
- {"free", "Free", " free", VARY, SIZE, 1,_F(free_count)},
- {"active", "Active", " actv", VARY, SIZE, 1,_F(active_count)},
- {"inactive", "Inactive", "inact", VARY, SIZE, 1,_F(inactive_count)},
- {"wired", "Wired", "wired", VARY, SIZE, 1,_F(wire_count)},
- {"zero-filled", "Zeroed", "zeroed", CUMUL,SIZE, 1,_F(zero_fill_count)},
- {"reactivated", "Reactivated", "react", CUMUL,SIZE, 1,_F(reactivations)},
- {"pageins", "Pageins", "pgins", CUMUL,SIZE, 1,_F(pageins)},
- {"pageouts", "Pageouts", "pgouts", CUMUL,SIZE, 1,_F(pageouts)},
- {"faults", "Faults", "pfaults",CUMUL,COUNT,1,_F(faults)},
- {"cow-faults", "Cow faults", "cowpfs", CUMUL,COUNT,1,_F(cow_faults)},
- {"cache-lookups","Cache lookups","clkups", CUMUL,COUNT,0,_F(lookups)},
- {"cache-hits", "Cache hits", "chits", CUMUL,COUNT,0,_F(hits)},
- {"cache-hit-ratio","Cache hit ratio","chrat",VARY,PCENT,1,-1,get_cache_hit_ratio},
- {"swap-size", "Swap size", "swsize", CONST,SIZE, 1,0,get_swap_size},
- {"swap-active", "Swap active", "swactv", VARY, SIZE, 0,0,get_swap_active},
- {"swap-free", "Swap free", "swfree", VARY, SIZE, 1,0,get_swap_free},
- {"swap-pagesize","Swap pagesize","swpgsz", CONST,PAGESZ, 0,0,get_swap_page_size},
+ {"pagesize", "pgsz", "System pagesize",
+ CONST, PAGESZ, 16*K, 1, _F (pagesize) },
+ {"size", "size", "Usable physical memory",
+ CONST, SIZE, VAL_MAX_MEM, 1, 0, get_size },
+ {"free", "free", "Unused physical memory",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (free_count) },
+ {"active", "actv", "Physical memory in active use",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (active_count) },
+ {"inactive", "inact", "Physical memory in the inactive queue",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (inactive_count) },
+ {"wired", "wired", "Unpageable physical memory",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (wire_count) },
+ {"zero filled", "zeroed","Cumulative zero-filled pages",
+ CUMUL, SIZE, 90*G, 1, _F (zero_fill_count) },
+ {"reactivated", "react", "Cumulative reactivated inactive pages",
+ CUMUL, SIZE, 900*M, 1, _F (reactivations) },
+ {"pageins", "pgins", "Cumulative pages paged in",
+ CUMUL, SIZE, 90*G, 1, _F (pageins) },
+ {"pageouts", "pgouts","Cumulative pages paged out",
+ CUMUL, SIZE, 90*G, 1, _F (pageouts) },
+ {"page faults", "pfaults","Cumulative page faults",
+ CUMUL, COUNT, 99999999, 1, _F (faults) },
+ {"cow faults", "cowpfs", "Cumulative copy-on-write page faults",
+ CUMUL, COUNT, 9999999, 1, _F (cow_faults) },
+ {"memobj lookups","lkups","Memory-object lookups",
+ CUMUL, COUNT, 999999, 0, _F (lookups) },
+ {"memobj hits", "hits", "Memory-object lookups with active pagers",
+ CUMUL, COUNT, 999999, 0, _F (hits) },
+ {"memobj hit ratio","hrat","Percentage of memory-object lookups with active pagers",
+ VARY, PCENT, 99, 1, -1, get_memobj_hit_ratio },
+ {"swap size", "swsize", "Size of the default-pager swap area",
+ CONST, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_size },
+ {"swap active", "swactv", "Default-pager swap area in use",
+ VARY, SIZE, VAL_MAX_SWAP, 0, 0 ,get_swap_active },
+ {"swap free", "swfree", "Default-pager swap area available for swapping",
+ VARY, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_free },
+ {"swap pagesize","swpgsz", "Units used for swapping to the default pager",
+ CONST, PAGESZ, 16*K, 0, 0 ,get_swap_page_size },
{0}
};
#undef _F
+/* Convert a field name to the corresponding user-option. */
+static char *name_to_option (const char *name)
+{
+ char *opt = strdup (name), *p;
+ if (opt)
+ for (p = opt; *p; p++)
+ if (*p == ' ')
+ *p = '-';
+ return opt;
+}
+
int
main (int argc, char **argv)
{
@@ -327,7 +395,7 @@ main (int argc, char **argv)
case 'H': print_heading = 0; break;
case 'b': size_units = 1; break;
case 'v': size_units = -1; break;
- case 'k': size_units = 1024; break;
+ case 'k': size_units = K; break;
case ARGP_KEY_ARG:
terse = 1;
@@ -352,8 +420,9 @@ main (int argc, char **argv)
struct argp_option *field_opts;
int field_opts_size;
struct argp field_argp = { 0, parse_opt };
- const struct argp *parents[] = { &field_argp, 0 };
- const struct argp argp = { options, parse_opt, args_doc, doc, parents };
+ const struct argp_child children[] =
+ {{&field_argp, 0, "Selecting which statistics to show:"}, {0}};
+ const struct argp argp = { options, parse_opt, args_doc, doc, children };
/* See how many fields we know about. */
for (field = fields; field->name; field++)
@@ -362,19 +431,19 @@ main (int argc, char **argv)
/* Construct an options vector for them. */
field_opts_size = ((num_fields + 1) * sizeof (struct argp_option));
field_opts = alloca (field_opts_size);
- bzero (field_opts, field_opts_size);
+ memset (field_opts, 0, field_opts_size);
for (field = fields; field->name; field++)
{
int which = field - fields;
struct argp_option *opt = &field_opts[which];
- opt->name = field->name;
+ opt->name = name_to_option (field->name);
opt->key = -1 - which; /* options are numbered -1 ... -(N - 1). */
- opt->doc = field->desc;
+ opt->doc = field->doc;
opt->group = 2;
}
- /* No need to terminate FIELD_OPTS because the bzero above's done so. */
+ /* No need to terminate FIELD_OPTS because the memset above has done so. */
field_argp.options = field_opts;
@@ -387,10 +456,10 @@ main (int argc, char **argv)
if (field->standard)
output_fields |= (1 << (field - fields));
- /* Returns an appropiate SIZE_UNITS for printing FIELD. */
-#define SIZE_UNITS(field) \
- (size_units >= 0 \
- ? size_units \
+ /* Returns an appropriate SIZE_UNITS for printing FIELD. */
+#define SIZE_UNITS(field) \
+ (size_units >= 0 \
+ ? size_units \
: ((field)->type == PAGESZ ? 0 : state.vmstats.pagesize))
/* Prints SEP if the variable FIRST is 0, otherwise, prints START (if
@@ -399,9 +468,15 @@ main (int argc, char **argv)
(first ? (first = 0, (start && fputs (start, stdout))) : fputs (sep, stdout))
#define PVAL(val, field, width, sign) \
print_val (val, (field)->type, SIZE_UNITS (field), width, sign)
-
+ /* Intuit the likely maximum field width of FIELD. */
+#define FWIDTH(field) \
+ val_width ((field)->max == VAL_MAX_MEM ? get_size (&state, field) \
+ : (field)->max == VAL_MAX_SWAP ? get_swap_size (&state, field) \
+ : (field)->max, \
+ (field)->type, SIZE_UNITS (field))
+
/* Actually fetch the statistics. */
- bzero (&state, sizeof (state)); /* Initialize STATE. */
+ memset (&state, 0, sizeof (state)); /* Initialize STATE. */
err = vm_state_refresh (&state);
if (err)
error (2, err, "vm_state_refresh");
@@ -429,6 +504,9 @@ main (int argc, char **argv)
do
{
+ int num;
+ int fwidths[num_fields];
+
if (first_hdr)
first_hdr = 0;
else
@@ -447,7 +525,7 @@ main (int argc, char **argv)
else
{
PSEP (", ", "(");
- printf ("%s: ", field->desc);
+ printf ("%s: ", field->name);
PVAL (val, field, 0, 0);
}
}
@@ -455,39 +533,62 @@ main (int argc, char **argv)
puts (")");
}
+ /* Calculate field widths. */
+ for (field = fields, num = 0; field->name; field++, num++)
+ if (output_fields & (1 << (field - fields)))
+ {
+ fwidths[num] = FWIDTH (field);
+ if (count != 1 && size_units == 0
+ && field->change_type == CUMUL && field->type == SIZE)
+ /* We may be printing a `+' prefix for field changes, and
+ since this is using the mostly constant-width SIZE
+ notation, individual changes may be the same width as
+ appropriated for absolute values -- so reserver another
+ column for the `+' character. */
+ fwidths[num]++;
+ if (fwidths[num] < strlen (field->hdr))
+ fwidths[num] = strlen (field->hdr);
+ }
+
if (print_heading)
{
- for (field = fields, first = 1; field->name; field++)
+ for (field = fields, num = 0, first = 1; field->name; field++, num++)
if (output_fields & (1 << (field - fields)))
{
PSEP (" ", 0);
- fputs (field->hdr, stdout);
+ fprintf (stdout, "%*s", fwidths[num], field->hdr);
}
putchar ('\n');
}
-
+
prev_state = state;
for (repeats = 0
- ; count && repeats < hdr_interval && count
+ ; count && repeats < hdr_interval
; repeats++, count--)
{
/* Output the fields. */
- for (field = fields, first = 1; field->name; field++)
+ for (field = fields, num = 0, first = 1; field->name; field++, num++)
if (output_fields & (1 << (field - fields)))
{
- int sign = 0;
- int width = strlen (field->hdr);
val_t val = vm_state_get_field (&state, field);
- if (repeats && field->change_type == CUMUL)
+ if (val < 0)
+ /* Couldn't fetch this field, don't try again. */
+ const_fields &= ~(1 << (field - fields));
+ else
{
- sign = 1;
- val -= vm_state_get_field (&prev_state, field);
- }
+ int sign = 0;
- PSEP (" ", 0);
- PVAL (val, field, width, sign);
+ if (repeats && field->change_type == CUMUL)
+ {
+ sign = 1;
+ val -= vm_state_get_field (&prev_state, field);
+ }
+
+ PSEP (" ", 0);
+ PVAL (val, field, fwidths[num], sign);
+ }
}
putchar ('\n');
@@ -507,7 +608,7 @@ main (int argc, char **argv)
else
/* Verbose output. */
{
- int max_desc_width = 0;
+ int max_width = 0;
if (print_prefix < 0)
/* By default, only print a prefix if there are multiple fields. */
@@ -518,23 +619,26 @@ main (int argc, char **argv)
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
- int desc_len = strlen (field->desc);
- if (desc_len > max_desc_width)
- max_desc_width = desc_len;
+ int width = strlen (field->name) + FWIDTH (field);
+ if (width > max_width)
+ max_width = width;
}
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
val_t val = vm_state_get_field (&state, field);
- int fwidth = 0;
- if (print_prefix)
+ if (val >= 0)
{
- printf ("%s:", field->desc);
- fwidth = max_desc_width + 5 - strlen (field->desc);
+ int fwidth = 0;
+ if (print_prefix)
+ {
+ printf ("%s: ", field->name);
+ fwidth = max_width - strlen (field->name);
+ }
+ PVAL (val, field, fwidth, 0);
+ putchar ('\n');
}
- PVAL (val, field, fwidth, 0);
- putchar ('\n');
}
}
diff --git a/utils/w.c b/utils/w.c
index 0b31385e..37555088 100644
--- a/utils/w.c
+++ b/utils/w.c
@@ -1,8 +1,8 @@
/* Hurdish w
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <paths.h>
#include <ctype.h>
@@ -29,6 +30,7 @@
#include <pwd.h>
#include <grp.h>
#include <netdb.h>
+#include <version.h>
#include <sys/fcntl.h>
@@ -42,13 +44,13 @@
#include "psout.h"
-#define DEFAULT_FMT_STRING "%^%user %tty %from %login %idle %what"
+#define DEFAULT_FMT_STRING "%^%user %tty %from %login %idle %pid %what"
extern char *canon_host (char *host);
extern char *shared_domain (char *host1, char *host2);
extern char *localhost ();
-char *argp_program_version = "w 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (w);
#define OA OPTION_ARG_OPTIONAL
@@ -71,7 +73,7 @@ static struct argp_option options[] =
{0, 0}
};
static char *args_doc = "[USER...]";
-static char *doc = 0;
+static char *doc = "Show logged in users and what they are doing";
/* The current time of day. */
static struct timeval now;
@@ -93,6 +95,14 @@ struct w_hook
#define W_PSTAT_LOGIN (PSTAT_USER_BASE << 3)
static ps_flags_t
+w_deps (ps_flags_t flags)
+{
+ if (flags & W_PSTAT_IDLE)
+ flags |= PSTAT_TTY;
+ return flags;
+}
+
+static ps_flags_t
w_fetch (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
{
struct w_hook *hook = ps->hook;
@@ -121,23 +131,34 @@ w_fetch (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
if (sd)
*sd = '\0';
}
-
- have |= W_PSTAT_HOST;
}
+ have |= W_PSTAT_HOST;
}
if (need & W_PSTAT_IDLE)
{
- struct stat stat;
- struct ps_tty *tty = ps->tty;
-
- hook->idle.tv_usec = 0;
- if (io_stat (tty->port, &stat) == 0)
+ if (have & PSTAT_TTY)
{
- hook->idle.tv_sec = now.tv_sec - stat.st_mtime;
- if (hook->idle.tv_sec > 0)
- have |= W_PSTAT_IDLE;
+ struct stat stat;
+ struct ps_tty *tty = ps->tty;
+
+ hook->idle.tv_usec = 0;
+ if (! tty)
+ {
+ hook->idle.tv_sec = 0;
+ have |= W_PSTAT_IDLE;
+ }
+ else
+ {
+ if (io_stat (tty->port, &stat) == 0)
+ {
+ hook->idle.tv_sec = now.tv_sec - stat.st_atime;
+ have |= W_PSTAT_IDLE;
+ }
+ }
}
+ else if (ps->inapp & PSTAT_TTY)
+ ps->inapp |= W_PSTAT_IDLE;
}
if (need & W_PSTAT_USER)
@@ -204,21 +225,22 @@ w_get_host (struct proc_stat *ps, char **host, unsigned *host_len)
{
struct w_hook *hook = ps->hook;
*host = hook->host;
- *host_len = strlen (*host);
+ *host_len = *host ? strlen (*host) : 0;
}
const struct ps_getter w_host_getter =
{"host", W_PSTAT_HOST, w_get_host};
extern error_t ps_emit_past_time (), ps_emit_string (), ps_emit_minutes ();
extern error_t ps_emit_user_name ();
-extern int ps_cmp_times (), ps_cmp_strings ();
+extern int ps_cmp_times (), ps_cmp_strings (), ps_cmp_unames ();
+extern int ps_nominal_string ();
const struct ps_fmt_spec _w_specs[] =
{
{"User", 0, 8, -1,0, &w_uname_getter,ps_emit_string, ps_cmp_strings},
- {"Name", 0, 20, -1,0, &w_user_getter, ps_emit_user_name,ps_cmp_strings},
+ {"Name", 0, 16, -1,0, &w_user_getter, ps_emit_user_name,ps_cmp_unames,ps_nominal_string},
{"Login","Login@", -7, -1,0,&w_login_getter,ps_emit_past_time,ps_cmp_times},
- {"From", 0, 16, -1,0, &w_host_getter, ps_emit_string, ps_cmp_strings},
- {"Idle", 0, -5, -1,0, &w_idle_getter, ps_emit_minutes,ps_cmp_times},
+ {"From", 0, 14, -1,0, &w_host_getter, ps_emit_string, ps_cmp_strings, ps_nominal_string},
+ {"Idle", 0, -5, -1,PS_FMT_FIELD_COLON_MOD, &w_idle_getter, ps_emit_minutes,ps_cmp_times},
{"What=args"},
{0}
};
@@ -231,7 +253,7 @@ static void
add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
{
/* The tty name, with space for '\0' termination and an
- appropiate prefix. */
+ appropriate prefix. */
char tty[sizeof _PATH_DEV + sizeof u->ut_line];
io_t tty_node;
error_t err;
@@ -239,6 +261,19 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
int pos;
struct proc_stat *ps;
+ switch (u->ut_type)
+ {
+ case LOGIN_PROCESS:
+ case USER_PROCESS:
+ /* These are the types that indicate a user job that we might
+ find processes for. */
+ if (u->ut_name[0] != '\0' && u->ut_line[0] != '\0')
+ break;
+ default:
+ /* This entry is not for a user, skip it. */
+ return;
+ }
+
strncpy (tty, u->ut_line, sizeof u->ut_line);
tty[sizeof u->ut_line] = '\0'; /* Ensure it's '\0' terminated. */
@@ -271,7 +306,7 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
else
{
struct proc_stat **pgrp_procs;
- unsigned num_procs;
+ size_t num_procs;
err = proc_stat_list_add_pgrp (procs, -pid, &pgrp_procs, &num_procs);
if (! err)
@@ -301,62 +336,74 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
tty, pid < 0 ? "pgrp" : "pid", pid < 0 ? -pid : pid);
}
-/* Read into PROCS from the utmp file called NAME. */
-static void
-read_utmp_procs (struct proc_stat_list *procs, char *name)
+/* Find the absolute timestamp of when the system was booted.
+ We define "system boot time" as the task creation time of PID 1 (init). */
+
+static error_t
+fetch_boot_time (struct timeval *when)
{
- int rd, fd;
- struct utmp buf[64];
+ struct ps_context *context;
+ struct proc_stat *ps;
+ error_t err;
- fd = open (name, O_RDONLY);
- if (fd < 0)
- error (9, errno, "%s", name);
+ err = ps_context_create (getproc (), &context);
+ if (err)
+ error (2, err, "ps_context_create");
+
+ err = ps_context_find_proc_stat (context, 1, &ps);
+ if (err)
+ error (3, err, "ps_context_find_proc_stat");
- while ((rd = read (fd, buf, sizeof (buf))) > 0)
+ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC);
+ if (!err && !(ps->flags & PSTAT_TASK_BASIC))
+ err = EGRATUITOUS;
+ if (err)
{
- struct utmp *u = buf;
- while (rd >= sizeof (*u))
- {
- if (*u->ut_name && *u->ut_line)
- /* An active entry. */
- add_utmp_procs (procs, u);
- rd -= sizeof (*u);
- u++;
- }
+ error (0, err, "cannot find boot time");
+ return err;
+ }
+ else
+ {
+ time_value_t *const tv = &proc_stat_task_basic_info (ps)->creation_time;
+ when->tv_sec = tv->seconds;
+ when->tv_usec = tv->microseconds;
}
- close (fd);
+ ps_context_free (context);
+
+ return 0;
}
-
+
static void
uptime (struct proc_stat_list *procs)
{
- struct stat st;
+ error_t err;
+ struct timeval boot_time;
char uptime_rep[20], tod_rep[20];
struct host_load_info *load;
unsigned nusers = 0;
- int maybe_add_user (struct proc_stat *ps) { if (ps->hook) nusers++; return 0; }
+ int maybe_add_user (struct proc_stat *ps)
+ { if (ps->hook) nusers++; return 0; }
proc_stat_list_for_each (procs, maybe_add_user);
- /* Until we get a better way of finding out how long the system's been
- up... XXX */
- if (stat ("/var/run/uptime", &st) != 0)
+ if (fetch_boot_time (&boot_time))
strcpy (uptime_rep, "chuck");
else
{
- struct timeval uptime = { now.tv_sec - st.st_ctime, 0 };
+ struct timeval uptime;
+ timersub (&now, &boot_time, &uptime);
fmt_named_interval (&uptime, 0, uptime_rep, sizeof (uptime_rep));
}
- strftime (tod_rep, sizeof (tod_rep), "%r",
+ strftime (tod_rep, sizeof (tod_rep), "%r",
localtime ((time_t *)&now.tv_sec));
if (tod_rep[0] == '0')
tod_rep[0] = ' '; /* Get rid of bletcherous leading 0. */
- errno = ps_host_load_info (&load);
- if (errno)
- error (0, errno, "ps_host_load_info");
+ err = ps_host_load_info (&load);
+ if (err)
+ error (0, err, "ps_host_load_info");
printf ("%s up %s, %u user%s, load averages: %.2f, %.2f, %.2f\n",
tod_rep, uptime_rep, nusers, nusers == 1 ? "" : "s",
@@ -365,10 +412,11 @@ uptime (struct proc_stat_list *procs)
(double)load->avenrun[2] / (double)LOAD_SCALE);
}
-void
+int
main(int argc, char *argv[])
{
error_t err;
+ struct utmp *ut;
struct ps_context *context;
int output_width = -1;
char *fmt_string = DEFAULT_FMT_STRING, *sort_key_name = NULL;
@@ -378,12 +426,23 @@ main(int argc, char *argv[])
#if 0
char *tty_names = 0;
unsigned num_tty_names = 0;
- struct idvec *only_uids = make_idvec (), *not_uids = make_idvec ();
#endif
- struct ps_user_hooks ps_hooks = { 0, w_fetch, w_cleanup };
+ uid_t *users = 0;
+ size_t num_users = 0;
+ struct ps_user_hooks ps_hooks = { w_deps, w_fetch, w_cleanup };
int has_hook (struct proc_stat *ps) { return ps->hook != 0; }
+ int keep_users (struct proc_stat *ps)
+ {
+ int i;
+ struct w_hook *h = ps->hook;
+ for (i = 0; i < num_users; i++)
+ if (users[i] == h->user->uid)
+ return 1;
+ return 0;
+ }
+
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -400,6 +459,19 @@ main(int argc, char *argv[])
case 'w': output_width = arg ? atoi (arg) : 0; break;
case ARGP_KEY_ARG:
+ num_users++;
+ users = realloc (users, num_users * sizeof (*users));
+ if (! users)
+ argp_failure (state, 5, ENOMEM, "%s", arg);
+ else if (isdigit (*arg))
+ users[num_users - 1] = atoi (arg);
+ else
+ {
+ struct passwd *pw = getpwnam (arg);
+ if (! pw)
+ argp_failure (state, 6, 0, "%s: Unknown user", arg);
+ users[num_users - 1] = pw->pw_uid;
+ }
break;
default:
@@ -424,18 +496,25 @@ main(int argc, char *argv[])
/* Parse our options. */
argp_parse (&argp, argc, argv, 0, 0, 0);
- read_utmp_procs (procs, _PATH_UTMP);
+ /* Read the utmp file. */
+ setutent ();
+ while ((ut = getutent ()) != NULL)
+ add_utmp_procs (procs, ut);
+ endutent ();
/* Keep only processes that have our hooks attached. */
proc_stat_list_filter1 (procs, has_hook, 0, 0);
+ if (num_users > 0)
+ proc_stat_list_filter1 (procs, keep_users, W_PSTAT_USER, 0);
+
if (show_uptime)
uptime (procs);
if (show_entries)
psout (procs, fmt_string, 0, &w_specs, sort_key_name, sort_reverse,
output_width, print_heading,
- squash_bogus_fields, squash_nominal_fields);
+ squash_bogus_fields, squash_nominal_fields, 0);
- exit(0);
+ return 0;
}
diff --git a/utils/x.c b/utils/x.c
index 0e4f7e02..e4e272f4 100644
--- a/utils/x.c
+++ b/utils/x.c
@@ -55,8 +55,8 @@ static struct argp_option options[] =
{0, 0}
};
static char *args_doc = "[USER...]";
-static char *doc =
- "A USER specified as an argument adds (or removes) that user's groups as"
+static char *doc = "Modify authentication of existing processes"
+ "\vA USER specified as an argument adds (or removes) that user's groups as"
" well. When removing groups implied by such an argument, the groups to"
" which uids remaining in the process after any we remove are ignored."
"\nUids and groups specified with options are used as-is.";