Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/miscutils


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
Location:
branches/2.2.9/mindi-busybox/miscutils
Files:
22 added
26 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/miscutils/Config.in

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    67menu "Miscellaneous Utilities"
    78
     9config CONSPY
     10    bool "conspy"
     11    default n
     12    depends on PLATFORM_LINUX
     13    help
     14      A text-mode VNC like program for Linux virtual terminals.
     15      example:  conspy NUM      shared access to console num
     16      or        conspy -nd NUM  screenshot of console num
     17      or        conspy -cs NUM  poor man's GNU screen like
     18config NANDWRITE
     19    bool "nandwrite"
     20    default n
     21    depends on PLATFORM_LINUX
     22    help
     23      Write to the specified MTD device, with bad blocks awareness
     24
     25config NANDDUMP
     26    bool "nanddump"
     27    default n
     28    depends on PLATFORM_LINUX
     29    help
     30      Dump the content of raw NAND chip
     31config UBIATTACH
     32    bool "ubiattach"
     33    default n
     34    depends on PLATFORM_LINUX
     35    help
     36      Attach MTD device to an UBI device.
     37
     38config UBIDETACH
     39    bool "ubidetach"
     40    default n
     41    depends on PLATFORM_LINUX
     42    help
     43      Detach MTD device from an UBI device.
     44
    845config ADJTIMEX
    946    bool "adjtimex"
    10     default n
     47    default y
     48    depends on PLATFORM_LINUX
    1149    help
    1250      Adjtimex reads and optionally sets adjustment parameters for
     
    2058      busybox was built.
    2159
     60config FEATURE_COMPRESS_BBCONFIG
     61    bool "Compress bbconfig data"
     62    default y
     63    depends on BBCONFIG
     64    help
     65      Store bbconfig data in compressed form, uncompress them on-the-fly
     66      before output.
     67
     68      If you have a really tiny busybox with few applets enabled (and
     69      bunzip2 isn't one of them), the overhead of the decompressor might
     70      be noticeable. Also, if you run executables directly from ROM
     71      and have very little memory, this might not be a win. Otherwise,
     72      you probably want this.
     73
     74config BEEP
     75    bool "beep"
     76    default y
     77    depends on PLATFORM_LINUX
     78    help
     79      The beep applets beeps in a given freq/Hz.
     80
     81config FEATURE_BEEP_FREQ
     82    int "default frequency"
     83    range 0 2147483647
     84    default 4000
     85    depends on BEEP
     86    help
     87      Frequency for default beep.
     88
     89config FEATURE_BEEP_LENGTH_MS
     90    int "default length"
     91    range 0 2147483647
     92    default 30
     93    depends on BEEP
     94    help
     95      Length in ms for default beep.
     96
     97config CHAT
     98    bool "chat"
     99    default y
     100    help
     101      Simple chat utility.
     102
     103config FEATURE_CHAT_NOFAIL
     104    bool "Enable NOFAIL expect strings"
     105    depends on CHAT
     106    default y
     107    help
     108      When enabled expect strings which are started with a dash trigger
     109      no-fail mode. That is when expectation is not met within timeout
     110      the script is not terminated but sends next SEND string and waits
     111      for next EXPECT string. This allows to compose far more flexible
     112      scripts.
     113
     114config FEATURE_CHAT_TTY_HIFI
     115    bool "Force STDIN to be a TTY"
     116    depends on CHAT
     117    default n
     118    help
     119      Original chat always treats STDIN as a TTY device and sets for it
     120      so-called raw mode. This option turns on such behaviour.
     121
     122config FEATURE_CHAT_IMPLICIT_CR
     123    bool "Enable implicit Carriage Return"
     124    depends on CHAT
     125    default y
     126    help
     127      When enabled make chat to terminate all SEND strings with a "\r"
     128      unless "\c" is met anywhere in the string.
     129
     130config FEATURE_CHAT_SWALLOW_OPTS
     131    bool "Swallow options"
     132    depends on CHAT
     133    default y
     134    help
     135      Busybox chat require no options. To make it not fail when used
     136      in place of original chat (which has a bunch of options) turn
     137      this on.
     138
     139config FEATURE_CHAT_SEND_ESCAPES
     140    bool "Support weird SEND escapes"
     141    depends on CHAT
     142    default y
     143    help
     144      Original chat uses some escape sequences in SEND arguments which
     145      are not sent to device but rather performs special actions.
     146      E.g. "\K" means to send a break sequence to device.
     147      "\d" delays execution for a second, "\p" -- for a 1/100 of second.
     148      Before turning this option on think twice: do you really need them?
     149
     150config FEATURE_CHAT_VAR_ABORT_LEN
     151    bool "Support variable-length ABORT conditions"
     152    depends on CHAT
     153    default y
     154    help
     155      Original chat uses fixed 50-bytes length ABORT conditions. Say N here.
     156
     157config FEATURE_CHAT_CLR_ABORT
     158    bool "Support revoking of ABORT conditions"
     159    depends on CHAT
     160    default y
     161    help
     162      Support CLR_ABORT directive.
     163
    22164config CHRT
    23165    bool "chrt"
    24     default n
     166    default y
    25167    help
    26168      manipulate real-time attributes of a process.
     
    29171config CROND
    30172    bool "crond"
    31     default n
    32     select FEATURE_SUID
     173    default y
    33174    select FEATURE_SYSLOG
    34175    help
    35176      Crond is a background daemon that parses individual crontab
    36177      files and executes commands on behalf of the users in question.
    37       This is a port of dcron from slackware.  It uses files of the
     178      This is a port of dcron from slackware. It uses files of the
    38179      format /var/spool/cron/crontabs/<username> files, for example:
    39180          $ cat /var/spool/cron/crontabs/root
    40181          # Run daily cron jobs at 4:40 every day:
    41182          40 4 * * * /etc/cron/daily > /dev/null 2>&1
     183
     184config FEATURE_CROND_D
     185    bool "Support option -d to redirect output to stderr"
     186    depends on CROND
     187    default y
     188    help
     189      -d sets loglevel to 0 (most verbose) and directs all output to stderr.
     190
     191config FEATURE_CROND_CALL_SENDMAIL
     192    bool "Report command output via email (using sendmail)"
     193    default y
     194    depends on CROND
     195    help
     196      Command output will be sent to corresponding user via email.
     197
     198config FEATURE_CROND_DIR
     199    string "crond spool directory"
     200    default "/var/spool/cron"
     201    depends on CROND || CRONTAB
     202    help
     203      Location of crond spool.
     204
     205config CRONTAB
     206    bool "crontab"
     207    default y
     208    help
     209      Crontab manipulates the crontab for a particular user. Only
     210      the superuser may specify a different user and/or crontab directory.
    42211      Note that Busybox binary must be setuid root for this applet to
    43212      work properly.
    44213
    45 config DEBUG_CROND_OPTION
    46     bool "Support debug option -d"
    47     depends on CROND
    48     default n
    49     help
    50       Support option -d to enter debug mode.
    51 
    52 config FEATURE_CROND_CALL_SENDMAIL
    53     bool "Using /usr/sbin/sendmail?"
    54     default n
    55     depends on CROND
    56     help
    57       Support calling /usr/sbin/sendmail for send cmd outputs.
    58 
    59 config CRONTAB
    60     bool "crontab"
    61     default n
    62     select FEATURE_SUID
    63     help
    64       Crontab manipulates the crontab for a particular user.  Only
    65       the superuser may specify a different user and/or crontab directory.
    66 
    67214config DC
    68215    bool "dc"
    69     default n
     216    default y
    70217    help
    71218      Dc is a reverse-polish desk calculator which supports unlimited
    72219      precision arithmetic.
    73220
     221config FEATURE_DC_LIBM
     222    bool "Enable power and exp functions (requires libm)"
     223    default y
     224    depends on DC
     225    help
     226      Enable power and exp functions.
     227      NOTE: This will require libm to be present for linking.
     228
    74229config DEVFSD
    75230    bool "devfsd (obsolete)"
    76231    default n
     232    depends on PLATFORM_LINUX
    77233    select FEATURE_SYSLOG
    78234    help
    79       This is deprecated, and will be removed at the end of 2008.
     235      This is deprecated and should NOT be used anymore.
     236      Use linux >= 2.6 (optionally with hotplug) and mdev instead!
     237      See docs/mdev.txt for detailed instructions on how to use mdev
     238      instead.
    80239
    81240      Provides compatibility with old device names on a devfs systems.
     
    86245      "MKOLDCOMPAT", "MKNEWCOMPAT","RMOLDCOMPAT", "RMNEWCOMPAT".
    87246
    88        But only if they are written UPPERCASE!!!!!!!!
     247      But only if they are written UPPERCASE!!!!!!!!
    89248
    90249config DEVFSD_MODLOAD
    91250    bool "Adds support for MODLOAD keyword in devsfd.conf"
    92     default n
     251    default y
    93252    depends on DEVFSD
    94253    help
     
    98257config DEVFSD_FG_NP
    99258    bool "Enables the -fg and -np options"
    100     default n
     259    default y
    101260    depends on DEVFSD
    102261    help
    103         -fg Run the daemon in the foreground.
    104         -np Exit  after  parsing  the configuration file. Do not poll for events.
     262      -fg  Run the daemon in the foreground.
     263      -np  Exit after parsing the configuration file.
     264           Do not poll for events.
    105265
    106266config DEVFSD_VERBOSE
    107267    bool "Increases logging (and size)"
    108     default n
     268    default y
    109269    depends on DEVFSD
    110270    help
     
    112272
    113273config FEATURE_DEVFS
    114     bool "  Use devfs names for all devices (obsolete)"
    115     default n
    116     help
    117       This is obsolete and will be going away at the end of 2008..
    118 
    119       This tells busybox to look for names like /dev/loop/0 instead of
    120       /dev/loop0.  If your /dev directory has normal names instead of
     274    bool "Use devfs names for all devices (obsolete)"
     275    default n
     276    depends on PLATFORM_LINUX
     277    help
     278      This is obsolete and should NOT be used anymore.
     279      Use linux >= 2.6 (optionally with hotplug) and mdev instead!
     280
     281      For legacy systems -- if there is no way around devfsd -- this
     282      tells busybox to look for names like /dev/loop/0 instead of
     283      /dev/loop0. If your /dev directory has normal names instead of
    121284      devfs names, you don't want this.
     285
     286config DEVMEM
     287    bool "devmem"
     288    default y
     289    help
     290      devmem is a small program that reads and writes from physical
     291      memory using /dev/mem.
    122292
    123293config EJECT
    124294    bool "eject"
    125     default n
    126     help
    127       Used to eject cdroms.  (defaults to /dev/cdrom)
     295    default y
     296    depends on PLATFORM_LINUX
     297    help
     298      Used to eject cdroms. (defaults to /dev/cdrom)
     299
     300config FEATURE_EJECT_SCSI
     301    bool "SCSI support"
     302    default y
     303    depends on EJECT
     304    help
     305      Add the -s option to eject, this allows to eject SCSI-Devices and
     306      usb-storage devices.
     307
     308config FBSPLASH
     309    bool "fbsplash"
     310    default y
     311    depends on PLATFORM_LINUX
     312    help
     313      Shows splash image and progress bar on framebuffer device.
     314      Can be used during boot phase of an embedded device. ~2kb.
     315      Usage:
     316      - use kernel option 'vga=xxx' or otherwise enable fb device.
     317      - put somewhere fbsplash.cfg file and an image in .ppm format.
     318      - $ setsid fbsplash [params] &
     319        -c: hide cursor
     320        -d /dev/fbN: framebuffer device (if not /dev/fb0)
     321        -s path_to_image_file (can be "-" for stdin)
     322        -i path_to_cfg_file (can be "-" for stdin)
     323        -f path_to_fifo (can be "-" for stdin)
     324      - if you want to run it only in presence of kernel parameter:
     325        grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params] &
     326      - commands for fifo:
     327        "NN" (ASCII decimal number) - percentage to show on progress bar
     328        "exit" - well you guessed it
     329
     330config FLASHCP
     331    bool "flashcp"
     332    default n  # doesn't build on Ubuntu 8.04
     333    help
     334      The flashcp binary, inspired by mtd-utils as of git head 5eceb74f7.
     335      This utility is used to copy images into a MTD device.
     336
     337config FLASH_LOCK
     338    bool "flash_lock"
     339    default n  # doesn't build on Ubuntu 8.04
     340    help
     341      The flash_lock binary from mtd-utils as of git head 5ec0c10d0. This
     342      utility locks part or all of the flash device.
     343
     344config FLASH_UNLOCK
     345    bool "flash_unlock"
     346    default n  # doesn't build on Ubuntu 8.04
     347    help
     348      The flash_unlock binary from mtd-utils as of git head 5ec0c10d0. This
     349      utility unlocks part or all of the flash device.
     350
     351config FLASH_ERASEALL
     352    bool "flash_eraseall"
     353    default n  # doesn't build on Ubuntu 8.04
     354    help
     355      The flash_eraseall binary from mtd-utils as of git head c4c6a59eb.
     356      This utility is used to erase the whole MTD device.
     357
     358config IONICE
     359    bool "ionice"
     360    default y
     361    depends on PLATFORM_LINUX
     362    help
     363      Set/set program io scheduling class and priority
     364      Requires kernel >= 2.6.13
     365
     366config INOTIFYD
     367    bool "inotifyd"
     368    default n  # doesn't build on Knoppix 5
     369    help
     370      Simple inotify daemon. Reports filesystem changes. Requires
     371      kernel >= 2.6.13
    128372
    129373config LAST
    130374    bool "last"
    131     default n
    132     select FEATURE_WTMP
     375    default y
     376    depends on FEATURE_WTMP
    133377    help
    134378      'last' displays a list of the last users that logged into the system.
     379
     380choice
     381    prompt "Choose last implementation"
     382    depends on LAST
     383    default FEATURE_LAST_FANCY
     384
     385config FEATURE_LAST_SMALL
     386    bool "small"
     387    help
     388      This is a small version of last with just the basic set of
     389      features.
     390
     391config FEATURE_LAST_FANCY
     392    bool "huge"
     393    help
     394      'last' displays detailed information about the last users that
     395      logged into the system (mimics sysvinit last). +900 bytes.
     396endchoice
    135397
    136398config LESS
    137399    bool "less"
    138     default n
     400    default y
    139401    help
    140402      'less' is a pager, meaning that it displays text files. It possesses
     
    164426      The -m flag enables a simpler status line with a percentage.
    165427
    166 config FEATURE_LESS_FLAGCS
    167     bool "Enable flag changes"
    168     default n
    169     depends on LESS
    170     help
    171       This enables the ability to change command-line flags within
    172       less itself.
    173 
    174428config FEATURE_LESS_MARKS
    175429    bool "Enable marks"
    176     default n
     430    default y
    177431    depends on LESS
    178432    help
     
    181435config FEATURE_LESS_REGEXP
    182436    bool "Enable regular expressions"
    183     default n
     437    default y
    184438    depends on LESS
    185439    help
    186440      Enable regular expressions, allowing complex file searches.
     441
     442config FEATURE_LESS_WINCH
     443    bool "Enable automatic resizing on window size changes"
     444    default y
     445    depends on LESS
     446    help
     447      Makes less track window size changes.
     448
     449config FEATURE_LESS_DASHCMD
     450    bool "Enable flag changes ('-' command)"
     451    default y
     452    depends on LESS
     453    help
     454      This enables the ability to change command-line flags within
     455      less itself ('-' keyboard command).
     456
     457config FEATURE_LESS_LINENUMS
     458    bool "Enable dynamic switching of line numbers"
     459    default y
     460    depends on FEATURE_LESS_DASHCMD
     461    help
     462      Enables "-N" command.
    187463
    188464config HDPARM
    189465    bool "hdparm"
    190     default n
    191     help
    192       Get/Set hard drive parameters.  Primarily intended for ATA
    193       drives.  Adds about 13k (or around 30k if you enable the
     466    default y
     467    depends on PLATFORM_LINUX
     468    help
     469      Get/Set hard drive parameters. Primarily intended for ATA
     470      drives. Adds about 13k (or around 30k if you enable the
    194471      FEATURE_HDPARM_GET_IDENTITY option)....
    195472
     
    206483config FEATURE_HDPARM_HDIO_SCAN_HWIF
    207484    bool "Register an IDE interface (DANGEROUS)"
    208     default n
     485    default y
    209486    depends on HDPARM
    210487    help
     
    214491config FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
    215492    bool "Un-register an IDE interface (DANGEROUS)"
    216     default n
     493    default y
    217494    depends on HDPARM
    218495    help
     
    221498
    222499config FEATURE_HDPARM_HDIO_DRIVE_RESET
    223     bool "perform device reset (DANGEROUS)"
    224     default n
     500    bool "Perform device reset (DANGEROUS)"
     501    default y
    225502    depends on HDPARM
    226503    help
     
    229506
    230507config FEATURE_HDPARM_HDIO_TRISTATE_HWIF
    231     bool "tristate device for hotswap (DANGEROUS)"
    232     default n
     508    bool "Tristate device for hotswap (DANGEROUS)"
     509    default y
    233510    depends on HDPARM
    234511    help
    235512      Enables the 'hdparm -x' option to tristate device for hotswap,
    236       and the '-b' option to get/set bus state.  This is dangerous
     513      and the '-b' option to get/set bus state. This is dangerous
    237514      stuff, so you should probably say N.
    238515
    239516config FEATURE_HDPARM_HDIO_GETSET_DMA
    240     bool "get/set using_dma flag (DANGEROUS)"
    241     default n
     517    bool "Get/set using_dma flag"
     518    default y
    242519    depends on HDPARM
    243520    help
    244521      Enables the 'hdparm -d' option to get/set using_dma flag.
    245       This is dangerous stuff, so you should probably say N.
    246522
    247523config MAKEDEVS
    248524    bool "makedevs"
    249     default n
     525    default y
    250526    help
    251527      'makedevs' is a utility used to create a batch of devices with
    252528      one command.
    253       .
     529
    254530      There are two choices for command line behaviour, the interface
    255531      as used by LEAF/Linux Router Project, or a device table file.
    256       .
     532
    257533      'leaf' is traditionally what busybox follows, it allows multiple
    258534      devices of a particluar type to be created per command.
    259535      e.g. /dev/hda[0-9]
    260536      Device properties are passed as command line arguments.
    261       .
     537
    262538      'table' reads device properties from a file or stdin, allowing
    263539      a batch of unrelated devices to be made with one command.
     
    277553endchoice
    278554
     555config MAN
     556    bool "man"
     557    default y
     558    help
     559      Format and display manual pages.
     560
     561config MICROCOM
     562    bool "microcom"
     563    default y
     564    help
     565      The poor man's minicom utility for chatting with serial port devices.
     566
    279567config MOUNTPOINT
    280568    bool "mountpoint"
    281     default n
     569    default y
    282570    help
    283571      mountpoint checks if the directory is a mountpoint.
     
    285573config MT
    286574    bool "mt"
    287     default n
    288     help
    289       mt is used to control tape devices.  You can use the mt utility
     575    default y
     576    help
     577      mt is used to control tape devices. You can use the mt utility
    290578      to advance or rewind a tape past a specified number of archive
    291579      files on the tape.
     
    293581config RAIDAUTORUN
    294582    bool "raidautorun"
    295     default n
     583    default y
     584    depends on PLATFORM_LINUX
    296585    help
    297586      raidautorun tells the kernel md driver to
     
    300589config READAHEAD
    301590    bool "readahead"
    302     default n
    303     depends on LFS
     591    default y
     592    depends on LFS && PLATFORM_LINUX
    304593    help
    305594      Preload the files listed on the command line into RAM cache so that
     
    308597      This applet just calls the readahead(2) system call on each file.
    309598      It is mainly useful in system startup scripts to preload files
    310       or executables before they are used.  When used at the right time
    311       (in particular when a CPU boundprocess is running) it can
     599      or executables before they are used. When used at the right time
     600      (in particular when a CPU bound process is running) it can
    312601      significantly speed up system startup.
    313602
     
    315604      run this applet as a background job.
    316605
     606config RFKILL
     607    bool "rfkill"
     608    default n  # doesn't build on Ubuntu 9.04
     609    depends on PLATFORM_LINUX
     610    help
     611      Enable/disable wireless devices.
     612
     613      rfkill list : list all wireless devices
     614      rfkill list bluetooth : list all bluetooth devices
     615      rfkill list 1 : list device corresponding to the given index
     616      rfkill block|unblock wlan : block/unblock all wlan(wifi) devices
     617
    317618config RUNLEVEL
    318619    bool "runlevel"
    319     default n
     620    default y
    320621    help
    321622      find the current and previous system runlevel.
     
    326627config RX
    327628    bool "rx"
    328     default n
     629    default y
     630    depends on PLATFORM_LINUX
    329631    help
    330632      Receive files using the Xmodem protocol.
     633
     634config SETSID
     635    bool "setsid"
     636    default y
     637    help
     638      setsid runs a program in a new session
    331639
    332640config STRINGS
    333641    bool "strings"
    334     default n
     642    default y
    335643    help
    336644      strings prints the printable character sequences for each file
    337645      specified.
    338646
    339 config SETSID
    340     bool "setsid"
    341     default n
    342     help
    343       setsid runs a program in a new session
    344 
    345647config TASKSET
    346648    bool "taskset"
    347     default n
     649    default n  # doesn't build on some non-x86 targets (m68k)
    348650    help
    349651      Retrieve or set a processes's CPU affinity.
     
    351653
    352654config FEATURE_TASKSET_FANCY
    353     bool "fancy output"
     655    bool "Fancy output"
    354656    default y
    355657    depends on TASKSET
     
    361663config TIME
    362664    bool "time"
    363     default n
     665    default y
    364666    help
    365667      The time command runs the specified program with the given arguments.
     
    367669      giving timing statistics about this program run.
    368670
     671config TIMEOUT
     672    bool "timeout"
     673    default y
     674    help
     675      Runs a program and watches it. If it does not terminate in
     676      specified number of seconds, it is sent a signal.
     677
    369678config TTYSIZE
    370679    bool "ttysize"
    371     default n
     680    default y
    372681    help
    373682      A replacement for "stty size". Unlike stty, can report only width,
    374       only height, or both, in any order. It also does not complain on error,
    375       but returns default 80x24. Usage in shell scripts: width=`ttysize w`.
     683      only height, or both, in any order. It also does not complain on
     684      error, but returns default 80x24.
     685      Usage in shell scripts: width=`ttysize w`.
     686
     687config VOLNAME
     688    bool "volname"
     689    default y
     690    help
     691      Prints a CD-ROM volume name.
     692
     693config WALL
     694    bool "wall"
     695    default y
     696    help
     697      Write a message to all users that are logged in.
    376698
    377699config WATCHDOG
    378700    bool "watchdog"
    379     default n
     701    default y
     702    depends on PLATFORM_LINUX
    380703    help
    381704      The watchdog utility is used with hardware or software watchdog
    382       device drivers.  It opens the specified watchdog device special file
    383       and periodically writes a magic character to the device.  If the
     705      device drivers. It opens the specified watchdog device special file
     706      and periodically writes a magic character to the device. If the
    384707      watchdog applet ever fails to write the magic character within a
    385708      certain amount of time, the watchdog device assumes the system has
     
    387710
    388711endmenu
    389 
  • branches/2.2.9/mindi-busybox/miscutils/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2, see the file LICENSE in this tarball.
     6# Licensed under GPLv2, see file LICENSE in this source tree.
    67
    78lib-y:=
     9
     10lib-$(CONFIG_CONSPY) += conspy.o
     11lib-$(CONFIG_NANDWRITE) += nandwrite.o
     12lib-$(CONFIG_NANDDUMP) += nandwrite.o
     13lib-$(CONFIG_UBIATTACH)   += ubi_attach_detach.o
     14lib-$(CONFIG_UBIDETACH)   += ubi_attach_detach.o
    815lib-$(CONFIG_ADJTIMEX)    += adjtimex.o
    916lib-$(CONFIG_BBCONFIG)    += bbconfig.o
     17lib-$(CONFIG_BEEP)        += beep.o
     18lib-$(CONFIG_CHAT)        += chat.o
    1019lib-$(CONFIG_CHRT)        += chrt.o
    1120lib-$(CONFIG_CROND)       += crond.o
     
    1322lib-$(CONFIG_DC)          += dc.o
    1423lib-$(CONFIG_DEVFSD)      += devfsd.o
     24lib-$(CONFIG_DEVMEM)      += devmem.o
    1525lib-$(CONFIG_EJECT)       += eject.o
     26lib-$(CONFIG_FBSPLASH)    += fbsplash.o
     27lib-$(CONFIG_FLASHCP)     += flashcp.o
     28lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o
     29lib-$(CONFIG_FLASH_LOCK)     += flash_lock_unlock.o
     30lib-$(CONFIG_FLASH_UNLOCK)   += flash_lock_unlock.o
     31lib-$(CONFIG_IONICE)      += ionice.o
    1632lib-$(CONFIG_HDPARM)      += hdparm.o
    17 lib-$(CONFIG_LAST)        += last.o
     33lib-$(CONFIG_INOTIFYD)    += inotifyd.o
     34lib-$(CONFIG_FEATURE_LAST_SMALL)+= last.o
     35lib-$(CONFIG_FEATURE_LAST_FANCY)+= last_fancy.o
    1836lib-$(CONFIG_LESS)        += less.o
    1937lib-$(CONFIG_MAKEDEVS)    += makedevs.o
     38lib-$(CONFIG_MAN)         += man.o
     39lib-$(CONFIG_MICROCOM)    += microcom.o
    2040lib-$(CONFIG_MOUNTPOINT)  += mountpoint.o
    2141lib-$(CONFIG_MT)          += mt.o
    2242lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o
    2343lib-$(CONFIG_READAHEAD)   += readahead.o
     44lib-$(CONFIG_RFKILL)      += rfkill.o
    2445lib-$(CONFIG_RUNLEVEL)    += runlevel.o
    2546lib-$(CONFIG_RX)          += rx.o
     
    2849lib-$(CONFIG_TASKSET)     += taskset.o
    2950lib-$(CONFIG_TIME)        += time.o
     51lib-$(CONFIG_TIMEOUT)     += timeout.o
    3052lib-$(CONFIG_TTYSIZE)     += ttysize.o
     53lib-$(CONFIG_VOLNAME)     += volname.o
     54lib-$(CONFIG_WALL)        += wall.o
    3155lib-$(CONFIG_WATCHDOG)    += watchdog.o
  • branches/2.2.9/mindi-busybox/miscutils/adjtimex.c

    r1765 r2725  
    99 * busyboxed 20 March 2001, Larry Doolittle <ldoolitt@recycle.lbl.gov>
    1010 *
    11  * Licensed under GPLv2 or later, see file License in this tarball for details.
     11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1212 */
    1313
     
    1515#include <sys/timex.h>
    1616
    17 static const struct {
    18     int bit;
    19     const char *name;
    20 } statlist[] = {
    21     { STA_PLL,       "PLL"       },
    22     { STA_PPSFREQ,   "PPSFREQ"   },
    23     { STA_PPSTIME,   "PPSTIME"   },
    24     { STA_FLL,       "FFL"       },
    25     { STA_INS,       "INS"       },
    26     { STA_DEL,       "DEL"       },
    27     { STA_UNSYNC,    "UNSYNC"    },
    28     { STA_FREQHOLD,  "FREQHOLD"  },
    29     { STA_PPSSIGNAL, "PPSSIGNAL" },
    30     { STA_PPSJITTER, "PPSJITTER" },
    31     { STA_PPSWANDER, "PPSWANDER" },
    32     { STA_PPSERROR,  "PPSERROR"  },
    33     { STA_CLOCKERR,  "CLOCKERR"  },
    34     { 0, NULL }
     17static const uint16_t statlist_bit[] = {
     18    STA_PLL,
     19    STA_PPSFREQ,
     20    STA_PPSTIME,
     21    STA_FLL,
     22    STA_INS,
     23    STA_DEL,
     24    STA_UNSYNC,
     25    STA_FREQHOLD,
     26    STA_PPSSIGNAL,
     27    STA_PPSJITTER,
     28    STA_PPSWANDER,
     29    STA_PPSERROR,
     30    STA_CLOCKERR,
     31    0
    3532};
     33static const char statlist_name[] =
     34    "PLL"       "\0"
     35    "PPSFREQ"   "\0"
     36    "PPSTIME"   "\0"
     37    "FFL"       "\0"
     38    "INS"       "\0"
     39    "DEL"       "\0"
     40    "UNSYNC"    "\0"
     41    "FREQHOLD"  "\0"
     42    "PPSSIGNAL" "\0"
     43    "PPSJITTER" "\0"
     44    "PPSWANDER" "\0"
     45    "PPSERROR"  "\0"
     46    "CLOCKERR"
     47;
    3648
    37 static const char *const ret_code_descript[] = {
    38     "clock synchronized",
    39     "insert leap second",
    40     "delete leap second",
    41     "leap second in progress",
    42     "leap second has occurred",
     49static const char ret_code_descript[] =
     50    "clock synchronized" "\0"
     51    "insert leap second" "\0"
     52    "delete leap second" "\0"
     53    "leap second in progress" "\0"
     54    "leap second has occurred" "\0"
    4355    "clock not synchronized"
    44 };
     56;
    4557
    46 int adjtimex_main(int argc, char **argv);
    47 int adjtimex_main(int argc, char **argv)
     58int adjtimex_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     59int adjtimex_main(int argc UNUSED_PARAM, char **argv)
    4860{
    4961    enum {
     
    5365    char *opt_o, *opt_f, *opt_p, *opt_t;
    5466    struct timex txc;
    55     int i, ret, sep;
     67    int i, ret;
    5668    const char *descript;
    57     txc.modes=0;
    5869
     70    opt_complementary = "=0"; /* no valid non-option parameters */
    5971    opt = getopt32(argv, "qo:f:p:t:",
    6072            &opt_o, &opt_f, &opt_p, &opt_t);
     73    txc.modes = 0;
    6174    //if (opt & 0x1) // -q
    6275    if (opt & 0x2) { // -o
     
    7689        txc.modes |= ADJ_TICK;
    7790    }
    78     if (argc != optind) { /* no valid non-option parameters */
    79         bb_show_usage();
    80     }
    8191
    8292    ret = adjtimex(&txc);
    8393
    84     if (ret < 0) perror("adjtimex");
     94    if (ret < 0) {
     95        bb_perror_nomsg_and_die();
     96    }
    8597
    86     if (!(opt & OPT_quiet) && ret>=0) {
     98    if (!(opt & OPT_quiet)) {
     99        int sep;
     100        const char *name;
     101
    87102        printf(
    88103            "    mode:         %d\n"
     
    91106            "    maxerror:     %ld\n"
    92107            "    esterror:     %ld\n"
    93             "    status:       %d ( ",
     108            "    status:       %d (",
    94109        txc.modes, txc.offset, txc.freq, txc.maxerror,
    95110        txc.esterror, txc.status);
     
    97112        /* representative output of next code fragment:
    98113           "PLL | PPSTIME" */
    99         sep=0;
    100         for (i=0; statlist[i].name; i++) {
    101             if (txc.status & statlist[i].bit) {
    102                 if (sep) fputs(" | ",stdout);
    103                 fputs(statlist[i].name,stdout);
    104                 sep=1;
     114        name = statlist_name;
     115        sep = 0;
     116        for (i = 0; statlist_bit[i]; i++) {
     117            if (txc.status & statlist_bit[i]) {
     118                if (sep)
     119                    fputs(" | ", stdout);
     120                fputs(name, stdout);
     121                sep = 1;
    105122            }
     123            name += strlen(name) + 1;
    106124        }
    107125
    108126        descript = "error";
    109         if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret];
    110         printf(" )\n"
     127        if (ret <= 5)
     128            descript = nth_string(ret_code_descript, ret);
     129        printf(")\n"
    111130            "-p  timeconstant: %ld\n"
    112131            "    precision:    %ld\n"
     
    120139        (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript);
    121140    }
    122     return (ret<0);
     141
     142    return 0;
    123143}
  • branches/2.2.9/mindi-busybox/miscutils/bbconfig.c

    r1765 r2725  
    44#include "libbb.h"
    55#include "bbconfigopts.h"
     6#if ENABLE_FEATURE_COMPRESS_BBCONFIG
     7# include "archive.h"
     8# include "bbconfigopts_bz2.h"
     9#endif
    610
    7 int bbconfig_main(int argc, char **argv);
    8 int bbconfig_main(int argc, char **argv)
     11int bbconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     12int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    913{
    10     printf(bbconfig_config);
     14#if ENABLE_FEATURE_COMPRESS_BBCONFIG
     15    bunzip_data *bd;
     16    int i = start_bunzip(&bd,
     17            /* src_fd: */ -1,
     18            /* inbuf:  */ bbconfig_config_bz2,
     19            /* len:    */ sizeof(bbconfig_config_bz2));
     20    /* read_bunzip can longjmp to start_bunzip, and ultimately
     21     * end up here with i != 0 on read data errors! Not trivial */
     22    if (!i) {
     23        /* Cannot use xmalloc: will leak bd in NOFORK case! */
     24        char *outbuf = malloc_or_warn(sizeof(bbconfig_config));
     25        if (outbuf) {
     26            read_bunzip(bd, outbuf, sizeof(bbconfig_config));
     27            full_write1_str(outbuf);
     28        }
     29    }
     30#else
     31    full_write1_str(bbconfig_config);
     32#endif
    1133    return 0;
    1234}
  • branches/2.2.9/mindi-busybox/miscutils/chrt.c

    r1765 r2725  
    22/*
    33 * chrt - manipulate real-time attributes of a process
    4  * Copyright (c) 2006-2007 Bernhard Fischer
     4 * Copyright (c) 2006-2007 Bernhard Reutner-Fischer
    55 *
    6  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    77 */
    8 
    98#include <sched.h>
    10 #include <getopt.h> /* optind */
    119#include "libbb.h"
    1210#ifndef _POSIX_PRIORITY_SCHEDULING
    1311#warning your system may be foobared
    1412#endif
     13
    1514static const struct {
    16     const int policy;
    17     const char const name[12];
     15    int policy;
     16    char name[sizeof("SCHED_OTHER")];
    1817} policies[] = {
    1918    {SCHED_OTHER, "SCHED_OTHER"},
     
    2221};
    2322
     23//TODO: add
     24// -b, SCHED_BATCH
     25// -i, SCHED_IDLE
     26
    2427static void show_min_max(int pol)
    2528{
    26     const char *fmt = "%s min/max priority\t: %d/%d\n\0%s not supported?\n";
     29    const char *fmt = "%s min/max priority\t: %u/%u\n";
    2730    int max, min;
     31
    2832    max = sched_get_priority_max(pol);
    2933    min = sched_get_priority_min(pol);
    30     if (max >= 0 && min >= 0)
    31         printf(fmt, policies[pol].name, min, max);
    32     else {
    33         fmt += 29;
    34         printf(fmt, policies[pol].name);
    35     }
     34    if ((max|min) < 0)
     35        fmt = "%s not supported\n";
     36    printf(fmt, policies[pol].name, min, max);
    3637}
    3738
     
    4243#define OPT_o (1<<4)
    4344
    44 int chrt_main(int argc, char** argv);
    45 int chrt_main(int argc, char** argv)
     45int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     46int chrt_main(int argc UNUSED_PARAM, char **argv)
    4647{
    4748    pid_t pid = 0;
    4849    unsigned opt;
    4950    struct sched_param sp;
    50     char *p_opt = NULL, *priority = NULL;
    51     const char *state = "current\0new";
    52     int prio = 0, policy = SCHED_RR;
     51    char *pid_str;
     52    char *priority = priority; /* for compiler */
     53    const char *current_new;
     54    int policy = SCHED_RR;
    5355
    54     opt_complementary = "r--fo:f--ro:r--fo"; /* only one policy accepted */
    55     opt = getopt32(argv, "+mp:rfo", &p_opt);
     56    /* at least 1 arg; only one policy accepted */
     57    opt_complementary = "-1:r--fo:f--ro:r--fo";
     58    opt = getopt32(argv, "+mprfo");
    5659    if (opt & OPT_r)
    5760        policy = SCHED_RR;
     
    6063    if (opt & OPT_o)
    6164        policy = SCHED_OTHER;
    62 
    6365    if (opt & OPT_m) { /* print min/max */
    6466        show_min_max(SCHED_FIFO);
     
    6769        fflush_stdout_and_exit(EXIT_SUCCESS);
    6870    }
     71
     72    argv += optind;
    6973    if (opt & OPT_p) {
    70         if (argc == optind+1) { /* -p <priority> <pid> */
    71             priority = p_opt;
    72             p_opt = argv[optind];
     74        pid_str = *argv++;
     75        if (*argv) { /* "-p <priority> <pid> [...]" */
     76            priority = pid_str;
     77            pid_str = *argv;
    7378        }
    74         argv += optind; /* me -p <arg> */
    75         pid = xatoul_range(p_opt, 1, ULONG_MAX); /* -p <pid> */
     79        /* else "-p <pid>", and *argv == NULL */
     80        pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
    7681    } else {
    77         argv += optind; /* me -p <arg> */
    78         priority = *argv;
    79     }
    80     if (priority) {
    81         /* from the manpage of sched_getscheduler:
    82            [...] sched_priority can have a value
    83            in the range 0 to 99.
    84            [...] SCHED_OTHER or SCHED_BATCH  must  be  assigned
    85            the  static  priority  0. [...] SCHED_FIFO  or
    86            SCHED_RR can have a static priority in the range 1 to 99.
    87          */
    88         prio = xstrtol_range(priority, 0, policy == SCHED_OTHER
    89                                                      ? 0 : 1, 99);
     82        priority = *argv++;
     83        if (!*argv)
     84            bb_show_usage();
    9085    }
    9186
     87    current_new = "current\0new";
    9288    if (opt & OPT_p) {
    93         int pol = 0;
    94 print_rt_info:
     89        int pol;
     90 print_rt_info:
    9591        pol = sched_getscheduler(pid);
    9692        if (pol < 0)
    97             bb_perror_msg_and_die("failed to %cet pid %d's policy", 'g', pid);
     93            bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', pid);
    9894        printf("pid %d's %s scheduling policy: %s\n",
    99                 pid, state, policies[pol].name);
     95                pid, current_new, policies[pol].name);
    10096        if (sched_getparam(pid, &sp))
    101             bb_perror_msg_and_die("failed to get pid %d's attributes", pid);
     97            bb_perror_msg_and_die("can't get pid %d's attributes", pid);
    10298        printf("pid %d's %s scheduling priority: %d\n",
    103                 pid, state, sp.sched_priority);
    104         if (!*argv) /* no new prio given or we did print already, done. */
     99                pid, current_new, sp.sched_priority);
     100        if (!*argv) {
     101            /* Either it was just "-p <pid>",
     102             * or it was "-p <priority> <pid>" and we came here
     103             * for the second time (see goto below) */
    105104            return EXIT_SUCCESS;
     105        }
     106        *argv = NULL;
     107        current_new += 8;
    106108    }
    107109
    108     sp.sched_priority = prio;
     110    /* from the manpage of sched_getscheduler:
     111    [...] sched_priority can have a value in the range 0 to 99.
     112    [...] SCHED_OTHER or SCHED_BATCH must be assigned static priority 0.
     113    [...] SCHED_FIFO or SCHED_RR can have static priority in 1..99 range.
     114    */
     115    sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
     116
    109117    if (sched_setscheduler(pid, policy, &sp) < 0)
    110         bb_perror_msg_and_die("failed to %cet pid %d's policy", 's', pid);
    111     if (opt & OPT_p) {
    112         state += 8;
    113         ++argv;
     118        bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid);
     119
     120    if (!argv[0]) /* "-p <priority> <pid> [...]" */
    114121        goto print_rt_info;
    115     }
    116     ++argv;
    117     BB_EXECVP(*argv, argv);
    118     bb_perror_msg_and_die("%s", *argv);
     122
     123    BB_EXECVP_or_die(argv);
    119124}
    120 #undef OPT_p
    121 #undef OPT_r
    122 #undef OPT_f
    123 #undef OPT_o
    124 #undef OPT_m
  • branches/2.2.9/mindi-busybox/miscutils/crond.c

    r1765 r2725  
    99 * Vladimir Oleynik <dzo@simtreas.ru> (C) 2002
    1010 *
    11  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1212 */
    1313
    14 #include <sys/syslog.h>
    1514#include "libbb.h"
    16 
    17 #ifndef CRONTABS
    18 #define CRONTABS        "/var/spool/cron/crontabs"
    19 #endif
    20 #ifndef TMPDIR
    21 #define TMPDIR          "/var/spool/cron"
    22 #endif
     15#include <syslog.h>
     16
     17/* glibc frees previous setenv'ed value when we do next setenv()
     18 * of the same variable. uclibc does not do this! */
     19#if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */
     20# define SETENV_LEAKS 0
     21#else
     22# define SETENV_LEAKS 1
     23#endif
     24
     25
     26#define TMPDIR          CONFIG_FEATURE_CROND_DIR
     27#define CRONTABS        CONFIG_FEATURE_CROND_DIR "/crontabs"
    2328#ifndef SENDMAIL
    24 #define SENDMAIL        "sendmail"
     29# define SENDMAIL       "sendmail"
    2530#endif
    2631#ifndef SENDMAIL_ARGS
    27 #define SENDMAIL_ARGS   "-ti", "oem"
     32# define SENDMAIL_ARGS  "-ti"
    2833#endif
    2934#ifndef CRONUPDATE
    30 #define CRONUPDATE      "cron.update"
     35# define CRONUPDATE     "cron.update"
    3136#endif
    3237#ifndef MAXLINES
    33 #define MAXLINES        256 /* max lines in non-root crontabs */
    34 #endif
     38# define MAXLINES       256  /* max lines in non-root crontabs */
     39#endif
     40
    3541
    3642typedef struct CronFile {
    37     struct CronFile *cf_Next;
    38     struct CronLine *cf_LineBase;
    39     char *cf_User;      /* username                     */
    40     int cf_Ready;       /* bool: one or more jobs ready */
    41     int cf_Running;     /* bool: one or more jobs running */
    42     int cf_Deleted;     /* marked for deletion, ignore */
     43    struct CronFile *cf_next;
     44    struct CronLine *cf_lines;
     45    char *cf_username;
     46    smallint cf_wants_starting;     /* bool: one or more jobs ready */
     47    smallint cf_has_running;        /* bool: one or more jobs running */
     48    smallint cf_deleted;            /* marked for deletion (but still has running jobs) */
    4349} CronFile;
    4450
    4551typedef struct CronLine {
    46     struct CronLine *cl_Next;
    47     char *cl_Shell;     /* shell command                        */
    48     pid_t cl_Pid;       /* running pid, 0, or armed (-1)        */
    49     int cl_MailFlag;    /* running pid is for mail              */
    50     int cl_MailPos;     /* 'empty file' size                    */
    51     char cl_Mins[60];   /* 0-59                                 */
    52     char cl_Hrs[24];    /* 0-23                                 */
    53     char cl_Days[32];   /* 1-31                                 */
    54     char cl_Mons[12];   /* 0-11                                 */
    55     char cl_Dow[7];     /* 0-6, beginning sunday                */
     52    struct CronLine *cl_next;
     53    char *cl_cmd;                   /* shell command */
     54    pid_t cl_pid;                   /* >0:running, <0:needs to be started in this minute, 0:dormant */
     55#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
     56    int cl_empty_mail_size;         /* size of mail header only, 0 if no mailfile */
     57    char *cl_mailto;                /* whom to mail results, may be NULL */
     58#endif
     59    /* ordered by size, not in natural order. makes code smaller: */
     60    char cl_Dow[7];                 /* 0-6, beginning sunday */
     61    char cl_Mons[12];               /* 0-11 */
     62    char cl_Hrs[24];                /* 0-23 */
     63    char cl_Days[32];               /* 1-31 */
     64    char cl_Mins[60];               /* 0-59 */
    5665} CronLine;
    5766
    58 #define RUN_RANOUT      1
    59 #define RUN_RUNNING     2
    60 #define RUN_FAILED      3
    61 
    62 #define DaemonUid 0
    63 
    64 #if ENABLE_DEBUG_CROND_OPTION
    65 static unsigned DebugOpt;
    66 #endif
    67 
    68 static unsigned LogLevel = 8;
    69 static const char *LogFile;
    70 static const char *CDir = CRONTABS;
    71 
    72 static void startlogger(void);
    73 
    74 static void CheckUpdates(void);
    75 static void SynchronizeDir(void);
    76 static int TestJobs(time_t t1, time_t t2);
    77 static void RunJobs(void);
    78 static int CheckJobs(void);
    79 
    80 static void RunJob(const char *user, CronLine * line);
    81 
    82 #if ENABLE_FEATURE_CROND_CALL_SENDMAIL
    83 static void EndJob(const char *user, CronLine * line);
     67
     68#define DAEMON_UID 0
     69
     70
     71enum {
     72    OPT_l = (1 << 0),
     73    OPT_L = (1 << 1),
     74    OPT_f = (1 << 2),
     75    OPT_b = (1 << 3),
     76    OPT_S = (1 << 4),
     77    OPT_c = (1 << 5),
     78    OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D,
     79};
     80#if ENABLE_FEATURE_CROND_D
     81# define DebugOpt (option_mask32 & OPT_d)
    8482#else
    85 #define EndJob(user, line)  line->cl_Pid = 0
    86 #endif
    87 
    88 static void DeleteFile(const char *userName);
    89 
    90 static CronFile *FileBase;
    91 
    92 
     83# define DebugOpt 0
     84#endif
     85
     86
     87struct globals {
     88    unsigned log_level; /* = 8; */
     89    time_t crontab_dir_mtime;
     90    const char *log_filename;
     91    const char *crontab_dir_name; /* = CRONTABS; */
     92    CronFile *cron_files;
     93#if SETENV_LEAKS
     94    char *env_var_user;
     95    char *env_var_home;
     96#endif
     97} FIX_ALIASING;
     98#define G (*(struct globals*)&bb_common_bufsiz1)
     99#define INIT_G() do { \
     100    G.log_level = 8; \
     101    G.crontab_dir_name = CRONTABS; \
     102} while (0)
     103
     104
     105/* 0 is the most verbose, default 8 */
     106#define LVL5  "\x05"
     107#define LVL7  "\x07"
     108#define LVL8  "\x08"
     109#define WARN9 "\x49"
     110#define DIE9  "\xc9"
     111/* level >= 20 is "error" */
     112#define ERR20 "\x14"
     113
     114static void crondlog(const char *ctl, ...) __attribute__ ((format (printf, 1, 2)));
    93115static void crondlog(const char *ctl, ...)
    94116{
    95117    va_list va;
    96     const char *fmt;
    97     int level = (int) (ctl[0] & 0xf);
    98     int type = level == 20 ?
    99         LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE);
    100 
     118    int level = (ctl[0] & 0x1f);
    101119
    102120    va_start(va, ctl);
    103     fmt = ctl + 1;
    104     if (level >= LogLevel) {
    105 
    106 #if ENABLE_DEBUG_CROND_OPTION
    107         if (DebugOpt) {
    108             vfprintf(stderr, fmt, va);
    109         } else
    110 #endif
    111         if (LogFile == 0) {
    112             vsyslog(type, fmt, va);
     121    if (level >= (int)G.log_level) {
     122        /* Debug mode: all to (non-redirected) stderr, */
     123        /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */
     124        if (!DebugOpt && G.log_filename) {
     125            /* Otherwise (log to file): we reopen log file at every write: */
     126            int logfd = open_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND);
     127            if (logfd >= 0)
     128                xmove_fd(logfd, STDERR_FILENO);
     129        }
     130        /* When we log to syslog, level > 8 is logged at LOG_ERR
     131         * syslog level, level <= 8 is logged at LOG_INFO. */
     132        if (level > 8) {
     133            bb_verror_msg(ctl + 1, va, /* strerr: */ NULL);
    113134        } else {
    114 #if !ENABLE_DEBUG_CROND_OPTION
    115             int logfd = open(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
    116 #else
    117             int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
    118 #endif
    119             if (logfd >= 0) {
    120                 vdprintf(logfd, fmt, va);
    121                 close(logfd);
    122             }
     135            char *msg = NULL;
     136            vasprintf(&msg, ctl + 1, va);
     137            bb_info_msg("%s: %s", applet_name, msg);
     138            free(msg);
    123139        }
    124140    }
    125141    va_end(va);
    126     if (ctl[0] & 0200) {
     142    if (ctl[0] & 0x80)
    127143        exit(20);
    128     }
    129 }
    130 
    131 int crond_main(int ac, char **av);
    132 int crond_main(int ac, char **av)
    133 {
    134     unsigned opt;
    135     char *lopt, *Lopt, *copt;
    136     USE_DEBUG_CROND_OPTION(char *dopt;)
    137 
    138     opt_complementary = "f-b:b-f:S-L:L-S" USE_DEBUG_CROND_OPTION(":d-l");
    139     opterr = 0;         /* disable getopt 'errors' message. */
    140     opt = getopt32(av, "l:L:fbSc:" USE_DEBUG_CROND_OPTION("d:"),
    141             &lopt, &Lopt, &copt USE_DEBUG_CROND_OPTION(, &dopt));
    142     if (opt & 1) /* -l */
    143         LogLevel = xatou(lopt);
    144     if (opt & 2) /* -L */
    145         if (*Lopt)
    146             LogFile = Lopt;
    147     if (opt & 32) /* -c */
    148         if (*copt)
    149             CDir = copt;
    150 #if ENABLE_DEBUG_CROND_OPTION
    151     if (opt & 64) { /* -d */
    152         DebugOpt = xatou(dopt);
    153         LogLevel = 0;
    154     }
    155 #endif
    156 
    157     /* close stdin and stdout, stderr.
    158      * close unused descriptors -  don't need.
    159      * optional detach from controlling terminal
    160      */
    161     if (!(opt & 4))
    162         bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, av);
    163 
    164     xchdir(CDir);
    165     signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */
    166 
    167     startlogger();  /* need if syslog mode selected */
    168 
    169     /*
    170      * main loop - synchronize to 1 second after the minute, minimum sleep
    171      *             of 1 second.
    172      */
    173     crondlog("\011%s " BB_VER " started, log level %d\n",
    174              applet_name, LogLevel);
    175 
    176     SynchronizeDir();
    177 
    178     {
    179         time_t t1 = time(NULL);
    180         time_t t2;
    181         long dt;
    182         int rescan = 60;
    183         short sleep_time = 60;
    184 
    185         write_pidfile("/var/run/crond.pid");
    186         for (;;) {
    187             sleep((sleep_time + 1) - (short) (time(NULL) % sleep_time));
    188 
    189             t2 = time(NULL);
    190             dt = t2 - t1;
    191 
    192             /*
    193              * The file 'cron.update' is checked to determine new cron
    194              * jobs.  The directory is rescanned once an hour to deal
    195              * with any screwups.
    196              *
    197              * check for disparity.  Disparities over an hour either way
    198              * result in resynchronization.  A reverse-indexed disparity
    199              * less then an hour causes us to effectively sleep until we
    200              * match the original time (i.e. no re-execution of jobs that
    201              * have just been run).  A forward-indexed disparity less then
    202              * an hour causes intermediate jobs to be run, but only once
    203              * in the worst case.
    204              *
    205              * when running jobs, the inequality used is greater but not
    206              * equal to t1, and less then or equal to t2.
    207              */
    208 
    209             if (--rescan == 0) {
    210                 rescan = 60;
    211                 SynchronizeDir();
    212             }
    213             CheckUpdates();
    214 #if ENABLE_DEBUG_CROND_OPTION
    215             if (DebugOpt)
    216                 crondlog("\005Wakeup dt=%d\n", dt);
    217 #endif
    218             if (dt < -60 * 60 || dt > 60 * 60) {
    219                 t1 = t2;
    220                 crondlog("\111time disparity of %d minutes detected\n", dt / 60);
    221             } else if (dt > 0) {
    222                 TestJobs(t1, t2);
    223                 RunJobs();
    224                 sleep(5);
    225                 if (CheckJobs() > 0) {
    226                     sleep_time = 10;
    227                 } else {
    228                     sleep_time = 60;
    229                 }
    230                 t1 = t2;
    231             }
    232         }
    233     }
    234     return 0; /* not reached */
    235 }
    236 
    237 static int ChangeUser(const char *user)
    238 {
    239     struct passwd *pas;
    240     const char *err_msg;
    241 
    242     /*
    243      * Obtain password entry and change privileges
    244      */
    245     pas = getpwnam(user);
    246     if (pas == 0) {
    247         crondlog("\011failed to get uid for %s", user);
    248         return -1;
    249     }
    250     setenv("USER", pas->pw_name, 1);
    251     setenv("HOME", pas->pw_dir, 1);
    252     setenv("SHELL", DEFAULT_SHELL, 1);
    253 
    254     /*
    255      * Change running state to the user in question
    256      */
    257     err_msg = change_identity_e2str(pas);
    258     if (err_msg) {
    259         crondlog("\011%s for user %s", err_msg, user);
    260         return -1;
    261     }
    262     if (chdir(pas->pw_dir) < 0) {
    263         crondlog("\011chdir failed: %s: %m", pas->pw_dir);
    264         if (chdir(TMPDIR) < 0) {
    265             crondlog("\011chdir failed: %s: %m", TMPDIR);
    266             return -1;
    267         }
    268     }
    269     return pas->pw_uid;
    270 }
    271 
    272 static void startlogger(void)
    273 {
    274     if (LogFile == 0) {
    275         openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
    276     }
    277 #if ENABLE_DEBUG_CROND_OPTION
    278     else {              /* test logfile */
    279         int logfd;
    280 
    281         logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
    282         if (logfd >= 0) {
    283             close(logfd);
    284         }
    285     }
    286 #endif
    287 }
    288 
     144}
    289145
    290146static const char DowAry[] ALIGN1 =
     
    298154;
    299155
    300 static char *ParseField(char *user, char *ary, int modvalue, int off,
     156static void ParseField(char *user, char *ary, int modvalue, int off,
    301157                const char *names, char *ptr)
    302158/* 'names' is a pointer to a set of 3-char abbreviations */
     
    306162    int n2 = -1;
    307163
    308     if (base == NULL) {
    309         return NULL;
    310     }
    311 
    312     while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
     164    // this can't happen due to config_read()
     165    /*if (base == NULL)
     166        return;*/
     167
     168    while (1) {
    313169        int skip = 0;
    314170
    315171        /* Handle numeric digit or symbol or '*' */
    316 
    317172        if (*ptr == '*') {
    318             n1 = 0;     /* everything will be filled */
     173            n1 = 0;  /* everything will be filled */
    319174            n2 = modvalue - 1;
    320175            skip = 1;
    321176            ++ptr;
    322         } else if (*ptr >= '0' && *ptr <= '9') {
     177        } else if (isdigit(*ptr)) {
     178            char *endp;
    323179            if (n1 < 0) {
    324                 n1 = strtol(ptr, &ptr, 10) + off;
     180                n1 = strtol(ptr, &endp, 10) + off;
    325181            } else {
    326                 n2 = strtol(ptr, &ptr, 10) + off;
    327             }
     182                n2 = strtol(ptr, &endp, 10) + off;
     183            }
     184            ptr = endp; /* gcc likes temp var for &endp */
    328185            skip = 1;
    329186        } else if (names) {
     
    346203
    347204        /* handle optional range '-' */
    348 
    349205        if (skip == 0) {
    350             crondlog("\111failed user %s parsing %s\n", user, base);
    351             return NULL;
     206            goto err;
    352207        }
    353208        if (*ptr == '-' && n2 < 0) {
     
    360215         * in the character array appropriately.
    361216         */
    362 
    363217        if (n2 < 0) {
    364218            n2 = n1;
    365219        }
    366220        if (*ptr == '/') {
    367             skip = strtol(ptr + 1, &ptr, 10);
    368         }
     221            char *endp;
     222            skip = strtol(ptr + 1, &endp, 10);
     223            ptr = endp; /* gcc likes temp var for &endp */
     224        }
     225
    369226        /*
    370227         * fill array, using a failsafe is the easiest way to prevent
    371228         * an endless loop
    372229         */
    373 
    374230        {
    375231            int s0 = 1;
     
    384240                    s0 = skip;
    385241                }
    386             }
    387             while (n1 != n2 && --failsafe);
    388 
    389             if (failsafe == 0) {
    390                 crondlog("\111failed user %s parsing %s\n", user, base);
    391                 return NULL;
    392             }
     242                if (--failsafe == 0) {
     243                    goto err;
     244                }
     245            } while (n1 != n2);
    393246        }
    394247        if (*ptr != ',') {
     
    400253    }
    401254
    402     if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
    403         crondlog("\111failed user %s parsing %s\n", user, base);
    404         return NULL;
    405     }
    406 
    407     while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') {
    408         ++ptr;
    409     }
    410 #if ENABLE_DEBUG_CROND_OPTION
    411     if (DebugOpt) {
     255    if (*ptr) {
     256 err:
     257        crondlog(WARN9 "user %s: parse error at %s", user, base);
     258        return;
     259    }
     260
     261    if (DebugOpt && (G.log_level <= 5)) { /* like LVL5 */
     262        /* can't use crondlog, it inserts '\n' */
    412263        int i;
    413 
    414         for (i = 0; i < modvalue; ++i) {
    415             crondlog("\005%d", ary[i]);
    416         }
    417         crondlog("\005\n");
    418     }
    419 #endif
    420 
    421     return ptr;
    422 }
    423 
    424 static void FixDayDow(CronLine * line)
    425 {
    426     int i;
     264        for (i = 0; i < modvalue; ++i)
     265            fprintf(stderr, "%d", (unsigned char)ary[i]);
     266        bb_putchar_stderr('\n');
     267    }
     268}
     269
     270static void FixDayDow(CronLine *line)
     271{
     272    unsigned i;
    427273    int weekUsed = 0;
    428274    int daysUsed = 0;
    429275
    430     for (i = 0; i < (int)(ARRAY_SIZE(line->cl_Dow)); ++i) {
     276    for (i = 0; i < ARRAY_SIZE(line->cl_Dow); ++i) {
    431277        if (line->cl_Dow[i] == 0) {
    432278            weekUsed = 1;
     
    434280        }
    435281    }
    436     for (i = 0; i < (int)(ARRAY_SIZE(line->cl_Days)); ++i) {
     282    for (i = 0; i < ARRAY_SIZE(line->cl_Days); ++i) {
    437283        if (line->cl_Days[i] == 0) {
    438284            daysUsed = 1;
     
    440286        }
    441287    }
    442     if (weekUsed && !daysUsed) {
    443         memset(line->cl_Days, 0, sizeof(line->cl_Days));
    444     }
    445     if (daysUsed && !weekUsed) {
    446         memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
    447     }
    448 }
    449 
    450 
    451 
    452 static void SynchronizeFile(const char *fileName)
    453 {
    454     int maxEntries = MAXLINES;
     288    if (weekUsed != daysUsed) {
     289        if (weekUsed)
     290            memset(line->cl_Days, 0, sizeof(line->cl_Days));
     291        else /* daysUsed */
     292            memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
     293    }
     294}
     295
     296/*
     297 * delete_cronfile() - delete user database
     298 *
     299 * Note: multiple entries for same user may exist if we were unable to
     300 * completely delete a database due to running processes.
     301 */
     302//FIXME: we will start a new job even if the old job is running
     303//if crontab was reloaded: crond thinks that "new" job is different from "old"
     304//even if they are in fact completely the same. Example
     305//Crontab was:
     306// 0-59 * * * * job1
     307// 0-59 * * * * long_running_job2
     308//User edits crontab to:
     309// 0-59 * * * * job1_updated
     310// 0-59 * * * * long_running_job2
     311//Bug: crond can now start another long_running_job2 even if old one
     312//is still running.
     313//OTOH most other versions of cron do not wait for job termination anyway,
     314//they end up with multiple copies of jobs if they don't terminate soon enough.
     315static void delete_cronfile(const char *userName)
     316{
     317    CronFile **pfile = &G.cron_files;
     318    CronFile *file;
     319
     320    while ((file = *pfile) != NULL) {
     321        if (strcmp(userName, file->cf_username) == 0) {
     322            CronLine **pline = &file->cf_lines;
     323            CronLine *line;
     324
     325            file->cf_has_running = 0;
     326            file->cf_deleted = 1;
     327
     328            while ((line = *pline) != NULL) {
     329                if (line->cl_pid > 0) {
     330                    file->cf_has_running = 1;
     331                    pline = &line->cl_next;
     332                } else {
     333                    *pline = line->cl_next;
     334                    free(line->cl_cmd);
     335                    free(line);
     336                }
     337            }
     338            if (file->cf_has_running == 0) {
     339                *pfile = file->cf_next;
     340                free(file->cf_username);
     341                free(file);
     342                continue;
     343            }
     344        }
     345        pfile = &file->cf_next;
     346    }
     347}
     348
     349static void load_crontab(const char *fileName)
     350{
     351    struct parser_t *parser;
     352    struct stat sbuf;
    455353    int maxLines;
    456     char buf[1024];
    457 
    458     if (strcmp(fileName, "root") == 0) {
    459         maxEntries = 65535;
    460     }
    461     maxLines = maxEntries * 10;
    462 
    463     if (fileName) {
    464         FILE *fi;
    465 
    466         DeleteFile(fileName);
    467 
    468         fi = fopen(fileName, "r");
    469         if (fi != NULL) {
    470             struct stat sbuf;
    471 
    472             if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
    473                 CronFile *file = xzalloc(sizeof(CronFile));
    474                 CronLine **pline;
    475 
    476                 file->cf_User = strdup(fileName);
    477                 pline = &file->cf_LineBase;
    478 
    479                 while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
    480                     CronLine line;
    481                     char *ptr;
    482 
    483                     trim(buf);
    484                     if (buf[0] == 0 || buf[0] == '#') {
    485                         continue;
    486                     }
    487                     if (--maxEntries == 0) {
    488                         break;
    489                     }
    490                     memset(&line, 0, sizeof(line));
    491 
    492 #if ENABLE_DEBUG_CROND_OPTION
    493                     if (DebugOpt) {
    494                         crondlog("\111User %s Entry %s\n", fileName, buf);
    495                     }
    496 #endif
    497 
    498                     /* parse date ranges */
    499                     ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf);
    500                     ptr = ParseField(file->cf_User, line.cl_Hrs, 24, 0, NULL, ptr);
    501                     ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr);
    502                     ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr);
    503                     ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
    504 
    505                     /* check failure */
    506                     if (ptr == NULL) {
    507                         continue;
    508                     }
    509 
    510                     /*
    511                      * fix days and dow - if one is not * and the other
    512                      * is *, the other is set to 0, and vise-versa
    513                      */
    514 
    515                     FixDayDow(&line);
    516 
    517                     *pline = xzalloc(sizeof(CronLine));
    518                     **pline = line;
    519 
    520                     /* copy command */
    521                     (*pline)->cl_Shell = strdup(ptr);
    522 
    523 #if ENABLE_DEBUG_CROND_OPTION
    524                     if (DebugOpt) {
    525                         crondlog("\111    Command %s\n", ptr);
    526                     }
    527 #endif
    528 
    529                     pline = &((*pline)->cl_Next);
    530                 }
    531                 *pline = NULL;
    532 
    533                 file->cf_Next = FileBase;
    534                 FileBase = file;
    535 
    536                 if (maxLines == 0 || maxEntries == 0) {
    537                     crondlog("\111Maximum number of lines reached for user %s\n", fileName);
    538                 }
    539             }
    540             fclose(fi);
    541         }
    542     }
    543 }
    544 
    545 static void CheckUpdates(void)
     354    char *tokens[6];
     355#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
     356    char *mailTo = NULL;
     357#endif
     358
     359    delete_cronfile(fileName);
     360
     361    if (!getpwnam(fileName)) {
     362        crondlog(LVL7 "ignoring file '%s' (no such user)", fileName);
     363        return;
     364    }
     365
     366    parser = config_open(fileName);
     367    if (!parser)
     368        return;
     369
     370    maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES;
     371
     372    if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) {
     373        CronFile *file = xzalloc(sizeof(CronFile));
     374        CronLine **pline;
     375        int n;
     376
     377        file->cf_username = xstrdup(fileName);
     378        pline = &file->cf_lines;
     379
     380        while (1) {
     381            CronLine *line;
     382
     383            if (!--maxLines)
     384                break;
     385            n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY);
     386            if (!n)
     387                break;
     388
     389            if (DebugOpt)
     390                crondlog(LVL5 "user:%s entry:%s", fileName, parser->data);
     391
     392            /* check if line is setting MAILTO= */
     393            if (0 == strncmp(tokens[0], "MAILTO=", 7)) {
     394#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
     395                free(mailTo);
     396                mailTo = (tokens[0][7]) ? xstrdup(&tokens[0][7]) : NULL;
     397#endif /* otherwise just ignore such lines */
     398                continue;
     399            }
     400            /* check if a minimum of tokens is specified */
     401            if (n < 6)
     402                continue;
     403            *pline = line = xzalloc(sizeof(*line));
     404            /* parse date ranges */
     405            ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]);
     406            ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]);
     407            ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]);
     408            ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]);
     409            ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]);
     410            /*
     411             * fix days and dow - if one is not "*" and the other
     412             * is "*", the other is set to 0, and vise-versa
     413             */
     414            FixDayDow(line);
     415#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
     416            /* copy mailto (can be NULL) */
     417            line->cl_mailto = xstrdup(mailTo);
     418#endif
     419            /* copy command */
     420            line->cl_cmd = xstrdup(tokens[5]);
     421            if (DebugOpt) {
     422                crondlog(LVL5 " command:%s", tokens[5]);
     423            }
     424            pline = &line->cl_next;
     425//bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
     426        }
     427        *pline = NULL;
     428
     429        file->cf_next = G.cron_files;
     430        G.cron_files = file;
     431
     432        if (maxLines == 0) {
     433            crondlog(WARN9 "user %s: too many lines", fileName);
     434        }
     435    }
     436    config_close(parser);
     437}
     438
     439static void process_cron_update_file(void)
    546440{
    547441    FILE *fi;
    548442    char buf[256];
    549443
    550     fi = fopen(CRONUPDATE, "r");
     444    fi = fopen_for_read(CRONUPDATE);
    551445    if (fi != NULL) {
    552         remove(CRONUPDATE);
     446        unlink(CRONUPDATE);
    553447        while (fgets(buf, sizeof(buf), fi) != NULL) {
    554             SynchronizeFile(strtok(buf, " \t\r\n"));
     448            /* use first word only */
     449            skip_non_whitespace(buf)[0] = '\0';
     450            load_crontab(buf);
    555451        }
    556452        fclose(fi);
     
    558454}
    559455
    560 static void SynchronizeDir(void)
    561 {
    562     /* Attempt to delete the database. */
    563 
    564     for (;;) {
    565         CronFile *file;
    566 
    567         for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next);
    568         if (file == NULL) {
    569             break;
    570         }
    571         DeleteFile(file->cf_User);
    572     }
    573 
    574     /*
    575      * Remove cron update file
    576      *
    577      * Re-chdir, in case directory was renamed & deleted, or otherwise
    578      * screwed up.
    579      *
    580      * scan directory and add associated users
    581      */
    582 
    583     remove(CRONUPDATE);
    584     if (chdir(CDir) < 0) {
    585         crondlog("\311cannot find %s\n", CDir);
    586     }
     456static void rescan_crontab_dir(void)
     457{
     458    CronFile *file;
     459
     460    /* Delete all files until we only have ones with running jobs (or none) */
     461 again:
     462    for (file = G.cron_files; file; file = file->cf_next) {
     463        if (!file->cf_deleted) {
     464            delete_cronfile(file->cf_username);
     465            goto again;
     466        }
     467    }
     468
     469    /* Remove cron update file */
     470    unlink(CRONUPDATE);
     471    /* Re-chdir, in case directory was renamed & deleted */
     472    if (chdir(G.crontab_dir_name) < 0) {
     473        crondlog(DIE9 "chdir(%s)", G.crontab_dir_name);
     474    }
     475
     476    /* Scan directory and add associated users */
    587477    {
    588478        DIR *dir = opendir(".");
    589479        struct dirent *den;
    590480
    591         if (dir) {
    592             while ((den = readdir(dir))) {
    593                 if (strchr(den->d_name, '.') != NULL) {
    594                     continue;
    595                 }
    596                 if (getpwnam(den->d_name)) {
    597                     SynchronizeFile(den->d_name);
    598                 } else {
    599                     crondlog("\007ignoring %s\n", den->d_name);
    600                 }
    601             }
    602             closedir(dir);
    603         } else {
    604             crondlog("\311cannot open current dir!\n");
    605         }
    606     }
    607 }
    608 
    609 
    610 /*
    611  *  DeleteFile() - delete user database
    612  *
    613  *  Note: multiple entries for same user may exist if we were unable to
    614  *  completely delete a database due to running processes.
    615  */
    616 
    617 static void DeleteFile(const char *userName)
    618 {
    619     CronFile **pfile = &FileBase;
    620     CronFile *file;
    621 
    622     while ((file = *pfile) != NULL) {
    623         if (strcmp(userName, file->cf_User) == 0) {
    624             CronLine **pline = &file->cf_LineBase;
    625             CronLine *line;
    626 
    627             file->cf_Running = 0;
    628             file->cf_Deleted = 1;
    629 
    630             while ((line = *pline) != NULL) {
    631                 if (line->cl_Pid > 0) {
    632                     file->cf_Running = 1;
    633                     pline = &line->cl_Next;
    634                 } else {
    635                     *pline = line->cl_Next;
    636                     free(line->cl_Shell);
    637                     free(line);
    638                 }
    639             }
    640             if (file->cf_Running == 0) {
    641                 *pfile = file->cf_Next;
    642                 free(file->cf_User);
    643                 free(file);
    644             } else {
    645                 pfile = &file->cf_Next;
    646             }
    647         } else {
    648             pfile = &file->cf_Next;
    649         }
    650     }
    651 }
    652 
    653 /*
    654  * TestJobs()
    655  *
    656  * determine which jobs need to be run.  Under normal conditions, the
    657  * period is about a minute (one scan).  Worst case it will be one
    658  * hour (60 scans).
    659  */
    660 
    661 static int TestJobs(time_t t1, time_t t2)
    662 {
    663     int nJobs = 0;
    664     time_t t;
    665 
    666     /* Find jobs > t1 and <= t2 */
    667 
    668     for (t = t1 - t1 % 60; t <= t2; t += 60) {
    669         if (t > t1) {
    670             struct tm *tp = localtime(&t);
    671             CronFile *file;
    672             CronLine *line;
    673 
    674             for (file = FileBase; file; file = file->cf_Next) {
    675 #if ENABLE_DEBUG_CROND_OPTION
    676                 if (DebugOpt)
    677                     crondlog("\005FILE %s:\n", file->cf_User);
    678 #endif
    679                 if (file->cf_Deleted)
    680                     continue;
    681                 for (line = file->cf_LineBase; line; line = line->cl_Next) {
    682 #if ENABLE_DEBUG_CROND_OPTION
    683                     if (DebugOpt)
    684                         crondlog("\005    LINE %s\n", line->cl_Shell);
    685 #endif
    686                     if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour] &&
    687                         (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])
    688                         && line->cl_Mons[tp->tm_mon]) {
    689 #if ENABLE_DEBUG_CROND_OPTION
    690                         if (DebugOpt) {
    691                             crondlog("\005    JobToDo: %d %s\n",
    692                                 line->cl_Pid, line->cl_Shell);
    693                         }
    694 #endif
    695                         if (line->cl_Pid > 0) {
    696                             crondlog("\010    process already running: %s %s\n",
    697                                 file->cf_User, line->cl_Shell);
    698                         } else if (line->cl_Pid == 0) {
    699                             line->cl_Pid = -1;
    700                             file->cf_Ready = 1;
    701                             ++nJobs;
    702                         }
    703                     }
    704                 }
    705             }
    706         }
    707     }
    708     return nJobs;
    709 }
    710 
    711 static void RunJobs(void)
    712 {
    713     CronFile *file;
    714     CronLine *line;
    715 
    716     for (file = FileBase; file; file = file->cf_Next) {
    717         if (file->cf_Ready) {
    718             file->cf_Ready = 0;
    719 
    720             for (line = file->cf_LineBase; line; line = line->cl_Next) {
    721                 if (line->cl_Pid < 0) {
    722 
    723                     RunJob(file->cf_User, line);
    724 
    725                     crondlog("\010USER %s pid %3d cmd %s\n",
    726                         file->cf_User, line->cl_Pid, line->cl_Shell);
    727                     if (line->cl_Pid < 0) {
    728                         file->cf_Ready = 1;
    729                     }
    730                     else if (line->cl_Pid > 0) {
    731                         file->cf_Running = 1;
    732                     }
    733                 }
    734             }
    735         }
    736     }
    737 }
    738 
    739 /*
    740  * CheckJobs() - check for job completion
    741  *
    742  * Check for job completion, return number of jobs still running after
    743  * all done.
    744  */
    745 
    746 static int CheckJobs(void)
    747 {
    748     CronFile *file;
    749     CronLine *line;
    750     int nStillRunning = 0;
    751 
    752     for (file = FileBase; file; file = file->cf_Next) {
    753         if (file->cf_Running) {
    754             file->cf_Running = 0;
    755 
    756             for (line = file->cf_LineBase; line; line = line->cl_Next) {
    757                 if (line->cl_Pid > 0) {
    758                     int status;
    759                     int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
    760 
    761                     if (r < 0 || r == line->cl_Pid) {
    762                         EndJob(file->cf_User, line);
    763                         if (line->cl_Pid) {
    764                             file->cf_Running = 1;
    765                         }
    766                     } else if (r == 0) {
    767                         file->cf_Running = 1;
    768                     }
    769                 }
    770             }
    771         }
    772         nStillRunning += file->cf_Running;
    773     }
    774     return nStillRunning;
    775 }
    776 
    777 
     481        if (!dir)
     482            crondlog(DIE9 "chdir(%s)", "."); /* exits */
     483        while ((den = readdir(dir)) != NULL) {
     484            if (strchr(den->d_name, '.') != NULL) {
     485                continue;
     486            }
     487            load_crontab(den->d_name);
     488        }
     489        closedir(dir);
     490    }
     491}
     492
     493#if SETENV_LEAKS
     494/* We set environment *before* vfork (because we want to use vfork),
     495 * so we cannot use setenv() - repeated calls to setenv() may leak memory!
     496 * Using putenv(), and freeing memory after unsetenv() won't leak */
     497static void safe_setenv(char **pvar_val, const char *var, const char *val)
     498{
     499    char *var_val = *pvar_val;
     500
     501    if (var_val) {
     502        bb_unsetenv_and_free(var_val);
     503    }
     504    *pvar_val = xasprintf("%s=%s", var, val);
     505    putenv(*pvar_val);
     506}
     507#endif
     508
     509static void set_env_vars(struct passwd *pas)
     510{
     511#if SETENV_LEAKS
     512    safe_setenv(&G.env_var_user, "USER", pas->pw_name);
     513    safe_setenv(&G.env_var_home, "HOME", pas->pw_dir);
     514    /* if we want to set user's shell instead: */
     515    /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/
     516#else
     517    xsetenv("USER", pas->pw_name);
     518    xsetenv("HOME", pas->pw_dir);
     519#endif
     520    /* currently, we use constant one: */
     521    /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */
     522}
     523
     524static void change_user(struct passwd *pas)
     525{
     526    /* careful: we're after vfork! */
     527    change_identity(pas); /* - initgroups, setgid, setuid */
     528    if (chdir(pas->pw_dir) < 0) {
     529        crondlog(WARN9 "chdir(%s)", pas->pw_dir);
     530        if (chdir(TMPDIR) < 0) {
     531            crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */
     532        }
     533    }
     534}
     535
     536// TODO: sendmail should be _run-time_ option, not compile-time!
    778537#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
    779 static void
    780 ForkJob(const char *user, CronLine * line, int mailFd,
    781         const char *prog, const char *cmd, const char *arg, const char *mailf)
    782 {
    783     /* Fork as the user in question and run program */
    784     pid_t pid = fork();
    785 
    786     line->cl_Pid = pid;
     538
     539static pid_t
     540fork_job(const char *user, int mailFd,
     541        const char *prog,
     542        const char *shell_cmd /* if NULL, we run sendmail */
     543) {
     544    struct passwd *pas;
     545    pid_t pid;
     546
     547    /* prepare things before vfork */
     548    pas = getpwnam(user);
     549    if (!pas) {
     550        crondlog(WARN9 "can't get uid for %s", user);
     551        goto err;
     552    }
     553    set_env_vars(pas);
     554
     555    pid = vfork();
    787556    if (pid == 0) {
    788557        /* CHILD */
    789 
    790         /* Change running state to the user in question */
    791 
    792         if (ChangeUser(user) < 0) {
    793             exit(0);
    794         }
    795 #if ENABLE_DEBUG_CROND_OPTION
     558        /* initgroups, setgid, setuid, and chdir to home or TMPDIR */
     559        change_user(pas);
    796560        if (DebugOpt) {
    797             crondlog("\005Child Running %s\n", prog);
    798         }
    799 #endif
    800 
     561            crondlog(LVL5 "child running %s", prog);
     562        }
    801563        if (mailFd >= 0) {
    802             dup2(mailFd, mailf != NULL);
    803             dup2((mailf ? mailFd : 1), 2);
    804             close(mailFd);
    805         }
    806         execl(prog, prog, cmd, arg, NULL);
    807         crondlog("\024cannot exec, user %s cmd %s %s %s\n", user, prog, cmd, arg);
    808         if (mailf) {
    809             fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
    810         }
    811         exit(0);
    812     } else if (pid < 0) {
     564            xmove_fd(mailFd, shell_cmd ? 1 : 0);
     565            dup2(1, 2);
     566        }
     567        /* crond 3.0pl1-100 puts tasks in separate process groups */
     568        bb_setpgrp();
     569        execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL);
     570        crondlog(ERR20 "can't execute '%s' for user %s", prog, user);
     571        if (shell_cmd) {
     572            fdprintf(1, "Exec failed: %s -c %s\n", prog, shell_cmd);
     573        }
     574        _exit(EXIT_SUCCESS);
     575    }
     576
     577    if (pid < 0) {
    813578        /* FORK FAILED */
    814         crondlog("\024cannot fork, user %s\n", user);
    815         line->cl_Pid = 0;
    816         if (mailf) {
    817             remove(mailf);
    818         }
    819     } else if (mailf) {
    820         /* PARENT, FORK SUCCESS
    821          * rename mail-file based on pid of process
    822          */
    823         char mailFile2[128];
    824 
    825         snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", user, pid);
    826         rename(mailf, mailFile2);
    827     }
     579        crondlog(ERR20 "can't vfork");
     580 err:
     581        pid = 0;
     582    } /* else: PARENT, FORK SUCCESS */
     583
    828584    /*
    829585     * Close the mail file descriptor.. we can't just leave it open in
    830586     * a structure, closing it later, because we might run out of descriptors
    831587     */
    832 
    833588    if (mailFd >= 0) {
    834589        close(mailFd);
    835590    }
    836 }
    837 
    838 static void RunJob(const char *user, CronLine * line)
     591    return pid;
     592}
     593
     594static void start_one_job(const char *user, CronLine *line)
    839595{
    840596    char mailFile[128];
    841     int mailFd;
    842 
    843     line->cl_Pid = 0;
    844     line->cl_MailFlag = 0;
    845 
    846     /* open mail file - owner root so nobody can screw with it. */
    847 
    848     snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, getpid());
    849     mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
    850 
     597    int mailFd = -1;
     598
     599    line->cl_pid = 0;
     600    line->cl_empty_mail_size = 0;
     601
     602    if (line->cl_mailto) {
     603        /* Open mail file (owner is root so nobody can screw with it) */
     604        snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid());
     605        mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
     606
     607        if (mailFd >= 0) {
     608            fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_mailto,
     609                line->cl_cmd);
     610            line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR);
     611        } else {
     612            crondlog(ERR20 "can't create mail file %s for user %s, "
     613                    "discarding output", mailFile, user);
     614        }
     615    }
     616
     617    line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd);
    851618    if (mailFd >= 0) {
    852         line->cl_MailFlag = 1;
    853         fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
    854             line->cl_Shell);
    855         line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR);
    856     } else {
    857         crondlog("\024cannot create mail file user %s file %s, output to /dev/null\n", user, mailFile);
    858     }
    859 
    860     ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
     619        if (line->cl_pid <= 0) {
     620            unlink(mailFile);
     621        } else {
     622            /* rename mail-file based on pid of process */
     623            char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)line->cl_pid);
     624            rename(mailFile, mailFile2); // TODO: xrename?
     625            free(mailFile2);
     626        }
     627    }
    861628}
    862629
    863630/*
    864  * EndJob - called when job terminates and when mail terminates
     631 * process_finished_job - called when job terminates and when mail terminates
    865632 */
    866 
    867 static void EndJob(const char *user, CronLine * line)
    868 {
     633static void process_finished_job(const char *user, CronLine *line)
     634{
     635    pid_t pid;
    869636    int mailFd;
    870637    char mailFile[128];
    871638    struct stat sbuf;
    872639
    873     /* No job */
    874 
    875     if (line->cl_Pid <= 0) {
    876         line->cl_Pid = 0;
     640    pid = line->cl_pid;
     641    line->cl_pid = 0;
     642    if (pid <= 0) {
     643        /* No job */
    877644        return;
    878645    }
     646    if (line->cl_empty_mail_size <= 0) {
     647        /* End of job and no mail file, or end of sendmail job */
     648        return;
     649    }
    879650
    880651    /*
    881      * End of job and no mail file
    882      * End of sendmail job
     652     * End of primary job - check for mail file.
     653     * If size has changed and the file is still valid, we send it.
    883654     */
    884 
    885     snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", user, line->cl_Pid);
    886     line->cl_Pid = 0;
    887 
    888     if (line->cl_MailFlag != 1) {
    889         return;
    890     }
    891     line->cl_MailFlag = 0;
    892 
    893     /*
    894      * End of primary job - check for mail file.  If size has increased and
    895      * the file is still valid, we sendmail it.
    896      */
    897 
     655    snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, (int)pid);
    898656    mailFd = open(mailFile, O_RDONLY);
    899     remove(mailFile);
     657    unlink(mailFile);
    900658    if (mailFd < 0) {
    901659        return;
    902660    }
    903661
    904     if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid
    905      || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos
     662    if (fstat(mailFd, &sbuf) < 0
     663     || sbuf.st_uid != DAEMON_UID
     664     || sbuf.st_nlink != 0
     665     || sbuf.st_size == line->cl_empty_mail_size
    906666     || !S_ISREG(sbuf.st_mode)
    907667    ) {
     
    909669        return;
    910670    }
    911     ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
    912 }
    913 #else
    914 /* crond without sendmail */
    915 
    916 static void RunJob(const char *user, CronLine * line)
    917 {
     671    line->cl_empty_mail_size = 0;
     672    /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */
     673        line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL);
     674}
     675
     676#else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */
     677
     678static void start_one_job(const char *user, CronLine *line)
     679{
     680    struct passwd *pas;
     681    pid_t pid;
     682
     683    pas = getpwnam(user);
     684    if (!pas) {
     685        crondlog(WARN9 "can't get uid for %s", user);
     686        goto err;
     687    }
     688
     689    /* Prepare things before vfork */
     690    set_env_vars(pas);
     691
    918692    /* Fork as the user in question and run program */
    919     pid_t pid = fork();
    920 
     693    pid = vfork();
    921694    if (pid == 0) {
    922695        /* CHILD */
    923 
    924         /* Change running state to the user in question */
    925 
    926         if (ChangeUser(user) < 0) {
    927             exit(0);
    928         }
    929 #if ENABLE_DEBUG_CROND_OPTION
     696        /* initgroups, setgid, setuid, and chdir to home or TMPDIR */
     697        change_user(pas);
    930698        if (DebugOpt) {
    931             crondlog("\005Child Running %s\n", DEFAULT_SHELL);
    932         }
    933 #endif
    934 
    935         execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);
    936         crondlog("\024cannot exec, user %s cmd %s -c %s\n", user,
    937                  DEFAULT_SHELL, line->cl_Shell);
    938         exit(0);
    939     } else if (pid < 0) {
     699            crondlog(LVL5 "child running %s", DEFAULT_SHELL);
     700        }
     701        /* crond 3.0pl1-100 puts tasks in separate process groups */
     702        bb_setpgrp();
     703        execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_cmd, (char *) NULL);
     704        crondlog(ERR20 "can't execute '%s' for user %s", DEFAULT_SHELL, user);
     705        _exit(EXIT_SUCCESS);
     706    }
     707    if (pid < 0) {
    940708        /* FORK FAILED */
    941         crondlog("\024cannot, user %s\n", user);
     709        crondlog(ERR20 "can't vfork");
     710 err:
    942711        pid = 0;
    943712    }
    944     line->cl_Pid = pid;
    945 }
    946 #endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */
     713    line->cl_pid = pid;
     714}
     715
     716#define process_finished_job(user, line)  ((line)->cl_pid = 0)
     717
     718#endif /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */
     719
     720/*
     721 * Determine which jobs need to be run.  Under normal conditions, the
     722 * period is about a minute (one scan).  Worst case it will be one
     723 * hour (60 scans).
     724 */
     725static void flag_starting_jobs(time_t t1, time_t t2)
     726{
     727    time_t t;
     728
     729    /* Find jobs > t1 and <= t2 */
     730
     731    for (t = t1 - t1 % 60; t <= t2; t += 60) {
     732        struct tm *ptm;
     733        CronFile *file;
     734        CronLine *line;
     735
     736        if (t <= t1)
     737            continue;
     738
     739        ptm = localtime(&t);
     740        for (file = G.cron_files; file; file = file->cf_next) {
     741            if (DebugOpt)
     742                crondlog(LVL5 "file %s:", file->cf_username);
     743            if (file->cf_deleted)
     744                continue;
     745            for (line = file->cf_lines; line; line = line->cl_next) {
     746                if (DebugOpt)
     747                    crondlog(LVL5 " line %s", line->cl_cmd);
     748                if (line->cl_Mins[ptm->tm_min]
     749                 && line->cl_Hrs[ptm->tm_hour]
     750                 && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday])
     751                 && line->cl_Mons[ptm->tm_mon]
     752                ) {
     753                    if (DebugOpt) {
     754                        crondlog(LVL5 " job: %d %s",
     755                            (int)line->cl_pid, line->cl_cmd);
     756                    }
     757                    if (line->cl_pid > 0) {
     758                        crondlog(LVL8 "user %s: process already running: %s",
     759                            file->cf_username, line->cl_cmd);
     760                    } else if (line->cl_pid == 0) {
     761                        line->cl_pid = -1;
     762                        file->cf_wants_starting = 1;
     763                    }
     764                }
     765            }
     766        }
     767    }
     768}
     769
     770static void start_jobs(void)
     771{
     772    CronFile *file;
     773    CronLine *line;
     774
     775    for (file = G.cron_files; file; file = file->cf_next) {
     776        if (!file->cf_wants_starting)
     777            continue;
     778
     779        file->cf_wants_starting = 0;
     780        for (line = file->cf_lines; line; line = line->cl_next) {
     781            pid_t pid;
     782            if (line->cl_pid >= 0)
     783                continue;
     784
     785            start_one_job(file->cf_username, line);
     786            pid = line->cl_pid;
     787            crondlog(LVL8 "USER %s pid %3d cmd %s",
     788                file->cf_username, (int)pid, line->cl_cmd);
     789            if (pid < 0) {
     790                file->cf_wants_starting = 1;
     791            }
     792            if (pid > 0) {
     793                file->cf_has_running = 1;
     794            }
     795        }
     796    }
     797}
     798
     799/*
     800 * Check for job completion, return number of jobs still running after
     801 * all done.
     802 */
     803static int check_completions(void)
     804{
     805    CronFile *file;
     806    CronLine *line;
     807    int num_still_running = 0;
     808
     809    for (file = G.cron_files; file; file = file->cf_next) {
     810        if (!file->cf_has_running)
     811            continue;
     812
     813        file->cf_has_running = 0;
     814        for (line = file->cf_lines; line; line = line->cl_next) {
     815            int r;
     816
     817            if (line->cl_pid <= 0)
     818                continue;
     819
     820            r = waitpid(line->cl_pid, NULL, WNOHANG);
     821            if (r < 0 || r == line->cl_pid) {
     822                process_finished_job(file->cf_username, line);
     823                if (line->cl_pid == 0) {
     824                    /* sendmail was not started for it */
     825                    continue;
     826                }
     827                /* else: sendmail was started, job is still running, fall thru */
     828            }
     829            /* else: r == 0: "process is still running" */
     830            file->cf_has_running = 1;
     831        }
     832//FIXME: if !file->cf_has_running && file->deleted: delete it!
     833//otherwise deleted entries will stay forever, right?
     834        num_still_running += file->cf_has_running;
     835    }
     836    return num_still_running;
     837}
     838
     839int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     840int crond_main(int argc UNUSED_PARAM, char **argv)
     841{
     842    time_t t2;
     843    int rescan;
     844    int sleep_time;
     845    unsigned opts;
     846
     847    INIT_G();
     848
     849    /* "-b after -f is ignored", and so on for every pair a-b */
     850    opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
     851            ":l+:d+"; /* -l and -d have numeric param */
     852    opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"),
     853            &G.log_level, &G.log_filename, &G.crontab_dir_name
     854            IF_FEATURE_CROND_D(,&G.log_level));
     855    /* both -d N and -l N set the same variable: G.log_level */
     856
     857    if (!(opts & OPT_f)) {
     858        /* close stdin, stdout, stderr.
     859         * close unused descriptors - don't need them. */
     860        bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
     861    }
     862
     863    if (!(opts & OPT_d) && G.log_filename == NULL) {
     864        /* logging to syslog */
     865        openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
     866        logmode = LOGMODE_SYSLOG;
     867    }
     868
     869    xchdir(G.crontab_dir_name);
     870    //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */
     871    xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */
     872    crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.log_level);
     873    rescan_crontab_dir();
     874    write_pidfile("/var/run/crond.pid");
     875
     876    /* Main loop */
     877    t2 = time(NULL);
     878    rescan = 60;
     879    sleep_time = 60;
     880    for (;;) {
     881        struct stat sbuf;
     882        time_t t1;
     883        long dt;
     884
     885        t1 = t2;
     886
     887        /* Synchronize to 1 minute, minimum 1 second */
     888        sleep(sleep_time - (time(NULL) % sleep_time) + 1);
     889
     890        t2 = time(NULL);
     891        dt = (long)t2 - (long)t1;
     892
     893        /*
     894         * The file 'cron.update' is checked to determine new cron
     895         * jobs.  The directory is rescanned once an hour to deal
     896         * with any screwups.
     897         *
     898         * Check for time jump.  Disparities over an hour either way
     899         * result in resynchronization.  A negative disparity
     900         * less than an hour causes us to effectively sleep until we
     901         * match the original time (i.e. no re-execution of jobs that
     902         * have just been run).  A positive disparity less than
     903         * an hour causes intermediate jobs to be run, but only once
     904         * in the worst case.
     905         *
     906         * When running jobs, the inequality used is greater but not
     907         * equal to t1, and less then or equal to t2.
     908         */
     909        if (stat(G.crontab_dir_name, &sbuf) != 0)
     910            sbuf.st_mtime = 0; /* force update (once) if dir was deleted */
     911        if (G.crontab_dir_mtime != sbuf.st_mtime) {
     912            G.crontab_dir_mtime = sbuf.st_mtime;
     913            rescan = 1;
     914        }
     915        if (--rescan == 0) {
     916            rescan = 60;
     917            rescan_crontab_dir();
     918        }
     919        process_cron_update_file();
     920        if (DebugOpt)
     921            crondlog(LVL5 "wakeup dt=%ld", dt);
     922        if (dt < -60 * 60 || dt > 60 * 60) {
     923            crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60);
     924            /* and we do not run any jobs in this case */
     925        } else if (dt > 0) {
     926            /* Usual case: time advances forward, as expected */
     927            flag_starting_jobs(t1, t2);
     928            start_jobs();
     929            if (check_completions() > 0) {
     930                /* some jobs are still running */
     931                sleep_time = 10;
     932            } else {
     933                sleep_time = 60;
     934            }
     935        }
     936        /* else: time jumped back, do not run any jobs */
     937    } /* for (;;) */
     938
     939    return 0; /* not reached */
     940}
  • branches/2.2.9/mindi-busybox/miscutils/crontab.c

    r1765 r2725  
    88 * Vladimir Oleynik <dzo@simtreas.ru> (C) 2002
    99 *
    10  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1111 */
    1212
    1313#include "libbb.h"
    1414
    15 #ifndef CRONTABS
    16 #define CRONTABS        "/var/spool/cron/crontabs"
    17 #endif
    18 #ifndef TMPDIR
    19 #define TMPDIR          "/var/spool/cron"
    20 #endif
     15#define CRONTABS        CONFIG_FEATURE_CROND_DIR "/crontabs"
    2116#ifndef CRONUPDATE
    2217#define CRONUPDATE      "cron.update"
    2318#endif
    24 #ifndef PATH_VI
    25 #define PATH_VI         "/bin/vi"   /* location of vi */
    26 #endif
    27 
    28 static const char *CDir = CRONTABS;
    29 
    30 static void EditFile(const char *user, const char *file);
    31 static int GetReplaceStream(const char *user, const char *file);
    32 static int ChangeUser(const char *user, short dochdir);
    33 
    34 int crontab_main(int ac, char **av);
    35 int crontab_main(int ac, char **av)
     19
     20static void edit_file(const struct passwd *pas, const char *file)
    3621{
    37     enum { NONE, EDIT, LIST, REPLACE, DELETE } option = NONE;
     22    const char *ptr;
     23    int pid = xvfork();
     24
     25    if (pid) { /* parent */
     26        wait4pid(pid);
     27        return;
     28    }
     29
     30    /* CHILD - change user and run editor */
     31    /* initgroups, setgid, setuid */
     32    change_identity(pas);
     33    setup_environment(DEFAULT_SHELL,
     34            SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP,
     35            pas);
     36    ptr = getenv("VISUAL");
     37    if (!ptr) {
     38        ptr = getenv("EDITOR");
     39        if (!ptr)
     40            ptr = "vi";
     41    }
     42
     43    BB_EXECLP(ptr, ptr, file, NULL);
     44    bb_perror_msg_and_die("exec %s", ptr);
     45}
     46
     47static int open_as_user(const struct passwd *pas, const char *file)
     48{
     49    pid_t pid;
     50    char c;
     51
     52    pid = xvfork();
     53    if (pid) { /* PARENT */
     54        if (wait4pid(pid) == 0) {
     55            /* exitcode 0: child says it can read */
     56            return open(file, O_RDONLY);
     57        }
     58        return -1;
     59    }
     60
     61    /* CHILD */
     62    /* initgroups, setgid, setuid */
     63    change_identity(pas);
     64    /* We just try to read one byte. If it works, file is readable
     65     * under this user. We signal that by exiting with 0. */
     66    _exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0);
     67}
     68
     69int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     70int crontab_main(int argc UNUSED_PARAM, char **argv)
     71{
    3872    const struct passwd *pas;
    39     const char *repFile = NULL;
    40     int repFd = 0;
    41     int i;
    42     char caller[256];           /* user that ran program */
    43     char buf[1024];
    44     int UserId;
    45 
    46     UserId = getuid();
    47     pas = getpwuid(UserId);
    48     if (pas == NULL)
    49         bb_perror_msg_and_die("getpwuid");
    50 
    51     safe_strncpy(caller, pas->pw_name, sizeof(caller));
    52 
    53     i = 1;
    54     if (ac > 1) {
    55         if (LONE_DASH(av[1])) {
    56             option = REPLACE;
    57             ++i;
    58         } else if (av[1][0] != '-') {
    59             option = REPLACE;
    60             ++i;
    61             repFile = av[1];
    62         }
    63     }
    64 
    65     for (; i < ac; ++i) {
    66         char *ptr = av[i];
    67 
    68         if (*ptr != '-')
     73    const char *crontab_dir = CRONTABS;
     74    char *tmp_fname;
     75    char *new_fname;
     76    char *user_name;  /* -u USER */
     77    int fd;
     78    int src_fd;
     79    int opt_ler;
     80
     81    /* file [opts]     Replace crontab from file
     82     * - [opts]        Replace crontab from stdin
     83     * -u user         User
     84     * -c dir          Crontab directory
     85     * -l              List crontab for user
     86     * -e              Edit crontab for user
     87     * -r              Delete crontab for user
     88     * bbox also supports -d == -r, but most other crontab
     89     * implementations do not. Deprecated.
     90     */
     91    enum {
     92        OPT_u = (1 << 0),
     93        OPT_c = (1 << 1),
     94        OPT_l = (1 << 2),
     95        OPT_e = (1 << 3),
     96        OPT_r = (1 << 4),
     97        OPT_ler = OPT_l + OPT_e + OPT_r,
     98    };
     99
     100    opt_complementary = "?1:dr"; /* max one argument; -d implies -r */
     101    opt_ler = getopt32(argv, "u:c:lerd", &user_name, &crontab_dir);
     102    argv += optind;
     103
     104    if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */
     105        /* Run by non-root */
     106        if (opt_ler & (OPT_u|OPT_c))
     107            bb_error_msg_and_die(bb_msg_you_must_be_root);
     108    }
     109
     110    if (opt_ler & OPT_u) {
     111        pas = xgetpwnam(user_name);
     112    } else {
     113        pas = xgetpwuid(getuid());
     114    }
     115
     116#define user_name DONT_USE_ME_BEYOND_THIS_POINT
     117
     118    /* From now on, keep only -l, -e, -r bits */
     119    opt_ler &= OPT_ler;
     120    if ((opt_ler - 1) & opt_ler) /* more than one bit set? */
     121        bb_show_usage();
     122
     123    /* Read replacement file under user's UID/GID/group vector */
     124    src_fd = STDIN_FILENO;
     125    if (!opt_ler) { /* Replace? */
     126        if (!argv[0])
     127            bb_show_usage();
     128        if (NOT_LONE_DASH(argv[0])) {
     129            src_fd = open_as_user(pas, argv[0]);
     130            if (src_fd < 0)
     131                bb_error_msg_and_die("user %s cannot read %s",
     132                        pas->pw_name, argv[0]);
     133        }
     134    }
     135
     136    /* cd to our crontab directory */
     137    xchdir(crontab_dir);
     138
     139    tmp_fname = NULL;
     140
     141    /* Handle requested operation */
     142    switch (opt_ler) {
     143
     144    default: /* case OPT_r: Delete */
     145        unlink(pas->pw_name);
     146        break;
     147
     148    case OPT_l: /* List */
     149        {
     150            char *args[2] = { pas->pw_name, NULL };
     151            return bb_cat(args);
     152            /* list exits,
     153             * the rest go play with cron update file */
     154        }
     155
     156    case OPT_e: /* Edit */
     157        tmp_fname = xasprintf("%s.%u", crontab_dir, (unsigned)getpid());
     158        /* No O_EXCL: we don't want to be stuck if earlier crontabs
     159         * were killed, leaving stale temp file behind */
     160        src_fd = xopen3(tmp_fname, O_RDWR|O_CREAT|O_TRUNC, 0600);
     161        fchown(src_fd, pas->pw_uid, pas->pw_gid);
     162        fd = open(pas->pw_name, O_RDONLY);
     163        if (fd >= 0) {
     164            bb_copyfd_eof(fd, src_fd);
     165            close(fd);
     166            xlseek(src_fd, 0, SEEK_SET);
     167        }
     168        close_on_exec_on(src_fd); /* don't want editor to see this fd */
     169        edit_file(pas, tmp_fname);
     170        /* fall through */
     171
     172    case 0: /* Replace (no -l, -e, or -r were given) */
     173        new_fname = xasprintf("%s.new", pas->pw_name);
     174        fd = open(new_fname, O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0600);
     175        if (fd >= 0) {
     176            bb_copyfd_eof(src_fd, fd);
     177            close(fd);
     178            xrename(new_fname, pas->pw_name);
     179        } else {
     180            bb_error_msg("can't create %s/%s",
     181                    crontab_dir, new_fname);
     182        }
     183        if (tmp_fname)
     184            unlink(tmp_fname);
     185        /*free(tmp_fname);*/
     186        /*free(new_fname);*/
     187
     188    } /* switch */
     189
     190    /* Bump notification file.  Handle window where crond picks file up
     191     * before we can write our entry out.
     192     */
     193    while ((fd = open(CRONUPDATE, O_WRONLY|O_CREAT|O_APPEND, 0600)) >= 0) {
     194        struct stat st;
     195
     196        fdprintf(fd, "%s\n", pas->pw_name);
     197        if (fstat(fd, &st) != 0 || st.st_nlink != 0) {
     198            /*close(fd);*/
    69199            break;
    70         ptr += 2;
    71 
    72         switch (ptr[-1]) {
    73         case 'l':
    74             if (ptr[-1] == 'l')
    75                 option = LIST;
    76             /* fall through */
    77         case 'e':
    78             if (ptr[-1] == 'e')
    79                 option = EDIT;
    80             /* fall through */
    81         case 'd':
    82             if (ptr[-1] == 'd')
    83                 option = DELETE;
    84             /* fall through */
    85         case 'u':
    86             if (i + 1 < ac && av[i+1][0] != '-') {
    87                 ++i;
    88                 if (getuid() == geteuid()) {
    89                     pas = getpwnam(av[i]);
    90                     if (pas) {
    91                         UserId = pas->pw_uid;
    92                     } else {
    93                         bb_error_msg_and_die("user %s unknown", av[i]);
    94                     }
    95                 } else {
    96                     bb_error_msg_and_die("only the superuser may specify a user");
    97                 }
    98             }
    99             break;
    100         case 'c':
    101             if (getuid() == geteuid()) {
    102                 CDir = (*ptr) ? ptr : av[++i];
    103             } else {
    104                 bb_error_msg_and_die("-c option: superuser only");
    105             }
    106             break;
    107         default:
    108             i = ac;
    109             break;
    110         }
    111     }
    112     if (i != ac || option == NONE)
    113         bb_show_usage();
    114 
    115     /*
    116      * Get password entry
    117      */
    118 
    119     pas = getpwuid(UserId);
    120     if (pas == NULL)
    121         bb_perror_msg_and_die("getpwuid");
    122 
    123     /*
    124      * If there is a replacement file, obtain a secure descriptor to it.
    125      */
    126 
    127     if (repFile) {
    128         repFd = GetReplaceStream(caller, repFile);
    129         if (repFd < 0)
    130             bb_error_msg_and_die("cannot read replacement file");
    131     }
    132 
    133     /*
    134      * Change directory to our crontab directory
    135      */
    136 
    137     xchdir(CDir);
    138 
    139     /*
    140      * Handle options as appropriate
    141      */
    142 
    143     switch (option) {
    144     case LIST:
    145         {
    146             FILE *fi;
    147 
    148             fi = fopen(pas->pw_name, "r");
    149             if (fi) {
    150                 while (fgets(buf, sizeof(buf), fi) != NULL)
    151                     fputs(buf, stdout);
    152                 fclose(fi);
    153             } else {
    154                 bb_error_msg("no crontab for %s", pas->pw_name);
    155             }
    156         }
    157         break;
    158     case EDIT:
    159         {
    160 /* FIXME: messy code here! we have file copying helpers for this! */
    161             FILE *fi;
    162             int fd;
    163             int n;
    164             char tmp[128];
    165 
    166             snprintf(tmp, sizeof(tmp), TMPDIR "/crontab.%d", getpid());
    167             fd = xopen3(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600);
    168 /* race, use fchown */
    169             chown(tmp, getuid(), getgid());
    170             fi = fopen(pas->pw_name, "r");
    171             if (fi) {
    172                 while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
    173                     full_write(fd, buf, n);
    174             }
    175             EditFile(caller, tmp);
    176             remove(tmp);
    177             lseek(fd, 0L, SEEK_SET);
    178             repFd = fd;
    179         }
    180         option = REPLACE;
    181         /* fall through */
    182     case REPLACE:
    183         {
    184 /* same here */
    185             char path[1024];
    186             int fd;
    187             int n;
    188 
    189             snprintf(path, sizeof(path), "%s.new", pas->pw_name);
    190             fd = open(path, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY, 0600);
    191             if (fd >= 0) {
    192                 while ((n = read(repFd, buf, sizeof(buf))) > 0) {
    193                     full_write(fd, buf, n);
    194                 }
    195                 close(fd);
    196                 rename(path, pas->pw_name);
    197             } else {
    198                 bb_error_msg("cannot create %s/%s", CDir, path);
    199             }
    200             close(repFd);
    201         }
    202         break;
    203     case DELETE:
    204         remove(pas->pw_name);
    205         break;
    206     case NONE:
    207     default:
    208         break;
    209     }
    210 
    211     /*
    212      *  Bump notification file.  Handle window where crond picks file up
    213      *  before we can write our entry out.
    214      */
    215 
    216     if (option == REPLACE || option == DELETE) {
    217         FILE *fo;
    218         struct stat st;
    219 
    220         while ((fo = fopen(CRONUPDATE, "a"))) {
    221             fprintf(fo, "%s\n", pas->pw_name);
    222             fflush(fo);
    223             if (fstat(fileno(fo), &st) != 0 || st.st_nlink != 0) {
    224                 fclose(fo);
    225                 break;
    226             }
    227             fclose(fo);
    228             /* loop */
    229         }
    230         if (fo == NULL) {
    231             bb_error_msg("cannot append to %s/%s", CDir, CRONUPDATE);
    232         }
     200        }
     201        /* st.st_nlink == 0:
     202         * file was deleted, maybe crond missed our notification */
     203        close(fd);
     204        /* loop */
     205    }
     206    if (fd < 0) {
     207        bb_error_msg("can't append to %s/%s",
     208                crontab_dir, CRONUPDATE);
    233209    }
    234210    return 0;
    235211}
    236 
    237 static int GetReplaceStream(const char *user, const char *file)
    238 {
    239     int filedes[2];
    240     int pid;
    241     int fd;
    242     int n;
    243     char buf[1024];
    244 
    245     if (pipe(filedes) < 0) {
    246         perror("pipe");
    247         return -1;
    248     }
    249     pid = fork();
    250     if (pid < 0) {
    251         perror("fork");
    252         return -1;
    253     }
    254     if (pid > 0) {
    255         /*
    256          * PARENT
    257          */
    258 
    259         close(filedes[1]);
    260         if (read(filedes[0], buf, 1) != 1) {
    261             close(filedes[0]);
    262             filedes[0] = -1;
    263         }
    264         return filedes[0];
    265     }
    266 
    267     /*
    268      * CHILD
    269      */
    270 
    271     close(filedes[0]);
    272 
    273     if (ChangeUser(user, 0) < 0)
    274         exit(0);
    275 
    276     xfunc_error_retval = 0;
    277     fd = xopen(file, O_RDONLY);
    278     buf[0] = 0;
    279     write(filedes[1], buf, 1);
    280     while ((n = read(fd, buf, sizeof(buf))) > 0) {
    281         write(filedes[1], buf, n);
    282     }
    283     exit(0);
    284 }
    285 
    286 static void EditFile(const char *user, const char *file)
    287 {
    288     int pid = fork();
    289 
    290     if (pid == 0) {
    291         /*
    292          * CHILD - change user and run editor
    293          */
    294         const char *ptr;
    295 
    296         if (ChangeUser(user, 1) < 0)
    297             exit(0);
    298         ptr = getenv("VISUAL");
    299         if (ptr == NULL)
    300             ptr = getenv("EDITOR");
    301         if (ptr == NULL)
    302             ptr = PATH_VI;
    303 
    304         ptr = xasprintf("%s %s", ptr, file);
    305         execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", ptr, NULL);
    306         bb_perror_msg_and_die("exec");
    307     }
    308     if (pid < 0) {
    309         /*
    310          * PARENT - failure
    311          */
    312         bb_perror_msg_and_die("fork");
    313     }
    314     wait4(pid, NULL, 0, NULL);
    315 }
    316 
    317 static int ChangeUser(const char *user, short dochdir)
    318 {
    319     struct passwd *pas;
    320 
    321     /*
    322      * Obtain password entry and change privileges
    323      */
    324 
    325     pas = getpwnam(user);
    326     if (pas == NULL) {
    327         bb_perror_msg_and_die("failed to get uid for %s", user);
    328     }
    329     setenv("USER", pas->pw_name, 1);
    330     setenv("HOME", pas->pw_dir, 1);
    331     setenv("SHELL", DEFAULT_SHELL, 1);
    332 
    333     /*
    334      * Change running state to the user in question
    335      */
    336     change_identity(pas);
    337 
    338     if (dochdir) {
    339         if (chdir(pas->pw_dir) < 0) {
    340             bb_perror_msg("chdir(%s) by %s failed", pas->pw_dir, user);
    341             xchdir(TMPDIR);
    342         }
    343     }
    344     return pas->pw_uid;
    345 }
  • branches/2.2.9/mindi-busybox/miscutils/dc.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
    55
     
    77#include <math.h>
    88
    9 /* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
    10 
    11 enum { STACK_SIZE = COMMON_BUFSIZE / sizeof(double) };
    12 
    13 #define stack ((double*)&bb_common_bufsiz1)
    14 static unsigned int pointer;
    15 static unsigned char base;
     9//usage:#define dc_trivial_usage
     10//usage:       "EXPRESSION..."
     11//usage:
     12//usage:#define dc_full_usage "\n\n"
     13//usage:       "Tiny RPN calculator. Operations:\n"
     14//usage:       "+, add, -, sub, *, mul, /, div, %, mod, **, exp, and, or, not, eor,\n"
     15//usage:       "p - print top of the stack (without popping),\n"
     16//usage:       "f - print entire stack,\n"
     17//usage:       "o - pop the value and set output radix (must be 10, 16, 8 or 2).\n"
     18//usage:       "Examples: 'dc 2 2 add' -> 4, 'dc 8 8 * 2 2 + /' -> 16"
     19//usage:
     20//usage:#define dc_example_usage
     21//usage:       "$ dc 2 2 + p\n"
     22//usage:       "4\n"
     23//usage:       "$ dc 8 8 \\* 2 2 + / p\n"
     24//usage:       "16\n"
     25//usage:       "$ dc 0 1 and p\n"
     26//usage:       "0\n"
     27//usage:       "$ dc 0 1 or p\n"
     28//usage:       "1\n"
     29//usage:       "$ echo 72 9 div 8 mul p | dc\n"
     30//usage:       "64\n"
     31
     32#if 0
     33typedef unsigned data_t;
     34#define DATA_FMT ""
     35#elif 0
     36typedef unsigned long data_t;
     37#define DATA_FMT "l"
     38#else
     39typedef unsigned long long data_t;
     40#define DATA_FMT "ll"
     41#endif
     42
     43
     44struct globals {
     45    unsigned pointer;
     46    unsigned base;
     47    double stack[1];
     48} FIX_ALIASING;
     49enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(double) };
     50#define G (*(struct globals*)&bb_common_bufsiz1)
     51#define pointer   (G.pointer   )
     52#define base      (G.base      )
     53#define stack     (G.stack     )
     54#define INIT_G() do { \
     55    base = 10; \
     56} while (0)
     57
    1658
    1759static void push(double a)
     
    4688}
    4789
     90#if ENABLE_FEATURE_DC_LIBM
    4891static void power(void)
    4992{
     
    5295    push(pow(pop(), topower));
    5396}
     97#endif
    5498
    5599static void divide(void)
     
    62106static void mod(void)
    63107{
    64     unsigned int d = pop();
    65 
    66     push((unsigned int) pop() % d);
     108    data_t d = pop();
     109
     110    push((data_t) pop() % d);
    67111}
    68112
    69113static void and(void)
    70114{
    71     push((unsigned int) pop() & (unsigned int) pop());
     115    push((data_t) pop() & (data_t) pop());
    72116}
    73117
    74118static void or(void)
    75119{
    76     push((unsigned int) pop() | (unsigned int) pop());
     120    push((data_t) pop() | (data_t) pop());
    77121}
    78122
    79123static void eor(void)
    80124{
    81     push((unsigned int) pop() ^ (unsigned int) pop());
     125    push((data_t) pop() ^ (data_t) pop());
    82126}
    83127
    84128static void not(void)
    85129{
    86     push(~(unsigned int) pop());
     130    push(~(data_t) pop());
    87131}
    88132
    89133static void set_output_base(void)
    90134{
    91     base = (unsigned char)pop();
    92     if ((base != 10) && (base != 16)) {
    93         bb_error_msg("error, base %d is not supported", base);
     135    static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 };
     136    unsigned b = (unsigned)pop();
     137
     138    base = *strchrnul(bases, b);
     139    if (base == 0) {
     140        bb_error_msg("error, base %u is not supported", b);
    94141        base = 10;
    95142    }
     
    98145static void print_base(double print)
    99146{
    100     if (base == 16)
    101         printf("%x\n", (unsigned int)print);
    102     else
    103         printf("%g\n", print);
     147    data_t x, i;
     148
     149    x = (data_t) print;
     150    if (base == 10) {
     151        if (x == print) /* exactly representable as unsigned integer */
     152            printf("%"DATA_FMT"u\n", x);
     153        else
     154            printf("%g\n", print);
     155        return;
     156    }
     157
     158    switch (base) {
     159    case 16:
     160        printf("%"DATA_FMT"x\n", x);
     161        break;
     162    case 8:
     163        printf("%"DATA_FMT"o\n", x);
     164        break;
     165    default: /* base 2 */
     166        i = MAXINT(data_t) - (MAXINT(data_t) >> 1);
     167        /* i is 100000...00000 */
     168        do {
     169            if (x & i)
     170                break;
     171            i >>= 1;
     172        } while (i > 1);
     173        do {
     174            bb_putchar('1' - !(x & i));
     175            i >>= 1;
     176        } while (i);
     177        bb_putchar('\n');
     178    }
    104179}
    105180
    106181static void print_stack_no_pop(void)
    107182{
    108     unsigned int i = pointer;
     183    unsigned i = pointer;
    109184    while (i)
    110185        print_base(stack[--i]);
     
    130205    {"/",   divide},
    131206    {"div", divide},
     207#if ENABLE_FEATURE_DC_LIBM
    132208    {"**",  power},
    133209    {"exp", power},
    134210    {"pow", power},
     211#endif
    135212    {"%",   mod},
    136213    {"mod", mod},
     
    143220    {"f", print_stack_no_pop},
    144221    {"o", set_output_base},
    145     {"", 0}
     222    { "", NULL }
    146223};
    147224
    148225static void stack_machine(const char *argument)
    149226{
    150     char *endPointer = 0;
     227    char *endPointer;
    151228    double d;
    152229    const struct op *o = operators;
    153230
    154     if (argument == 0)
    155         return;
    156 
    157231    d = strtod(argument, &endPointer);
    158232
    159     if (endPointer != argument) {
     233    if (endPointer != argument && *endPointer == '\0') {
    160234        push(d);
    161235        return;
    162236    }
    163237
    164     while (o->name[0]) {
     238    while (o->function) {
    165239        if (strcmp(o->name, argument) == 0) {
    166240            o->function();
     
    169243        o++;
    170244    }
    171     bb_error_msg_and_die("%s: syntax error", argument);
     245    bb_error_msg_and_die("syntax error at '%s'", argument);
    172246}
    173247
     
    177251static char *get_token(char **buffer)
    178252{
    179     char *start = NULL;
    180     char *current;
    181 
    182     current = skip_whitespace(*buffer);
    183     if (*current != 0) {
    184         start = current;
    185         current = skip_non_whitespace(current);
    186         *buffer = current;
    187     }
    188     return start;
    189 }
    190 
    191 /* In Perl one might say, scalar m|\s*(\S+)\s*|g */
    192 static int number_of_tokens(char *buffer)
    193 {
    194     int   i = 0;
    195     char *b = buffer;
    196     while (get_token(&b)) { i++; }
    197     return i;
    198 }
    199 
    200 int dc_main(int argc, char **argv);
    201 int dc_main(int argc, char **argv)
    202 {
    203     /* take stuff from stdin if no args are given */
    204     if (argc <= 1) {
    205         int i, len;
    206         char *line   = NULL;
    207         char *cursor = NULL;
    208         char *token  = NULL;
    209         while ((line = xmalloc_getline(stdin))) {
     253    char *current = skip_whitespace(*buffer);
     254    if (*current != '\0') {
     255        *buffer = skip_non_whitespace(current);
     256        return current;
     257    }
     258    return NULL;
     259}
     260
     261int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     262int dc_main(int argc UNUSED_PARAM, char **argv)
     263{
     264    INIT_G();
     265
     266    argv++;
     267    if (!argv[0]) {
     268        /* take stuff from stdin if no args are given */
     269        char *line;
     270        char *cursor;
     271        char *token;
     272        while ((line = xmalloc_fgetline(stdin)) != NULL) {
    210273            cursor = line;
    211             len = number_of_tokens(line);
    212             for (i = 0; i < len; i++) {
     274            while (1) {
    213275                token = get_token(&cursor);
    214                 *cursor++ = 0;
     276                if (!token)
     277                    break;
     278                *cursor++ = '\0';
    215279                stack_machine(token);
    216280            }
     
    218282        }
    219283    } else {
    220         if (*argv[1] == '-')
    221             bb_show_usage();
    222         while (argc >= 2) {
    223             stack_machine(argv[1]);
    224             argv++;
    225             argc--;
    226         }
     284        // why? it breaks "dc -2 2 * p"
     285        //if (argv[0][0] == '-')
     286        //  bb_show_usage();
     287        do {
     288            stack_machine(*argv);
     289        } while (*++argv);
    227290    }
    228291    return EXIT_SUCCESS;
  • branches/2.2.9/mindi-busybox/miscutils/devfsd.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
    55
     
    5454      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
    5555*/
    56 
    57 //#include <sys/wait.h>
    58 //#include <sys/ioctl.h>
    59 //#include <sys/socket.h>
    60 #include <sys/un.h>
    61 #include <dirent.h>
    62 #include <syslog.h>
    63 #include <sys/sysmacros.h>
    6456#include "libbb.h"
    6557#include "xregex.h"
    66 
     58#include <syslog.h>
     59
     60#include <sys/un.h>
     61#include <sys/sysmacros.h>
    6762
    6863/* Various defines taken from linux/major.h */
     
    8176/* Various defines taken from linux/devfs_fs.h */
    8277#define DEVFSD_PROTOCOL_REVISION_KERNEL  5
    83 #define DEVFSD_IOCTL_BASE   'd'
     78#define DEVFSD_IOCTL_BASE   'd'
    8479/*  These are the various ioctls  */
    8580#define DEVFSDIOC_GET_PROTO_REV         _IOR(DEVFSD_IOCTL_BASE, 0, int)
     
    9893/*  Never change this otherwise the binary interface will change   */
    9994
    100 struct devfsd_notify_struct
    101 {   /*  Use native C types to ensure same types in kernel and user space     */
    102     unsigned int type;           /*  DEVFSD_NOTIFY_* value                   */
    103     unsigned int mode;           /*  Mode of the inode or device entry       */
    104     unsigned int major;          /*  Major number of device entry            */
    105     unsigned int minor;          /*  Minor number of device entry            */
    106     unsigned int uid;            /*  Uid of process, inode or device entry   */
    107     unsigned int gid;            /*  Gid of process, inode or device entry   */
    108     unsigned int overrun_count;  /*  Number of lost events                   */
    109     unsigned int namelen;        /*  Number of characters not including '\0' */
    110     /*  The device name MUST come last                                       */
    111     char devname[DEVFS_PATHLEN]; /*  This will be '\0' terminated            */
     95struct devfsd_notify_struct {
     96    /*  Use native C types to ensure same types in kernel and user space     */
     97    unsigned int type;           /*  DEVFSD_NOTIFY_* value                   */
     98    unsigned int mode;           /*  Mode of the inode or device entry       */
     99    unsigned int major;          /*  Major number of device entry            */
     100    unsigned int minor;          /*  Minor number of device entry            */
     101    unsigned int uid;            /*  Uid of process, inode or device entry   */
     102    unsigned int gid;            /*  Gid of process, inode or device entry   */
     103    unsigned int overrun_count;  /*  Number of lost events                   */
     104    unsigned int namelen;        /*  Number of characters not including '\0' */
     105    /*  The device name MUST come last                                       */
     106    char devname[DEVFS_PATHLEN]; /*  This will be '\0' terminated            */
    112107};
    113108
     
    157152#define AC_RESTORE                  11
    158153
    159 struct permissions_type
    160 {
     154struct permissions_type {
    161155    mode_t mode;
    162156    uid_t uid;
     
    164158};
    165159
    166 struct execute_type
    167 {
     160struct execute_type {
    168161    char *argv[MAX_ARGS + 1];  /*  argv[0] must always be the programme  */
    169162};
    170163
    171 struct copy_type
    172 {
     164struct copy_type {
    173165    const char *source;
    174166    const char *destination;
    175167};
    176168
    177 struct action_type
    178 {
     169struct action_type {
    179170    unsigned int what;
    180171    unsigned int when;
    181172};
    182173
    183 struct config_entry_struct
    184 {
     174struct config_entry_struct {
    185175    struct action_type action;
    186176    regex_t preg;
     
    195185};
    196186
    197 struct get_variable_info
    198 {
     187struct get_variable_info {
    199188    const struct devfsd_notify_struct *info;
    200189    const char *devname;
     
    289278#define info_logger(p, fmt, args...)
    290279#define msg_logger(p, fmt, args...)
    291 #define msg_logger_and_die(p, fmt, args...)           exit(1)
     280#define msg_logger_and_die(p, fmt, args...)           exit(EXIT_FAILURE)
    292281#define error_logger(p, fmt, args...)
    293 #define error_logger_and_die(p, fmt, args...)         exit(1)
     282#define error_logger_and_die(p, fmt, args...)         exit(EXIT_FAILURE)
    294283#endif
    295284
     
    337326/*  Public functions follow  */
    338327
    339 int devfsd_main(int argc, char **argv);
     328int devfsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    340329int devfsd_main(int argc, char **argv)
    341330{
     
    372361
    373362    fd = xopen(".devfsd", O_RDONLY);
    374 
    375     if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
    376         bb_perror_msg_and_die("FD_CLOEXEC");
    377 
     363    close_on_exec_on(fd);
    378364    xioctl(fd, DEVFSDIOC_GET_PROTO_REV, &proto_rev);
    379365
     
    395381    xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0);
    396382
     383    /*  Set up SIGHUP and SIGUSR1 handlers  */
    397384    sigemptyset(&new_action.sa_mask);
    398385    new_action.sa_flags = 0;
    399 
    400     /*  Set up SIGHUP and SIGUSR1 handlers  */
    401386    new_action.sa_handler = signal_handler;
    402     if (sigaction(SIGHUP, &new_action, NULL) != 0 || sigaction(SIGUSR1, &new_action, NULL) != 0)
    403         bb_error_msg_and_die("sigaction");
    404 
    405     printf("%s v%s  started for %s\n",applet_name, DEVFSD_VERSION, mount_point);
     387    sigaction_set(SIGHUP, &new_action);
     388    sigaction_set(SIGUSR1, &new_action);
     389
     390    printf("%s v%s started for %s\n", applet_name, DEVFSD_VERSION, mount_point);
    406391
    407392    /*  Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions  */
     
    412397
    413398    if (ENABLE_DEVFSD_FG_NP && no_polling)
    414         exit(0);
     399        exit(EXIT_SUCCESS);
    415400
    416401    if (ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG)
     
    469454            return;
    470455        }
    471         if ((fp = fopen(path, "r")) != NULL) {
     456        fp = fopen_for_read(path);
     457        if (fp != NULL) {
    472458            while (fgets(buf, STRING_LENGTH, fp) != NULL) {
    473459                /*  Skip whitespace  */
     
    564550            new->action.what = AC_PERMISSIONS;
    565551            /*  Get user and group  */
    566             if ((ptr = strchr(p[0], '.')) == NULL) {
     552            ptr = strchr(p[0], '.');
     553            if (ptr == NULL) {
    567554                msg = "UID.GID";
    568555                goto process_config_line_err; /*"missing '.' in UID.GID"*/
     
    651638    while (!caught_signal) {
    652639        errno = 0;
    653         bytes = read(fd,(char *) &info, sizeof info);
     640        bytes = read(fd, (char *) &info, sizeof info);
    654641        if (caught_signal)
    655642            break;      /*  Must test for this first     */
     
    749736
    750737static void action_modload(const struct devfsd_notify_struct *info,
    751                 const struct config_entry_struct *entry ATTRIBUTE_UNUSED)
     738                const struct config_entry_struct *entry UNUSED_PARAM)
    752739/*  [SUMMARY] Load a module.
    753740    <info> The devfs change.
     
    765752    argv[5] = NULL;
    766753
    767     wait4pid(xspawn(argv));
     754    spawn_and_wait(argv);
    768755    free(argv[4]);
    769756}  /*  End Function action_modload  */
     
    797784    }
    798785    argv[count] = NULL;
    799     wait4pid(spawn(argv));
     786    spawn_and_wait(argv);
    800787}   /*  End Function action_execute  */
    801788
     
    955942    free(dpath);
    956943    if (S_ISLNK(source_stat.st_mode) || (source_stat.st_mode & S_ISVTX))
    957         copy_inode(dpath, &dest_stat,(source_stat.st_mode & ~S_ISVTX) , spath, &source_stat);
     944        copy_inode(dpath, &dest_stat, (source_stat.st_mode & ~S_ISVTX), spath, &source_stat);
    958945
    959946    if (S_ISDIR(source_stat.st_mode))
    960         dir_operation(RESTORE, spath, rootlen,NULL);
     947        dir_operation(RESTORE, spath, rootlen, NULL);
    961948}
    962949
     
    983970        /*  Same type  */
    984971        if (S_ISLNK(source_stat->st_mode)) {
    985             if ((source_len = readlink(sourcepath, source_link, STRING_LENGTH - 1)) < 0
    986                 || (dest_len   = readlink(destpath  , dest_link  , STRING_LENGTH - 1)) < 0
     972            source_len = readlink(sourcepath, source_link, STRING_LENGTH - 1);
     973            if ((source_len < 0)
     974             || (dest_len = readlink(destpath, dest_link, STRING_LENGTH - 1)) < 0
    987975            )
    988976                return FALSE;
     
    1003991    switch (source_stat->st_mode & S_IFMT) {
    1004992        case S_IFSOCK:
    1005             if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
     993            fd = socket(AF_UNIX, SOCK_STREAM, 0);
     994            if (fd < 0)
    1006995                break;
    1007996            un_addr.sun_family = AF_UNIX;
    1008997            snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s", destpath);
    1009             val = bind(fd,(struct sockaddr *) &un_addr,(int) sizeof un_addr);
     998            val = bind(fd, (struct sockaddr *) &un_addr, (int) sizeof un_addr);
    1010999            close(fd);
    10111000            if (val != 0 || chmod(destpath, new_mode & ~S_IFMT) != 0)
     
    10131002            goto do_chown;
    10141003        case S_IFLNK:
    1015             if ((val = readlink(sourcepath, symlink_val, STRING_LENGTH - 1)) < 0)
     1004            val = readlink(sourcepath, symlink_val, STRING_LENGTH - 1);
     1005            if (val < 0)
    10161006                break;
    10171007            symlink_val[val] = '\0';
     
    10201010            break;
    10211011        case S_IFREG:
    1022             if ((fd = open(destpath, O_RDONLY | O_CREAT, new_mode & ~S_IFMT)) < 0)
     1012            fd = open(destpath, O_RDONLY | O_CREAT, new_mode & ~S_IFMT);
     1013            if (fd < 0)
    10231014                break;
    10241015            close(fd);
     
    10861077        return atoi(string);
    10871078
    1088     if (flag == UID && (pw_ent  = getpwnam(string)) != NULL)
     1079    if (flag == UID && (pw_ent = getpwnam(string)) != NULL)
    10891080        return pw_ent->pw_uid;
    10901081
     
    10951086
    10961087    if (ENABLE_DEVFSD_VERBOSE)
    1097         msg_logger(LOG_ERR,"unknown %s: %s, defaulting to %cid=0",  msg, string, msg[0]);
     1088        msg_logger(LOG_ERR, "unknown %s: %s, defaulting to %cid=0",  msg, string, msg[0]);
    10981089    return 0;
    10991090}/*  End Function get_uid_gid  */
     
    11361127{
    11371128    static char sbuf[sizeof(int)*3 + 2]; /* sign and NUL */
    1138 
    1139     char hostname[STRING_LENGTH];
     1129    static char *hostname;
     1130
    11401131    struct get_variable_info *gv_info = info;
    11411132    const char *field_names[] = {
     
    11461137    int i;
    11471138
    1148     if (gethostname(hostname, STRING_LENGTH - 1) != 0)
    1149         /* Here on error we should do exit(RV_SYS_ERROR), instead we do exit(EXIT_FAILURE) */
    1150         error_logger_and_die(LOG_ERR, "gethostname");
    1151 
    1152     hostname[STRING_LENGTH - 1] = '\0';
    1153 
     1139    if (!hostname)
     1140        hostname = safe_gethostname();
    11541141    /* index_in_str_array returns i>=0  */
    11551142    i = index_in_str_array(field_names, variable);
     
    12011188    char *path;
    12021189
    1203     if ((dp = warn_opendir(dir_name)) == NULL)
     1190    dp = warn_opendir(dir_name);
     1191    if (dp == NULL)
    12041192        return;
    12051193
     
    13431331/* from compat_name.c */
    13441332
    1345 struct translate_struct
    1346 {
     1333struct translate_struct {
    13471334    const char *match;    /*  The string to match to(up to length)                */
    13481335    const char *format;   /*  Format of output, "%s" takes data past match string,
     
    14461433    /* 2 ==scsi/disc, 4 == scsi/part */
    14471434    if (i == 2 || i == 4)
    1448         compat_name = write_old_sd_name(buffer, major, minor,((i == 2) ? "" : (ptr + 4)));
     1435        compat_name = write_old_sd_name(buffer, major, minor, ((i == 2) ? "" : (ptr + 4)));
    14491436
    14501437    /* 5 == scsi/mt */
     
    15851572                if (isspace(ch) ||(ch == '/') ||(ch == '\0')) {
    15861573                    /* User's own home directory: leave separator for next time */
    1587                     if ((env = getenv("HOME")) == NULL) {
     1574                    env = getenv("HOME");
     1575                    if (env == NULL) {
    15881576                        info_logger(LOG_INFO, bb_msg_variable_not_found, "HOME");
    15891577                        return FALSE;
     
    16041592                safe_memcpy(tmp, input, len);
    16051593                input = ptr - 1;
    1606                 if ((pwent = getpwnam(tmp)) == NULL) {
     1594                pwent = getpwnam(tmp);
     1595                if (pwent == NULL) {
    16071596                    info_logger(LOG_INFO, "no pwent for: %s", tmp);
    16081597                    return FALSE;
     
    16641653    if (ch == '$') {
    16651654        /*  Special case for "$$": PID  */
    1666         sprintf(tmp, "%d",(int) getpid());
     1655        sprintf(tmp, "%d", (int) getpid());
    16671656        len = strlen(tmp);
    16681657        if (len + *out_pos >= length)
     
    16841673        safe_memcpy(tmp, input, len);
    16851674        input = ptr - 1;
    1686         if ((env = get_variable_v2(tmp, func, info)) == NULL) {
     1675        env = get_variable_v2(tmp, func, info);
     1676        if (env == NULL) {
    16871677            info_logger(LOG_INFO, bb_msg_variable_not_found, tmp);
    16881678            return NULL;
     
    17361726                break;
    17371727            case '\0':
    1738                 info_logger(LOG_INFO,"\"}\" not found in: %s", input);
     1728                info_logger(LOG_INFO, "\"}\" not found in: %s", input);
    17391729                return NULL;
    17401730            default:
     
    17441734    --ptr;
    17451735    /*  At this point ptr should point to closing brace of "${var:-word}"  */
    1746     if ((env = get_variable_v2(tmp, func, info)) != NULL) {
     1736    env = get_variable_v2(tmp, func, info);
     1737    if (env != NULL) {
    17471738        /*  Found environment variable, so skip the input to the closing brace
    17481739            and return the variable  */
  • branches/2.2.9/mindi-busybox/miscutils/eject.c

    r1765 r2725  
    66 * Copyright (C) 2005  Tito Ragusa <farmatito@tiscali.it>
    77 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
     
    1414 */
    1515
     16#include <sys/mount.h>
    1617#include "libbb.h"
     18/* Must be after libbb.h: they need size_t */
     19#include "fix_u32.h"
     20#include <scsi/sg.h>
     21#include <scsi/scsi.h>
    1722
    1823/* various defines swiped from linux/cdrom.h */
     
    2328#define CDS_TRAY_OPEN        2
    2429
     30#define dev_fd 3
     31
     32/* Code taken from the original eject (http://eject.sourceforge.net/),
     33 * refactored it a bit for busybox (ne-bb@nicoerfurth.de) */
     34
     35static void eject_scsi(const char *dev)
     36{
     37    static const char sg_commands[3][6] = {
     38        { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 },
     39        { START_STOP, 0, 0, 0, 1, 0 },
     40        { START_STOP, 0, 0, 0, 2, 0 }
     41    };
     42
     43    unsigned i;
     44    unsigned char sense_buffer[32];
     45    unsigned char inqBuff[2];
     46    sg_io_hdr_t io_hdr;
     47
     48    if ((ioctl(dev_fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000))
     49        bb_error_msg_and_die("not a sg device or old sg driver");
     50
     51    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
     52    io_hdr.interface_id = 'S';
     53    io_hdr.cmd_len = 6;
     54    io_hdr.mx_sb_len = sizeof(sense_buffer);
     55    io_hdr.dxfer_direction = SG_DXFER_NONE;
     56    /* io_hdr.dxfer_len = 0; */
     57    io_hdr.dxferp = inqBuff;
     58    io_hdr.sbp = sense_buffer;
     59    io_hdr.timeout = 2000;
     60
     61    for (i = 0; i < 3; i++) {
     62        io_hdr.cmdp = (void *)sg_commands[i];
     63        ioctl_or_perror_and_die(dev_fd, SG_IO, (void *)&io_hdr, "%s", dev);
     64    }
     65
     66    /* force kernel to reread partition table when new disc is inserted */
     67    ioctl(dev_fd, BLKRRPART);
     68}
     69
    2570#define FLAG_CLOSE  1
    2671#define FLAG_SMART  2
     72#define FLAG_SCSI   4
    2773
    28 int eject_main(int argc, char **argv);
    29 int eject_main(int argc, char **argv)
     74static void eject_cdrom(unsigned flags, const char *dev)
    3075{
    31     unsigned long flags;
     76    int cmd = CDROMEJECT;
     77
     78    if (flags & FLAG_CLOSE
     79     || ((flags & FLAG_SMART) && ioctl(dev_fd, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN)
     80    ) {
     81        cmd = CDROMCLOSETRAY;
     82    }
     83
     84    ioctl_or_perror_and_die(dev_fd, cmd, NULL, "%s", dev);
     85}
     86
     87int eject_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     88int eject_main(int argc UNUSED_PARAM, char **argv)
     89{
     90    unsigned flags;
    3291    const char *device;
    33     int dev, cmd;
    3492
    3593    opt_complementary = "?1:t--T:T--t";
    36     flags = getopt32(argv, "tT");
    37     device = argv[optind] ? : "/dev/cdrom";
     94    flags = getopt32(argv, "tT" IF_FEATURE_EJECT_SCSI("s"));
     95    device = argv[optind] ? argv[optind] : "/dev/cdrom";
    3896
    39     // We used to do "umount <device>" here, but it was buggy
    40     // if something was mounted OVER cdrom and
    41     // if cdrom is mounted many times.
    42     //
    43     // This works equally well (or better):
    44     // #!/bin/sh
    45     // umount /dev/cdrom
    46     // eject
     97    /* We used to do "umount <device>" here, but it was buggy
     98       if something was mounted OVER cdrom and
     99       if cdrom is mounted many times.
    47100
    48     dev = xopen(device, O_RDONLY|O_NONBLOCK);
    49     cmd = CDROMEJECT;
    50     if (flags & FLAG_CLOSE
    51      || (flags & FLAG_SMART && ioctl(dev, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN))
    52         cmd = CDROMCLOSETRAY;
     101       This works equally well (or better):
     102       #!/bin/sh
     103       umount /dev/cdrom
     104       eject /dev/cdrom
     105    */
    53106
    54     ioctl_or_perror_and_die(dev, cmd, NULL, "%s", device);
     107    xmove_fd(xopen_nonblocking(device), dev_fd);
     108
     109    if (ENABLE_FEATURE_EJECT_SCSI && (flags & FLAG_SCSI))
     110        eject_scsi(device);
     111    else
     112        eject_cdrom(flags, device);
    55113
    56114    if (ENABLE_FEATURE_CLEAN_UP)
    57         close(dev);
     115        close(dev_fd);
    58116
    59117    return EXIT_SUCCESS;
  • branches/2.2.9/mindi-busybox/miscutils/hdparm.c

    r1765 r2725  
    66 * Hacked by Tito <farmatito@tiscali.it> for size optimization.
    77 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 *
    1010 * This program is based on the source code of hdparm: see below...
     
    1212 *          - by Mark Lord (C) 1994-2002 -- freely distributable
    1313 */
    14 
    1514#include "libbb.h"
     15/* must be _after_ libbb.h: */
    1616#include <linux/hdreg.h>
     17#include <sys/mount.h>
     18#if !defined(BLKGETSIZE64)
     19# define BLKGETSIZE64 _IOR(0x12,114,size_t)
     20#endif
    1721
    1822/* device types */
     
    6064                    /* multiword DMA xfer cycle time: */
    6165#define DMA_TIME_MIN        65  /*   - minimum */
    62 #define DMA_TIME_NORM       66  /*   - manufacturer's recommended   */
     66#define DMA_TIME_NORM       66  /*   - manufacturer's recommended */
    6367                    /* minimum PIO xfer cycle time: */
    6468#define PIO_NO_FLOW     67  /*   - without flow control */
     
    8387#define ADV_PWR         91  /* current advanced power management level
    8488                       in low byte, 0x40 in high byte. */
    85 #define PSWD_CODE       92  /* master password revision code    */
     89#define PSWD_CODE       92  /* master password revision code */
    8690#define HWRST_RSLT      93  /* hardware reset result */
    8791#define ACOUSTIC        94  /* acoustic mgmt values ( >= ATA-6) */
     
    128132#define CDROM 0x0005
    129133
    130 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    131 static const char *const pkt_str[] = {
    132     "Direct-access device",         /* word 0, bits 12-8 = 00 */
    133     "Sequential-access device",     /* word 0, bits 12-8 = 01 */
    134     "Printer",              /* word 0, bits 12-8 = 02 */
    135     "Processor",                /* word 0, bits 12-8 = 03 */
    136     "Write-once device",            /* word 0, bits 12-8 = 04 */
    137     "CD-ROM",               /* word 0, bits 12-8 = 05 */
    138     "Scanner",              /* word 0, bits 12-8 = 06 */
    139     "Optical memory",           /* word 0, bits 12-8 = 07 */
    140     "Medium changer",           /* word 0, bits 12-8 = 08 */
    141     "Communications device",        /* word 0, bits 12-8 = 09 */
    142     "ACS-IT8 device",           /* word 0, bits 12-8 = 0a */
    143     "ACS-IT8 device",           /* word 0, bits 12-8 = 0b */
    144     "Array controller",         /* word 0, bits 12-8 = 0c */
    145     "Enclosure services",           /* word 0, bits 12-8 = 0d */
    146     "Reduced block command device",     /* word 0, bits 12-8 = 0e */
    147     "Optical card reader/writer",       /* word 0, bits 12-8 = 0f */
    148     "",                 /* word 0, bits 12-8 = 10 */
    149     "",                 /* word 0, bits 12-8 = 11 */
    150     "",                 /* word 0, bits 12-8 = 12 */
    151     "",                 /* word 0, bits 12-8 = 13 */
    152     "",                 /* word 0, bits 12-8 = 14 */
    153     "",                 /* word 0, bits 12-8 = 15 */
    154     "",                 /* word 0, bits 12-8 = 16 */
    155     "",                 /* word 0, bits 12-8 = 17 */
    156     "",                 /* word 0, bits 12-8 = 18 */
    157     "",                 /* word 0, bits 12-8 = 19 */
    158     "",                 /* word 0, bits 12-8 = 1a */
    159     "",                 /* word 0, bits 12-8 = 1b */
    160     "",                 /* word 0, bits 12-8 = 1c */
    161     "",                 /* word 0, bits 12-8 = 1d */
    162     "",                 /* word 0, bits 12-8 = 1e */
    163     "Unknown",          /* word 0, bits 12-8 = 1f */
    164 };
    165 
    166 static const char *const ata1_cfg_str[] = {         /* word 0 in ATA-1 mode */
    167     "Reserved",             /* bit 0 */
    168     "hard sectored",            /* bit 1 */
    169     "soft sectored",            /* bit 2 */
    170     "not MFM encoded ",         /* bit 3 */
    171     "head switch time > 15us",      /* bit 4 */
    172     "spindle motor control option",     /* bit 5 */
    173     "fixed drive",              /* bit 6 */
    174     "removable drive",          /* bit 7 */
    175     "disk xfer rate <= 5Mbs",       /* bit 8 */
    176     "disk xfer rate > 5Mbs, <= 10Mbs",  /* bit 9 */
    177     "disk xfer rate > 5Mbs",        /* bit 10 */
    178     "rotational speed tol.",        /* bit 11 */
    179     "data strobe offset option",        /* bit 12 */
    180     "track offset option",          /* bit 13 */
    181     "format speed tolerance gap reqd",  /* bit 14 */
    182     "ATAPI"                 /* bit 14 */
    183 };
    184 #endif
    185 
    186134/* word 1: number of logical cylinders */
    187135#define LCYLS_MAX       0x3fff /* maximum allowable value */
     
    239187/* word 81: minor version number */
    240188#define MINOR_MAX       0x22
     189/* words 82-84: cmds/feats supported */
     190#define CMDS_W82        0x77ff  /* word 82: defined command locations*/
     191#define CMDS_W83        0x3fff  /* word 83: defined command locations*/
     192#define CMDS_W84        0x002f  /* word 83: defined command locations*/
     193#define SUPPORT_48_BIT      0x0400
     194#define NUM_CMD_FEAT_STR    48
     195
     196/* words 85-87: cmds/feats enabled */
     197/* use cmd_feat_str[] to display what commands and features have
     198 * been enabled with words 85-87
     199 */
     200
     201/* words 89, 90, SECU ERASE TIME */
     202#define ERASE_BITS      0x00ff
     203
     204/* word 92: master password revision */
     205/* NOVAL_0 or  NOVAL_1 means no support for master password revision */
     206
     207/* word 93: hw reset result */
     208#define CBLID           0x2000  /* CBLID status */
     209#define RST0            0x0001  /* 1=reset to device #0 */
     210#define DEV_DET         0x0006  /* how device num determined */
     211#define JUMPER_VAL      0x0002  /* device num determined by jumper */
     212#define CSEL_VAL        0x0004  /* device num determined by CSEL_VAL */
     213
     214/* word 127: removable media status notification feature set support */
     215#define RM_STAT_BITS    0x0003
     216#define RM_STAT_SUP     0x0001
     217
     218/* word 128: security */
     219#define SECU_ENABLED    0x0002
     220#define SECU_LEVEL      0x0010
     221#define NUM_SECU_STR    6
     222
     223/* word 160: CFA power mode */
     224#define VALID_W160              0x8000  /* 1=word valid */
     225#define PWR_MODE_REQ            0x2000  /* 1=CFA power mode req'd by some cmds*/
     226#define PWR_MODE_OFF            0x1000  /* 1=CFA power moded disabled */
     227#define MAX_AMPS                0x0fff  /* value = max current in ma */
     228
     229/* word 255: integrity */
     230#define SIG                     0x00ff  /* signature location */
     231#define SIG_VAL                 0x00a5  /* signature value */
     232
     233#define TIMING_BUF_MB           1
     234#define TIMING_BUF_BYTES        (TIMING_BUF_MB * 1024 * 1024)
     235
     236#undef DO_FLUSHCACHE            /* under construction: force cache flush on -W0 */
     237
     238
     239#define IS_GET 1
     240#define IS_SET 2
     241
     242
     243enum { fd = 3 };
     244
     245
     246struct globals {
     247    smallint get_identity, get_geom;
     248    smallint do_flush;
     249    smallint do_ctimings, do_timings;
     250    smallint reread_partn;
     251    smallint set_piomode, noisy_piomode;
     252    smallint getset_readahead;
     253    smallint getset_readonly;
     254    smallint getset_unmask;
     255    smallint getset_mult;
     256#ifdef HDIO_GET_QDMA
     257    smallint getset_dma_q;
     258#endif
     259    smallint getset_nowerr;
     260    smallint getset_keep;
     261    smallint getset_io32bit;
     262    int piomode;
     263    unsigned long Xreadahead;
     264    unsigned long readonly;
     265    unsigned long unmask;
     266    unsigned long mult;
     267#ifdef HDIO_SET_QDMA
     268    unsigned long dma_q;
     269#endif
     270    unsigned long nowerr;
     271    unsigned long keep;
     272    unsigned long io32bit;
     273#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
     274    unsigned long dma;
     275    smallint getset_dma;
     276#endif
     277#ifdef HDIO_DRIVE_CMD
     278    smallint set_xfermode, get_xfermode;
     279    smallint getset_dkeep;
     280    smallint getset_standby;
     281    smallint getset_lookahead;
     282    smallint getset_prefetch;
     283    smallint getset_defects;
     284    smallint getset_wcache;
     285    smallint getset_doorlock;
     286    smallint set_seagate;
     287    smallint set_standbynow;
     288    smallint set_sleepnow;
     289    smallint get_powermode;
     290    smallint getset_apmmode;
     291    int xfermode_requested;
     292    unsigned long dkeep;
     293    unsigned long standby_requested; /* 0..255 */
     294    unsigned long lookahead;
     295    unsigned long prefetch;
     296    unsigned long defects;
     297    unsigned long wcache;
     298    unsigned long doorlock;
     299    unsigned long apmmode;
     300#endif
     301    IF_FEATURE_HDPARM_GET_IDENTITY(        smallint get_IDentity;)
     302    IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint getset_busstate;)
     303    IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(    smallint perform_reset;)
     304    IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint perform_tristate;)
     305    IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
     306    IF_FEATURE_HDPARM_HDIO_SCAN_HWIF(      smallint scan_hwif;)
     307    IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long busstate;)
     308    IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long tristate;)
     309    IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
     310#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
     311    unsigned long hwif_data;
     312    unsigned long hwif_ctrl;
     313    unsigned long hwif_irq;
     314#endif
     315#ifdef DO_FLUSHCACHE
     316    unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
     317#endif
     318} FIX_ALIASING;
     319#define G (*(struct globals*)&bb_common_bufsiz1)
     320struct BUG_G_too_big {
     321    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     322};
     323#define get_identity       (G.get_identity           )
     324#define get_geom           (G.get_geom               )
     325#define do_flush           (G.do_flush               )
     326#define do_ctimings        (G.do_ctimings            )
     327#define do_timings         (G.do_timings             )
     328#define reread_partn       (G.reread_partn           )
     329#define set_piomode        (G.set_piomode            )
     330#define noisy_piomode      (G.noisy_piomode          )
     331#define getset_readahead   (G.getset_readahead       )
     332#define getset_readonly    (G.getset_readonly        )
     333#define getset_unmask      (G.getset_unmask          )
     334#define getset_mult        (G.getset_mult            )
     335#define getset_dma_q       (G.getset_dma_q           )
     336#define getset_nowerr      (G.getset_nowerr          )
     337#define getset_keep        (G.getset_keep            )
     338#define getset_io32bit     (G.getset_io32bit         )
     339#define piomode            (G.piomode                )
     340#define Xreadahead         (G.Xreadahead             )
     341#define readonly           (G.readonly               )
     342#define unmask             (G.unmask                 )
     343#define mult               (G.mult                   )
     344#define dma_q              (G.dma_q                  )
     345#define nowerr             (G.nowerr                 )
     346#define keep               (G.keep                   )
     347#define io32bit            (G.io32bit                )
     348#define dma                (G.dma                    )
     349#define getset_dma         (G.getset_dma             )
     350#define set_xfermode       (G.set_xfermode           )
     351#define get_xfermode       (G.get_xfermode           )
     352#define getset_dkeep       (G.getset_dkeep           )
     353#define getset_standby     (G.getset_standby         )
     354#define getset_lookahead   (G.getset_lookahead       )
     355#define getset_prefetch    (G.getset_prefetch        )
     356#define getset_defects     (G.getset_defects         )
     357#define getset_wcache      (G.getset_wcache          )
     358#define getset_doorlock    (G.getset_doorlock        )
     359#define set_seagate        (G.set_seagate            )
     360#define set_standbynow     (G.set_standbynow         )
     361#define set_sleepnow       (G.set_sleepnow           )
     362#define get_powermode      (G.get_powermode          )
     363#define getset_apmmode     (G.getset_apmmode         )
     364#define xfermode_requested (G.xfermode_requested     )
     365#define dkeep              (G.dkeep                  )
     366#define standby_requested  (G.standby_requested      )
     367#define lookahead          (G.lookahead              )
     368#define prefetch           (G.prefetch               )
     369#define defects            (G.defects                )
     370#define wcache             (G.wcache                 )
     371#define doorlock           (G.doorlock               )
     372#define apmmode            (G.apmmode                )
     373#define get_IDentity       (G.get_IDentity           )
     374#define getset_busstate    (G.getset_busstate        )
     375#define perform_reset      (G.perform_reset          )
     376#define perform_tristate   (G.perform_tristate       )
     377#define unregister_hwif    (G.unregister_hwif        )
     378#define scan_hwif          (G.scan_hwif              )
     379#define busstate           (G.busstate               )
     380#define tristate           (G.tristate               )
     381#define hwif               (G.hwif                   )
     382#define hwif_data          (G.hwif_data              )
     383#define hwif_ctrl          (G.hwif_ctrl              )
     384#define hwif_irq           (G.hwif_irq               )
     385
     386
     387/* Busybox messages and functions */
     388#if ENABLE_IOCTL_HEX2STR_ERROR
     389static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
     390{
     391    if (!ioctl(fd, cmd, args))
     392        return 0;
     393    args[0] = alt;
     394    return bb_ioctl_or_warn(fd, cmd, args, string);
     395}
     396#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
     397#else
     398static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
     399{
     400    if (!ioctl(fd, cmd, args))
     401        return 0;
     402    args[0] = alt;
     403    return bb_ioctl_or_warn(fd, cmd, args);
     404}
     405#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
     406#endif
     407
     408static void on_off(int value)
     409{
     410    puts(value ? " (on)" : " (off)");
     411}
     412
     413static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
     414{
     415    if (get_arg) {
     416        printf(" setting %s to %ld", s, arg);
     417        on_off(arg);
     418    }
     419}
     420
     421static void print_value_on_off(const char *str, unsigned long argp)
     422{
     423    printf(" %s\t= %2ld", str, argp);
     424    on_off(argp != 0);
     425}
     426
    241427#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    242 static const char *const minor_str[MINOR_MAX + 2] = {
     428static void print_ascii(const char *p, int length)
     429{
     430#if BB_BIG_ENDIAN
     431#define LE_ONLY(x)
     432    enum { ofs = 0 };
     433#else
     434#define LE_ONLY(x) x
     435    /* every 16bit word is big-endian (i.e. inverted) */
     436    /* accessing bytes in 1,0, 3,2, 5,4... sequence */
     437    int ofs = 1;
     438#endif
     439
     440    length *= 2;
     441    /* find first non-space & print it */
     442    while (length && p[ofs] != ' ') {
     443        p++;
     444        LE_ONLY(ofs = -ofs;)
     445        length--;
     446    }
     447    while (length && p[ofs]) {
     448        bb_putchar(p[ofs]);
     449        p++;
     450        LE_ONLY(ofs = -ofs;)
     451        length--;
     452    }
     453    bb_putchar('\n');
     454#undef LE_ONLY
     455}
     456
     457static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
     458{
     459    if (val[i]) {
     460        printf("\t%-20s", string);
     461        print_ascii((void*)&val[i], n);
     462    }
     463}
     464
     465static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
     466{
     467    uint16_t ii;
     468    uint8_t err_dma = 0;
     469
     470    for (ii = 0; ii <= MODE_MAX; ii++) {
     471        if (mode_sel & 0x0001) {
     472            printf("*%cdma%u ", cc, ii);
     473            if (*have_mode)
     474                err_dma = 1;
     475            *have_mode = 1;
     476        } else if (mode_sup & 0x0001)
     477            printf("%cdma%u ", cc, ii);
     478
     479        mode_sup >>= 1;
     480        mode_sel >>= 1;
     481    }
     482    return err_dma;
     483}
     484
     485static const char pkt_str[] ALIGN1 =
     486    "Direct-access device" "\0"             /* word 0, bits 12-8 = 00 */
     487    "Sequential-access device" "\0"         /* word 0, bits 12-8 = 01 */
     488    "Printer" "\0"                          /* word 0, bits 12-8 = 02 */
     489    "Processor" "\0"                        /* word 0, bits 12-8 = 03 */
     490    "Write-once device" "\0"                /* word 0, bits 12-8 = 04 */
     491    "CD-ROM" "\0"                           /* word 0, bits 12-8 = 05 */
     492    "Scanner" "\0"                          /* word 0, bits 12-8 = 06 */
     493    "Optical memory" "\0"                   /* word 0, bits 12-8 = 07 */
     494    "Medium changer" "\0"                   /* word 0, bits 12-8 = 08 */
     495    "Communications device" "\0"            /* word 0, bits 12-8 = 09 */
     496    "ACS-IT8 device" "\0"                   /* word 0, bits 12-8 = 0a */
     497    "ACS-IT8 device" "\0"                   /* word 0, bits 12-8 = 0b */
     498    "Array controller" "\0"                 /* word 0, bits 12-8 = 0c */
     499    "Enclosure services" "\0"               /* word 0, bits 12-8 = 0d */
     500    "Reduced block command device" "\0"     /* word 0, bits 12-8 = 0e */
     501    "Optical card reader/writer" "\0"       /* word 0, bits 12-8 = 0f */
     502;
     503
     504static const char ata1_cfg_str[] ALIGN1 =       /* word 0 in ATA-1 mode */
     505    "reserved" "\0"                         /* bit 0 */
     506    "hard sectored" "\0"                    /* bit 1 */
     507    "soft sectored" "\0"                    /* bit 2 */
     508    "not MFM encoded " "\0"                 /* bit 3 */
     509    "head switch time > 15us" "\0"          /* bit 4 */
     510    "spindle motor control option" "\0"     /* bit 5 */
     511    "fixed drive" "\0"                      /* bit 6 */
     512    "removable drive" "\0"                  /* bit 7 */
     513    "disk xfer rate <= 5Mbs" "\0"           /* bit 8 */
     514    "disk xfer rate > 5Mbs, <= 10Mbs" "\0"  /* bit 9 */
     515    "disk xfer rate > 5Mbs" "\0"            /* bit 10 */
     516    "rotational speed tol." "\0"            /* bit 11 */
     517    "data strobe offset option" "\0"        /* bit 12 */
     518    "track offset option" "\0"              /* bit 13 */
     519    "format speed tolerance gap reqd" "\0"  /* bit 14 */
     520    "ATAPI"                                 /* bit 14 */
     521;
     522
     523static const char minor_str[] ALIGN1 =
    243524    /* word 81 value: */
    244     "Unspecified",                                  /* 0x0000 */
    245     "ATA-1 X3T9.2 781D prior to rev.4",             /* 0x0001 */
    246     "ATA-1 published, ANSI X3.221-1994",            /* 0x0002 */
    247     "ATA-1 X3T9.2 781D rev.4",                      /* 0x0003 */
    248     "ATA-2 published, ANSI X3.279-1996",            /* 0x0004 */
    249     "ATA-2 X3T10 948D prior to rev.2k",             /* 0x0005 */
    250     "ATA-3 X3T10 2008D rev.1",                      /* 0x0006 */
    251     "ATA-2 X3T10 948D rev.2k",                      /* 0x0007 */
    252     "ATA-3 X3T10 2008D rev.0",                      /* 0x0008 */
    253     "ATA-2 X3T10 948D rev.3",                       /* 0x0009 */
    254     "ATA-3 published, ANSI X3.298-199x",            /* 0x000a */
    255     "ATA-3 X3T10 2008D rev.6",                      /* 0x000b */
    256     "ATA-3 X3T13 2008D rev.7 and 7a",               /* 0x000c */
    257     "ATA/ATAPI-4 X3T13 1153D rev.6",                /* 0x000d */
    258     "ATA/ATAPI-4 T13 1153D rev.13",                 /* 0x000e */
    259     "ATA/ATAPI-4 X3T13 1153D rev.7",                /* 0x000f */
    260     "ATA/ATAPI-4 T13 1153D rev.18",                 /* 0x0010 */
    261     "ATA/ATAPI-4 T13 1153D rev.15",                 /* 0x0011 */
    262     "ATA/ATAPI-4 published, ANSI INCITS 317-1998",  /* 0x0012 */
    263     "ATA/ATAPI-5 T13 1321D rev.3",                  /* 0x0013 */
    264     "ATA/ATAPI-4 T13 1153D rev.14",                 /* 0x0014 */
    265     "ATA/ATAPI-5 T13 1321D rev.1",                  /* 0x0015 */
    266     "ATA/ATAPI-5 published, ANSI INCITS 340-2000",  /* 0x0016 */
    267     "ATA/ATAPI-4 T13 1153D rev.17",                 /* 0x0017 */
    268     "ATA/ATAPI-6 T13 1410D rev.0",                  /* 0x0018 */
    269     "ATA/ATAPI-6 T13 1410D rev.3a",                 /* 0x0019 */
    270     "ATA/ATAPI-7 T13 1532D rev.1",                  /* 0x001a */
    271     "ATA/ATAPI-6 T13 1410D rev.2",                  /* 0x001b */
    272     "ATA/ATAPI-6 T13 1410D rev.1",                  /* 0x001c */
    273     "ATA/ATAPI-7 published, ANSI INCITS 397-2005",  /* 0x001d */
    274     "ATA/ATAPI-7 T13 1532D rev.0",                  /* 0x001e */
    275     "Reserved"                                      /* 0x001f */
    276     "Reserved"                                      /* 0x0020 */
    277     "ATA/ATAPI-7 T13 1532D rev.4a",                 /* 0x0021 */
    278     "ATA/ATAPI-6 published, ANSI INCITS 361-2002",  /* 0x0022 */
    279     "Reserved"                                      /* 0x0023-0xfffe */
    280 };
    281 #endif
     525    "Unspecified" "\0"                                  /* 0x0000 */
     526    "ATA-1 X3T9.2 781D prior to rev.4" "\0"             /* 0x0001 */
     527    "ATA-1 published, ANSI X3.221-1994" "\0"            /* 0x0002 */
     528    "ATA-1 X3T9.2 781D rev.4" "\0"                      /* 0x0003 */
     529    "ATA-2 published, ANSI X3.279-1996" "\0"            /* 0x0004 */
     530    "ATA-2 X3T10 948D prior to rev.2k" "\0"             /* 0x0005 */
     531    "ATA-3 X3T10 2008D rev.1" "\0"                      /* 0x0006 */
     532    "ATA-2 X3T10 948D rev.2k" "\0"                      /* 0x0007 */
     533    "ATA-3 X3T10 2008D rev.0" "\0"                      /* 0x0008 */
     534    "ATA-2 X3T10 948D rev.3" "\0"                       /* 0x0009 */
     535    "ATA-3 published, ANSI X3.298-199x" "\0"            /* 0x000a */
     536    "ATA-3 X3T10 2008D rev.6" "\0"                      /* 0x000b */
     537    "ATA-3 X3T13 2008D rev.7 and 7a" "\0"               /* 0x000c */
     538    "ATA/ATAPI-4 X3T13 1153D rev.6" "\0"                /* 0x000d */
     539    "ATA/ATAPI-4 T13 1153D rev.13" "\0"                 /* 0x000e */
     540    "ATA/ATAPI-4 X3T13 1153D rev.7" "\0"                /* 0x000f */
     541    "ATA/ATAPI-4 T13 1153D rev.18" "\0"                 /* 0x0010 */
     542    "ATA/ATAPI-4 T13 1153D rev.15" "\0"                 /* 0x0011 */
     543    "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0"  /* 0x0012 */
     544    "ATA/ATAPI-5 T13 1321D rev.3" "\0"                  /* 0x0013 */
     545    "ATA/ATAPI-4 T13 1153D rev.14" "\0"                 /* 0x0014 */
     546    "ATA/ATAPI-5 T13 1321D rev.1" "\0"                  /* 0x0015 */
     547    "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0"  /* 0x0016 */
     548    "ATA/ATAPI-4 T13 1153D rev.17" "\0"                 /* 0x0017 */
     549    "ATA/ATAPI-6 T13 1410D rev.0" "\0"                  /* 0x0018 */
     550    "ATA/ATAPI-6 T13 1410D rev.3a" "\0"                 /* 0x0019 */
     551    "ATA/ATAPI-7 T13 1532D rev.1" "\0"                  /* 0x001a */
     552    "ATA/ATAPI-6 T13 1410D rev.2" "\0"                  /* 0x001b */
     553    "ATA/ATAPI-6 T13 1410D rev.1" "\0"                  /* 0x001c */
     554    "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0"  /* 0x001d */
     555    "ATA/ATAPI-7 T13 1532D rev.0" "\0"                  /* 0x001e */
     556    "reserved" "\0"                                     /* 0x001f */
     557    "reserved" "\0"                                     /* 0x0020 */
     558    "ATA/ATAPI-7 T13 1532D rev.4a" "\0"                 /* 0x0021 */
     559    "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0"  /* 0x0022 */
     560    "reserved"                                          /* 0x0023-0xfffe */
     561;
    282562static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
    283563       /* word 81 value: */
     
    320600};
    321601
    322 /* words 82-84: cmds/feats supported */
    323 #define CMDS_W82        0x77ff  /* word 82: defined command locations*/
    324 #define CMDS_W83        0x3fff  /* word 83: defined command locations*/
    325 #define CMDS_W84        0x002f  /* word 83: defined command locations*/
    326 #define SUPPORT_48_BIT      0x0400
    327 #define NUM_CMD_FEAT_STR    48
    328 
    329 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    330 static const char *const cmd_feat_str[] = {
    331     "",                 /* word 82 bit 15: obsolete  */
    332     "NOP cmd",              /* word 82 bit 14 */
    333     "READ BUFFER cmd",          /* word 82 bit 13 */
    334     "WRITE BUFFER cmd",         /* word 82 bit 12 */
    335     "",                 /* word 82 bit 11: obsolete  */
    336     "Host Protected Area feature set",  /* word 82 bit 10 */
    337     "DEVICE RESET cmd",         /* word 82 bit  9 */
    338     "SERVICE interrupt",            /* word 82 bit  8 */
    339     "Release interrupt",            /* word 82 bit  7 */
    340     "Look-ahead",               /* word 82 bit  6 */
    341     "Write cache",              /* word 82 bit  5 */
    342     "PACKET command feature set",       /* word 82 bit  4 */
    343     "Power Management feature set",     /* word 82 bit  3 */
    344     "Removable Media feature set",      /* word 82 bit  2 */
    345     "Security Mode feature set",        /* word 82 bit  1 */
    346     "SMART feature set",            /* word 82 bit  0 */
    347                         /* -------------- */
    348     "",                 /* word 83 bit 15: !valid bit */
    349     "",                 /* word 83 bit 14:  valid bit */
    350     "FLUSH CACHE EXT cmd",          /* word 83 bit 13 */
    351     "Mandatory FLUSH CACHE cmd ",       /* word 83 bit 12 */
    352     "Device Configuration Overlay feature set ",
    353     "48-bit Address feature set ",      /* word 83 bit 10 */
    354     "",
    355     "SET MAX security extension",       /* word 83 bit  8 */
    356     "Address Offset Reserved Area Boot",    /* word 83 bit  7 */
    357     "SET FEATURES subcommand required to spinup after power up",
    358     "Power-Up In Standby feature set",  /* word 83 bit  5 */
    359     "Removable Media Status Notification feature set",
    360     "Adv. Power Management feature set",    /* word 83 bit  3 */
    361     "CFA feature set",          /* word 83 bit  2 */
    362     "READ/WRITE DMA QUEUED",        /* word 83 bit  1 */
    363     "DOWNLOAD MICROCODE cmd",       /* word 83 bit  0 */
    364                         /* -------------- */
    365     "",                 /* word 84 bit 15: !valid bit */
    366     "",                 /* word 84 bit 14:  valid bit */
    367     "",                 /* word 84 bit 13:  reserved */
    368     "",                 /* word 84 bit 12:  reserved */
    369     "",                 /* word 84 bit 11:  reserved */
    370     "",                 /* word 84 bit 10:  reserved */
    371     "",                 /* word 84 bit  9:  reserved */
    372     "",                 /* word 84 bit  8:  reserved */
    373     "",                 /* word 84 bit  7:  reserved */
    374     "",                 /* word 84 bit  6:  reserved */
    375     "General Purpose Logging feature set",  /* word 84 bit  5 */
    376     "",                 /* word 84 bit  4:  reserved */
    377     "Media Card Pass Through Command feature set ",
    378     "Media serial number ",         /* word 84 bit  2 */
    379     "SMART self-test ",         /* word 84 bit  1 */
    380     "SMART error logging "          /* word 84 bit  0 */
    381 };
    382 
    383 static void identify(uint16_t *id_supplied) ATTRIBUTE_NORETURN;
    384 static void identify_from_stdin(void) ATTRIBUTE_NORETURN;
    385 #else
    386 void identify_from_stdin(void);
    387 #endif
    388 
    389 
    390 /* words 85-87: cmds/feats enabled */
    391 /* use cmd_feat_str[] to display what commands and features have
    392  * been enabled with words 85-87
    393  */
    394 
    395 /* words 89, 90, SECU ERASE TIME */
    396 #define ERASE_BITS      0x00ff
    397 
    398 /* word 92: master password revision */
    399 /* NOVAL_0 or  NOVAL_1 means no support for master password revision */
    400 
    401 /* word 93: hw reset result */
    402 #define CBLID           0x2000  /* CBLID status */
    403 #define RST0            0x0001  /* 1=reset to device #0 */
    404 #define DEV_DET         0x0006  /* how device num determined */
    405 #define JUMPER_VAL      0x0002  /* device num determined by jumper */
    406 #define CSEL_VAL        0x0004  /* device num determined by CSEL_VAL */
    407 
    408 /* word 127: removable media status notification feature set support */
    409 #define RM_STAT_BITS    0x0003
    410 #define RM_STAT_SUP     0x0001
    411 
    412 /* word 128: security */
    413 #define SECU_ENABLED    0x0002
    414 #define SECU_LEVEL      0x0010
    415 #define NUM_SECU_STR    6
    416 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    417 static const char *const secu_str[] = {
    418     "supported",            /* word 128, bit 0 */
    419     "enabled",          /* word 128, bit 1 */
    420     "locked",           /* word 128, bit 2 */
    421     "frozen",           /* word 128, bit 3 */
    422     "expired: security count",  /* word 128, bit 4 */
    423     "supported: enhanced erase" /* word 128, bit 5 */
    424 };
    425 #endif
    426 
    427 /* word 160: CFA power mode */
    428 #define VALID_W160              0x8000  /* 1=word valid */
    429 #define PWR_MODE_REQ            0x2000  /* 1=CFA power mode req'd by some cmds*/
    430 #define PWR_MODE_OFF            0x1000  /* 1=CFA power moded disabled */
    431 #define MAX_AMPS                0x0fff  /* value = max current in ma */
    432 
    433 /* word 255: integrity */
    434 #define SIG                     0x00ff  /* signature location */
    435 #define SIG_VAL                 0x00a5  /* signature value */
    436 
    437 #define TIMING_MB               64
    438 #define TIMING_BUF_MB           1
    439 #define TIMING_BUF_BYTES        (TIMING_BUF_MB * 1024 * 1024)
    440 #define BUFCACHE_FACTOR         2
    441 
    442 #undef DO_FLUSHCACHE            /* under construction: force cache flush on -W0 */
    443 
    444 /* Busybox messages and functions */
    445 #if ENABLE_IOCTL_HEX2STR_ERROR
    446 static int ioctl_alt_func(int fd, int cmd, unsigned char *args, int alt, const char *string)
    447 {
    448     if (!ioctl(fd, cmd, args))
    449         return 0;
    450     args[0] = alt;
    451     return bb_ioctl_or_warn(fd, cmd, args, string);
    452 }
    453 #define ioctl_alt_or_warn(fd,cmd,args,alt) ioctl_alt_func(fd,cmd,args,alt,#cmd)
    454 #else
    455 static int ioctl_alt_func(int fd, int cmd, unsigned char *args, int alt)
    456 {
    457     if (!ioctl(fd, cmd, args))
    458         return 0;
    459     args[0] = alt;
    460     return bb_ioctl_or_warn(fd, cmd, args);
    461 }
    462 #define ioctl_alt_or_warn(fd,cmd,args,alt) ioctl_alt_func(fd,cmd,args,alt)
    463 #endif
    464 
    465 static void on_off(int value)
    466 {
    467     puts(value ? " (on)" : " (off)");
    468 }
    469 
    470 static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
    471 {
    472     if (get_arg) {
    473         printf(" setting %s to %ld", s, arg);
    474         on_off(arg);
    475     }
    476 }
    477 
    478 static void print_value_on_off(const char *str, unsigned long argp)
    479 {
    480     printf(" %s\t= %2ld", str, argp);
    481     on_off(argp != 0);
    482 }
    483 
    484 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    485 static void print_ascii(uint16_t *p, uint8_t length);
    486 
    487 static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
    488 {
    489     if (val[i]) {
    490         printf("\t%-20s", string);
    491         print_ascii(&val[i], n);
    492     }
    493 }
    494 #endif
    495 /* end of busybox specific stuff */
    496 
    497 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    498 static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
    499 {
    500     uint16_t ii;
    501     uint8_t err_dma = 0;
    502 
    503     for (ii = 0; ii <= MODE_MAX; ii++) {
    504         if (mode_sel & 0x0001) {
    505             printf("*%cdma%u ", cc, ii);
    506             if (*have_mode)
    507                 err_dma = 1;
    508             *have_mode = 1;
    509         } else if (mode_sup & 0x0001)
    510             printf("%cdma%u ", cc, ii);
    511 
    512         mode_sup >>= 1;
    513         mode_sel >>= 1;
    514     }
    515     return err_dma;
    516 }
    517 
    518 static void print_ascii(uint16_t *p, uint8_t length)
    519 {
    520     uint8_t ii;
    521     char cl;
    522 
    523     /* find first non-space & print it */
    524     for (ii = 0; ii < length; ii++) {
    525         if ((char)((*p)>>8) != ' ')
    526             break;
    527         cl = (char)(*p);
    528         if (cl != ' ') {
    529             if (cl != '\0')
    530                 printf("%c", cl);
    531             p++;
    532             ii++;
    533             break;
    534         }
    535         p++;
    536     }
    537     /* print the rest */
    538     for (; ii< length; ii++) {
    539         if (!(*p))
    540             break; /* some older devices have NULLs */
    541         printf("%c%c", (char)((*p)>>8), (char)(*p));
    542         p++;
    543     }
    544     puts("");
    545 }
     602static const char cmd_feat_str[] ALIGN1 =
     603    "" "\0"                                     /* word 82 bit 15: obsolete  */
     604    "NOP cmd" "\0"                              /* word 82 bit 14 */
     605    "READ BUFFER cmd" "\0"                      /* word 82 bit 13 */
     606    "WRITE BUFFER cmd" "\0"                     /* word 82 bit 12 */
     607    "" "\0"                                     /* word 82 bit 11: obsolete  */
     608    "Host Protected Area feature set" "\0"      /* word 82 bit 10 */
     609    "DEVICE RESET cmd" "\0"                     /* word 82 bit  9 */
     610    "SERVICE interrupt" "\0"                    /* word 82 bit  8 */
     611    "Release interrupt" "\0"                    /* word 82 bit  7 */
     612    "Look-ahead" "\0"                           /* word 82 bit  6 */
     613    "Write cache" "\0"                          /* word 82 bit  5 */
     614    "PACKET command feature set" "\0"           /* word 82 bit  4 */
     615    "Power Management feature set" "\0"         /* word 82 bit  3 */
     616    "Removable Media feature set" "\0"          /* word 82 bit  2 */
     617    "Security Mode feature set" "\0"            /* word 82 bit  1 */
     618    "SMART feature set" "\0"                    /* word 82 bit  0 */
     619                                                /* -------------- */
     620    "" "\0"                                     /* word 83 bit 15: !valid bit */
     621    "" "\0"                                     /* word 83 bit 14:  valid bit */
     622    "FLUSH CACHE EXT cmd" "\0"                  /* word 83 bit 13 */
     623    "Mandatory FLUSH CACHE cmd " "\0"           /* word 83 bit 12 */
     624    "Device Configuration Overlay feature set " "\0"
     625    "48-bit Address feature set " "\0"          /* word 83 bit 10 */
     626    "" "\0"
     627    "SET MAX security extension" "\0"           /* word 83 bit  8 */
     628    "Address Offset Reserved Area Boot" "\0"    /* word 83 bit  7 */
     629    "SET FEATURES subcommand required to spinup after power up" "\0"
     630    "Power-Up In Standby feature set" "\0"      /* word 83 bit  5 */
     631    "Removable Media Status Notification feature set" "\0"
     632    "Adv. Power Management feature set" "\0"    /* word 83 bit  3 */
     633    "CFA feature set" "\0"                      /* word 83 bit  2 */
     634    "READ/WRITE DMA QUEUED" "\0"                /* word 83 bit  1 */
     635    "DOWNLOAD MICROCODE cmd" "\0"               /* word 83 bit  0 */
     636                                                /* -------------- */
     637    "" "\0"                                     /* word 84 bit 15: !valid bit */
     638    "" "\0"                                     /* word 84 bit 14:  valid bit */
     639    "" "\0"                                     /* word 84 bit 13:  reserved */
     640    "" "\0"                                     /* word 84 bit 12:  reserved */
     641    "" "\0"                                     /* word 84 bit 11:  reserved */
     642    "" "\0"                                     /* word 84 bit 10:  reserved */
     643    "" "\0"                                     /* word 84 bit  9:  reserved */
     644    "" "\0"                                     /* word 84 bit  8:  reserved */
     645    "" "\0"                                     /* word 84 bit  7:  reserved */
     646    "" "\0"                                     /* word 84 bit  6:  reserved */
     647    "General Purpose Logging feature set" "\0"  /* word 84 bit  5 */
     648    "" "\0"                                     /* word 84 bit  4:  reserved */
     649    "Media Card Pass Through Command feature set " "\0"
     650    "Media serial number " "\0"                 /* word 84 bit  2 */
     651    "SMART self-test " "\0"                     /* word 84 bit  1 */
     652    "SMART error logging "                      /* word 84 bit  0 */
     653;
     654
     655static const char secu_str[] ALIGN1 =
     656    "supported" "\0"                /* word 128, bit 0 */
     657    "enabled" "\0"                  /* word 128, bit 1 */
     658    "locked" "\0"                   /* word 128, bit 2 */
     659    "frozen" "\0"                   /* word 128, bit 3 */
     660    "expired: security count" "\0"  /* word 128, bit 4 */
     661    "supported: enhanced erase"     /* word 128, bit 5 */
     662;
    546663
    547664// Parse 512 byte disk identification block and print much crap.
    548 
    549 static void identify(uint16_t *id_supplied)
    550 {
    551     uint16_t buf[256];
    552     uint16_t *val, ii, jj, kk;
     665static void identify(uint16_t *val) NORETURN;
     666static void identify(uint16_t *val)
     667{
     668    uint16_t ii, jj, kk;
    553669    uint16_t like_std = 1, std = 0, min_std = 0xffff;
    554670    uint16_t dev = NO_DEV, eqpt = NO_DEV;
     
    558674    uint64_t bbbig; /* (:) */
    559675    const char *strng;
    560 
    561     // Adjust for endianness if necessary.
    562 
    563     if (BB_BIG_ENDIAN) {
    564         swab(id_supplied, buf, sizeof(buf));
    565         val = buf;
    566     } else
    567         val = id_supplied;
    568 
    569     chksum &= 0xff;
    570 
    571     /* check if we recognise the device type */
    572     puts("");
     676#if BB_BIG_ENDIAN
     677    uint16_t buf[256];
     678
     679    // Adjust for endianness
     680    swab(val, buf, sizeof(buf));
     681    val = buf;
     682#endif
     683    /* check if we recognize the device type */
     684    bb_putchar('\n');
    573685    if (!(val[GEN_CONFIG] & NOT_ATA)) {
    574686        dev = ATA_DEV;
     
    581693        dev = ATAPI_DEV;
    582694        eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
    583         printf("ATAPI %s, with ", pkt_str[eqpt]);
     695        printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
    584696        like_std = 3;
    585697    } else
    586         /*"Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n"*/
     698        /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
    587699        bb_error_msg_and_die("unknown device type");
    588700
     
    619731            if (like_std < 3) like_std = 3;
    620732            std = actual_ver[val[MINOR]];
    621             if (std) printf("\n\tUsed: %s ", minor_str[val[MINOR]]);
    622 
     733            if (std)
     734                printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
    623735        }
    624736        /* looks like when they up-issue the std, they obsolete one;
     
    687799            printf("& some of %u\n", like_std);
    688800        else
    689             puts("");
     801            bb_putchar('\n');
    690802    } else {
    691803        /* TBD: do CDROM stuff more thoroughly.  For now... */
     
    704816            }
    705817        }
    706         printf("%s\n", kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
     818        puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
    707819        /* the cdrom stuff is more like ATA-2 than anything else, so: */
    708820        like_std = 2;
     
    718830        for (ii = 1; ii < 15; ii++) {
    719831            if (jj & 0x0001)
    720                 printf("\t%s\n", ata1_cfg_str[ii]);
     832                printf("\t%s\n", nth_string(ata1_cfg_str, ii));
    721833            jj >>=1;
    722834        }
     
    730842            strng ="50us";
    731843        else
    732             strng = "Unknown";
     844            strng = "unknown";
    733845        printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
    734846
     
    738850            strng = "16 bytes";
    739851        else
    740             strng = "Unknown";
     852            strng = "unknown";
    741853        puts(strng);
    742854    } else {
    743855        /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
    744856        ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
    745         mm = 0; bbbig = 0;
     857        mm = 0;
     858        bbbig = 0;
    746859        if ((ll > 0x00FBFC10) && (!val[LCYLS]))
    747860            printf("\tCHS addressing not supported\n");
    748861        else {
    749862            jj = val[WHATS_VALID] & OK_W54_58;
    750             printf("\tLogical\t\tmax\tcurrent\n\tcylinders\t%u\t%u\n\theads\t\t%u\t%u\n\tsectors/track\t%u\t%u\n\t--\n",
    751                     val[LCYLS],jj?val[LCYLS_CUR]:0, val[LHEADS],jj?val[LHEADS_CUR]:0, val[LSECTS],jj?val[LSECTS_CUR]:0);
     863            printf("\tLogical\t\tmax\tcurrent\n"
     864                "\tcylinders\t%u\t%u\n"
     865                "\theads\t\t%u\t%u\n"
     866                "\tsectors/track\t%u\t%u\n"
     867                "\t--\n",
     868                val[LCYLS],
     869                jj ? val[LCYLS_CUR] : 0,
     870                val[LHEADS],
     871                jj ? val[LHEADS_CUR] : 0,
     872                val[LSECTS],
     873                jj ? val[LSECTS_CUR] : 0);
    752874
    753875            if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
    754                 printf("\tbytes/track: %u\tbytes/sector: %u\n", val[TRACK_BYTES], val[SECT_BYTES]);
     876                printf("\tbytes/track: %u\tbytes/sector: %u\n",
     877                    val[TRACK_BYTES], val[SECT_BYTES]);
    755878
    756879            if (jj) {
     
    787910            printf("(%"PRIu64" GB)\n", bbbig/1000);
    788911        else
    789             puts("");
     912            bb_putchar('\n');
    790913    }
    791914
     
    794917
    795918    if (dev == ATAPI_DEV) {
    796         if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP)) printf("Cmd queuing, ");
    797         if (val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, ");
     919        if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP))
     920            printf("Cmd queuing, ");
     921        if (val[CAPAB_0] & OVLP_SUP)
     922            printf("Cmd overlap, ");
    798923    }
    799924    if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
     
    801926    if (like_std != 1) {
    802927        printf("IORDY%s(can%s be disabled)\n",
    803                 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
    804                 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
     928            !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
     929            (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
    805930    } else
    806931        printf("no IORDY\n");
     
    808933    if ((like_std == 1) && val[BUF_TYPE]) {
    809934        printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
    810                 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
    811                 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
     935            (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
     936            (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
    812937    }
    813938
     
    826951            printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
    827952        else {
    828             printf("\tStandby timer values: spec'd by %s", (val[CAPAB_0] & STD_STBY) ? "Standard" : "Vendor");
     953            printf("\tStandby timer values: spec'd by %s",
     954                (val[CAPAB_0] & STD_STBY) ? "standard" : "vendor");
    829955            if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
    830                 printf(", %s device specific minimum\n", (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
     956                printf(", %s device specific minimum\n",
     957                    (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
    831958            else
    832                 puts("");
     959                bb_putchar('\n');
    833960        }
    834961        printf("\tR/W multiple sector transfer: ");
     
    856983        if (like_std > 5 && val[ACOUSTIC]) {
    857984            printf("\tRecommended acoustic management value: %u, current value: %u\n",
    858                     (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff);
     985                (val[ACOUSTIC] >> 8) & 0x00ff,
     986                val[ACOUSTIC] & 0x00ff);
    859987        }
    860988    } else {
     
    865993        if (val[PKT_REL] || val[SVC_NBSY]) {
    866994            printf("\tOverlap support:");
    867             if (val[PKT_REL]) printf(" %uus to release bus.", val[PKT_REL]);
    868             if (val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.", val[SVC_NBSY]);
    869             puts("");
     995            if (val[PKT_REL])
     996                printf(" %uus to release bus.", val[PKT_REL]);
     997            if (val[SVC_NBSY])
     998                printf(" %uus to clear BSY after SERVICE cmd.",
     999                    val[SVC_NBSY]);
     1000            bb_putchar('\n');
    8701001        }
    8711002    }
     
    8941025        }
    8951026        if (err_dma || !have_mode) printf("(?)");
    896         puts("");
     1027        bb_putchar('\n');
    8971028
    8981029        if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
     
    9051036            if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
    9061037            if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
    907             puts("");
     1038            bb_putchar('\n');
    9081039        }
    9091040    }
     
    9191050            jj >>=1;
    9201051        }
    921         puts("");
     1052        bb_putchar('\n');
    9221053    } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
    9231054        for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
    9241055            printf("pio%d ", ii);
    925         puts("");
     1056        bb_putchar('\n');
    9261057    } else
    927         printf("unknown\n");
     1058        puts("unknown");
    9281059
    9291060    if (val[WHATS_VALID] & OK_W64_70) {
    9301061        if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
    9311062            printf("\t\tCycle time:");
    932             if (val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]);
    933             if (val[PIO_FLOW]) printf("  IORDY flow control=%uns", val[PIO_FLOW]);
    934             puts("");
     1063            if (val[PIO_NO_FLOW])
     1064                printf(" no flow control=%uns", val[PIO_NO_FLOW]);
     1065            if (val[PIO_FLOW])
     1066                printf("  IORDY flow control=%uns", val[PIO_FLOW]);
     1067            bb_putchar('\n');
    9351068        }
    9361069    }
    9371070
    9381071    if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
    939         printf("Commands/features:\n\tEnabled\tSupported:\n");
     1072        printf("Commands/features:\n"
     1073            "\tEnabled\tSupported:\n");
    9401074        jj = val[CMDS_SUPP_0];
    9411075        kk = val[CMDS_EN_0];
    9421076        for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
    943             if ((jj & 0x8000) && (*cmd_feat_str[ii] != '\0')) {
    944                 printf("\t%s\t%s\n", (kk & 0x8000) ? "   *" : "", cmd_feat_str[ii]);
     1077            const char *feat_str = nth_string(cmd_feat_str, ii);
     1078            if ((jj & 0x8000) && (*feat_str != '\0')) {
     1079                printf("\t%s\t%s\n", (kk & 0x8000) ? "   *" : "", feat_str);
    9451080            }
    9461081            jj <<= 1;
     
    9581093    /* Removable Media Status Notification feature set */
    9591094    if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
    960         printf("\t%s supported\n", cmd_feat_str[27]);
     1095        printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
    9611096
    9621097    /* security */
     
    9701105        if (jj) {
    9711106            for (ii = 0; ii < NUM_SECU_STR; ii++) {
    972                 printf("\t%s\t%s\n", (!(jj & 0x0001)) ? "not" : "",  secu_str[ii]);
     1107                printf("\t%s\t%s\n",
     1108                    (!(jj & 0x0001)) ? "not" : "",
     1109                    nth_string(secu_str, ii));
    9731110                jj >>=1;
    9741111            }
    9751112            if (val[SECU_STATUS] & SECU_ENABLED) {
    976                 printf("\tSecurity level %s\n", (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
     1113                printf("\tSecurity level %s\n",
     1114                    (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
    9771115            }
    9781116        }
     
    9801118        kk =  val[ENH_ERASE_TIME] & ERASE_BITS;
    9811119        if (jj || kk) {
    982             printf("\t");
     1120            bb_putchar('\t');
    9831121            if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
    9841122            if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
    985             puts("");
     1123            bb_putchar('\n');
    9861124        }
    9871125    }
     
    9901128    jj = val[HWRST_RSLT];
    9911129    if ((jj & VALID) == VALID_VAL) {
    992         if (!(oo = (jj & RST0)))
     1130        oo = (jj & RST0);
     1131        if (!oo)
    9931132            jj >>= 8;
    9941133        if ((jj & DEV_DET) == JUMPER_VAL)
     
    9981137        else
    9991138            strng = "";
    1000         printf("HW reset results:\n\tCBLID- %s Vih\n\tDevice num = %i%s\n",
    1001                 (val[HWRST_RSLT] & CBLID) ? "above" : "below", !(oo), strng);
     1139        printf("HW reset results:\n"
     1140            "\tCBLID- %s Vih\n"
     1141            "\tDevice num = %i%s\n",
     1142            (val[HWRST_RSLT] & CBLID) ? "above" : "below",
     1143            !(oo), strng);
    10021144    }
    10031145
     
    10051147    if ((like_std > 4) && (eqpt != CDROM)) {
    10061148        if (val[CFA_PWR_MODE] & VALID_W160) {
    1007             printf("CFA power mode 1:\n\t%s%s\n", (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
    1008                     (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
    1009 
     1149            printf("CFA power mode 1:\n"
     1150                "\t%s%s\n",
     1151                (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
     1152                (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
    10101153            if (val[CFA_PWR_MODE] & MAX_AMPS)
    10111154                printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
     
    10181161    exit(EXIT_SUCCESS);
    10191162}
    1020 #endif
    1021 
    1022 static smallint get_identity, get_geom;
    1023 static smallint do_flush;
    1024 static smallint do_ctimings, do_timings;
    1025 static smallint reread_partn;
    1026 
    1027 static smallint set_piomode, noisy_piomode;
    1028 static smallint set_readahead, get_readahead;
    1029 static smallint set_readonly, get_readonly;
    1030 static smallint set_unmask, get_unmask;
    1031 static smallint set_mult, get_mult;
    1032 static smallint set_dma_q, get_dma_q;
    1033 static smallint set_nowerr, get_nowerr;
    1034 static smallint set_keep, get_keep;
    1035 static smallint set_io32bit, get_io32bit;
    1036 static int piomode;
    1037 static unsigned long Xreadahead;
    1038 static unsigned long readonly;
    1039 static unsigned long unmask;
    1040 static unsigned long mult;
    1041 static unsigned long dma_q;
    1042 static unsigned long nowerr;
    1043 static unsigned long keep;
    1044 static unsigned long io32bit;
    1045 #if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
    1046 static unsigned long dma;
    1047 static smallint set_dma, get_dma;
    1048 #endif
    1049 #ifdef HDIO_DRIVE_CMD
    1050 static smallint set_xfermode, get_xfermode;
    1051 static smallint set_dkeep, get_dkeep;
    1052 static smallint set_standby, get_standby;
    1053 static smallint set_lookahead, get_lookahead;
    1054 static smallint set_prefetch, get_prefetch;
    1055 static smallint set_defects, get_defects;
    1056 static smallint set_wcache, get_wcache;
    1057 static smallint set_doorlock, get_doorlock;
    1058 static smallint set_seagate, get_seagate;
    1059 static smallint set_standbynow, get_standbynow;
    1060 static smallint set_sleepnow, get_sleepnow;
    1061 static smallint get_powermode;
    1062 static smallint set_apmmode, get_apmmode;
    1063 static int xfermode_requested;
    1064 static unsigned long dkeep;
    1065 static unsigned long standby_requested;
    1066 static unsigned long lookahead;
    1067 static unsigned long prefetch;
    1068 static unsigned long defects;
    1069 static unsigned long wcache;
    1070 static unsigned long doorlock;
    1071 static unsigned long apmmode;
    1072 #endif
    1073 USE_FEATURE_HDPARM_GET_IDENTITY(        static smallint get_IDentity;)
    1074 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  static smallint set_busstate, get_busstate;)
    1075 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(    static smallint perform_reset;)
    1076 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  static smallint perform_tristate;)
    1077 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(static smallint unregister_hwif;)
    1078 USE_FEATURE_HDPARM_HDIO_SCAN_HWIF(      static smallint scan_hwif;)
    1079 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  static unsigned long busstate;)
    1080 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  static unsigned long tristate;)
    1081 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(static unsigned long hwif;)
    1082 #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
    1083 static unsigned long hwif_data;
    1084 static unsigned long hwif_ctrl;
    1085 static unsigned long hwif_irq;
    10861163#endif
    10871164
     
    10981175
    10991176#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
    1100 static const char *const cfg_str[] = {
    1101     "",      "HardSect",   "SoftSect",   "NotMFM",
    1102     "HdSw>15uSec", "SpinMotCtl", "Fixed",     "Removeable",
    1103     "DTR<=5Mbs",   "DTR>5Mbs",   "DTR>10Mbs", "RotSpdTol>.5%",
    1104     "dStbOff",     "TrkOff",     "FmtGapReq", "nonMagnetic"
    1105 };
    1106 
    1107 static const char *const BuffType[] = {
    1108     "Unknown", "1Sect", "DualPort", "DualPortCache"
    1109 };
    1110 
    1111 static void dump_identity(const struct hd_driveid *id)
     1177static const char cfg_str[] ALIGN1 =
     1178    """\0"            "HardSect""\0"   "SoftSect""\0"  "NotMFM""\0"
     1179    "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0"     "Removeable""\0"
     1180    "DTR<=5Mbs""\0"   "DTR>5Mbs""\0"   "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
     1181    "dStbOff""\0"     "TrkOff""\0"     "FmtGapReq""\0" "nonMagnetic"
     1182;
     1183
     1184static const char BuffType[] ALIGN1 =
     1185    "unknown""\0"     "1Sect""\0"      "DualPort""\0" "DualPortCache"
     1186;
     1187
     1188static NOINLINE void dump_identity(const struct hd_driveid *id)
    11121189{
    11131190    int i;
    1114     const unsigned short int *id_regs = (const void*) id;
     1191    const unsigned short *id_regs = (const void*) id;
    11151192
    11161193    printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
     
    11181195    for (i = 0; i <= 15; i++) {
    11191196        if (id->config & (1<<i))
    1120             printf(" %s", cfg_str[i]);
     1197            printf(" %s", nth_string(cfg_str, i));
    11211198    }
    11221199    printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
    1123             " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
    1124                 id->cyls, id->heads, id->sectors, id->track_bytes,
    1125                 id->sector_bytes, id->ecc_bytes,
    1126                 id->buf_type, BuffType[(id->buf_type > 3) ? 0 :  id->buf_type],
    1127                 id->buf_size/2, id->max_multsect);
     1200        " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
     1201        id->cyls, id->heads, id->sectors, id->track_bytes,
     1202        id->sector_bytes, id->ecc_bytes,
     1203        id->buf_type,
     1204        nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
     1205        id->buf_size/2, id->max_multsect);
    11281206    if (id->max_multsect) {
    11291207        printf(", MultSect=");
     
    11351213            printf("off");
    11361214    }
    1137     puts("");
     1215    bb_putchar('\n');
    11381216
    11391217    if (!(id->field_valid & 1))
     
    11501228        printf(", LBAsects=%u", id->lba_capacity);
    11511229
    1152     printf("\n IORDY=%s", (id->capability & 8) ? (id->capability & 4) ?  "on/off" : "yes" : "no");
     1230    printf("\n IORDY=%s",
     1231        (id->capability & 8)
     1232            ? ((id->capability & 4) ? "on/off" : "yes")
     1233            : "no");
    11531234
    11541235    if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
     
    11651246    }
    11661247    if (id->field_valid & 2) {
    1167         if (id->eide_pio_modes & 1) printf("pio3 ");
    1168         if (id->eide_pio_modes & 2) printf("pio4 ");
    1169         if (id->eide_pio_modes &~3) printf("pio? ");
     1248        static const masks_labels_t pio_modes = {
     1249            .masks = { 1, 2, ~3 },
     1250            .labels = "pio3 \0""pio4 \0""pio? \0",
     1251        };
     1252        print_flags(&pio_modes, id->eide_pio_modes);
    11701253    }
    11711254    if (id->capability & 1) {
    11721255        if (id->dma_1word | id->dma_mword) {
     1256            static const int dma_wmode_masks[] = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
    11731257            printf("\n DMA modes:  ");
    1174             if (id->dma_1word & 0x100) printf("*");
    1175             if (id->dma_1word & 1) printf("sdma0 ");
    1176             if (id->dma_1word & 0x200) printf("*");
    1177             if (id->dma_1word & 2) printf("sdma1 ");
    1178             if (id->dma_1word & 0x400) printf("*");
    1179             if (id->dma_1word & 4) printf("sdma2 ");
    1180             if (id->dma_1word & 0xf800) printf("*");
    1181             if (id->dma_1word & 0xf8) printf("sdma? ");
    1182             if (id->dma_mword & 0x100) printf("*");
    1183             if (id->dma_mword & 1) printf("mdma0 ");
    1184             if (id->dma_mword & 0x200) printf("*");
    1185             if (id->dma_mword & 2) printf("mdma1 ");
    1186             if (id->dma_mword & 0x400) printf("*");
    1187             if (id->dma_mword & 4) printf("mdma2 ");
    1188             if (id->dma_mword & 0xf800) printf("*");
    1189             if (id->dma_mword & 0xf8) printf("mdma? ");
     1258            print_flags_separated(dma_wmode_masks,
     1259                "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
     1260                id->dma_1word, NULL);
     1261            print_flags_separated(dma_wmode_masks,
     1262                "*\0""mdma0 \0""*\0""mdma1 \0""*\0""mdma2 \0""*\0""mdma? \0",
     1263                id->dma_mword, NULL);
    11901264        }
    11911265    }
    11921266    if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
     1267        static const masks_labels_t ultra_modes1 = {
     1268            .masks = { 0x100, 0x001, 0x200, 0x002, 0x400, 0x004 },
     1269            .labels = "*\0""udma0 \0""*\0""udma1 \0""*\0""udma2 \0",
     1270        };
     1271
    11931272        printf("\n UDMA modes: ");
    1194         if (id->dma_ultra & 0x100) printf("*");
    1195         if (id->dma_ultra & 0x001) printf("udma0 ");
    1196         if (id->dma_ultra & 0x200) printf("*");
    1197         if (id->dma_ultra & 0x002) printf("udma1 ");
    1198         if (id->dma_ultra & 0x400) printf("*");
    1199         if (id->dma_ultra & 0x004) printf("udma2 ");
     1273        print_flags(&ultra_modes1, id->dma_ultra);
    12001274#ifdef __NEW_HD_DRIVE_ID
    12011275        if (id->hw_config & 0x2000) {
     
    12031277        if (id->word93 & 0x2000) {
    12041278#endif /* __NEW_HD_DRIVE_ID */
    1205             if (id->dma_ultra & 0x0800) printf("*");
    1206             if (id->dma_ultra & 0x0008) printf("udma3 ");
    1207             if (id->dma_ultra & 0x1000) printf("*");
    1208             if (id->dma_ultra & 0x0010) printf("udma4 ");
    1209             if (id->dma_ultra & 0x2000) printf("*");
    1210             if (id->dma_ultra & 0x0020) printf("udma5 ");
    1211             if (id->dma_ultra & 0x4000) printf("*");
    1212             if (id->dma_ultra & 0x0040) printf("udma6 ");
    1213             if (id->dma_ultra & 0x8000) printf("*");
    1214             if (id->dma_ultra & 0x0080) printf("udma7 ");
     1279            static const masks_labels_t ultra_modes2 = {
     1280                .masks = { 0x0800, 0x0008, 0x1000, 0x0010,
     1281                    0x2000, 0x0020, 0x4000, 0x0040,
     1282                    0x8000, 0x0080 },
     1283                .labels = "*\0""udma3 \0""*\0""udma4 \0"
     1284                    "*\0""udma5 \0""*\0""udma6 \0"
     1285                    "*\0""udma7 \0"
     1286            };
     1287            print_flags(&ultra_modes2, id->dma_ultra);
    12151288        }
    12161289    }
     
    12301303     || (id->major_rev_num && id->minor_rev_num <= 31)
    12311304    ) {
    1232         printf("\n Drive conforms to: %s: ", (id->minor_rev_num <= 31) ? minor_str[id->minor_rev_num] : "Unknown");
    1233         if (id->major_rev_num != 0x0000 &&  /* NOVAL_0 */
    1234             id->major_rev_num != 0xFFFF) {  /* NOVAL_1 */
     1305        printf("\n Drive conforms to: %s: ",
     1306            (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
     1307        if (id->major_rev_num != 0x0000 /* NOVAL_0 */
     1308         && id->major_rev_num != 0xFFFF /* NOVAL_1 */
     1309        ) {
    12351310            for (i = 0; i <= 15; i++) {
    12361311                if (id->major_rev_num & (1<<i))
    1237                         printf(" ATA/ATAPI-%u", i);
     1312                    printf(" ATA/ATAPI-%u", i);
    12381313            }
    12391314        }
     
    12441319#endif
    12451320
    1246 static void flush_buffer_cache(int fd)
     1321static void flush_buffer_cache(/*int fd*/ void)
    12471322{
    12481323    fsync(fd);              /* flush buffers */
     
    12591334}
    12601335
    1261 static int seek_to_zero(int fd)
    1262 {
    1263     if (lseek(fd, (off_t) 0, SEEK_SET))
    1264         return 1;
    1265     return 0;
    1266 }
    1267 
    1268 static int read_big_block(int fd, char *buf)
     1336static void seek_to_zero(/*int fd*/ void)
     1337{
     1338    xlseek(fd, (off_t) 0, SEEK_SET);
     1339}
     1340
     1341static void read_big_block(/*int fd,*/ char *buf)
    12691342{
    12701343    int i;
    12711344
    1272     i = read(fd, buf, TIMING_BUF_BYTES);
    1273     if (i != TIMING_BUF_BYTES) {
    1274         bb_error_msg("read(%d bytes) failed (rc=%d)", TIMING_BUF_BYTES, i);
    1275         return 1;
    1276     }
     1345    xread(fd, buf, TIMING_BUF_BYTES);
    12771346    /* access all sectors of buf to ensure the read fully completed */
    12781347    for (i = 0; i < TIMING_BUF_BYTES; i += 512)
    12791348        buf[i] &= 1;
    1280     return 0;
    1281 }
    1282 
    1283 static int do_blkgetsize(int fd, unsigned long long *blksize64)
    1284 {
    1285     int rc;
    1286     unsigned blksize32 = 0;
    1287 
    1288     if (0 == ioctl(fd, BLKGETSIZE64, blksize64)) {  // returns bytes
    1289         *blksize64 /= 512;
    1290         return 0;
    1291     }
    1292     rc = ioctl_or_warn(fd, BLKGETSIZE, &blksize32); // returns sectors
    1293     *blksize64 = blksize32;
    1294     return rc;
    1295 }
    1296 
    1297 static void print_timing(unsigned t, double e)
    1298 {
    1299     if (t >= e)  /* more than 1MB/s */
    1300         printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e, 'M');
    1301     else
    1302         printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e * 1024, 'k');
    1303 }
    1304 
    1305 static void do_time(int flag, int fd)
    1306 /* flag = 0 time_cache, 1 time_device */
    1307 {
    1308     static const struct itimerval thousand = {{1000, 0}, {1000, 0}};
    1309 
    1310     struct itimerval itv;
     1349}
     1350
     1351static unsigned dev_size_mb(/*int fd*/ void)
     1352{
     1353    union {
     1354        unsigned long long blksize64;
     1355        unsigned blksize32;
     1356    } u;
     1357
     1358    if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
     1359        u.blksize64 /= (1024 * 1024);
     1360    } else {
     1361        xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
     1362        u.blksize64 = u.blksize32 / (2 * 1024);
     1363    }
     1364    if (u.blksize64 > UINT_MAX)
     1365        return UINT_MAX;
     1366    return u.blksize64;
     1367}
     1368
     1369static void print_timing(unsigned m, unsigned elapsed_us)
     1370{
     1371    unsigned sec = elapsed_us / 1000000;
     1372    unsigned hs = (elapsed_us % 1000000) / 10000;
     1373
     1374    printf("%5u MB in %u.%02u seconds = %u kB/s\n",
     1375        m, sec, hs,
     1376        /* "| 1" prevents div-by-0 */
     1377        (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
     1378        // ~= (m * 1024) / (elapsed_us / 1000000)
     1379        // = kb / elapsed_sec
     1380    );
     1381}
     1382
     1383static void do_time(int cache /*,int fd*/)
     1384/* cache=1: time cache: repeatedly read N MB at offset 0
     1385 * cache=0: time device: linear read, starting at offset 0
     1386 */
     1387{
     1388    unsigned max_iterations, iterations;
     1389    unsigned start; /* doesn't need to be long long */
    13111390    unsigned elapsed, elapsed2;
    1312     unsigned max_iterations, total_MB, iterations;
    1313     unsigned long long blksize;
    1314     RESERVE_CONFIG_BUFFER(buf, TIMING_BUF_BYTES);
    1315 
    1316     if (mlock(buf, TIMING_BUF_BYTES)) {
    1317         bb_perror_msg("mlock");
    1318         goto quit2;
    1319     }
    1320 
    1321     max_iterations = 1024;
    1322     if (0 == do_blkgetsize(fd, &blksize)) {
    1323         max_iterations = blksize / (2 * 1024) / TIMING_BUF_MB;
    1324     }
    1325 
    1326     /* Clear out the device request queues & give them time to complete */
     1391    unsigned total_MB;
     1392    char *buf = xmalloc(TIMING_BUF_BYTES);
     1393
     1394    if (mlock(buf, TIMING_BUF_BYTES))
     1395        bb_perror_msg_and_die("mlock");
     1396
     1397    /* Clear out the device request queues & give them time to complete.
     1398     * NB: *small* delay. User is expected to have a clue and to not run
     1399     * heavy io in parallel with measurements. */
    13271400    sync();
    1328     sleep(2);
    1329     if (flag == 0) { /* Time cache */
    1330         if (seek_to_zero(fd))
    1331             goto quit;
    1332         if (read_big_block(fd, buf))
    1333             goto quit;
    1334         printf(" Timing buffer-cache reads:  ");
     1401    sleep(1);
     1402    if (cache) { /* Time cache */
     1403        seek_to_zero();
     1404        read_big_block(buf);
     1405        printf("Timing buffer-cache reads: ");
    13351406    } else { /* Time device */
    1336         printf(" Timing buffered disk reads: ");
    1337     }
    1338     fflush(stdout);
     1407        printf("Timing buffered disk reads:");
     1408    }
     1409    fflush_all();
     1410
     1411    /* Now do the timing */
    13391412    iterations = 0;
    1340     /*
    1341      * getitimer() is used rather than gettimeofday() because
    1342      * it is much more consistent (on my machine, at least).
    1343      */
    1344     setitimer(ITIMER_REAL, &thousand, NULL);
    1345     /* Now do the timing */
     1413    /* Max time to run (small for cache, avoids getting
     1414     * huge total_MB which can overlow unsigned type) */
     1415    elapsed2 = 510000; /* cache */
     1416    max_iterations = UINT_MAX;
     1417    if (!cache) {
     1418        elapsed2 = 3000000; /* not cache */
     1419        /* Don't want to read past the end! */
     1420        max_iterations = dev_size_mb() / TIMING_BUF_MB;
     1421    }
     1422    start = monotonic_us();
    13461423    do {
     1424        if (cache)
     1425            seek_to_zero();
     1426        read_big_block(buf);
     1427        elapsed = (unsigned)monotonic_us() - start;
    13471428        ++iterations;
    1348         if ((flag == 0) && seek_to_zero(fd))
    1349             goto quit;
    1350         if (read_big_block(fd, buf))
    1351             goto quit;
    1352         getitimer(ITIMER_REAL, &itv);
    1353         elapsed = (1000 - itv.it_value.tv_sec) * 1000000
    1354                 - itv.it_value.tv_usec;
    1355     } while (elapsed < 3000000 && iterations < max_iterations);
     1429    } while (elapsed < elapsed2 && iterations < max_iterations);
    13561430    total_MB = iterations * TIMING_BUF_MB;
    1357     if (flag == 0) {
    1358         /* Now remove the lseek() and getitimer() overheads from the elapsed time */
    1359         setitimer(ITIMER_REAL, &thousand, NULL);
     1431    //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
     1432    if (cache) {
     1433        /* Cache: remove lseek() and monotonic_us() overheads
     1434         * from elapsed */
     1435        start = monotonic_us();
    13601436        do {
    1361             if (seek_to_zero(fd))
    1362                 goto quit;
    1363             getitimer(ITIMER_REAL, &itv);
    1364             elapsed2 = (1000 - itv.it_value.tv_sec) * 1000000
    1365                     - itv.it_value.tv_usec;
     1437            seek_to_zero();
     1438            elapsed2 = (unsigned)monotonic_us() - start;
    13661439        } while (--iterations);
     1440        //printf(" elapsed2:%u ", elapsed2);
    13671441        elapsed -= elapsed2;
    1368         total_MB *= BUFCACHE_FACTOR;
    1369         flush_buffer_cache(fd);
    1370     }
    1371     print_timing(total_MB, elapsed / 1000000.0);
    1372  quit:
     1442        total_MB *= 2; // BUFCACHE_FACTOR (why?)
     1443        flush_buffer_cache();
     1444    }
     1445    print_timing(total_MB, elapsed);
    13731446    munlock(buf, TIMING_BUF_BYTES);
    1374  quit2:
    1375     RELEASE_CONFIG_BUFFER(buf);
     1447    free(buf);
    13761448}
    13771449
     
    13911463
    13921464#ifdef HDIO_DRIVE_CMD
    1393 static void interpret_standby(unsigned standby)
    1394 {
    1395     unsigned t;
    1396 
     1465static void interpret_standby(uint8_t standby)
     1466{
    13971467    printf(" (");
    1398     if (standby == 0)
     1468    if (standby == 0) {
    13991469        printf("off");
    1400     else if (standby == 252)
    1401         printf("21 minutes");
    1402     else if (standby == 253)
     1470    } else if (standby <= 240 || standby == 252 || standby == 255) {
     1471        /* standby is in 5 sec units */
     1472        unsigned t = standby * 5;
     1473        printf("%u minutes %u seconds", t / 60, t % 60);
     1474    } else if (standby <= 251) {
     1475        unsigned t = (standby - 240); /* t is in 30 min units */;
     1476        printf("%u.%c hours", t / 2, (t & 1) ? '5' : '0');
     1477    }
     1478    if (standby == 253)
    14031479        printf("vendor-specific");
    1404     else if (standby == 254)
    1405         printf("Reserved");
    1406     else if (standby == 255)
    1407         printf("21 minutes + 15 seconds");
    1408     else if (standby <= 240) {
    1409         t = standby * 5;
    1410         printf("%u minutes + %u seconds", t / 60, t % 60);
    1411     } else if (standby <= 251) {
    1412         t = (standby - 240) * 30;
    1413         printf("%u hours + %u minutes", t / 60, t % 60);
    1414     } else
    1415         printf("illegal value");
     1480    if (standby == 254)
     1481        printf("reserved");
    14161482    printf(")\n");
    14171483}
     
    14331499static int translate_xfermode(const char *name)
    14341500{
    1435     int val, i;
     1501    int val;
     1502    unsigned i;
    14361503
    14371504    for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
     
    14631530        printf("UltraDMA mode%u", xfermode - 64);
    14641531    else
    1465         printf("Unknown");
     1532        printf("unknown");
    14661533    printf(")\n");
    14671534}
     
    14761543static void process_dev(char *devname)
    14771544{
    1478     int fd;
     1545    /*int fd;*/
    14791546    long parm, multcount;
    14801547#ifndef HDIO_DRIVE_CMD
     
    14861553    const char *fmt = " %s\t= %2ld";
    14871554
    1488     fd = xopen(devname, O_RDONLY|O_NONBLOCK);
     1555    /*fd = xopen_nonblocking(devname);*/
     1556    xmove_fd(xopen_nonblocking(devname), fd);
    14891557    printf("\n%s:\n", devname);
    14901558
    1491     if (set_readahead) {
    1492         print_flag(get_readahead, "fs readahead", Xreadahead);
     1559    if (getset_readahead == IS_SET) {
     1560        print_flag(getset_readahead, "fs readahead", Xreadahead);
    14931561        ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
    14941562    }
     
    15001568#endif
    15011569#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
    1502     if (scan_hwif) {
     1570    if (scan_hwif == IS_SET) {
    15031571        printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
    15041572        args[0] = hwif_data;
     
    15241592        ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
    15251593    }
    1526     if (set_io32bit) {
    1527         print_flag(get_io32bit, "32-bit IO_support flag", io32bit);
     1594    if (getset_io32bit == IS_SET) {
     1595        print_flag(getset_io32bit, "32-bit IO_support flag", io32bit);
    15281596        ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
    15291597    }
    1530     if (set_mult) {
    1531         print_flag(get_mult, "multcount", mult);
     1598    if (getset_mult == IS_SET) {
     1599        print_flag(getset_mult, "multcount", mult);
    15321600#ifdef HDIO_DRIVE_CMD
    15331601        ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
     
    15361604#endif
    15371605    }
    1538     if (set_readonly) {
    1539         print_flag_on_off(get_readonly, "readonly", readonly);
     1606    if (getset_readonly == IS_SET) {
     1607        print_flag_on_off(getset_readonly, "readonly", readonly);
    15401608        ioctl_or_warn(fd, BLKROSET, &readonly);
    15411609    }
    1542     if (set_unmask) {
    1543         print_flag_on_off(get_unmask, "unmaskirq", unmask);
     1610    if (getset_unmask == IS_SET) {
     1611        print_flag_on_off(getset_unmask, "unmaskirq", unmask);
    15441612        ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
    15451613    }
    15461614#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
    1547     if (set_dma) {
    1548         print_flag_on_off(get_dma, "using_dma", dma);
     1615    if (getset_dma == IS_SET) {
     1616        print_flag_on_off(getset_dma, "using_dma", dma);
    15491617        ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
    15501618    }
    15511619#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
    1552     if (set_dma_q) {
    1553         print_flag_on_off(get_dma_q, "DMA queue_depth", dma_q);
     1620#ifdef HDIO_SET_QDMA
     1621    if (getset_dma_q == IS_SET) {
     1622        print_flag_on_off(getset_dma_q, "DMA queue_depth", dma_q);
    15541623        ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
    15551624    }
    1556     if (set_nowerr) {
    1557         print_flag_on_off(get_nowerr, "nowerr", nowerr);
     1625#endif
     1626    if (getset_nowerr == IS_SET) {
     1627        print_flag_on_off(getset_nowerr, "nowerr", nowerr);
    15581628        ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
    15591629    }
    1560     if (set_keep) {
    1561         print_flag_on_off(get_keep, "keep_settings", keep);
     1630    if (getset_keep == IS_SET) {
     1631        print_flag_on_off(getset_keep, "keep_settings", keep);
    15621632        ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
    15631633    }
    15641634#ifdef HDIO_DRIVE_CMD
    1565     if (set_doorlock) {
     1635    if (getset_doorlock == IS_SET) {
    15661636        args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
    15671637        args[2] = 0;
    1568         print_flag_on_off(get_doorlock, "drive doorlock", doorlock);
     1638        print_flag_on_off(getset_doorlock, "drive doorlock", doorlock);
    15691639        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    15701640        args[0] = WIN_SETFEATURES;
    15711641    }
    1572     if (set_dkeep) {
     1642    if (getset_dkeep == IS_SET) {
    15731643        /* lock/unlock the drive's "feature" settings */
    1574         print_flag_on_off(get_dkeep, "drive keep features", dkeep);
     1644        print_flag_on_off(getset_dkeep, "drive keep features", dkeep);
    15751645        args[2] = dkeep ? 0x66 : 0xcc;
    15761646        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    15771647    }
    1578     if (set_defects) {
     1648    if (getset_defects == IS_SET) {
    15791649        args[2] = defects ? 0x04 : 0x84;
    1580         print_flag(get_defects, "drive defect-mgmt", defects);
     1650        print_flag(getset_defects, "drive defect-mgmt", defects);
    15811651        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    15821652    }
    1583     if (set_prefetch) {
     1653    if (getset_prefetch == IS_SET) {
    15841654        args[1] = prefetch;
    15851655        args[2] = 0xab;
    1586         print_flag(get_prefetch, "drive prefetch", prefetch);
     1656        print_flag(getset_prefetch, "drive prefetch", prefetch);
    15871657        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    15881658        args[1] = 0;
     
    15911661        args[1] = xfermode_requested;
    15921662        args[2] = 3;
    1593         if (get_xfermode) {
    1594             print_flag(1, "xfermode", xfermode_requested);
    1595             interpret_xfermode(xfermode_requested);
    1596         }
     1663        print_flag(1, "xfermode", xfermode_requested);
     1664        interpret_xfermode(xfermode_requested);
    15971665        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    15981666        args[1] = 0;
    15991667    }
    1600     if (set_lookahead) {
     1668    if (getset_lookahead == IS_SET) {
    16011669        args[2] = lookahead ? 0xaa : 0x55;
    1602         print_flag_on_off(get_lookahead, "drive read-lookahead", lookahead);
     1670        print_flag_on_off(getset_lookahead, "drive read-lookahead", lookahead);
    16031671        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    16041672    }
    1605     if (set_apmmode) {
    1606         args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */; /* feature register */
     1673    if (getset_apmmode == IS_SET) {
     1674        /* feature register */
     1675        args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */;
    16071676        args[1] = apmmode; /* sector count register 1-255 */
    1608         if (get_apmmode)
    1609             printf(" setting APM level to %s 0x%02lX (%ld)\n", (apmmode == 255) ? "disabled" : "", apmmode, apmmode);
     1677        printf(" setting APM level to %s 0x%02lX (%ld)\n",
     1678            (apmmode == 255) ? "disabled" : "",
     1679            apmmode, apmmode);
    16101680        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    16111681        args[1] = 0;
    16121682    }
    1613     if (set_wcache) {
     1683    if (getset_wcache == IS_SET) {
    16141684#ifdef DO_FLUSHCACHE
    16151685#ifndef WIN_FLUSHCACHE
    16161686#define WIN_FLUSHCACHE 0xe7
    16171687#endif
    1618         static unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
    16191688#endif /* DO_FLUSHCACHE */
    16201689        args[2] = wcache ? 0x02 : 0x82;
    1621         print_flag_on_off(get_wcache, "drive write-caching", wcache);
     1690        print_flag_on_off(getset_wcache, "drive write-caching", wcache);
    16221691#ifdef DO_FLUSHCACHE
    16231692        if (!wcache)
     
    16421711#define WIN_STANDBYNOW2 0x94
    16431712#endif
    1644         if (get_standbynow) printf(" issuing standby command\n");
     1713        printf(" issuing standby command\n");
    16451714        args[0] = WIN_STANDBYNOW1;
    1646         ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
     1715        ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
    16471716    }
    16481717    if (set_sleepnow) {
     
    16531722#define WIN_SLEEPNOW2 0x99
    16541723#endif
    1655         if (get_sleepnow) printf(" issuing sleep command\n");
     1724        printf(" issuing sleep command\n");
    16561725        args[0] = WIN_SLEEPNOW1;
    1657         ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
     1726        ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
    16581727    }
    16591728    if (set_seagate) {
    16601729        args[0] = 0xfb;
    1661         if (get_seagate) printf(" disabling Seagate auto powersaving mode\n");
     1730        printf(" disabling Seagate auto powersaving mode\n");
    16621731        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    16631732    }
    1664     if (set_standby) {
     1733    if (getset_standby == IS_SET) {
    16651734        args[0] = WIN_SETIDLE1;
    16661735        args[1] = standby_requested;
    1667         if (get_standby) {
    1668             print_flag(1, "standby", standby_requested);
    1669             interpret_standby(standby_requested);
    1670         }
     1736        print_flag(1, "standby", standby_requested);
     1737        interpret_standby(standby_requested);
    16711738        ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
    16721739        args[1] = 0;
     
    16751742    if (force_operation) {
    16761743        char buf[512];
    1677         flush_buffer_cache(fd);
     1744        flush_buffer_cache();
    16781745        if (-1 == read(fd, buf, sizeof(buf)))
    1679             bb_perror_msg("read(%d bytes) failed (rc=%d)", sizeof(buf), -1);
    1680     }
    1681 #endif  /* HDIO_DRIVE_CMD */
    1682 
    1683     if (get_mult || get_identity) {
     1746            bb_perror_msg("read of 512 bytes failed");
     1747    }
     1748#endif  /* HDIO_DRIVE_CMD */
     1749    if (getset_mult || get_identity) {
    16841750        multcount = -1;
    16851751        if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
    1686             if (get_mult && ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn. */
     1752            /* To be coherent with ioctl_or_warn. */
     1753            if (getset_mult && ENABLE_IOCTL_HEX2STR_ERROR)
    16871754                bb_perror_msg("HDIO_GET_MULTCOUNT");
    16881755            else
    16891756                bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
    1690         } else if (get_mult) {
     1757        } else if (getset_mult) {
    16911758            printf(fmt, "multcount", multcount);
    16921759            on_off(multcount != 0);
    16931760        }
    16941761    }
    1695     if (get_io32bit) {
     1762    if (getset_io32bit) {
    16961763        if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
    16971764            printf(" IO_support\t=%3ld (", parm);
     
    17101777        }
    17111778    }
    1712     if (get_unmask) {
    1713         if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, (unsigned long *)parm))
     1779    if (getset_unmask) {
     1780        if (!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
    17141781            print_value_on_off("unmaskirq", parm);
    17151782    }
    1716 
    1717 
    17181783#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
    1719     if (get_dma) {
     1784    if (getset_dma) {
    17201785        if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
    17211786            printf(fmt, "using_dma", parm);
     
    17271792    }
    17281793#endif
    1729     if (get_dma_q) {
    1730         if(!ioctl_or_warn(fd, HDIO_GET_QDMA, (unsigned long *)parm))
     1794#ifdef HDIO_GET_QDMA
     1795    if (getset_dma_q) {
     1796        if (!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
    17311797            print_value_on_off("queue_depth", parm);
    17321798    }
    1733     if (get_keep) {
    1734         if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, (unsigned long *)parm))
     1799#endif
     1800    if (getset_keep) {
     1801        if (!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
    17351802            print_value_on_off("keepsettings", parm);
    17361803    }
    1737 
    1738     if (get_nowerr) {
    1739         if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, (unsigned long *)parm))
     1804    if (getset_nowerr) {
     1805        if (!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
    17401806            print_value_on_off("nowerr", parm);
    17411807    }
    1742     if (get_readonly) {
    1743         if(!ioctl_or_warn(fd, BLKROGET, (unsigned long *)parm))
     1808    if (getset_readonly) {
     1809        if (!ioctl_or_warn(fd, BLKROGET, &parm))
    17441810            print_value_on_off("readonly", parm);
    17451811    }
    1746     if (get_readahead) {
    1747         if(!ioctl_or_warn(fd, BLKRAGET, (unsigned long *)parm))
     1812    if (getset_readahead) {
     1813        if (!ioctl_or_warn(fd, BLKRAGET, &parm))
    17481814            print_value_on_off("readahead", parm);
    17491815    }
     
    17541820            if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
    17551821                printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
    1756                         g.cylinders, g.heads, g.sectors, parm, g.start);
     1822                    g.cylinders, g.heads, g.sectors, parm, g.start);
    17571823        }
    17581824    }
     
    17681834
    17691835        args[0] = WIN_CHECKPOWERMODE1;
    1770         if (ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
     1836        if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
    17711837            if (errno != EIO || args[0] != 0 || args[1] != 0)
    17721838                state = "unknown";
     
    18171883        args1[0] = WIN_IDENTIFY;
    18181884        args1[3] = 1;
    1819         if (!ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
     1885        if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
    18201886            identify((void *)(args1 + 4));
    18211887    }
    18221888#endif
    18231889#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
    1824     if (set_busstate) {
    1825         if (get_busstate) {
    1826             print_flag(1, "bus state", busstate);
    1827             bus_state_value(busstate);
    1828         }
     1890    if (getset_busstate == IS_SET) {
     1891        print_flag(1, "bus state", busstate);
     1892        bus_state_value(busstate);
    18291893        ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
    18301894    }
    1831     if (get_busstate) {
     1895    if (getset_busstate) {
    18321896        if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
    18331897            printf(fmt, "bus state", parm);
     
    18401904
    18411905    if (do_ctimings)
    1842         do_time(0, fd); /* time cache */
     1906        do_time(1 /*,fd*/); /* time cache */
    18431907    if (do_timings)
    1844         do_time(1, fd); /* time device */
     1908        do_time(0 /*,fd*/); /* time device */
    18451909    if (do_flush)
    1846         flush_buffer_cache(fd);
     1910        flush_buffer_cache();
    18471911    close(fd);
    18481912}
     
    18581922}
    18591923
     1924static void identify_from_stdin(void) NORETURN;
    18601925static void identify_from_stdin(void)
    18611926{
     
    18651930    int i;
    18661931
    1867     xread(0, buf, 1280);
     1932    xread(STDIN_FILENO, buf, 1280);
    18681933
    18691934    // Convert the newline-separated hex data into an identify block.
     
    18791944    identify(sbuf);
    18801945}
     1946#else
     1947void identify_from_stdin(void);
    18811948#endif
    18821949
    18831950/* busybox specific stuff */
    1884 static void parse_opts(smallint *get, smallint *set, unsigned long *value, int min, int max)
    1885 {
    1886     if (get) {
    1887         *get = 1;
    1888     }
     1951static int parse_opts(unsigned long *value, int min, int max)
     1952{
    18891953    if (optarg) {
    1890         *set = 1;
    18911954        *value = xatol_range(optarg, min, max);
    1892     }
     1955        return IS_SET;
     1956    }
     1957    return IS_GET;
     1958}
     1959static int parse_opts_0_max(unsigned long *value, int max)
     1960{
     1961    return parse_opts(value, 0, max);
     1962}
     1963static int parse_opts_0_1(unsigned long *value)
     1964{
     1965    return parse_opts(value, 0, 1);
     1966}
     1967static int parse_opts_0_INTMAX(unsigned long *value)
     1968{
     1969    return parse_opts(value, 0, INT_MAX);
    18931970}
    18941971
     
    18961973{
    18971974    if (flag) {
    1898         *get = 1;
     1975        *get = IS_GET;
    18991976        if (optarg) {
    19001977            *value = translate_xfermode(optarg);
     
    19061983/*------- getopt short options --------*/
    19071984static const char hdparm_options[] ALIGN1 =
    1908     "gfu::n::p:r::m::c::k::a::B:tTh"
    1909     USE_FEATURE_HDPARM_GET_IDENTITY("iI")
    1910     USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
     1985    "gfu::n::p:r::m::c::k::a::B:tT"
     1986    IF_FEATURE_HDPARM_GET_IDENTITY("iI")
     1987    IF_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
    19111988#ifdef HDIO_DRIVE_CMD
    19121989    "S:D:P:X:K:A:L:W:CyYzZ"
    19131990#endif
    1914     USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
     1991    IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
    19151992#ifdef HDIO_GET_QDMA
    19161993#ifdef HDIO_SET_QDMA
     
    19201997#endif
    19211998#endif
    1922     USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
    1923     USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
    1924     USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
     1999    IF_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
     2000    IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
     2001    IF_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
    19252002/*-------------------------------------*/
    19262003
    19272004/* our main() routine: */
    1928 int hdparm_main(int argc, char **argv);
     2005int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    19292006int hdparm_main(int argc, char **argv)
    19302007{
     
    19342011    while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
    19352012        flagcount++;
    1936         if (c == 'h') bb_show_usage(); /* EXIT */
    1937         USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
    1938         USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
     2013        IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
     2014        IF_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
    19392015        get_geom |= (c == 'g');
    19402016        do_flush |= (c == 'f');
    1941         if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
    1942         USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
    1943         if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
     2017        if (c == 'u') getset_unmask    = parse_opts_0_1(&unmask);
     2018    IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
     2019        if (c == 'd') getset_dma       = parse_opts_0_max(&dma, 9);
     2020    )
     2021        if (c == 'n') getset_nowerr    = parse_opts_0_1(&nowerr);
    19442022        parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
    1945         if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
    1946         if (c == 'm') parse_opts(&get_mult, &set_mult, &mult, 0, INT_MAX /*32*/);
    1947         if (c == 'c') parse_opts(&get_io32bit, &set_io32bit, &io32bit, 0, INT_MAX /*8*/);
    1948         if (c == 'k') parse_opts(&get_keep, &set_keep, &keep, 0, 1);
    1949         if (c == 'a') parse_opts(&get_readahead, &set_readahead, &Xreadahead, 0, INT_MAX);
    1950         if (c == 'B') parse_opts(&get_apmmode, &set_apmmode, &apmmode, 1, 255);
     2023        if (c == 'r') getset_readonly  = parse_opts_0_1(&readonly);
     2024        if (c == 'm') getset_mult      = parse_opts_0_INTMAX(&mult /*32*/);
     2025        if (c == 'c') getset_io32bit   = parse_opts_0_INTMAX(&io32bit /*8*/);
     2026        if (c == 'k') getset_keep      = parse_opts_0_1(&keep);
     2027        if (c == 'a') getset_readahead = parse_opts_0_INTMAX(&Xreadahead);
     2028        if (c == 'B') getset_apmmode   = parse_opts(&apmmode, 1, 255);
    19512029        do_flush |= do_timings |= (c == 't');
    19522030        do_flush |= do_ctimings |= (c == 'T');
    19532031#ifdef HDIO_DRIVE_CMD
    1954         if (c == 'S') parse_opts(&get_standby, &set_standby, &standby_requested, 0, INT_MAX);
    1955         if (c == 'D') parse_opts(&get_defects, &set_defects, &defects, 0, INT_MAX);
    1956         if (c == 'P') parse_opts(&get_prefetch, &set_prefetch, &prefetch, 0, INT_MAX);
     2032        if (c == 'S') getset_standby  = parse_opts_0_max(&standby_requested, 255);
     2033        if (c == 'D') getset_defects  = parse_opts_0_INTMAX(&defects);
     2034        if (c == 'P') getset_prefetch = parse_opts_0_INTMAX(&prefetch);
    19572035        parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
    1958         if (c == 'K') parse_opts(&get_dkeep, &set_dkeep, &prefetch, 0, 1);
    1959         if (c == 'A') parse_opts(&get_lookahead, &set_lookahead, &lookahead, 0, 1);
    1960         if (c == 'L') parse_opts(&get_doorlock, &set_doorlock, &doorlock, 0, 1);
    1961         if (c == 'W') parse_opts(&get_wcache, &set_wcache, &wcache, 0, 1);
     2036        if (c == 'K') getset_dkeep     = parse_opts_0_1(&prefetch);
     2037        if (c == 'A') getset_lookahead = parse_opts_0_1(&lookahead);
     2038        if (c == 'L') getset_doorlock  = parse_opts_0_1(&doorlock);
     2039        if (c == 'W') getset_wcache    = parse_opts_0_1(&wcache);
    19622040        get_powermode |= (c == 'C');
    1963         get_standbynow = set_standbynow |= (c == 'y');
    1964         get_sleepnow = set_sleepnow |= (c == 'Y');
     2041        set_standbynow |= (c == 'y');
     2042        set_sleepnow |= (c == 'Y');
    19652043        reread_partn |= (c == 'z');
    1966         get_seagate = set_seagate |= (c == 'Z');
    1967 #endif
    1968         USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
     2044        set_seagate |= (c == 'Z');
     2045#endif
     2046        IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') unregister_hwif = parse_opts_0_INTMAX(&hwif));
    19692047#ifdef HDIO_GET_QDMA
    19702048        if (c == 'Q') {
    1971 #ifdef HDIO_SET_QDMA
    1972             parse_opts(&get_dma_q, &set_dma_q, &dma_q, 0, INT_MAX);
    1973 #else
    1974             parse_opts(&get_dma_q, NULL, NULL, 0, 0);
    1975 #endif
    1976         }
    1977 #endif
    1978         USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
    1979         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
    1980         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
     2049            getset_dma_q = parse_opts_0_INTMAX(&dma_q);
     2050        }
     2051#endif
     2052        IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
     2053        IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') perform_tristate = parse_opts_0_1(&tristate));
     2054        IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') getset_busstate = parse_opts_0_max(&busstate, 2));
    19812055#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
    19822056        if (c == 'R') {
    1983             parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
    1984             hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
    1985             hwif_irq  = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
     2057            scan_hwif = parse_opts_0_INTMAX(&hwif_data);
     2058            hwif_ctrl = xatoi_positive((argv[optind]) ? argv[optind] : "");
     2059            hwif_irq  = xatoi_positive((argv[optind+1]) ? argv[optind+1] : "");
    19862060            /* Move past the 2 additional arguments */
    19872061            argv += 2;
     
    19922066    /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
    19932067    if (!flagcount) {
    1994         get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
    1995         USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
     2068        getset_mult = getset_io32bit = getset_unmask = getset_keep = getset_readonly = getset_readahead = get_geom = IS_GET;
     2069        IF_FEATURE_HDPARM_HDIO_GETSET_DMA(getset_dma = IS_GET);
    19962070    }
    19972071    argv += optind;
     
    20002074        if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
    20012075            identify_from_stdin(); /* EXIT */
    2002         else bb_show_usage();
     2076        bb_show_usage();
    20032077    }
    20042078
  • branches/2.2.9/mindi-busybox/miscutils/last.c

    r1765 r2725  
    55 * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org>
    66 *
    7  * Licensed under the GPL version 2, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    99
     
    1111#include <utmp.h>
    1212
     13/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
     14 * to reduce confusion */
     15
    1316#ifndef SHUTDOWN_TIME
    1417#  define SHUTDOWN_TIME 254
    1518#endif
    1619
    17 /* Grr... utmp char[] members  do not have to be nul-terminated.
     20/* Grr... utmp char[] members do not have to be nul-terminated.
    1821 * Do what we can while still keeping this reasonably small.
    1922 * Note: We are assuming the ut_id[] size is fixed at 4. */
     
    2730#endif
    2831
    29 int last_main(int argc, char **argv);
    30 int last_main(int argc, char **argv)
     32#if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \
     33    OLD_TIME != 4
     34#error Values for the ut_type field of struct utmp changed
     35#endif
     36
     37int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     38int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    3139{
    3240    struct utmp ut;
    3341    int n, file = STDIN_FILENO;
    3442    time_t t_tmp;
     43    off_t pos;
     44    static const char _ut_usr[] ALIGN1 =
     45            "runlevel\0" "reboot\0" "shutdown\0";
     46    static const char _ut_lin[] ALIGN1 =
     47            "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */;
     48    enum {
     49        TYPE_RUN_LVL = RUN_LVL,         /* 1 */
     50        TYPE_BOOT_TIME = BOOT_TIME,     /* 2 */
     51        TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME
     52    };
     53    enum {
     54        _TILDE = EMPTY, /* 0 */
     55        TYPE_NEW_TIME,  /* NEW_TIME, 3 */
     56        TYPE_OLD_TIME   /* OLD_TIME, 4 */
     57    };
    3558
    36     if (argc > 1) {
     59    if (argv[1]) {
    3760        bb_show_usage();
    3861    }
    3962    file = xopen(bb_path_wtmp_file, O_RDONLY);
    4063
    41     printf("%-10s %-14s %-18s %-12.12s %s\n", "USER", "TTY", "HOST", "LOGIN", "TIME");
    42     while ((n = safe_read(file, (void*)&ut, sizeof(struct utmp))) != 0) {
    43 
    44         if (n != sizeof(struct utmp)) {
     64    printf("%-10s %-14s %-18s %-12.12s %s\n",
     65           "USER", "TTY", "HOST", "LOGIN", "TIME");
     66    /* yikes. We reverse over the file and that is a not too elegant way */
     67    pos = xlseek(file, 0, SEEK_END);
     68    pos = lseek(file, pos - sizeof(ut), SEEK_SET);
     69    while ((n = full_read(file, &ut, sizeof(ut))) > 0) {
     70        if (n != sizeof(ut)) {
    4571            bb_perror_msg_and_die("short read");
    4672        }
    47 
    48         if (ut.ut_line[0] == '~') {
     73        n = index_in_strings(_ut_lin, ut.ut_line);
     74        if (n == _TILDE) { /* '~' */
     75#if 1
     76/* do we really need to be cautious here? */
     77            n = index_in_strings(_ut_usr, ut.ut_user);
     78            if (++n > 0)
     79                ut.ut_type = n != 3 ? n : SHUTDOWN_TIME;
     80#else
    4981            if (strncmp(ut.ut_user, "shutdown", 8) == 0)
    5082                ut.ut_type = SHUTDOWN_TIME;
    5183            else if (strncmp(ut.ut_user, "reboot", 6) == 0)
    5284                ut.ut_type = BOOT_TIME;
    53             else if (strncmp(ut.ut_user, "runlevel", 7) == 0)
     85            else if (strncmp(ut.ut_user, "runlevel", 8) == 0)
    5486                ut.ut_type = RUN_LVL;
     87#endif
    5588        } else {
    56             if (!ut.ut_name[0] || strcmp(ut.ut_name, "LOGIN") == 0 ||
    57                     ut.ut_name[0] == 0)
    58             {
     89            if (ut.ut_user[0] == '\0' || strcmp(ut.ut_user, "LOGIN") == 0) {
    5990                /* Don't bother.  This means we can't find how long
    6091                 * someone was logged in for.  Oh well. */
    61                 continue;
     92                goto next;
    6293            }
    63             if (ut.ut_type != DEAD_PROCESS &&
    64                     ut.ut_name[0] && ut.ut_line[0])
    65             {
     94            if (ut.ut_type != DEAD_PROCESS
     95             && ut.ut_user[0]
     96             && ut.ut_line[0]
     97            ) {
    6698                ut.ut_type = USER_PROCESS;
    6799            }
    68             if (strcmp(ut.ut_name, "date") == 0) {
    69                 if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
    70                 if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
     100            if (strcmp(ut.ut_user, "date") == 0) {
     101                if (n == TYPE_OLD_TIME) { /* '|' */
     102                    ut.ut_type = OLD_TIME;
     103                }
     104                if (n == TYPE_NEW_TIME) { /* '{' */
     105                    ut.ut_type = NEW_TIME;
     106                }
    71107            }
    72108        }
    73109
    74         if (ut.ut_type!=USER_PROCESS) {
     110        if (ut.ut_type != USER_PROCESS) {
    75111            switch (ut.ut_type) {
    76112                case OLD_TIME:
     
    78114                case RUN_LVL:
    79115                case SHUTDOWN_TIME:
    80                     continue;
     116                    goto next;
    81117                case BOOT_TIME:
    82118                    strcpy(ut.ut_line, "system boot");
    83                     break;
    84119            }
    85120        }
     121        /* manpages say ut_tv.tv_sec *is* time_t,
     122         * but some systems have it wrong */
    86123        t_tmp = (time_t)ut.ut_tv.tv_sec;
    87         printf("%-10s %-14s %-18s %-12.12s\n", ut.ut_user, ut.ut_line, ut.ut_host,
    88                 ctime(&t_tmp) + 4);
     124        printf("%-10s %-14s %-18s %-12.12s\n",
     125               ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4);
     126 next:
     127        pos -= sizeof(ut);
     128        if (pos <= 0)
     129            break; /* done. */
     130        xlseek(file, pos, SEEK_SET);
    89131    }
    90132
  • branches/2.2.9/mindi-busybox/miscutils/less.c

    r1765 r2725  
    55 * Copyright (C) 2005 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
    66 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    2222 */
    2323
    24 #include <sched.h>  /* sched_yield() */
     24#include <sched.h>  /* sched_yield() */
    2525
    2626#include "libbb.h"
     
    2929#endif
    3030
    31 /* FIXME: currently doesn't work right */
    32 #undef ENABLE_FEATURE_LESS_FLAGCS
    33 #define ENABLE_FEATURE_LESS_FLAGCS 0
    34 
     31
     32#define ESC "\033"
    3533/* The escape codes for highlighted and normal text */
    36 #define HIGHLIGHT "\033[7m"
    37 #define NORMAL "\033[0m"
    38 /* The escape code to clear the screen */
    39 #define CLEAR "\033[H\033[J"
    40 /* The escape code to clear to end of line */
    41 #define CLEAR_2_EOL "\033[K"
    42 
    43 /* These are the escape sequences corresponding to special keys */
     34#define HIGHLIGHT   ESC"[7m"
     35#define NORMAL      ESC"[0m"
     36/* The escape code to home and clear to the end of screen */
     37#define CLEAR       ESC"[H\033[J"
     38/* The escape code to clear to the end of line */
     39#define CLEAR_2_EOL ESC"[K"
     40
    4441enum {
    45     REAL_KEY_UP = 'A',
    46     REAL_KEY_DOWN = 'B',
    47     REAL_KEY_RIGHT = 'C',
    48     REAL_KEY_LEFT = 'D',
    49     REAL_PAGE_UP = '5',
    50     REAL_PAGE_DOWN = '6',
    51     REAL_KEY_HOME = '7', // vt100? linux vt? or what?
    52     REAL_KEY_END = '8',
    53     REAL_KEY_HOME_ALT = '1', // ESC [1~ (vt100? linux vt? or what?)
    54     REAL_KEY_END_ALT = '4', // ESC [4~
    55     REAL_KEY_HOME_XTERM = 'H',
    56     REAL_KEY_END_XTERM = 'F',
    57 
    58 /* These are the special codes assigned by this program to the special keys */
    59     KEY_UP = 20,
    60     KEY_DOWN = 21,
    61     KEY_RIGHT = 22,
    62     KEY_LEFT = 23,
    63     PAGE_UP = 24,
    64     PAGE_DOWN = 25,
    65     KEY_HOME = 26,
    66     KEY_END = 27,
    67 
    6842/* Absolute max of lines eaten */
    6943    MAXLINES = CONFIG_FEATURE_LESS_MAXLINES,
    70 
    7144/* This many "after the end" lines we will show (at max) */
    7245    TILDES = 1,
     
    7548/* Command line options */
    7649enum {
    77     FLAG_E = 1,
     50    FLAG_E = 1 << 0,
    7851    FLAG_M = 1 << 1,
    7952    FLAG_m = 1 << 2,
    8053    FLAG_N = 1 << 3,
    8154    FLAG_TILDE = 1 << 4,
     55    FLAG_I = 1 << 5,
     56    FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_DASHCMD,
    8257/* hijack command line options variable for internal state vars */
    8358    LESS_STATE_MATCH_BACKWARDS = 1 << 15,
     
    9166    int cur_fline; /* signed */
    9267    int kbd_fd;  /* fd to get input from */
     68    int less_gets_pos;
    9369/* last position in last line, taking into account tabs */
    94     size_t linepos;
    95     unsigned max_displayed_line;
     70    size_t last_line_pos;
    9671    unsigned max_fline;
    9772    unsigned max_lineno; /* this one tracks linewrap */
     73    unsigned max_displayed_line;
    9874    unsigned width;
     75#if ENABLE_FEATURE_LESS_WINCH
     76    unsigned winch_counter;
     77#endif
    9978    ssize_t eof_error; /* eof if 0, error if < 0 */
    100     size_t readpos;
    101     size_t readeof;
     79    ssize_t readpos;
     80    ssize_t readeof; /* must be signed */
    10281    const char **buffer;
    10382    const char **flines;
     
    11493    unsigned *match_lines;
    11594    int match_pos; /* signed! */
    116     unsigned num_matches;
     95    int wanted_match; /* signed! */
     96    int num_matches;
    11797    regex_t pattern;
    11898    smallint pattern_valid;
     
    120100    smallint terminated;
    121101    struct termios term_orig, term_less;
     102    char kbd_input[KEYCODE_BUFFER_SIZE];
    122103};
    123104#define G (*ptr_to_globals)
    124105#define cur_fline           (G.cur_fline         )
    125106#define kbd_fd              (G.kbd_fd            )
    126 #define linepos             (G.linepos           )
    127 #define max_displayed_line  (G.max_displayed_line)
     107#define less_gets_pos       (G.less_gets_pos     )
     108#define last_line_pos       (G.last_line_pos     )
    128109#define max_fline           (G.max_fline         )
    129110#define max_lineno          (G.max_lineno        )
     111#define max_displayed_line  (G.max_displayed_line)
    130112#define width               (G.width             )
     113#define winch_counter       (G.winch_counter     )
     114/* This one is 100% not cached by compiler on read access */
     115#define WINCH_COUNTER (*(volatile unsigned *)&winch_counter)
    131116#define eof_error           (G.eof_error         )
    132117#define readpos             (G.readpos           )
     
    145130#define match_pos           (G.match_pos         )
    146131#define num_matches         (G.num_matches       )
     132#define wanted_match        (G.wanted_match      )
    147133#define pattern             (G.pattern           )
    148134#define pattern_valid       (G.pattern_valid     )
     
    151137#define term_orig           (G.term_orig         )
    152138#define term_less           (G.term_less         )
     139#define kbd_input           (G.kbd_input         )
    153140#define INIT_G() do { \
    154         PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
    155         empty_line_marker = "~"; \
    156         num_files = 1; \
    157         current_file = 1; \
    158         eof_error = 1; \
    159         terminated = 1; \
    160     } while (0)
     141    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     142    less_gets_pos = -1; \
     143    empty_line_marker = "~"; \
     144    num_files = 1; \
     145    current_file = 1; \
     146    eof_error = 1; \
     147    terminated = 1; \
     148    IF_FEATURE_LESS_REGEXP(wanted_match = -1;) \
     149} while (0)
     150
     151/* flines[] are lines read from stdin, each in malloc'ed buffer.
     152 * Line numbers are stored as uint32_t prepended to each line.
     153 * Pointer is adjusted so that flines[i] points directly past
     154 * line number. Accesor: */
     155#define MEMPTR(p) ((char*)(p) - 4)
     156#define LINENO(p) (*(uint32_t*)((p) - 4))
     157
    161158
    162159/* Reset terminal input to normal */
    163160static void set_tty_cooked(void)
    164161{
    165     fflush(stdout);
     162    fflush_all();
    166163    tcsetattr(kbd_fd, TCSANOW, &term_orig);
    167 }
    168 
    169 /* Exit the program gracefully */
    170 static void less_exit(int code)
    171 {
    172     /* TODO: We really should save the terminal state when we start,
    173      * and restore it when we exit. Less does this with the
    174      * "ti" and "te" termcap commands; can this be done with
    175      * only termios.h? */
    176     putchar('\n');
    177     fflush_stdout_and_exit(code);
    178164}
    179165
     
    182168static void move_cursor(int line, int row)
    183169{
    184     printf("\033[%u;%uH", line, row);
     170    printf(ESC"[%u;%uH", line, row);
    185171}
    186172
    187173static void clear_line(void)
    188174{
    189     printf("\033[%u;0H" CLEAR_2_EOL, max_displayed_line + 2);
     175    printf(ESC"[%u;0H" CLEAR_2_EOL, max_displayed_line + 2);
    190176}
    191177
     
    200186    printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str);
    201187}
     188
     189/* Exit the program gracefully */
     190static void less_exit(int code)
     191{
     192    set_tty_cooked();
     193    clear_line();
     194    if (code < 0)
     195        kill_myself_with_sig(- code); /* does not return */
     196    exit(code);
     197}
     198
     199#if (ENABLE_FEATURE_LESS_DASHCMD && ENABLE_FEATURE_LESS_LINENUMS) \
     200 || ENABLE_FEATURE_LESS_WINCH
     201static void re_wrap(void)
     202{
     203    int w = width;
     204    int new_line_pos;
     205    int src_idx;
     206    int dst_idx;
     207    int new_cur_fline = 0;
     208    uint32_t lineno;
     209    char linebuf[w + 1];
     210    const char **old_flines = flines;
     211    const char *s;
     212    char **new_flines = NULL;
     213    char *d;
     214
     215    if (option_mask32 & FLAG_N)
     216        w -= 8;
     217
     218    src_idx = 0;
     219    dst_idx = 0;
     220    s = old_flines[0];
     221    lineno = LINENO(s);
     222    d = linebuf;
     223    new_line_pos = 0;
     224    while (1) {
     225        *d = *s;
     226        if (*d != '\0') {
     227            new_line_pos++;
     228            if (*d == '\t') /* tab */
     229                new_line_pos += 7;
     230            s++;
     231            d++;
     232            if (new_line_pos >= w) {
     233                int sz;
     234                /* new line is full, create next one */
     235                *d = '\0';
     236 next_new:
     237                sz = (d - linebuf) + 1; /* + 1: NUL */
     238                d = ((char*)xmalloc(sz + 4)) + 4;
     239                LINENO(d) = lineno;
     240                memcpy(d, linebuf, sz);
     241                new_flines = xrealloc_vector(new_flines, 8, dst_idx);
     242                new_flines[dst_idx] = d;
     243                dst_idx++;
     244                if (new_line_pos < w) {
     245                    /* if we came here thru "goto next_new" */
     246                    if (src_idx > max_fline)
     247                        break;
     248                    lineno = LINENO(s);
     249                }
     250                d = linebuf;
     251                new_line_pos = 0;
     252            }
     253            continue;
     254        }
     255        /* *d == NUL: old line ended, go to next old one */
     256        free(MEMPTR(old_flines[src_idx]));
     257        /* btw, convert cur_fline... */
     258        if (cur_fline == src_idx)
     259            new_cur_fline = dst_idx;
     260        src_idx++;
     261        /* no more lines? finish last new line (and exit the loop) */
     262        if (src_idx > max_fline)
     263            goto next_new;
     264        s = old_flines[src_idx];
     265        if (lineno != LINENO(s)) {
     266            /* this is not a continuation line!
     267             * create next _new_ line too */
     268            goto next_new;
     269        }
     270    }
     271
     272    free(old_flines);
     273    flines = (const char **)new_flines;
     274
     275    max_fline = dst_idx - 1;
     276    last_line_pos = new_line_pos;
     277    cur_fline = new_cur_fline;
     278    /* max_lineno is screen-size independent */
     279#if ENABLE_FEATURE_LESS_REGEXP
     280    pattern_valid = 0;
     281#endif
     282}
     283#endif
    202284
    203285#if ENABLE_FEATURE_LESS_REGEXP
     
    226308 * readbuf[0..readeof-1] - small preliminary buffer.
    227309 * readbuf[readpos] - next character to add to current line.
    228  * linepos - screen line position of next char to be read
     310 * last_line_pos - screen line position of next char to be read
    229311 *      (takes into account tabs and backspaces)
    230312 * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error
     
    234316#define readbuf bb_common_bufsiz1
    235317    char *current_line, *p;
    236     USE_FEATURE_LESS_REGEXP(unsigned old_max_fline = max_fline;)
    237318    int w = width;
    238319    char last_terminated = terminated;
     320#if ENABLE_FEATURE_LESS_REGEXP
     321    unsigned old_max_fline = max_fline;
     322    time_t last_time = 0;
     323    unsigned seconds_p1 = 3; /* seconds_to_loop + 1 */
     324#endif
    239325
    240326    if (option_mask32 & FLAG_N)
    241327        w -= 8;
    242328
    243     current_line = xmalloc(w);
    244     p = current_line;
     329 IF_FEATURE_LESS_REGEXP(again0:)
     330
     331    p = current_line = ((char*)xmalloc(w + 4)) + 4;
    245332    max_fline += last_terminated;
    246333    if (!last_terminated) {
    247334        const char *cp = flines[max_fline];
    248         if (option_mask32 & FLAG_N)
    249             cp += 8;
    250         strcpy(current_line, cp);
     335        strcpy(p, cp);
    251336        p += strlen(current_line);
    252         /* linepos is still valid from previous read_lines() */
     337        free(MEMPTR(flines[max_fline]));
     338        /* last_line_pos is still valid from previous read_lines() */
    253339    } else {
    254         linepos = 0;
    255     }
    256 
    257     while (1) {
    258  again:
     340        last_line_pos = 0;
     341    }
     342
     343    while (1) { /* read lines until we reach cur_fline or wanted_match */
    259344        *p = '\0';
    260345        terminated = 0;
    261         while (1) {
     346        while (1) { /* read chars until we have a line */
    262347            char c;
    263348            /* if no unprocessed chars left, eat more */
    264349            if (readpos >= readeof) {
    265                 smallint yielded = 0;
    266 
    267350                ndelay_on(0);
    268  read_again:
    269                 eof_error = safe_read(0, readbuf, sizeof(readbuf));
     351                eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf));
     352                ndelay_off(0);
    270353                readpos = 0;
    271354                readeof = eof_error;
    272                 if (eof_error < 0) {
    273                     if (errno == EAGAIN && !yielded) {
    274             /* We can hit EAGAIN while searching for regexp match.
    275              * Yield is not 100% reliable solution in general,
    276              * but for less it should be good enough -
    277              * we give stdin supplier some CPU time to produce
    278              * more input. We do it just once.
    279              * Currently, we do not stop when we found the Nth
    280              * occurrence we were looking for. We read till end
    281              * (or double EAGAIN). TODO? */
    282                         sched_yield();
    283                         yielded = 1;
    284                         goto read_again;
    285                     }
    286                     readeof = 0;
    287                     if (errno != EAGAIN)
    288                         print_statusline("read error");
    289                 }
    290                 ndelay_off(0);
    291 
    292                 if (eof_error <= 0) {
     355                if (eof_error <= 0)
    293356                    goto reached_eof;
    294                 }
    295357            }
    296358            c = readbuf[readpos];
     
    298360            /* <tab><bs> is (a) insane and */
    299361            /* (b) harder to do correctly, so we refuse to do it */
    300             if (c == '\x8' && linepos && p[-1] != '\t') {
     362            if (c == '\x8' && last_line_pos && p[-1] != '\t') {
    301363                readpos++; /* eat it */
    302                 linepos--;
     364                last_line_pos--;
    303365            /* was buggy (p could end up <= current_line)... */
    304366                *--p = '\0';
     
    306368            }
    307369            {
    308                 size_t new_linepos = linepos + 1;
     370                size_t new_last_line_pos = last_line_pos + 1;
    309371                if (c == '\t') {
    310                     new_linepos += 7;
    311                     new_linepos &= (~7);
     372                    new_last_line_pos += 7;
     373                    new_last_line_pos &= (~7);
    312374                }
    313                 if (new_linepos >= w)
     375                if ((int)new_last_line_pos >= w)
    314376                    break;
    315                 linepos = new_linepos;
     377                last_line_pos = new_last_line_pos;
    316378            }
    317379            /* ok, we will eat this char */
     
    319381            if (c == '\n') {
    320382                terminated = 1;
    321                 linepos = 0;
     383                last_line_pos = 0;
    322384                break;
    323385            }
     
    326388            *p++ = c;
    327389            *p = '\0';
    328         }
     390        } /* end of "read chars until we have a line" loop */
    329391        /* Corner case: linewrap with only "" wrapping to next line */
    330392        /* Looks ugly on screen, so we do not store this empty line */
     
    332394            last_terminated = 1;
    333395            max_lineno++;
    334             goto again;
     396            continue;
    335397        }
    336398 reached_eof:
    337399        last_terminated = terminated;
    338         flines = xrealloc(flines, (max_fline+1) * sizeof(char *));
    339         if (option_mask32 & FLAG_N) {
    340             /* Width of 7 preserves tab spacing in the text */
    341             flines[max_fline] = xasprintf(
    342                 (max_lineno <= 9999999) ? "%7u %s" : "%07u %s",
    343                 max_lineno % 10000000, current_line);
    344             free(current_line);
    345             if (terminated)
    346                 max_lineno++;
    347         } else {
    348             flines[max_fline] = xrealloc(current_line, strlen(current_line)+1);
    349         }
     400        flines = xrealloc_vector(flines, 8, max_fline);
     401
     402        flines[max_fline] = (char*)xrealloc(MEMPTR(current_line), strlen(current_line) + 1 + 4) + 4;
     403        LINENO(flines[max_fline]) = max_lineno;
     404        if (terminated)
     405            max_lineno++;
     406
    350407        if (max_fline >= MAXLINES) {
    351408            eof_error = 0; /* Pretend we saw EOF */
    352409            break;
    353410        }
    354         if (max_fline > cur_fline + max_displayed_line)
     411        if (!(option_mask32 & FLAG_S)
     412          ? (max_fline > cur_fline + max_displayed_line)
     413          : (max_fline >= cur_fline
     414             && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line)
     415        ) {
     416#if !ENABLE_FEATURE_LESS_REGEXP
    355417            break;
     418#else
     419            if (wanted_match >= num_matches) { /* goto_match called us */
     420                fill_match_lines(old_max_fline);
     421                old_max_fline = max_fline;
     422            }
     423            if (wanted_match < num_matches)
     424                break;
     425#endif
     426        }
    356427        if (eof_error <= 0) {
    357             if (eof_error < 0 && errno == EAGAIN) {
    358                 /* not yet eof or error, reset flag (or else
    359                  * we will hog CPU - select() will return
    360                  * immediately */
    361                 eof_error = 1;
     428            if (eof_error < 0) {
     429                if (errno == EAGAIN) {
     430                    /* not yet eof or error, reset flag (or else
     431                     * we will hog CPU - select() will return
     432                     * immediately */
     433                    eof_error = 1;
     434                } else {
     435                    print_statusline(bb_msg_read_error);
     436                }
    362437            }
     438#if !ENABLE_FEATURE_LESS_REGEXP
    363439            break;
     440#else
     441            if (wanted_match < num_matches) {
     442                break;
     443            } else { /* goto_match called us */
     444                time_t t = time(NULL);
     445                if (t != last_time) {
     446                    last_time = t;
     447                    if (--seconds_p1 == 0)
     448                        break;
     449                }
     450                sched_yield();
     451                goto again0; /* go loop again (max 2 seconds) */
     452            }
     453#endif
    364454        }
    365455        max_fline++;
    366         current_line = xmalloc(w);
     456        current_line = ((char*)xmalloc(w + 4)) + 4;
    367457        p = current_line;
    368         linepos = 0;
    369     }
     458        last_line_pos = 0;
     459    } /* end of "read lines until we reach cur_fline" loop */
    370460    fill_match_lines(old_max_fline);
     461#if ENABLE_FEATURE_LESS_REGEXP
     462    /* prevent us from being stuck in search for a match */
     463    wanted_match = -1;
     464#endif
    371465#undef readbuf
    372466}
     
    385479{
    386480    int percentage;
     481
     482    if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
     483        return;
    387484
    388485    clear_line();
     
    393490            cur_fline + 1, cur_fline + max_displayed_line + 1,
    394491            max_fline + 1);
    395     if (cur_fline >= max_fline - max_displayed_line) {
     492    if (cur_fline >= (int)(max_fline - max_displayed_line)) {
    396493        printf("(END)"NORMAL);
    397494        if (num_files > 1 && current_file != num_files)
     
    408505{
    409506    const char *p;
     507
     508    if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
     509        return;
    410510
    411511    /* Change the status if flags have been set */
     
    419519
    420520    clear_line();
    421     if (cur_fline && cur_fline < max_fline - max_displayed_line) {
    422         putchar(':');
     521    if (cur_fline && cur_fline < (int)(max_fline - max_displayed_line)) {
     522        bb_putchar(':');
    423523        return;
    424524    }
     
    445545        diff = max_fline - (cur_fline + max_displayed_line) + TILDES;
    446546        /* As the number of lines requested was too large, we just move
    447         to the end of the file */
     547         * to the end of the file */
    448548        if (diff > 0)
    449549            cur_fline += diff;
     
    457557    "\x7f\x9b"; /* DEL and infamous Meta-ESC :( */
    458558static const char ctrlconv[] ALIGN1 =
    459     /* '\n': it's a former NUL - subst with '@', not 'J' */
     559    /* why 40 instead of 4a below? - it is a replacement for '\n'.
     560     * '\n' is a former NUL - we subst it with @, not J */
    460561    "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x40\x4b\x4c\x4d\x4e\x4f"
    461562    "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f";
     563
     564static void lineno_str(char *nbuf9, const char *line)
     565{
     566    nbuf9[0] = '\0';
     567    if (option_mask32 & FLAG_N) {
     568        const char *fmt;
     569        unsigned n;
     570
     571        if (line == empty_line_marker) {
     572            memset(nbuf9, ' ', 8);
     573            nbuf9[8] = '\0';
     574            return;
     575        }
     576        /* Width of 7 preserves tab spacing in the text */
     577        fmt = "%7u ";
     578        n = LINENO(line) + 1;
     579        if (n > 9999999) {
     580            n %= 10000000;
     581            fmt = "%07u ";
     582        }
     583        sprintf(nbuf9, fmt, n);
     584    }
     585}
     586
    462587
    463588#if ENABLE_FEATURE_LESS_REGEXP
     
    470595
    471596    char buf[width];
     597    char nbuf9[9];
    472598    const char *str = line;
    473599    char *p = buf;
     
    502628    while (match_status == 0) {
    503629        char *new = xasprintf("%s%.*s"HIGHLIGHT"%.*s"NORMAL,
    504                 growline ? : "",
     630                growline ? growline : "",
    505631                match_structs.rm_so, str,
    506632                match_structs.rm_eo - match_structs.rm_so,
    507633                        str + match_structs.rm_so);
    508         free(growline); growline = new;
     634        free(growline);
     635        growline = new;
    509636        str += match_structs.rm_eo;
    510637        line += match_structs.rm_eo;
     
    513640        /* Most of the time doesn't find the regex, optimize for that */
    514641        match_status = regexec(&pattern, line, 1, &match_structs, eflags);
    515     }
    516 
     642        /* if even "" matches, treat it as "not a match" */
     643        if (match_structs.rm_so >= match_structs.rm_eo)
     644            match_status = 1;
     645    }
     646
     647    lineno_str(nbuf9, line);
    517648    if (!growline) {
    518         printf(CLEAR_2_EOL"%s\n", str);
     649        printf(CLEAR_2_EOL"%s%s\n", nbuf9, str);
    519650        return;
    520651    }
    521     printf(CLEAR_2_EOL"%s%s\n", growline, str);
     652    printf(CLEAR_2_EOL"%s%s%s\n", nbuf9, growline, str);
    522653    free(growline);
    523654}
     
    529660{
    530661    char buf[width];
     662    char nbuf9[9];
    531663    char *p;
    532664    size_t n;
    533665
    534     printf(CLEAR_2_EOL);
     666    lineno_str(nbuf9, str);
     667    printf(CLEAR_2_EOL"%s", nbuf9);
     668
    535669    while (*str) {
    536670        n = strcspn(str, controls);
     
    562696static void buffer_print(void)
    563697{
    564     int i;
     698    unsigned i;
    565699
    566700    move_cursor(0, 0);
     
    575709static void buffer_fill_and_print(void)
    576710{
    577     int i;
     711    unsigned i;
     712#if ENABLE_FEATURE_LESS_DASHCMD
     713    int fpos = cur_fline;
     714
     715    if (option_mask32 & FLAG_S) {
     716        /* Go back to the beginning of this line */
     717        while (fpos && LINENO(flines[fpos]) == LINENO(flines[fpos-1]))
     718            fpos--;
     719    }
     720
     721    i = 0;
     722    while (i <= max_displayed_line && fpos <= max_fline) {
     723        int lineno = LINENO(flines[fpos]);
     724        buffer[i] = flines[fpos];
     725        i++;
     726        do {
     727            fpos++;
     728        } while ((fpos <= max_fline)
     729              && (option_mask32 & FLAG_S)
     730              && lineno == LINENO(flines[fpos])
     731        );
     732    }
     733#else
    578734    for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) {
    579735        buffer[i] = flines[cur_fline + i];
    580736    }
     737#endif
    581738    for (; i <= max_displayed_line; i++) {
    582739        buffer[i] = empty_line_marker;
     
    619776{
    620777    if (filename) {
    621         int fd = xopen(filename, O_RDONLY);
    622         dup2(fd, 0);
    623         if (fd) close(fd);
     778        xmove_fd(xopen(filename, O_RDONLY), STDIN_FILENO);
    624779    } else {
    625780        /* "less" with no arguments in argv[] */
     
    629784    readpos = 0;
    630785    readeof = 0;
    631     linepos = 0;
     786    last_line_pos = 0;
    632787    terminated = 1;
    633788    read_lines();
     
    637792static void reinitialize(void)
    638793{
    639     int i;
     794    unsigned i;
    640795
    641796    if (flines) {
    642797        for (i = 0; i <= max_fline; i++)
    643             free((void*)(flines[i]));
     798            free(MEMPTR(flines[i]));
    644799        free(flines);
    645800        flines = NULL;
     
    653808}
    654809
    655 static void getch_nowait(char* input, int sz)
    656 {
    657     ssize_t rd;
    658     fd_set readfds;
     810static int getch_nowait(void)
     811{
     812    int rd;
     813    struct pollfd pfd[2];
     814
     815    pfd[0].fd = STDIN_FILENO;
     816    pfd[0].events = POLLIN;
     817    pfd[1].fd = kbd_fd;
     818    pfd[1].events = POLLIN;
    659819 again:
    660     fflush(stdout);
    661 
    662     /* NB: select returns whenever read will not block. Therefore:
    663      * (a) with O_NONBLOCK'ed fds select will return immediately
    664      * (b) if eof is reached, select will also return
    665      *     because read will immediately return 0 bytes.
    666      * Even if select says that input is available, read CAN block
     820    tcsetattr(kbd_fd, TCSANOW, &term_less);
     821    /* NB: select/poll returns whenever read will not block. Therefore:
     822     * if eof is reached, select/poll will return immediately
     823     * because read will immediately return 0 bytes.
     824     * Even if select/poll says that input is available, read CAN block
    667825     * (switch fd into O_NONBLOCK'ed mode to avoid it)
    668826     */
    669     FD_ZERO(&readfds);
    670     if (max_fline <= cur_fline + max_displayed_line
    671      && eof_error > 0 /* did NOT reach eof yet */
     827    rd = 1;
     828    /* Are we interested in stdin? */
     829//TODO: reuse code for determining this
     830    if (!(option_mask32 & FLAG_S)
     831       ? !(max_fline > cur_fline + max_displayed_line)
     832       : !(max_fline >= cur_fline
     833           && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line)
    672834    ) {
    673         /* We are interested in stdin */
    674         FD_SET(0, &readfds);
    675     }
    676     FD_SET(kbd_fd, &readfds);
    677     tcsetattr(kbd_fd, TCSANOW, &term_less);
    678     select(kbd_fd + 1, &readfds, NULL, NULL, NULL);
    679 
    680     input[0] = '\0';
    681     ndelay_on(kbd_fd);
    682     rd = read(kbd_fd, input, sz);
    683     ndelay_off(kbd_fd);
    684     if (rd < 0) {
    685         /* No keyboard input, but we have input on stdin! */
    686         if (errno != EAGAIN) /* Huh?? */
    687             return;
    688         read_lines();
    689         buffer_fill_and_print();
     835        if (eof_error > 0) /* did NOT reach eof yet */
     836            rd = 0; /* yes, we are interested in stdin */
     837    }
     838    /* Position cursor if line input is done */
     839    if (less_gets_pos >= 0)
     840        move_cursor(max_displayed_line + 2, less_gets_pos + 1);
     841    fflush_all();
     842
     843    if (kbd_input[0] == 0) { /* if nothing is buffered */
     844#if ENABLE_FEATURE_LESS_WINCH
     845        while (1) {
     846            int r;
     847            /* NB: SIGWINCH interrupts poll() */
     848            r = poll(pfd + rd, 2 - rd, -1);
     849            if (/*r < 0 && errno == EINTR &&*/ winch_counter)
     850                return '\\'; /* anything which has no defined function */
     851            if (r) break;
     852        }
     853#else
     854        safe_poll(pfd + rd, 2 - rd, -1);
     855#endif
     856    }
     857
     858    /* We have kbd_fd in O_NONBLOCK mode, read inside read_key()
     859     * would not block even if there is no input available */
     860    rd = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2);
     861    if (rd == -1) {
     862        if (errno == EAGAIN) {
     863            /* No keyboard input available. Since poll() did return,
     864             * we should have input on stdin */
     865            read_lines();
     866            buffer_fill_and_print();
     867            goto again;
     868        }
     869        /* EOF/error (ssh session got killed etc) */
     870        less_exit(0);
     871    }
     872    set_tty_cooked();
     873    return rd;
     874}
     875
     876/* Grab a character from input without requiring the return key.
     877 * May return KEYCODE_xxx values.
     878 * Note that this function works best with raw input. */
     879static int less_getch(int pos)
     880{
     881    int i;
     882
     883 again:
     884    less_gets_pos = pos;
     885    i = getch_nowait();
     886    less_gets_pos = -1;
     887
     888    /* Discard Ctrl-something chars */
     889    if (i >= 0 && i < ' ' && i != 0x0d && i != 8)
    690890        goto again;
    691     }
    692 }
    693 
    694 /* Grab a character from input without requiring the return key. If the
    695  * character is ASCII \033, get more characters and assign certain sequences
    696  * special return codes. Note that this function works best with raw input. */
    697 static int less_getch(void)
    698 {
    699     char input[16];
    700     unsigned i;
    701  again:
    702     memset(input, 0, sizeof(input));
    703     getch_nowait(input, sizeof(input));
    704 
    705     /* Detect escape sequences (i.e. arrow keys) and handle
    706      * them accordingly */
    707     if (input[0] == '\033' && input[1] == '[') {
    708         set_tty_cooked();
    709         i = input[2] - REAL_KEY_UP;
    710         if (i < 4)
    711             return 20 + i;
    712         i = input[2] - REAL_PAGE_UP;
    713         if (i < 4)
    714             return 24 + i;
    715         if (input[2] == REAL_KEY_HOME_XTERM)
    716             return KEY_HOME;
    717         if (input[2] == REAL_KEY_HOME_ALT)
    718             return KEY_HOME;
    719         if (input[2] == REAL_KEY_END_XTERM)
    720             return KEY_END;
    721         if (input[2] == REAL_KEY_END_ALT)
    722             return KEY_END;
    723         return 0;
    724     }
    725     /* Reject almost all control chars */
    726     i = input[0];
    727     if (i < ' ' && i != 0x0d && i != 8) goto again;
    728     set_tty_cooked();
    729891    return i;
    730892}
     
    732894static char* less_gets(int sz)
    733895{
    734     char c;
    735     int i = 0;
     896    int c;
     897    unsigned i = 0;
    736898    char *result = xzalloc(1);
     899
    737900    while (1) {
    738         fflush(stdout);
    739 
    740         /* I be damned if I know why is it needed *repeatedly*,
    741          * but it is needed. Is it because of stdio? */
    742         tcsetattr(kbd_fd, TCSANOW, &term_less);
    743 
    744901        c = '\0';
    745         read(kbd_fd, &c, 1);
    746         if (c == 0x0d)
     902        less_gets_pos = sz + i;
     903        c = getch_nowait();
     904        if (c == 0x0d) {
     905            result[i] = '\0';
     906            less_gets_pos = -1;
    747907            return result;
     908        }
    748909        if (c == 0x7f)
    749910            c = 8;
     
    752913            i--;
    753914        }
    754         if (c < ' ')
     915        if (c < ' ') /* filters out KEYCODE_xxx too (<0) */
    755916            continue;
    756917        if (i >= width - sz - 1)
    757918            continue; /* len limit */
    758         putchar(c);
     919        bb_putchar(c);
    759920        result[i++] = c;
    760921        result = xrealloc(result, i+1);
    761         result[i] = '\0';
    762922    }
    763923}
     
    765925static void examine_file(void)
    766926{
     927    char *new_fname;
     928
    767929    print_statusline("Examine: ");
     930    new_fname = less_gets(sizeof("Examine: ") - 1);
     931    if (!new_fname[0]) {
     932        status_print();
     933 err:
     934        free(new_fname);
     935        return;
     936    }
     937    if (access(new_fname, R_OK) != 0) {
     938        print_statusline("Cannot read this file");
     939        goto err;
     940    }
    768941    free(filename);
    769     filename = less_gets(sizeof("Examine: ")-1);
     942    filename = new_fname;
    770943    /* files start by = argv. why we assume that argv is infinitely long??
    771944    files[num_files] = filename;
     
    795968static void remove_current_file(void)
    796969{
    797     int i;
     970    unsigned i;
    798971
    799972    if (num_files < 2)
     
    821994    print_statusline(" :");
    822995
    823     keypress = less_getch();
     996    keypress = less_getch(2);
    824997    switch (keypress) {
    825998    case 'd':
     
    8411014        break;
    8421015    case 'q':
    843         less_exit(0);
     1016        less_exit(EXIT_SUCCESS);
    8441017        break;
    8451018    case 'x':
     
    8611034static void goto_match(int match)
    8621035{
    863     int sv;
    864 
    8651036    if (!pattern_valid)
    8661037        return;
    8671038    if (match < 0)
    8681039        match = 0;
    869     sv = cur_fline;
    8701040    /* Try to find next match if eof isn't reached yet */
    8711041    if (match >= num_matches && eof_error > 0) {
    872         cur_fline = MAXLINES; /* look as far as needed */
     1042        wanted_match = match; /* "I want to read until I see N'th match" */
    8731043        read_lines();
    8741044    }
    8751045    if (num_matches) {
    876         cap_cur_fline(cur_fline);
    8771046        normalize_match_pos(match);
    8781047        buffer_line(match_lines[match_pos]);
    8791048    } else {
    880         cur_fline = sv;
    8811049        print_statusline("No matches found");
    8821050    }
     
    8941062         && !(num_matches && match_lines[num_matches-1] == pos)
    8951063        ) {
    896             match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
     1064            match_lines = xrealloc_vector(match_lines, 4, num_matches);
    8971065            match_lines[num_matches++] = pos;
    8981066        }
     
    9171085    /* Get the uncompiled regular expression from the user */
    9181086    clear_line();
    919     putchar((option_mask32 & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/');
     1087    bb_putchar((option_mask32 & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/');
    9201088    uncomp_regex = less_gets(1);
    9211089    if (!uncomp_regex[0]) {
     
    9261094
    9271095    /* Compile the regex and check for errors */
    928     err = regcomp_or_errmsg(&pattern, uncomp_regex, 0);
     1096    err = regcomp_or_errmsg(&pattern, uncomp_regex,
     1097                (option_mask32 & FLAG_I) ? REG_ICASE : 0);
    9291098    free(uncomp_regex);
    9301099    if (err) {
     
    9381107    fill_match_lines(0);
    9391108    while (match_pos < num_matches) {
    940         if (match_lines[match_pos] > cur_fline)
     1109        if ((int)match_lines[match_pos] > cur_fline)
    9411110            break;
    9421111        match_pos++;
     
    9541123static void number_process(int first_digit)
    9551124{
    956     int i = 1;
     1125    unsigned i;
    9571126    int num;
     1127    int keypress;
    9581128    char num_input[sizeof(int)*4]; /* more than enough */
    959     char keypress;
    9601129
    9611130    num_input[0] = first_digit;
     
    9661135
    9671136    /* Receive input until a letter is given */
     1137    i = 1;
    9681138    while (i < sizeof(num_input)-1) {
    969         num_input[i] = less_getch();
    970         if (!num_input[i] || !isdigit(num_input[i]))
     1139        keypress = less_getch(i + 1);
     1140        if ((unsigned)keypress > 255 || !isdigit(num_input[i]))
    9711141            break;
    972         putchar(num_input[i]);
     1142        num_input[i] = keypress;
     1143        bb_putchar(keypress);
    9731144        i++;
    9741145    }
    9751146
    976     /* Take the final letter out of the digits string */
    977     keypress = num_input[i];
    9781147    num_input[i] = '\0';
    9791148    num = bb_strtou(num_input, NULL, 10);
     
    9861155    /* We now know the number and the letter entered, so we process them */
    9871156    switch (keypress) {
    988     case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
     1157    case KEYCODE_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
    9891158        buffer_down(num);
    9901159        break;
    991     case KEY_UP: case 'b': case 'w': case 'y': case 'u':
     1160    case KEYCODE_UP: case 'b': case 'w': case 'y': case 'u':
    9921161        buffer_up(num);
    9931162        break;
     
    10191188}
    10201189
    1021 #if ENABLE_FEATURE_LESS_FLAGCS
     1190#if ENABLE_FEATURE_LESS_DASHCMD
    10221191static void flag_change(void)
    10231192{
     
    10251194
    10261195    clear_line();
    1027     putchar('-');
    1028     keypress = less_getch();
     1196    bb_putchar('-');
     1197    keypress = less_getch(1);
    10291198
    10301199    switch (keypress) {
     
    10411210        option_mask32 ^= FLAG_TILDE;
    10421211        break;
    1043     }
    1044 }
    1045 
     1212    case 'S':
     1213        option_mask32 ^= FLAG_S;
     1214        buffer_fill_and_print();
     1215        break;
     1216#if ENABLE_FEATURE_LESS_LINENUMS
     1217    case 'N':
     1218        option_mask32 ^= FLAG_N;
     1219        re_wrap();
     1220        buffer_fill_and_print();
     1221        break;
     1222#endif
     1223    }
     1224}
     1225
     1226#ifdef BLOAT
    10461227static void show_flag_status(void)
    10471228{
     
    10501231
    10511232    clear_line();
    1052     putchar('_');
    1053     keypress = less_getch();
     1233    bb_putchar('_');
     1234    keypress = less_getch(1);
    10541235
    10551236    switch (keypress) {
     
    10791260#endif
    10801261
     1262#endif /* ENABLE_FEATURE_LESS_DASHCMD */
     1263
    10811264static void save_input_to_file(void)
    10821265{
    10831266    const char *msg = "";
    10841267    char *current_line;
    1085     int i;
     1268    unsigned i;
    10861269    FILE *fp;
    10871270
    10881271    print_statusline("Log file: ");
    10891272    current_line = less_gets(sizeof("Log file: ")-1);
    1090     if (strlen(current_line) > 0) {
    1091         fp = fopen(current_line, "w");
     1273    if (current_line[0]) {
     1274        fp = fopen_for_write(current_line);
    10921275        if (!fp) {
    10931276            msg = "Error opening log file";
     
    11101293
    11111294    print_statusline("Mark: ");
    1112     letter = less_getch();
     1295    letter = less_getch(sizeof("Mark: ") - 1);
    11131296
    11141297    if (isalpha(letter)) {
     
    11311314
    11321315    print_statusline("Go to mark: ");
    1133     letter = less_getch();
     1316    letter = less_getch(sizeof("Go to mark: ") - 1);
    11341317    clear_line();
    11351318
     
    11511334{
    11521335    switch (bracket) {
    1153     case '{': case '[':
    1154         return bracket + 2;
    1155     case '(':
    1156         return ')';
    1157     case '}': case ']':
    1158         return bracket - 2;
    1159     case ')':
    1160         return '(';
    1161     }
    1162     return 0;
     1336        case '{': case '[': /* '}' == '{' + 2. Same for '[' */
     1337            bracket++;
     1338        case '(':           /* ')' == '(' + 1 */
     1339            bracket++;
     1340            break;
     1341        case '}': case ']':
     1342            bracket--;
     1343        case ')':
     1344            bracket--;
     1345            break;
     1346    };
     1347    return bracket;
    11631348}
    11641349
    11651350static void match_right_bracket(char bracket)
    11661351{
    1167     int bracket_line = -1;
    1168     int i;
     1352    unsigned i;
    11691353
    11701354    if (strchr(flines[cur_fline], bracket) == NULL) {
     
    11721356        return;
    11731357    }
     1358    bracket = opp_bracket(bracket);
    11741359    for (i = cur_fline + 1; i < max_fline; i++) {
    1175         if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
    1176             bracket_line = i;
    1177             break;
    1178         }
    1179     }
    1180     if (bracket_line == -1)
    1181         print_statusline("No matching bracket found");
    1182     buffer_line(bracket_line - max_displayed_line);
     1360        if (strchr(flines[i], bracket) != NULL) {
     1361            buffer_line(i);
     1362            return;
     1363        }
     1364    }
     1365    print_statusline("No matching bracket found");
    11831366}
    11841367
    11851368static void match_left_bracket(char bracket)
    11861369{
    1187     int bracket_line = -1;
    11881370    int i;
    11891371
     
    11931375    }
    11941376
     1377    bracket = opp_bracket(bracket);
    11951378    for (i = cur_fline + max_displayed_line; i >= 0; i--) {
    1196         if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
    1197             bracket_line = i;
    1198             break;
    1199         }
    1200     }
    1201     if (bracket_line == -1)
    1202         print_statusline("No matching bracket found");
    1203     buffer_line(bracket_line);
     1379        if (strchr(flines[i], bracket) != NULL) {
     1380            buffer_line(i);
     1381            return;
     1382        }
     1383    }
     1384    print_statusline("No matching bracket found");
    12041385}
    12051386#endif  /* FEATURE_LESS_BRACKETS */
     
    12081389{
    12091390    switch (keypress) {
    1210     case KEY_DOWN: case 'e': case 'j': case 0x0d:
     1391    case KEYCODE_DOWN: case 'e': case 'j': case 0x0d:
    12111392        buffer_down(1);
    12121393        break;
    1213     case KEY_UP: case 'y': case 'k':
     1394    case KEYCODE_UP: case 'y': case 'k':
    12141395        buffer_up(1);
    12151396        break;
    1216     case PAGE_DOWN: case ' ': case 'z':
     1397    case KEYCODE_PAGEDOWN: case ' ': case 'z': case 'f':
    12171398        buffer_down(max_displayed_line + 1);
    12181399        break;
    1219     case PAGE_UP: case 'w': case 'b':
     1400    case KEYCODE_PAGEUP: case 'w': case 'b':
    12201401        buffer_up(max_displayed_line + 1);
    12211402        break;
     
    12261407        buffer_up((max_displayed_line + 1) / 2);
    12271408        break;
    1228     case KEY_HOME: case 'g': case 'p': case '<': case '%':
     1409    case KEYCODE_HOME: case 'g': case 'p': case '<': case '%':
    12291410        buffer_line(0);
    12301411        break;
    1231     case KEY_END: case 'G': case '>':
     1412    case KEYCODE_END: case 'G': case '>':
    12321413        cur_fline = MAXLINES;
    12331414        read_lines();
     
    12351416        break;
    12361417    case 'q': case 'Q':
    1237         less_exit(0);
     1418        less_exit(EXIT_SUCCESS);
    12381419        break;
    12391420#if ENABLE_FEATURE_LESS_MARKS
     
    12801461        break;
    12811462#endif
    1282 #if ENABLE_FEATURE_LESS_FLAGCS
     1463#if ENABLE_FEATURE_LESS_DASHCMD
    12831464    case '-':
    12841465        flag_change();
    12851466        buffer_print();
    12861467        break;
     1468#ifdef BLOAT
    12871469    case '_':
    12881470        show_flag_status();
    12891471        break;
     1472#endif
    12901473#endif
    12911474#if ENABLE_FEATURE_LESS_BRACKETS
     
    13061489}
    13071490
    1308 static void sig_catcher(int sig ATTRIBUTE_UNUSED)
    1309 {
    1310     set_tty_cooked();
    1311     exit(1);
    1312 }
    1313 
    1314 int less_main(int argc, char **argv);
     1491static void sig_catcher(int sig)
     1492{
     1493    less_exit(- sig);
     1494}
     1495
     1496#if ENABLE_FEATURE_LESS_WINCH
     1497static void sigwinch_handler(int sig UNUSED_PARAM)
     1498{
     1499    winch_counter++;
     1500}
     1501#endif
     1502
     1503int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    13151504int less_main(int argc, char **argv)
    13161505{
     
    13221511    /* -xxx: newline also */
    13231512    /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */
    1324     getopt32(argv, "EMmN~");
     1513    getopt32(argv, "EMmN~I" IF_FEATURE_LESS_DASHCMD("S"));
    13251514    argc -= optind;
    13261515    argv += optind;
     
    13311520     * is not a tty and turns into cat. This makes sense. */
    13321521    if (!isatty(STDOUT_FILENO))
    1333         return bb_cat(argv);
    1334     kbd_fd = open(CURRENT_TTY, O_RDONLY);
    1335     if (kbd_fd < 0)
    13361522        return bb_cat(argv);
    13371523
     
    13421528            bb_show_usage();
    13431529        }
    1344     } else
     1530    } else {
    13451531        filename = xstrdup(files[0]);
    1346 
    1347     get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
    1348     /* 20: two tabstops + 4 */
    1349     if (width < 20 || max_displayed_line < 3)
    1350         bb_error_msg_and_die("too narrow here");
    1351     max_displayed_line -= 2;
    1352 
    1353     buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
     1532    }
     1533
    13541534    if (option_mask32 & FLAG_TILDE)
    13551535        empty_line_marker = "";
    13561536
     1537    kbd_fd = open(CURRENT_TTY, O_RDONLY);
     1538    if (kbd_fd < 0)
     1539        return bb_cat(argv);
     1540    ndelay_on(kbd_fd);
     1541
    13571542    tcgetattr(kbd_fd, &term_orig);
    1358     signal(SIGTERM, sig_catcher);
    1359     signal(SIGINT, sig_catcher);
    13601543    term_less = term_orig;
    13611544    term_less.c_lflag &= ~(ICANON | ECHO);
     
    13651548    term_less.c_cc[VTIME] = 0;
    13661549
    1367     /* Want to do it just once, but it doesn't work, */
    1368     /* so we are redoing it (see code above). Mystery... */
    1369     /*tcsetattr(kbd_fd, TCSANOW, &term_less);*/
    1370 
     1550    get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
     1551    /* 20: two tabstops + 4 */
     1552    if (width < 20 || max_displayed_line < 3)
     1553        return bb_cat(argv);
     1554    max_displayed_line -= 2;
     1555
     1556    /* We want to restore term_orig on exit */
     1557    bb_signals(BB_FATAL_SIGS, sig_catcher);
     1558#if ENABLE_FEATURE_LESS_WINCH
     1559    signal(SIGWINCH, sigwinch_handler);
     1560#endif
     1561
     1562    buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
    13711563    reinitialize();
    13721564    while (1) {
    1373         keypress = less_getch();
     1565#if ENABLE_FEATURE_LESS_WINCH
     1566        while (WINCH_COUNTER) {
     1567 again:
     1568            winch_counter--;
     1569            get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
     1570            /* 20: two tabstops + 4 */
     1571            if (width < 20)
     1572                width = 20;
     1573            if (max_displayed_line < 3)
     1574                max_displayed_line = 3;
     1575            max_displayed_line -= 2;
     1576            free(buffer);
     1577            buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
     1578            /* Avoid re-wrap and/or redraw if we already know
     1579             * we need to do it again. These ops are expensive */
     1580            if (WINCH_COUNTER)
     1581                goto again;
     1582            re_wrap();
     1583            if (WINCH_COUNTER)
     1584                goto again;
     1585            buffer_fill_and_print();
     1586            /* This took some time. Loop back and check,
     1587             * were there another SIGWINCH? */
     1588        }
     1589#endif
     1590        keypress = less_getch(-1); /* -1: do not position cursor */
    13741591        keypress_process(keypress);
    13751592    }
    13761593}
     1594
     1595/*
     1596Help text of less version 418 is below.
     1597If you are implementing something, keeping
     1598key and/or command line switch compatibility is a good idea:
     1599
     1600
     1601                   SUMMARY OF LESS COMMANDS
     1602
     1603      Commands marked with * may be preceded by a number, N.
     1604      Notes in parentheses indicate the behavior if N is given.
     1605  h  H                 Display this help.
     1606  q  :q  Q  :Q  ZZ     Exit.
     1607 ---------------------------------------------------------------------------
     1608                           MOVING
     1609  e  ^E  j  ^N  CR  *  Forward  one line   (or N lines).
     1610  y  ^Y  k  ^K  ^P  *  Backward one line   (or N lines).
     1611  f  ^F  ^V  SPACE  *  Forward  one window (or N lines).
     1612  b  ^B  ESC-v      *  Backward one window (or N lines).
     1613  z                 *  Forward  one window (and set window to N).
     1614  w                 *  Backward one window (and set window to N).
     1615  ESC-SPACE         *  Forward  one window, but don't stop at end-of-file.
     1616  d  ^D             *  Forward  one half-window (and set half-window to N).
     1617  u  ^U             *  Backward one half-window (and set half-window to N).
     1618  ESC-)  RightArrow *  Left  one half screen width (or N positions).
     1619  ESC-(  LeftArrow  *  Right one half screen width (or N positions).
     1620  F                    Forward forever; like "tail -f".
     1621  r  ^R  ^L            Repaint screen.
     1622  R                    Repaint screen, discarding buffered input.
     1623        ---------------------------------------------------
     1624        Default "window" is the screen height.
     1625        Default "half-window" is half of the screen height.
     1626 ---------------------------------------------------------------------------
     1627                          SEARCHING
     1628  /pattern          *  Search forward for (N-th) matching line.
     1629  ?pattern          *  Search backward for (N-th) matching line.
     1630  n                 *  Repeat previous search (for N-th occurrence).
     1631  N                 *  Repeat previous search in reverse direction.
     1632  ESC-n             *  Repeat previous search, spanning files.
     1633  ESC-N             *  Repeat previous search, reverse dir. & spanning files.
     1634  ESC-u                Undo (toggle) search highlighting.
     1635        ---------------------------------------------------
     1636        Search patterns may be modified by one or more of:
     1637        ^N or !  Search for NON-matching lines.
     1638        ^E or *  Search multiple files (pass thru END OF FILE).
     1639        ^F or @  Start search at FIRST file (for /) or last file (for ?).
     1640        ^K       Highlight matches, but don't move (KEEP position).
     1641        ^R       Don't use REGULAR EXPRESSIONS.
     1642 ---------------------------------------------------------------------------
     1643                           JUMPING
     1644  g  <  ESC-<       *  Go to first line in file (or line N).
     1645  G  >  ESC->       *  Go to last line in file (or line N).
     1646  p  %              *  Go to beginning of file (or N percent into file).
     1647  t                 *  Go to the (N-th) next tag.
     1648  T                 *  Go to the (N-th) previous tag.
     1649  {  (  [           *  Find close bracket } ) ].
     1650  }  )  ]           *  Find open bracket { ( [.
     1651  ESC-^F <c1> <c2>  *  Find close bracket <c2>.
     1652  ESC-^B <c1> <c2>  *  Find open bracket <c1>
     1653        ---------------------------------------------------
     1654        Each "find close bracket" command goes forward to the close bracket
     1655          matching the (N-th) open bracket in the top line.
     1656        Each "find open bracket" command goes backward to the open bracket
     1657          matching the (N-th) close bracket in the bottom line.
     1658  m<letter>            Mark the current position with <letter>.
     1659  '<letter>            Go to a previously marked position.
     1660  ''                   Go to the previous position.
     1661  ^X^X                 Same as '.
     1662        ---------------------------------------------------
     1663        A mark is any upper-case or lower-case letter.
     1664        Certain marks are predefined:
     1665             ^  means  beginning of the file
     1666             $  means  end of the file
     1667 ---------------------------------------------------------------------------
     1668                        CHANGING FILES
     1669  :e [file]            Examine a new file.
     1670  ^X^V                 Same as :e.
     1671  :n                *  Examine the (N-th) next file from the command line.
     1672  :p                *  Examine the (N-th) previous file from the command line.
     1673  :x                *  Examine the first (or N-th) file from the command line.
     1674  :d                   Delete the current file from the command line list.
     1675  =  ^G  :f            Print current file name.
     1676 ---------------------------------------------------------------------------
     1677                    MISCELLANEOUS COMMANDS
     1678  -<flag>              Toggle a command line option [see OPTIONS below].
     1679  --<name>             Toggle a command line option, by name.
     1680  _<flag>              Display the setting of a command line option.
     1681  __<name>             Display the setting of an option, by name.
     1682  +cmd                 Execute the less cmd each time a new file is examined.
     1683  !command             Execute the shell command with $SHELL.
     1684  |Xcommand            Pipe file between current pos & mark X to shell command.
     1685  v                    Edit the current file with $VISUAL or $EDITOR.
     1686  V                    Print version number of "less".
     1687 ---------------------------------------------------------------------------
     1688                           OPTIONS
     1689        Most options may be changed either on the command line,
     1690        or from within less by using the - or -- command.
     1691        Options may be given in one of two forms: either a single
     1692        character preceded by a -, or a name preceeded by --.
     1693  -?  ........  --help
     1694                  Display help (from command line).
     1695  -a  ........  --search-skip-screen
     1696                  Forward search skips current screen.
     1697  -b [N]  ....  --buffers=[N]
     1698                  Number of buffers.
     1699  -B  ........  --auto-buffers
     1700                  Don't automatically allocate buffers for pipes.
     1701  -c  ........  --clear-screen
     1702                  Repaint by clearing rather than scrolling.
     1703  -d  ........  --dumb
     1704                  Dumb terminal.
     1705  -D [xn.n]  .  --color=xn.n
     1706                  Set screen colors. (MS-DOS only)
     1707  -e  -E  ....  --quit-at-eof  --QUIT-AT-EOF
     1708                  Quit at end of file.
     1709  -f  ........  --force
     1710                  Force open non-regular files.
     1711  -F  ........  --quit-if-one-screen
     1712                  Quit if entire file fits on first screen.
     1713  -g  ........  --hilite-search
     1714                  Highlight only last match for searches.
     1715  -G  ........  --HILITE-SEARCH
     1716                  Don't highlight any matches for searches.
     1717  -h [N]  ....  --max-back-scroll=[N]
     1718                  Backward scroll limit.
     1719  -i  ........  --ignore-case
     1720                  Ignore case in searches that do not contain uppercase.
     1721  -I  ........  --IGNORE-CASE
     1722                  Ignore case in all searches.
     1723  -j [N]  ....  --jump-target=[N]
     1724                  Screen position of target lines.
     1725  -J  ........  --status-column
     1726                  Display a status column at left edge of screen.
     1727  -k [file]  .  --lesskey-file=[file]
     1728                  Use a lesskey file.
     1729  -L  ........  --no-lessopen
     1730                  Ignore the LESSOPEN environment variable.
     1731  -m  -M  ....  --long-prompt  --LONG-PROMPT
     1732                  Set prompt style.
     1733  -n  -N  ....  --line-numbers  --LINE-NUMBERS
     1734                  Don't use line numbers.
     1735  -o [file]  .  --log-file=[file]
     1736                  Copy to log file (standard input only).
     1737  -O [file]  .  --LOG-FILE=[file]
     1738                  Copy to log file (unconditionally overwrite).
     1739  -p [pattern]  --pattern=[pattern]
     1740                  Start at pattern (from command line).
     1741  -P [prompt]   --prompt=[prompt]
     1742                  Define new prompt.
     1743  -q  -Q  ....  --quiet  --QUIET  --silent --SILENT
     1744                  Quiet the terminal bell.
     1745  -r  -R  ....  --raw-control-chars  --RAW-CONTROL-CHARS
     1746                  Output "raw" control characters.
     1747  -s  ........  --squeeze-blank-lines
     1748                  Squeeze multiple blank lines.
     1749  -S  ........  --chop-long-lines
     1750                  Chop long lines.
     1751  -t [tag]  ..  --tag=[tag]
     1752                  Find a tag.
     1753  -T [tagsfile] --tag-file=[tagsfile]
     1754                  Use an alternate tags file.
     1755  -u  -U  ....  --underline-special  --UNDERLINE-SPECIAL
     1756                  Change handling of backspaces.
     1757  -V  ........  --version
     1758                  Display the version number of "less".
     1759  -w  ........  --hilite-unread
     1760                  Highlight first new line after forward-screen.
     1761  -W  ........  --HILITE-UNREAD
     1762                  Highlight first new line after any forward movement.
     1763  -x [N[,...]]  --tabs=[N[,...]]
     1764                  Set tab stops.
     1765  -X  ........  --no-init
     1766                  Don't use termcap init/deinit strings.
     1767                --no-keypad
     1768                  Don't use termcap keypad init/deinit strings.
     1769  -y [N]  ....  --max-forw-scroll=[N]
     1770                  Forward scroll limit.
     1771  -z [N]  ....  --window=[N]
     1772                  Set size of window.
     1773  -" [c[c]]  .  --quotes=[c[c]]
     1774                  Set shell quote characters.
     1775  -~  ........  --tilde
     1776                  Don't display tildes after end of file.
     1777  -# [N]  ....  --shift=[N]
     1778                  Horizontal scroll amount (0 = one half screen width)
     1779
     1780 ---------------------------------------------------------------------------
     1781                          LINE EDITING
     1782        These keys can be used to edit text being entered
     1783        on the "command line" at the bottom of the screen.
     1784 RightArrow                       ESC-l     Move cursor right one character.
     1785 LeftArrow                        ESC-h     Move cursor left one character.
     1786 CNTL-RightArrow  ESC-RightArrow  ESC-w     Move cursor right one word.
     1787 CNTL-LeftArrow   ESC-LeftArrow   ESC-b     Move cursor left one word.
     1788 HOME                             ESC-0     Move cursor to start of line.
     1789 END                              ESC-$     Move cursor to end of line.
     1790 BACKSPACE                                  Delete char to left of cursor.
     1791 DELETE                           ESC-x     Delete char under cursor.
     1792 CNTL-BACKSPACE   ESC-BACKSPACE             Delete word to left of cursor.
     1793 CNTL-DELETE      ESC-DELETE      ESC-X     Delete word under cursor.
     1794 CNTL-U           ESC (MS-DOS only)         Delete entire line.
     1795 UpArrow                          ESC-k     Retrieve previous command line.
     1796 DownArrow                        ESC-j     Retrieve next command line.
     1797 TAB                                        Complete filename & cycle.
     1798 SHIFT-TAB                        ESC-TAB   Complete filename & reverse cycle.
     1799 CNTL-L                                     Complete filename, list all.
     1800*/
  • branches/2.2.9/mindi-busybox/miscutils/makedevs.c

    r1765 r2725  
    1111
    1212#if ENABLE_FEATURE_MAKEDEVS_LEAF
    13 int makedevs_main(int argc, char **argv);
     13/*
     14makedevs NAME TYPE MAJOR MINOR FIRST LAST [s]
     15TYPEs:
     16b       Block device
     17c       Character device
     18f       FIFO
     19
     20FIRST..LAST specify numbers appended to NAME.
     21If 's' is the last argument, the base device is created as well.
     22Examples:
     23        makedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63
     24        makedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8
     25*/
     26int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    1427int makedevs_main(int argc, char **argv)
    1528{
    1629    mode_t mode;
    17     char *basedev, *type, *nodname, buf[255];
     30    char *basedev, *type, *nodname, *buf;
    1831    int Smajor, Sminor, S, E;
    1932
    20     if (argc < 7 || *argv[1]=='-')
     33    if (argc < 7 || argv[1][0] == '-')
    2134        bb_show_usage();
    2235
    2336    basedev = argv[1];
     37    buf = xasprintf("%s%u", argv[1], (unsigned)-1);
    2438    type = argv[2];
    25     Smajor = xatoi_u(argv[3]);
    26     Sminor = xatoi_u(argv[4]);
    27     S = xatoi_u(argv[5]);
    28     E = xatoi_u(argv[6]);
    29     nodname = argc == 8 ? basedev : buf;
     39    Smajor = xatoi_positive(argv[3]);
     40    Sminor = xatoi_positive(argv[4]);
     41    S = xatoi_positive(argv[5]);
     42    E = xatoi_positive(argv[6]);
     43    nodname = argv[7] ? basedev : buf;
    3044
    3145    mode = 0660;
    32 
    3346    switch (type[0]) {
    3447    case 'c':
     
    4659
    4760    while (S <= E) {
    48         int sz;
    49 
    50         sz = snprintf(buf, sizeof(buf), "%s%d", basedev, S);
    51         if (sz < 0 || sz >= sizeof(buf))  /* libc different */
    52             bb_error_msg_and_die("%s too large", basedev);
    53 
    54     /* if mode != S_IFCHR and != S_IFBLK third param in mknod() ignored */
    55 
     61        sprintf(buf, "%s%u", basedev, S);
     62
     63        /* if mode != S_IFCHR and != S_IFBLK,
     64         * third param in mknod() ignored */
    5665        if (mknod(nodname, mode, makedev(Smajor, Sminor)))
    57             bb_error_msg("failed to create: %s", nodname);
    58 
    59         if (nodname == basedev) /* ex. /dev/hda - to /dev/hda1 ... */
     66            bb_perror_msg("can't create '%s'", nodname);
     67
     68        /*if (nodname == basedev)*/ /* ex. /dev/hda - to /dev/hda1 ... */
    6069            nodname = buf;
    6170        S++;
     
    6877#elif ENABLE_FEATURE_MAKEDEVS_TABLE
    6978
    70 /* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */
    71 
    72 int makedevs_main(int argc, char **argv);
    73 int makedevs_main(int argc, char **argv)
     79/* Licensed under GPLv2 or later, see file LICENSE in this source tree. */
     80
     81int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     82int makedevs_main(int argc UNUSED_PARAM, char **argv)
    7483{
    75     FILE *table = stdin;
    76     char *rootdir = NULL;
    77     char *line = NULL;
    78     int linenum = 0;
     84    parser_t *parser;
     85    char *line = (char *)"-";
    7986    int ret = EXIT_SUCCESS;
    8087
     88    opt_complementary = "=1"; /* exactly one param */
    8189    getopt32(argv, "d:", &line);
    82     if (line)
    83         table = xfopen(line, "r");
    84 
    85     if (optind >= argc || (rootdir=argv[optind])==NULL) {
    86         bb_error_msg_and_die("root directory not specified");
    87     }
    88 
    89     xchdir(rootdir);
     90    argv += optind;
     91
     92    xchdir(*argv); /* ensure root dir exists */
    9093
    9194    umask(0);
    9295
    93     printf("rootdir=%s\n", rootdir);
    94     if (line) {
    95         printf("table='%s'\n", line);
     96    printf("rootdir=%s\ntable=", *argv);
     97    if (NOT_LONE_DASH(line)) {
     98        printf("'%s'\n", line);
    9699    } else {
    97         printf("table=<stdin>\n");
    98     }
    99 
    100     while ((line = xmalloc_getline(table))) {
     100        puts("<stdin>");
     101    }
     102
     103    parser = config_open(line);
     104    while (config_read(parser, &line, 1, 1, "# \t", PARSE_NORMAL)) {
     105        int linenum;
    101106        char type;
    102         unsigned int mode = 0755;
    103         unsigned int major = 0;
    104         unsigned int minor = 0;
    105         unsigned int count = 0;
    106         unsigned int increment = 0;
    107         unsigned int start = 0;
     107        unsigned mode = 0755;
     108        unsigned major = 0;
     109        unsigned minor = 0;
     110        unsigned count = 0;
     111        unsigned increment = 0;
     112        unsigned start = 0;
    108113        char name[41];
    109114        char user[41];
    110115        char group[41];
    111         char *full_name;
     116        char *full_name = name;
    112117        uid_t uid;
    113118        gid_t gid;
    114119
    115         linenum++;
    116 
    117         if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name,
    118                         &type, &mode, user, group, &major,
    119                         &minor, &start, &increment, &count)) ||
    120                 ((major | minor | start | count | increment) > 255))
    121         {
    122             if (*line=='\0' || *line=='#' || isspace(*line))
    123                 continue;
    124             bb_error_msg("line %d invalid: '%s'", linenum, line);
     120        linenum = parser->lineno;
     121
     122        if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u",
     123                    name, &type, &mode, user, group,
     124                    &major, &minor, &start, &increment, &count))
     125         || ((unsigned)(major | minor | start | count | increment) > 255)
     126        ) {
     127            bb_error_msg("invalid line %d: '%s'", linenum, line);
    125128            ret = EXIT_FAILURE;
    126129            continue;
    127130        }
    128         if (name[0] == '#') {
    129             continue;
    130         }
    131131
    132132        gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid();
    133133        uid = (*user) ? get_ug_id(user, xuname2uid) : getuid();
    134         full_name = concat_path_file(rootdir, name);
     134        /* We are already in the right root dir,
     135         * so make absolute paths relative */
     136        if ('/' == *full_name)
     137            full_name++;
    135138
    136139        if (type == 'd') {
    137140            bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
    138141            if (chown(full_name, uid, gid) == -1) {
    139                 bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
    140                 ret = EXIT_FAILURE;
    141                 goto loop;
    142             }
    143             if ((mode != -1) && (chmod(full_name, mode) < 0)){
    144                 bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
    145                 ret = EXIT_FAILURE;
    146                 goto loop;
     142 chown_fail:
     143                bb_perror_msg("line %d: can't chown %s", linenum, full_name);
     144                ret = EXIT_FAILURE;
     145                continue;
     146            }
     147            if (chmod(full_name, mode) < 0) {
     148 chmod_fail:
     149                bb_perror_msg("line %d: can't chmod %s", linenum, full_name);
     150                ret = EXIT_FAILURE;
     151                continue;
    147152            }
    148153        } else if (type == 'f') {
     
    151156                bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
    152157                ret = EXIT_FAILURE;
    153                 goto loop;
    154             }
    155             if (chown(full_name, uid, gid) == -1) {
    156                 bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
    157                 ret = EXIT_FAILURE;
    158                 goto loop;
    159             }
    160             if ((mode != -1) && (chmod(full_name, mode) < 0)){
    161                 bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
    162                 ret = EXIT_FAILURE;
    163                 goto loop;
    164             }
     158                continue;
     159            }
     160            if (chown(full_name, uid, gid) < 0)
     161                goto chown_fail;
     162            if (chmod(full_name, mode) < 0)
     163                goto chmod_fail;
    165164        } else {
    166165            dev_t rdev;
     166            unsigned i;
     167            char *full_name_inc;
    167168
    168169            if (type == 'p') {
    169170                mode |= S_IFIFO;
    170             }
    171             else if (type == 'c') {
     171            } else if (type == 'c') {
    172172                mode |= S_IFCHR;
    173             }
    174             else if (type == 'b') {
     173            } else if (type == 'b') {
    175174                mode |= S_IFBLK;
    176175            } else {
    177176                bb_error_msg("line %d: unsupported file type %c", linenum, type);
    178177                ret = EXIT_FAILURE;
    179                 goto loop;
    180             }
    181 
    182             if (count > 0) {
    183                 int i;
    184                 char *full_name_inc;
    185 
    186                 full_name_inc = xmalloc(strlen(full_name) + 4);
    187                 for (i = start; i < count; i++) {
    188                     sprintf(full_name_inc, "%s%d", full_name, i);
    189                     rdev = makedev(major, minor + (i * increment - start));
    190                     if (mknod(full_name_inc, mode, rdev) == -1) {
    191                         bb_perror_msg("line %d: cannot create node %s", linenum, full_name_inc);
    192                         ret = EXIT_FAILURE;
    193                     }
    194                     else if (chown(full_name_inc, uid, gid) == -1) {
    195                         bb_perror_msg("line %d: chown failed for %s", linenum, full_name_inc);
    196                         ret = EXIT_FAILURE;
    197                     }
    198                     if ((mode != -1) && (chmod(full_name_inc, mode) < 0)){
    199                         bb_perror_msg("line %d: chmod failed for %s", linenum, full_name_inc);
    200                         ret = EXIT_FAILURE;
    201                     }
    202                 }
    203                 free(full_name_inc);
    204             } else {
    205                 rdev = makedev(major, minor);
    206                 if (mknod(full_name, mode, rdev) == -1) {
    207                     bb_perror_msg("line %d: cannot create node %s", linenum, full_name);
     178                continue;
     179            }
     180
     181            full_name_inc = xmalloc(strlen(full_name) + sizeof(int)*3 + 2);
     182            if (count)
     183                count--;
     184            for (i = start; i <= start + count; i++) {
     185                sprintf(full_name_inc, count ? "%s%u" : "%s", full_name, i);
     186                rdev = makedev(major, minor + (i - start) * increment);
     187                if (mknod(full_name_inc, mode, rdev) < 0) {
     188                    bb_perror_msg("line %d: can't create node %s", linenum, full_name_inc);
     189                    ret = EXIT_FAILURE;
     190                } else if (chown(full_name_inc, uid, gid) < 0) {
     191                    bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc);
     192                    ret = EXIT_FAILURE;
     193                } else if (chmod(full_name_inc, mode) < 0) {
     194                    bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc);
    208195                    ret = EXIT_FAILURE;
    209196                }
    210                 else if (chown(full_name, uid, gid) == -1) {
    211                     bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
    212                     ret = EXIT_FAILURE;
    213                 }
    214                 if ((mode != -1) && (chmod(full_name, mode) < 0)){
    215                     bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
    216                     ret = EXIT_FAILURE;
    217                 }
    218             }
     197            }
     198            free(full_name_inc);
    219199        }
    220 loop:
    221         free(line);
    222         free(full_name);
    223     }
    224     fclose(table);
     200    }
     201    if (ENABLE_FEATURE_CLEAN_UP)
     202        config_close(parser);
    225203
    226204    return ret;
  • branches/2.2.9/mindi-busybox/miscutils/mountpoint.c

    r1765 r2725  
    33 * mountpoint implementation for busybox
    44 *
    5  * Copyright (C) 2005 Bernhard Fischer
     5 * Copyright (C) 2005 Bernhard Reutner-Fischer
    66 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 *
    99 * Based on sysvinit's mountpoint
     
    1212#include "libbb.h"
    1313
    14 int mountpoint_main(int argc, char **argv);
    15 int mountpoint_main(int argc, char **argv)
     14int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     15int mountpoint_main(int argc UNUSED_PARAM, char **argv)
    1616{
    1717    struct stat st;
     18    const char *msg;
    1819    char *arg;
    19     int opt = getopt32(argv, "qdx");
     20    int rc, opt;
     21
     22    opt_complementary = "=1"; /* must have one argument */
     23    opt = getopt32(argv, "qdxn");
    2024#define OPT_q (1)
    2125#define OPT_d (2)
    2226#define OPT_x (4)
     27#define OPT_n (8)
     28    arg = argv[optind];
     29    msg = "%s";
    2330
    24     if (optind != argc - 1)
    25         bb_show_usage();
     31    rc = (opt & OPT_x) ? stat(arg, &st) : lstat(arg, &st);
     32    if (rc != 0)
     33        goto err;
    2634
    27     arg = argv[optind];
     35    if (opt & OPT_x) {
     36        if (S_ISBLK(st.st_mode)) {
     37            printf("%u:%u\n", major(st.st_rdev),
     38                        minor(st.st_rdev));
     39            return EXIT_SUCCESS;
     40        }
     41        errno = 0; /* make perror_msg work as error_msg */
     42        msg = "%s: not a block device";
     43        goto err;
     44    }
    2845
    29     if ( (opt & OPT_x && stat(arg, &st) == 0) || (lstat(arg, &st) == 0) ) {
    30         if (opt & OPT_x) {
    31             if (S_ISBLK(st.st_mode)) {
    32                 printf("%u:%u\n", major(st.st_rdev),
    33                             minor(st.st_rdev));
    34                 return EXIT_SUCCESS;
    35             } else {
    36                 if (opt & OPT_q)
    37                     putchar('\n');
    38                 else
    39                     bb_error_msg("%s: not a block device", arg);
     46    errno = ENOTDIR;
     47    if (S_ISDIR(st.st_mode)) {
     48        dev_t st_dev = st.st_dev;
     49        ino_t st_ino = st.st_ino;
     50        char *p = xasprintf("%s/..", arg);
     51
     52        if (stat(p, &st) == 0) {
     53            //int is_mnt = (st_dev != st.st_dev) || (st_dev == st.st_dev && st_ino == st.st_ino);
     54            int is_not_mnt = (st_dev == st.st_dev) && (st_ino != st.st_ino);
     55
     56            if (opt & OPT_d)
     57                printf("%u:%u\n", major(st_dev), minor(st_dev));
     58            if (opt & OPT_n) {
     59                const char *d = find_block_device(arg);
     60                /* name is undefined, but device is mounted -> anonymous superblock! */
     61                /* happens with btrfs */
     62                if (!d) {
     63                    d = "UNKNOWN";
     64                    /* TODO: iterate /proc/mounts, or /proc/self/mountinfo
     65                     * to find out the device name */
     66                }
     67                printf("%s %s\n", d, arg);
    4068            }
    41             return EXIT_FAILURE;
    42         } else
    43         if (S_ISDIR(st.st_mode)) {
    44             dev_t st_dev = st.st_dev;
    45             ino_t st_ino = st.st_ino;
    46             char *p = xasprintf("%s/..", arg);
     69            if (!(opt & (OPT_q | OPT_d | OPT_n)))
     70                printf("%s is %sa mountpoint\n", arg, is_not_mnt ? "not " : "");
     71            return is_not_mnt;
     72        }
     73        arg = p;
     74        /* else: stat had set errno, just fall through */
     75    }
    4776
    48             if (stat(p, &st) == 0) {
    49                 int ret = (st_dev != st.st_dev) ||
    50                     (st_dev == st.st_dev && st_ino == st.st_ino);
    51                 if (opt & OPT_d)
    52                     printf("%u:%u\n", major(st_dev), minor(st_dev));
    53                 else if (!(opt & OPT_q))
    54                     printf("%s is %sa mountpoint\n", arg, ret?"":"not ");
    55                 return !ret;
    56             }
    57         } else {
    58             if (!(opt & OPT_q))
    59                 bb_error_msg("%s: not a directory", arg);
    60             return EXIT_FAILURE;
    61         }
    62     }
     77 err:
    6378    if (!(opt & OPT_q))
    64         bb_perror_msg("%s", arg);
     79        bb_perror_msg(msg, arg);
    6580    return EXIT_FAILURE;
    6681}
  • branches/2.2.9/mindi-busybox/miscutils/mt.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
    55
     
    77#include <sys/mtio.h>
    88
    9 struct mt_opcodes {
    10     const char *name;
    11     short value;
     9/* missing: eod/seod, stoptions, stwrthreshold, densities */
     10static const short opcode_value[] = {
     11    MTBSF,
     12    MTBSFM,
     13    MTBSR,
     14    MTBSS,
     15    MTCOMPRESSION,
     16    MTEOM,
     17    MTERASE,
     18    MTFSF,
     19    MTFSFM,
     20    MTFSR,
     21    MTFSS,
     22    MTLOAD,
     23    MTLOCK,
     24    MTMKPART,
     25    MTNOP,
     26    MTOFFL,
     27    MTOFFL,
     28    MTRAS1,
     29    MTRAS2,
     30    MTRAS3,
     31    MTRESET,
     32    MTRETEN,
     33    MTREW,
     34    MTSEEK,
     35    MTSETBLK,
     36    MTSETDENSITY,
     37    MTSETDRVBUFFER,
     38    MTSETPART,
     39    MTTELL,
     40    MTWSM,
     41    MTUNLOAD,
     42    MTUNLOCK,
     43    MTWEOF,
     44    MTWEOF
    1245};
    1346
    14 /* missing: eod/seod, stoptions, stwrthreshold, densities */
    15 static const struct mt_opcodes opcodes[] = {
    16     {"bsf", MTBSF},
    17     {"bsfm", MTBSFM},
    18     {"bsr", MTBSR},
    19     {"bss", MTBSS},
    20     {"datacompression", MTCOMPRESSION},
    21     {"eom", MTEOM},
    22     {"erase", MTERASE},
    23     {"fsf", MTFSF},
    24     {"fsfm", MTFSFM},
    25     {"fsr", MTFSR},
    26     {"fss", MTFSS},
    27     {"load", MTLOAD},
    28     {"lock", MTLOCK},
    29     {"mkpart", MTMKPART},
    30     {"nop", MTNOP},
    31     {"offline", MTOFFL},
    32     {"rewoffline", MTOFFL},
    33     {"ras1", MTRAS1},
    34     {"ras2", MTRAS2},
    35     {"ras3", MTRAS3},
    36     {"reset", MTRESET},
    37     {"retension", MTRETEN},
    38     {"rewind", MTREW},
    39     {"seek", MTSEEK},
    40     {"setblk", MTSETBLK},
    41     {"setdensity", MTSETDENSITY},
    42     {"drvbuffer", MTSETDRVBUFFER},
    43     {"setpart", MTSETPART},
    44     {"tell", MTTELL},
    45     {"wset", MTWSM},
    46     {"unload", MTUNLOAD},
    47     {"unlock", MTUNLOCK},
    48     {"eof", MTWEOF},
    49     {"weof", MTWEOF},
    50     {0, 0}
    51 };
     47static const char opcode_name[] ALIGN1 =
     48    "bsf"             "\0"
     49    "bsfm"            "\0"
     50    "bsr"             "\0"
     51    "bss"             "\0"
     52    "datacompression" "\0"
     53    "eom"             "\0"
     54    "erase"           "\0"
     55    "fsf"             "\0"
     56    "fsfm"            "\0"
     57    "fsr"             "\0"
     58    "fss"             "\0"
     59    "load"            "\0"
     60    "lock"            "\0"
     61    "mkpart"          "\0"
     62    "nop"             "\0"
     63    "offline"         "\0"
     64    "rewoffline"      "\0"
     65    "ras1"            "\0"
     66    "ras2"            "\0"
     67    "ras3"            "\0"
     68    "reset"           "\0"
     69    "retension"       "\0"
     70    "rewind"          "\0"
     71    "seek"            "\0"
     72    "setblk"          "\0"
     73    "setdensity"      "\0"
     74    "drvbuffer"       "\0"
     75    "setpart"         "\0"
     76    "tell"            "\0"
     77    "wset"            "\0"
     78    "unload"          "\0"
     79    "unlock"          "\0"
     80    "eof"             "\0"
     81    "weof"            "\0";
    5282
    53 int mt_main(int argc, char **argv);
    54 int mt_main(int argc, char **argv)
     83int mt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     84int mt_main(int argc UNUSED_PARAM, char **argv)
    5585{
    5686    const char *file = "/dev/tape";
    57     const struct mt_opcodes *code = opcodes;
    5887    struct mtop op;
    5988    struct mtpos position;
    60     int fd, mode;
     89    int fd, mode, idx;
    6190
    62     if (argc < 2) {
     91    if (!argv[1]) {
    6392        bb_show_usage();
    6493    }
    6594
    6695    if (strcmp(argv[1], "-f") == 0) {
    67         if (argc < 4) {
     96        if (!argv[2] || !argv[3])
    6897            bb_show_usage();
    69         }
    7098        file = argv[2];
    7199        argv += 2;
    72         argc -= 2;
    73100    }
    74101
    75     while (code->name != 0) {
    76         if (strcmp(code->name, argv[1]) == 0)
    77             break;
    78         code++;
    79     }
     102    idx = index_in_strings(opcode_name, argv[1]);
    80103
    81     if (code->name == 0) {
    82         bb_error_msg("unrecognized opcode %s", argv[1]);
    83         return EXIT_FAILURE;
    84     }
     104    if (idx < 0)
     105        bb_error_msg_and_die("unrecognized opcode %s", argv[1]);
    85106
    86     op.mt_op = code->value;
    87     if (argc >= 3)
    88         op.mt_count = xatoi_u(argv[2]);
     107    op.mt_op = opcode_value[idx];
     108    if (argv[2])
     109        op.mt_count = xatoi_positive(argv[2]);
    89110    else
    90         op.mt_count = 1;        /* One, not zero, right? */
     111        op.mt_count = 1;  /* One, not zero, right? */
    91112
    92     switch (code->value) {
     113    switch (opcode_value[idx]) {
    93114        case MTWEOF:
    94115        case MTERASE:
     
    105126    fd = xopen(file, mode);
    106127
    107     switch (code->value) {
     128    switch (opcode_value[idx]) {
    108129        case MTTELL:
    109130            ioctl_or_perror_and_die(fd, MTIOCPOS, &position, "%s", file);
    110             printf("At block %d.\n", (int) position.mt_blkno);
     131            printf("At block %d\n", (int) position.mt_blkno);
    111132            break;
    112133
  • branches/2.2.9/mindi-busybox/miscutils/raidautorun.c

    r1765 r2725  
    33 * raidautorun implementation for busybox
    44 *
    5  * Copyright (C) 2006 Bernhard Fischer
     5 * Copyright (C) 2006 Bernhard Reutner-Fischer
    66 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 *
    99 */
     
    1414#include <linux/raid/md_u.h>
    1515
    16 int raidautorun_main(int argc, char **argv);
    17 int raidautorun_main(int argc, char **argv)
     16int raidautorun_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     17int raidautorun_main(int argc UNUSED_PARAM, char **argv)
    1818{
    19     if (argc != 2)
    20         bb_show_usage();
    21 
    22     xioctl(xopen(argv[1], O_RDONLY), RAID_AUTORUN, NULL);
    23 
     19    xioctl(xopen(single_argv(argv), O_RDONLY), RAID_AUTORUN, NULL);
    2420    return EXIT_SUCCESS;
    2521}
  • branches/2.2.9/mindi-busybox/miscutils/readahead.c

    r1765 r2725  
    88 * Copyright (C) 2006  Michael Opdenacker <michael@free-electrons.com>
    99 *
    10  * Licensed under GPLv2 or later, see file License in this tarball for details.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1111 */
    1212
    1313#include "libbb.h"
    1414
    15 int readahead_main(int argc, char **argv);
    16 int readahead_main(int argc, char **argv)
     15int readahead_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     16int readahead_main(int argc UNUSED_PARAM, char **argv)
    1717{
    18     FILE *f;
    1918    int retval = EXIT_SUCCESS;
    2019
    21     if (argc == 1) bb_show_usage();
     20    if (!argv[1]) {
     21        bb_show_usage();
     22    }
    2223
    2324    while (*++argv) {
    24         if ((f = fopen_or_warn(*argv, "r")) != NULL) {
    25             int r, fd=fileno(f);
     25        int fd = open_or_warn(*argv, O_RDONLY);
     26        if (fd >= 0) {
     27            off_t len;
     28            int r;
    2629
    27             r = readahead(fd, 0, fdlength(fd));
    28             fclose(f);
    29             if (r >= 0) continue;
     30            /* fdlength was reported to be unreliable - use seek */
     31            len = xlseek(fd, 0, SEEK_END);
     32            xlseek(fd, 0, SEEK_SET);
     33            r = readahead(fd, 0, len);
     34            close(fd);
     35            if (r >= 0)
     36                continue;
    3037        }
    3138        retval = EXIT_FAILURE;
  • branches/2.2.9/mindi-busybox/miscutils/runlevel.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * runlevel Prints out the previous and the current runlevel.
     3 * Prints out the previous and the current runlevel.
    44 *
    5  * Version: @(#)runlevel  1.20  16-Apr-1997  MvS
     5 * Version: @(#)runlevel  1.20  16-Apr-1997  MvS
    66 *
    7  *      This file is part of the sysvinit suite,
    8  *      Copyright 1991-1997 Miquel van Smoorenburg.
     7 * This file is part of the sysvinit suite,
     8 * Copyright 1991-1997 Miquel van Smoorenburg.
    99 *
    10  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1111 *
    12  * initially busyboxified by Bernhard Fischer
     12 * initially busyboxified by Bernhard Reutner-Fischer
    1313 */
     14#include "libbb.h"
     15#include <utmp.h>
    1416
    15 #include <utmp.h>
    16 #include "libbb.h"
    17 
    18 int runlevel_main(int argc, char **argv);
    19 int runlevel_main(int argc, char **argv)
     17int runlevel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     18int runlevel_main(int argc UNUSED_PARAM, char **argv)
    2019{
    2120    struct utmp *ut;
    2221    char prev;
    2322
    24     if (argc > 1) utmpname(argv[1]);
     23    if (argv[1]) utmpname(argv[1]);
    2524
    2625    setutent();
  • branches/2.2.9/mindi-busybox/miscutils/rx.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /*-------------------------------------------------------------------------
    3  * Filename:      xmodem.c
     2/*
    43 * Copyright:     Copyright (C) 2001, Hewlett-Packard Company
    54 * Author:        Christopher Hoover <ch@hpl.hp.com>
     
    76 *                and the like
    87 * Created at:    Thu Dec 20 01:58:08 PST 2001
    9  *-----------------------------------------------------------------------*/
    10 /*
    11  * xmodem.c: xmodem functionality for uploading of kernels and
    12  *            the like
     8 *
     9 * xmodem functionality for uploading of kernels and the like
    1310 *
    1411 * Copyright (C) 2001 Hewlett-Packard Laboratories
    1512 *
    16  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1714 *
    1815 * This was originally written for blob and then adapted for busybox.
    19  *
    2016 */
    2117
     
    2824#define NAK 0x15
    2925#define BS  0x08
     26#define PAD 0x1A
    3027
    3128/*
    32 
    3329Cf:
    34 
    3530  http://www.textfiles.com/apple/xmodem
    3631  http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt
    3732  http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt
    3833  http://www.phys.washington.edu/~belonis/xmodem/modmprot.col
    39 
    4034*/
    4135
     
    4438#define MAXERRORS 10
    4539
    46 static int read_byte(int fd, unsigned int timeout)
    47 {
    48     char buf[1];
     40#define read_fd  STDIN_FILENO
     41#define write_fd STDOUT_FILENO
     42
     43static int read_byte(unsigned timeout)
     44{
     45    unsigned char buf;
    4946    int n;
    5047
    5148    alarm(timeout);
    52 
    53     n = read(fd, &buf, 1);
    54 
     49    /* NOT safe_read! We want ALRM to interrupt us */
     50    n = read(read_fd, &buf, 1);
    5551    alarm(0);
    56 
    5752    if (n == 1)
    58         return buf[0] & 0xff;
    59     else
    60         return -1;
    61 }
    62 
    63 static int receive(char *error_buf, size_t error_buf_size,
    64                    int ttyfd, int filefd)
    65 {
    66     char blockBuf[1024];
    67     unsigned int errors = 0;
    68     unsigned int wantBlockNo = 1;
    69     unsigned int length = 0;
    70     int docrc = 1;
    71     char nak = 'C';
    72     unsigned int timeout = TIMEOUT_LONG;
    73 
    74 #define note_error(fmt,args...) \
    75     snprintf(error_buf, error_buf_size, fmt,##args)
     53        return buf;
     54    return -1;
     55}
     56
     57static int receive(/*int read_fd, */int file_fd)
     58{
     59    unsigned char blockBuf[1024];
     60    unsigned blockLength = 0;
     61    unsigned errors = 0;
     62    unsigned wantBlockNo = 1;
     63    unsigned length = 0;
     64    int do_crc = 1;
     65    char reply_char;
     66    unsigned timeout = TIMEOUT_LONG;
    7667
    7768    /* Flush pending input */
    78     tcflush(ttyfd, TCIFLUSH);
     69    tcflush(read_fd, TCIFLUSH);
    7970
    8071    /* Ask for CRC; if we get errors, we will go with checksum */
    81     write(ttyfd, &nak, 1);
     72    reply_char = 'C';
     73    full_write(write_fd, &reply_char, 1);
    8274
    8375    for (;;) {
    8476        int blockBegin;
    8577        int blockNo, blockNoOnesCompl;
    86         int blockLength;
    87         int cksum = 0;
    88         int crcHi = 0;
    89         int crcLo = 0;
    90 
    91         blockBegin = read_byte(ttyfd, timeout);
     78        int cksum_or_crc;
     79        int expected;
     80        int i, j;
     81
     82        blockBegin = read_byte(timeout);
    9283        if (blockBegin < 0)
    9384            goto timeout;
    9485
     86        /* If last block, remove padding */
     87        if (blockBegin == EOT) {
     88            /* Data blocks can be padded with ^Z characters */
     89            /* This code tries to detect and remove them */
     90            if (blockLength >= 3
     91             && blockBuf[blockLength - 1] == PAD
     92             && blockBuf[blockLength - 2] == PAD
     93             && blockBuf[blockLength - 3] == PAD
     94            ) {
     95                while (blockLength
     96                       && blockBuf[blockLength - 1] == PAD
     97                ) {
     98                    blockLength--;
     99                }
     100            }
     101        }
     102        /* Write previously received block */
     103        if (blockLength) {
     104            errno = 0;
     105            if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
     106                bb_perror_msg("can't write to file");
     107                goto fatal;
     108            }
     109        }
     110
    95111        timeout = TIMEOUT;
    96         nak = NAK;
     112        reply_char = NAK;
    97113
    98114        switch (blockBegin) {
     
    100116        case STX:
    101117            break;
    102 
    103118        case EOT:
    104             nak = ACK;
    105             write(ttyfd, &nak, 1);
    106             goto done;
    107 
     119            reply_char = ACK;
     120            full_write(write_fd, &reply_char, 1);
     121            return length;
    108122        default:
    109123            goto error;
    110124        }
    111125
    112         /* block no */
    113         blockNo = read_byte(ttyfd, TIMEOUT);
     126        /* Block no */
     127        blockNo = read_byte(TIMEOUT);
    114128        if (blockNo < 0)
    115129            goto timeout;
    116130
    117         /* block no one's compliment */
    118         blockNoOnesCompl = read_byte(ttyfd, TIMEOUT);
     131        /* Block no, in one's complement form */
     132        blockNoOnesCompl = read_byte(TIMEOUT);
    119133        if (blockNoOnesCompl < 0)
    120134            goto timeout;
    121135
    122136        if (blockNo != (255 - blockNoOnesCompl)) {
    123             note_error("bad block ones compl");
     137            bb_error_msg("bad block ones compl");
    124138            goto error;
    125139        }
     
    127141        blockLength = (blockBegin == SOH) ? 128 : 1024;
    128142
    129         {
    130             int i;
    131 
    132             for (i = 0; i < blockLength; i++) {
    133                 int cc = read_byte(ttyfd, TIMEOUT);
    134                 if (cc < 0)
    135                     goto timeout;
    136                 blockBuf[i] = cc;
    137             }
    138         }
    139 
    140         if (docrc) {
    141             crcHi = read_byte(ttyfd, TIMEOUT);
    142             if (crcHi < 0)
    143                 goto timeout;
    144 
    145             crcLo = read_byte(ttyfd, TIMEOUT);
    146             if (crcLo < 0)
     143        for (i = 0; i < blockLength; i++) {
     144            int cc = read_byte(TIMEOUT);
     145            if (cc < 0)
     146                goto timeout;
     147            blockBuf[i] = cc;
     148        }
     149
     150        if (do_crc) {
     151            cksum_or_crc = read_byte(TIMEOUT);
     152            if (cksum_or_crc < 0)
     153                goto timeout;
     154            cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT);
     155            if (cksum_or_crc < 0)
    147156                goto timeout;
    148157        } else {
    149             cksum = read_byte(ttyfd, TIMEOUT);
    150             if (cksum < 0)
     158            cksum_or_crc = read_byte(TIMEOUT);
     159            if (cksum_or_crc < 0)
    151160                goto timeout;
    152161        }
     
    157166            /* meta data. */
    158167            goto next;
    159         } else if (blockNo != (wantBlockNo & 0xff)) {
    160             note_error("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
    161             goto error;
    162         }
    163 
    164         if (docrc) {
    165             int crc = 0;
    166             int i, j;
    167             int expectedCrcHi;
    168             int expectedCrcLo;
    169 
     168        }
     169        if (blockNo != (wantBlockNo & 0xff)) {
     170            bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
     171            goto error;
     172        }
     173
     174        expected = 0;
     175        if (do_crc) {
    170176            for (i = 0; i < blockLength; i++) {
    171                 crc = crc ^ (int) blockBuf[i] << 8;
    172                 for (j = 0; j < 8; j++)
    173                     if (crc & 0x8000)
    174                         crc = crc << 1 ^ 0x1021;
     177                expected = expected ^ blockBuf[i] << 8;
     178                for (j = 0; j < 8; j++) {
     179                    if (expected & 0x8000)
     180                        expected = (expected << 1) ^ 0x1021;
    175181                    else
    176                         crc = crc << 1;
    177             }
    178 
    179             expectedCrcHi = (crc >> 8) & 0xff;
    180             expectedCrcLo = crc & 0xff;
    181 
    182             if ((crcHi != expectedCrcHi) ||
    183                 (crcLo != expectedCrcLo)) {
    184                 note_error("crc error, expected 0x%02x 0x%02x, got 0x%02x 0x%02x", expectedCrcHi, expectedCrcLo, crcHi, crcLo);
    185                 goto error;
    186             }
     182                        expected = (expected << 1);
     183                }
     184            }
     185            expected &= 0xffff;
    187186        } else {
    188             unsigned char expectedCksum = 0;
    189             int i;
    190 
    191187            for (i = 0; i < blockLength; i++)
    192                 expectedCksum += blockBuf[i];
    193 
    194             if (cksum != expectedCksum) {
    195                 note_error("checksum error, expected 0x%02x, got 0x%02x", expectedCksum, cksum);
    196                 goto error;
    197             }
     188                expected += blockBuf[i];
     189            expected &= 0xff;
     190        }
     191        if (cksum_or_crc != expected) {
     192            bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
     193                               : "checksum error, expected 0x%02x, got 0x%02x",
     194                    expected, cksum_or_crc);
     195            goto error;
    198196        }
    199197
    200198        wantBlockNo++;
    201199        length += blockLength;
    202 
    203         if (full_write(filefd, blockBuf, blockLength) < 0) {
    204             note_error("write to file failed: %m");
    205             goto fatal;
    206         }
    207 
    208     next:
     200 next:
    209201        errors = 0;
    210         nak = ACK;
    211         write(ttyfd, &nak, 1);
     202        reply_char = ACK;
     203        full_write(write_fd, &reply_char, 1);
    212204        continue;
    213 
    214     error:
    215     timeout:
     205 error:
     206 timeout:
    216207        errors++;
    217208        if (errors == MAXERRORS) {
    218209            /* Abort */
    219210
    220             // if using crc, try again w/o crc
    221             if (nak == 'C') {
    222                 nak = NAK;
     211            /* If were asking for crc, try again w/o crc */
     212            if (reply_char == 'C') {
     213                reply_char = NAK;
    223214                errors = 0;
    224                 docrc = 0;
    225                 goto timeout;
    226             }
    227 
    228             note_error("too many errors; giving up");
    229 
    230         fatal:
    231             /* 5 CAN followed by 5 BS */
    232             write(ttyfd, "\030\030\030\030\030\010\010\010\010\010", 10);
     215                do_crc = 0;
     216                goto timeout;
     217            }
     218            bb_error_msg("too many errors; giving up");
     219 fatal:
     220            /* 5 CAN followed by 5 BS. Don't try too hard... */
     221            safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10);
    233222            return -1;
    234223        }
    235224
    236225        /* Flush pending input */
    237         tcflush(ttyfd, TCIFLUSH);
    238 
    239         write(ttyfd, &nak, 1);
     226        tcflush(read_fd, TCIFLUSH);
     227
     228        full_write(write_fd, &reply_char, 1);
     229    } /* for (;;) */
     230}
     231
     232static void sigalrm_handler(int UNUSED_PARAM signum)
     233{
     234}
     235
     236int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     237int rx_main(int argc UNUSED_PARAM, char **argv)
     238{
     239    struct termios tty, orig_tty;
     240    int termios_err;
     241    int file_fd;
     242    int n;
     243
     244    /* Disabled by vda:
     245     * why we can't receive from stdin? Why we *require*
     246     * controlling tty?? */
     247    /*read_fd = xopen(CURRENT_TTY, O_RDWR);*/
     248    file_fd = xopen(single_argv(argv), O_RDWR|O_CREAT|O_TRUNC);
     249
     250    termios_err = tcgetattr(read_fd, &tty);
     251    if (termios_err == 0) {
     252        orig_tty = tty;
     253        cfmakeraw(&tty);
     254        tcsetattr(read_fd, TCSAFLUSH, &tty);
    240255    }
    241256
    242  done:
    243     return length;
    244 
    245 #undef note_error
    246 }
    247 
    248 static void sigalrm_handler(int ATTRIBUTE_UNUSED signum)
    249 {
    250 }
    251 
    252 int rx_main(int argc, char **argv);
    253 int rx_main(int argc, char **argv)
    254 {
    255     char *fn;
    256     int ttyfd, filefd;
    257     struct termios tty, orig_tty;
    258     struct sigaction act;
    259     int n;
    260     char error_buf[256];
    261 
    262     if (argc != 2)
    263             bb_show_usage();
    264 
    265     fn = argv[1];
    266     ttyfd = xopen(CURRENT_TTY, O_RDWR);
    267     filefd = xopen(fn, O_RDWR|O_CREAT|O_TRUNC);
    268 
    269     if (tcgetattr(ttyfd, &tty) < 0)
    270             bb_perror_msg_and_die("tcgetattr");
    271 
    272     orig_tty = tty;
    273 
    274     cfmakeraw(&tty);
    275     tcsetattr(ttyfd, TCSAFLUSH, &tty);
    276 
    277     memset(&act, 0, sizeof(act));
    278     act.sa_handler = sigalrm_handler;
    279     sigaction(SIGALRM, &act, 0);
    280 
    281     n = receive(error_buf, sizeof(error_buf), ttyfd, filefd);
    282 
    283     close(filefd);
    284 
    285     tcsetattr(ttyfd, TCSAFLUSH, &orig_tty);
    286 
    287     if (n < 0)
    288         bb_error_msg_and_die("\nreceive failed:\n  %s", error_buf);
    289 
    290     fflush_stdout_and_exit(EXIT_SUCCESS);
    291 }
     257    /* No SA_RESTART: we want ALRM to interrupt read() */
     258    signal_no_SA_RESTART_empty_mask(SIGALRM, sigalrm_handler);
     259
     260    n = receive(file_fd);
     261
     262    if (termios_err == 0)
     263        tcsetattr(read_fd, TCSAFLUSH, &orig_tty);
     264    if (ENABLE_FEATURE_CLEAN_UP)
     265        close(file_fd);
     266    fflush_stdout_and_exit(n >= 0);
     267}
  • branches/2.2.9/mindi-busybox/miscutils/setsid.c

    r1765 r2725  
    55 * In the public domain.
    66 *
    7  * 1999-02-22 Arkadiusz Mikiewicz <misiek@pld.ORG.PL>
     7 * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
    88 * - added Native Language Support
    99 *
     
    1717#include "libbb.h"
    1818
    19 int setsid_main(int argc, char **argv);
    20 int setsid_main(int argc, char **argv)
     19int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     20int setsid_main(int argc UNUSED_PARAM, char **argv)
    2121{
    22     if (argc < 2)
     22    if (!argv[1])
    2323        bb_show_usage();
    2424
    25     /* Comment why is this necessary? */
    26     if (getpgrp() == getpid())
    27         forkexit_or_rexec(argv);
     25    /* setsid() is allowed only when we are not a process group leader.
     26     * Otherwise our PID serves as PGID of some existing process group
     27     * and cannot be used as PGID of a new process group. */
     28    if (setsid() < 0) {
     29        pid_t pid = fork_or_rexec(argv);
     30        if (pid != 0) {
     31            /* parent */
     32            /* TODO:
     33             * we can waitpid(pid, &status, 0) and then even
     34             * emulate exitcode, making the behavior consistent
     35             * in both forked and non forked cases.
     36             * However, the code is larger and upstream
     37             * does not do such trick.
     38             */
     39            exit(EXIT_SUCCESS);
     40        }
    2841
    29     setsid();  /* no error possible */
     42        /* child */
     43        /* now there should be no error: */
     44        setsid();
     45    }
    3046
    31     BB_EXECVP(argv[1], argv + 1);
    32     bb_perror_msg_and_die("%s", argv[1]);
     47    argv++;
     48    BB_EXECVP_or_die(argv);
    3349}
  • branches/2.2.9/mindi-busybox/miscutils/strings.c

    r1765 r2725  
    33 * strings implementation for busybox
    44 *
    5  * Copyright Tito Ragusa <farmatito@tiscali.it>
     5 * Copyright 2003 Tito Ragusa <farmatito@tiscali.it>
    66 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    9 
    10 #include <getopt.h>
    119
    1210#include "libbb.h"
    1311
    14 #define WHOLE_FILE      1
    15 #define PRINT_NAME      2
    16 #define PRINT_OFFSET    4
    17 #define SIZE            8
     12#define WHOLE_FILE    1
     13#define PRINT_NAME    2
     14#define PRINT_OFFSET  4
     15#define SIZE          8
    1816
    19 int strings_main(int argc, char **argv);
    20 int strings_main(int argc, char **argv)
     17int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     18int strings_main(int argc UNUSED_PARAM, char **argv)
    2119{
    2220    int n, c, status = EXIT_SUCCESS;
    23     unsigned opt;
    2421    unsigned count;
    2522    off_t offset;
    26     FILE *file = stdin;
     23    FILE *file;
    2724    char *string;
    2825    const char *fmt = "%s: ";
    2926    const char *n_arg = "4";
    3027
    31     opt = getopt32(argv, "afon:", &n_arg);
     28    getopt32(argv, "afon:", &n_arg);
    3229    /* -a is our default behaviour */
    3330    /*argc -= optind;*/
     
    4138        fmt = "{%s}: ";
    4239        *--argv = (char *)bb_msg_standard_input;
    43         goto PIPE;
    4440    }
    4541
    4642    do {
    47         file = fopen_or_warn(*argv, "r");
     43        file = fopen_or_warn_stdin(*argv);
    4844        if (!file) {
    4945            status = EXIT_FAILURE;
    5046            continue;
    5147        }
    52  PIPE:
    5348        offset = 0;
    5449        count = 0;
    5550        do {
    5651            c = fgetc(file);
    57             if (isprint(c) || c == '\t') {
     52            if (isprint_asciionly(c) || c == '\t') {
    5853                if (count > n) {
    59                     putchar(c);
     54                    bb_putchar(c);
    6055                } else {
    6156                    string[count] = c;
    6257                    if (count == n) {
    63                         if (opt & PRINT_NAME) {
     58                        if (option_mask32 & PRINT_NAME) {
    6459                            printf(fmt, *argv);
    6560                        }
    66                         if (opt & PRINT_OFFSET) {
     61                        if (option_mask32 & PRINT_OFFSET) {
    6762                            printf("%7"OFF_FMT"o ", offset - n);
    6863                        }
     
    7368            } else {
    7469                if (count > n) {
    75                     putchar('\n');
     70                    bb_putchar('\n');
    7671                }
    7772                count = 0;
  • branches/2.2.9/mindi-busybox/miscutils/taskset.c

    r1765 r2725  
    22/*
    33 * taskset - retrieve or set a processes' CPU affinity
    4  * Copyright (c) 2006 Bernhard Fischer
     4 * Copyright (c) 2006 Bernhard Reutner-Fischer
    55 *
    6  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    77 */
    88
    99#include <sched.h>
    10 #include <getopt.h> /* optind */
    1110#include "libbb.h"
    1211
    1312#if ENABLE_FEATURE_TASKSET_FANCY
    1413#define TASKSET_PRINTF_MASK "%s"
    15 #define from_cpuset(x) __from_cpuset(&x)
    1614/* craft a string from the mask */
    17 static char *__from_cpuset(cpu_set_t *mask)
     15static char *from_cpuset(cpu_set_t *mask)
    1816{
    1917    int i;
    20     char *ret = 0, *str = xzalloc(9);
     18    char *ret = NULL;
     19    char *str = xzalloc((CPU_SETSIZE / 4) + 1); /* we will leak it */
    2120
    2221    for (i = CPU_SETSIZE - 4; i >= 0; i -= 4) {
    23         char val = 0;
     22        int val = 0;
    2423        int off;
    2524        for (off = 0; off <= 3; ++off)
    26             if (CPU_ISSET(i+off, mask))
    27                 val |= 1<<off;
    28 
     25            if (CPU_ISSET(i + off, mask))
     26                val |= 1 << off;
    2927        if (!ret && val)
    3028            ret = str;
    31         *str++ = (val-'0'<=9) ? (val+48) : (val+87);
     29        *str++ = bb_hexdigits_upcase[val] | 0x20;
    3230    }
    3331    return ret;
    3432}
    3533#else
    36 #define TASKSET_PRINTF_MASK "%x"
    37 /* (void*) cast is for battling gcc: */
    38 /* "dereferencing type-punned pointer will break strict-aliasing rules" */
    39 #define from_cpuset(mask) (*(unsigned*)(void*)&(mask))
     34#define TASKSET_PRINTF_MASK "%llx"
     35static unsigned long long from_cpuset(cpu_set_t *mask)
     36{
     37    struct BUG_CPU_SETSIZE_is_too_small {
     38        char BUG_CPU_SETSIZE_is_too_small[
     39            CPU_SETSIZE < sizeof(int) ? -1 : 1];
     40    };
     41    char *p = (void*)mask;
     42
     43    /* Take the least significant bits. Careful!
     44     * Consider both CPU_SETSIZE=4 and CPU_SETSIZE=1024 cases
     45     */
     46#if BB_BIG_ENDIAN
     47    /* For big endian, it means LAST bits */
     48    if (CPU_SETSIZE < sizeof(long))
     49        p += CPU_SETSIZE - sizeof(int);
     50    else if (CPU_SETSIZE < sizeof(long long))
     51        p += CPU_SETSIZE - sizeof(long);
     52    else
     53        p += CPU_SETSIZE - sizeof(long long);
     54#endif
     55    if (CPU_SETSIZE < sizeof(long))
     56        return *(unsigned*)p;
     57    if (CPU_SETSIZE < sizeof(long long))
     58        return *(unsigned long*)p;
     59    return *(unsigned long long*)p;
     60}
    4061#endif
    4162
    42 #define OPT_p 1
    4363
    44 int taskset_main(int argc, char** argv);
    45 int taskset_main(int argc, char** argv)
     64int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     65int taskset_main(int argc UNUSED_PARAM, char **argv)
    4666{
    47     cpu_set_t mask, new_mask;
     67    cpu_set_t mask;
    4868    pid_t pid = 0;
    49     unsigned opt;
    50     const char *state = "current\0new";
    51     char *p_opt = NULL, *aff = NULL;
     69    unsigned opt_p;
     70    const char *current_new;
     71    char *pid_str;
     72    char *aff = aff; /* for compiler */
    5273
    53     opt = getopt32(argv, "+p:", &p_opt);
     74    /* NB: we mimic util-linux's taskset: -p does not take
     75     * an argument, i.e., "-pN" is NOT valid, only "-p N"!
     76     * Indeed, util-linux-2.13-pre7 uses:
     77     * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
    5478
    55     if (opt & OPT_p) {
    56         if (argc == optind+1) { /* -p <aff> <pid> */
    57             aff = p_opt;
    58             p_opt = argv[optind];
     79    opt_complementary = "-1"; /* at least 1 arg */
     80    opt_p = getopt32(argv, "+p");
     81    argv += optind;
     82
     83    if (opt_p) {
     84        pid_str = *argv++;
     85        if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
     86            aff = pid_str;
     87            pid_str = *argv; /* NB: *argv != NULL in this case */
    5988        }
    60         argv += optind; /* me -p <arg> */
    61         pid = xatoul_range(p_opt, 1, ULONG_MAX); /* -p <pid> */
    62     } else
    63         aff = *++argv; /* <aff> <cmd...> */
    64     if (aff) {
    65         unsigned i = 0;
    66         unsigned long l = xstrtol_range(aff, 0, 1, LONG_MAX);
     89        /* else it was just "-p <pid>", and *argv == NULL */
     90        pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
     91    } else {
     92        aff = *argv++; /* <aff> <cmd...> */
     93        if (!*argv)
     94            bb_show_usage();
     95    }
    6796
    68         CPU_ZERO(&new_mask);
    69         while (i < CPU_SETSIZE && l >= (1<<i)) {
    70             if ((1<<i) & l)
    71                 CPU_SET(i, &new_mask);
    72             ++i;
     97    current_new = "current\0new";
     98    if (opt_p) {
     99 print_aff:
     100        if (sched_getaffinity(pid, sizeof(mask), &mask) < 0)
     101            bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
     102        printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
     103                pid, current_new, from_cpuset(&mask));
     104        if (!*argv) {
     105            /* Either it was just "-p <pid>",
     106             * or it was "-p <aff> <pid>" and we came here
     107             * for the second time (see goto below) */
     108            return EXIT_SUCCESS;
     109        }
     110        *argv = NULL;
     111        current_new += 8; /* "new" */
     112    }
     113
     114    { /* Affinity was specified, translate it into cpu_set_t */
     115        unsigned i;
     116        /* Do not allow zero mask: */
     117        unsigned long long m = xstrtoull_range(aff, 0, 1, ULLONG_MAX);
     118        enum { CNT_BIT = CPU_SETSIZE < sizeof(m)*8 ? CPU_SETSIZE : sizeof(m)*8 };
     119
     120        CPU_ZERO(&mask);
     121        for (i = 0; i < CNT_BIT; i++) {
     122            unsigned long long bit = (1ULL << i);
     123            if (bit & m)
     124                CPU_SET(i, &mask);
    73125        }
    74126    }
    75127
    76     if (opt & OPT_p) {
    77  print_aff:
    78         if (sched_getaffinity(pid, sizeof(mask), &mask) < 0)
    79             bb_perror_msg_and_die("failed to %cet pid %d's affinity", 'g', pid);
    80         printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
    81                 pid, state, from_cpuset(mask));
    82         if (!*argv) /* no new affinity given or we did print already, done. */
    83             return EXIT_SUCCESS;
    84     }
     128    /* Set pid's or our own (pid==0) affinity */
     129    if (sched_setaffinity(pid, sizeof(mask), &mask))
     130        bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
    85131
    86     if (sched_setaffinity(pid, sizeof(new_mask), &new_mask))
    87         bb_perror_msg_and_die("failed to %cet pid %d's affinity", 's', pid);
    88     if (opt & OPT_p) {
    89         state += 8;
    90         ++argv;
    91         goto print_aff;
    92     }
    93     ++argv;
    94     BB_EXECVP(*argv, argv);
    95     bb_perror_msg_and_die("%s", *argv);
     132    if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */
     133        goto print_aff; /* print new affinity and exit */
     134
     135    BB_EXECVP_or_die(argv);
    96136}
    97 #undef OPT_p
    98 #undef TASKSET_PRINTF_MASK
    99 #undef from_cpuset
  • branches/2.2.9/mindi-busybox/miscutils/time.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* `time' utility to display resource usage of processes.
     2/* 'time' utility to display resource usage of processes.
    33   Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc.
    44
    5    Licensed under GPL version 2, see file LICENSE in this tarball for details.
     5   Licensed under GPLv2, see file LICENSE in this source tree.
    66*/
    77/* Originally written by David Keppel <pardo@cs.washington.edu>.
     
    2828/* The output format for the -p option .*/
    2929static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S";
    30 
    3130
    3231/* Format string for printing all statistics verbosely.
     
    5756    "\tExit status: %x";
    5857
    59 
    6058/* Wait for and fill in data on child process PID.
    6159   Return 0 on error, 1 if ok.  */
    62 
    6360/* pid_t is short on BSDI, so don't try to promote it.  */
    64 static int resuse_end(pid_t pid, resource_t * resp)
    65 {
    66     int status;
     61static void resuse_end(pid_t pid, resource_t *resp)
     62{
    6763    pid_t caught;
    6864
    6965    /* Ignore signals, but don't ignore the children.  When wait3
    7066       returns the child process, set the time the command finished. */
    71     while ((caught = wait3(&status, 0, &resp->ru)) != pid) {
    72         if (caught == -1)
    73             return 0;
     67    while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) {
     68        if (caught == -1 && errno != EINTR) {
     69            bb_perror_msg("wait");
     70            return;
     71        }
    7472    }
    75     resp->elapsed_ms = (monotonic_us() / 1000) - resp->elapsed_ms;
    76     resp->waitstatus = status;
    77     return 1;
    78 }
    79 
    80 /* Print ARGV, with each entry in ARGV separated by FILLER.  */
    81 static void printargv(char *const *argv, const char *filler)
    82 {
    83     fputs(*argv, stdout);
    84     while (*++argv) {
    85         fputs(filler, stdout);
    86         fputs(*argv, stdout);
    87     }
     73    resp->elapsed_ms = monotonic_ms() - resp->elapsed_ms;
     74}
     75
     76static void printargv(char *const *argv)
     77{
     78    const char *fmt = " %s" + 1;
     79    do {
     80        printf(fmt, *argv);
     81        fmt = " %s";
     82    } while (*++argv);
    8883}
    8984
     
    9590   Note: Some machines express getrusage statistics in terms of K,
    9691   others in terms of pages.  */
    97 
    98 static unsigned long ptok(unsigned long pages)
    99 {
    100     static unsigned long ps;
     92static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
     93{
    10194    unsigned long tmp;
    10295
    103     /* Initialization.  */
    104     if (ps == 0)
    105         ps = getpagesize();
    106 
    10796    /* Conversion.  */
    108     if (pages > (LONG_MAX / ps)) {  /* Could overflow.  */
    109         tmp = pages / 1024; /* Smaller first, */
    110         return tmp * ps;    /* then larger.  */
     97    if (pages > (LONG_MAX / pagesize)) { /* Could overflow.  */
     98        tmp = pages / 1024;     /* Smaller first, */
     99        return tmp * pagesize;  /* then larger.  */
    111100    }
    112101    /* Could underflow.  */
    113     tmp = pages * ps;   /* Larger first, */
    114     return tmp / 1024;  /* then smaller.  */
     102    tmp = pages * pagesize; /* Larger first, */
     103    return tmp / 1024;      /* then smaller.  */
    115104}
    116105
     
    163152#endif
    164153
    165 static void summarize(const char *fmt, char **command, resource_t * resp)
     154static void summarize(const char *fmt, char **command, resource_t *resp)
    166155{
    167156    unsigned vv_ms;     /* Elapsed virtual (CPU) milliseconds */
    168157    unsigned cpu_ticks; /* Same, in "CPU ticks" */
    169 
     158    unsigned pagesize = getpagesize();
     159
     160    /* Impossible: we do not use WUNTRACED flag in wait()...
    170161    if (WIFSTOPPED(resp->waitstatus))
    171162        printf("Command stopped by signal %u\n",
    172163                WSTOPSIG(resp->waitstatus));
    173     else if (WIFSIGNALED(resp->waitstatus))
     164    else */
     165    if (WIFSIGNALED(resp->waitstatus))
    174166        printf("Command terminated by signal %u\n",
    175167                WTERMSIG(resp->waitstatus));
     
    182174
    183175#if (1000 / TICKS_PER_SEC) * TICKS_PER_SEC == 1000
    184     /* 1000 is exactly divisible by TICKS_PER_SEC */
     176    /* 1000 is exactly divisible by TICKS_PER_SEC (typical) */
    185177    cpu_ticks = vv_ms / (1000 / TICKS_PER_SEC);
    186178#else
     
    188180#endif
    189181    if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
    190 
    191     /* putchar() != putc(stdout) in glibc! */
    192182
    193183    while (*fmt) {
     
    206196         * for everything. With this we do a lot of 1-byte writes */
    207197        default:
    208             putc(*fmt, stdout);
     198            bb_putchar(*fmt);
    209199            break;
    210200#endif
     
    216206        /* and we do not take format str from user */
    217207            default:
    218                 putc('%', stdout);
     208                bb_putchar('%');
    219209                /*FALLTHROUGH*/
    220210            case '%':
    221211                if (!*fmt) goto ret;
    222                 putc(*fmt, stdout);
     212                bb_putchar(*fmt);
    223213                break;
    224214#endif
    225215            case 'C':   /* The command that got timed.  */
    226                 printargv(command, " ");
     216                printargv(command);
    227217                break;
    228218            case 'D':   /* Average unshared data size.  */
    229219                printf("%lu",
    230                         ptok((UL) resp->ru.ru_idrss) / cpu_ticks +
    231                         ptok((UL) resp->ru.ru_isrss) / cpu_ticks);
     220                    (ptok(pagesize, (UL) resp->ru.ru_idrss) +
     221                     ptok(pagesize, (UL) resp->ru.ru_isrss)) / cpu_ticks);
    232222                break;
    233223            case 'E': { /* Elapsed real (wall clock) time.  */
     
    253243            case 'K':   /* Average mem usage == data+stack+text.  */
    254244                printf("%lu",
    255                         ptok((UL) resp->ru.ru_idrss) / cpu_ticks +
    256                         ptok((UL) resp->ru.ru_isrss) / cpu_ticks +
    257                         ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);
     245                    (ptok(pagesize, (UL) resp->ru.ru_idrss) +
     246                     ptok(pagesize, (UL) resp->ru.ru_isrss) +
     247                     ptok(pagesize, (UL) resp->ru.ru_ixrss)) / cpu_ticks);
    258248                break;
    259249            case 'M':   /* Maximum resident set size.  */
    260                 printf("%lu", ptok((UL) resp->ru.ru_maxrss));
     250                printf("%lu", ptok(pagesize, (UL) resp->ru.ru_maxrss));
    261251                break;
    262252            case 'O':   /* Outputs.  */
     
    311301                break;
    312302            case 'X':   /* Average shared text size.  */
    313                 printf("%lu", ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);
     303                printf("%lu", ptok(pagesize, (UL) resp->ru.ru_ixrss) / cpu_ticks);
    314304                break;
    315305            case 'Z':   /* Page size.  */
    316                 printf("%u", getpagesize());
     306                printf("%u", pagesize);
    317307                break;
    318308            case 'c':   /* Involuntary context switches.  */
     
    328318                break;
    329319            case 'p':   /* Average stack segment.  */
    330                 printf("%lu", ptok((UL) resp->ru.ru_isrss) / cpu_ticks);
     320                printf("%lu", ptok(pagesize, (UL) resp->ru.ru_isrss) / cpu_ticks);
    331321                break;
    332322            case 'r':   /* Incoming socket messages received.  */
     
    337327                break;
    338328            case 't':   /* Average resident set size.  */
    339                 printf("%lu", ptok((UL) resp->ru.ru_idrss) / cpu_ticks);
     329                printf("%lu", ptok(pagesize, (UL) resp->ru.ru_idrss) / cpu_ticks);
    340330                break;
    341331            case 'w':   /* Voluntary context switches.  */
     
    352342            switch (*++fmt) {
    353343            default:
    354                 putc('\\', stdout);
     344                bb_putchar('\\');
    355345                /*FALLTHROUGH*/
    356346            case '\\':
    357347                if (!*fmt) goto ret;
    358                 putc(*fmt, stdout);
     348                bb_putchar(*fmt);
    359349                break;
    360350            case 't':
    361                 putc('\t', stdout);
     351                bb_putchar('\t');
    362352                break;
    363353            case 'n':
    364                 putc('\n', stdout);
     354                bb_putchar('\n');
    365355                break;
    366356            }
     
    371361    }
    372362 /* ret: */
    373     putc('\n', stdout);
     363    bb_putchar('\n');
    374364}
    375365
    376366/* Run command CMD and return statistics on it.
    377367   Put the statistics in *RESP.  */
    378 static void run_command(char *const *cmd, resource_t * resp)
    379 {
    380     pid_t pid;          /* Pid of child.  */
    381     __sighandler_t interrupt_signal, quit_signal;
    382 
    383     resp->elapsed_ms = monotonic_us() / 1000;
    384     pid = vfork();      /* Run CMD as child process.  */
    385     if (pid < 0)
    386         bb_error_msg_and_die("cannot fork");
    387     else if (pid == 0) {    /* If child.  */
    388         /* Don't cast execvp arguments; that causes errors on some systems,
    389            versus merely warnings if the cast is left off.  */
    390         BB_EXECVP(cmd[0], cmd);
    391         bb_error_msg("cannot run %s", cmd[0]);
    392         _exit(errno == ENOENT ? 127 : 126);
     368static void run_command(char *const *cmd, resource_t *resp)
     369{
     370    pid_t pid;
     371    void (*interrupt_signal)(int);
     372    void (*quit_signal)(int);
     373
     374    resp->elapsed_ms = monotonic_ms();
     375    pid = xvfork();
     376    if (pid == 0) {
     377        /* Child */
     378        BB_EXECVP_or_die((char**)cmd);
    393379    }
    394380
    395381    /* Have signals kill the child but not self (if possible).  */
     382//TODO: just block all sigs? and reenable them in the very end in main?
    396383    interrupt_signal = signal(SIGINT, SIG_IGN);
    397384    quit_signal = signal(SIGQUIT, SIG_IGN);
    398385
    399     if (resuse_end(pid, resp) == 0)
    400         bb_error_msg("error waiting for child process");
     386    resuse_end(pid, resp);
    401387
    402388    /* Re-enable signals.  */
     
    405391}
    406392
    407 int time_main(int argc, char **argv);
    408 int time_main(int argc, char **argv)
     393int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     394int time_main(int argc UNUSED_PARAM, char **argv)
    409395{
    410396    resource_t res;
    411397    const char *output_format = default_format;
    412     char c;
    413 
    414     goto next;
    415     /* Parse any options  -- don't use getopt() here so we don't
    416      * consume the args of our client application... */
    417     while (argc > 0 && argv[0][0] == '-') {
    418         while ((c = *++*argv)) {
    419             switch (c) {
    420             case 'v':
    421                 output_format = long_format;
    422                 break;
    423             case 'p':
    424                 output_format = posix_format;
    425                 break;
    426             default:
    427                 bb_show_usage();
    428             }
    429         }
    430  next:
    431         argv++;
    432         argc--;
    433         if (!argc)
    434             bb_show_usage();
    435     }
     398    int opt;
     399
     400    opt_complementary = "-1"; /* at least one arg */
     401    /* "+": stop on first non-option */
     402    opt = getopt32(argv, "+vp");
     403    argv += optind;
     404    if (opt & 1)
     405        output_format = long_format;
     406    if (opt & 2)
     407        output_format = posix_format;
    436408
    437409    run_command(argv, &res);
    438410
    439411    /* Cheat. printf's are shorter :) */
    440     stdout = stderr;
    441     dup2(2, 1); /* just in case libc does something silly :( */
     412    xdup2(STDERR_FILENO, STDOUT_FILENO);
    442413    summarize(output_format, argv, &res);
    443414
     
    448419    if (WIFEXITED(res.waitstatus))
    449420        return WEXITSTATUS(res.waitstatus);
    450     fflush_stdout_and_exit(0);
    451 }
     421    fflush_stdout_and_exit(EXIT_SUCCESS);
     422}
  • branches/2.2.9/mindi-busybox/miscutils/ttysize.c

    r1765 r2725  
    88 * Copyright (C) 2007 by Denys Vlasenko <vda.linux@googlemail.com>
    99 *
    10  * Licensed under the GPL v2, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2, see file LICENSE in this source tree.
    1111 */
    1212#include "libbb.h"
    1313
    14 int ttysize_main(int argc, char **argv);
    15 int ttysize_main(int argc, char **argv)
     14int ttysize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     15int ttysize_main(int argc UNUSED_PARAM, char **argv)
    1616{
    17     unsigned w,h;
     17    unsigned w, h;
    1818    struct winsize wsz;
    1919
     
    2525    }
    2626
    27     if (argc == 1) {
     27    if (!argv[1]) {
    2828        printf("%u %u", w, h);
    2929    } else {
     
    4040        }
    4141    }
    42     putchar('\n');
     42    bb_putchar('\n');
    4343    return 0;
    4444}
  • branches/2.2.9/mindi-busybox/miscutils/watchdog.c

    r1765 r2725  
    44 *
    55 * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
    6  * Copyright (C) 2006  Bernhard Fischer <busybox@busybox.net>
     6 * Copyright (C) 2006  Bernhard Reutner-Fischer <busybox@busybox.net>
     7 * Copyright (C) 2008  Darius Augulis <augulis.darius@gmail.com>
    78 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    910 */
    1011
    1112#include "libbb.h"
     13#include "linux/types.h" /* for __u32 */
     14#include "linux/watchdog.h"
    1215
    13 #define OPT_FOREGROUND 0x01
    14 #define OPT_TIMER      0x02
     16#define OPT_FOREGROUND  (1 << 0)
     17#define OPT_STIMER      (1 << 1)
     18#define OPT_HTIMER      (1 << 2)
    1519
    16 static void watchdog_shutdown(int ATTRIBUTE_UNUSED sig) ATTRIBUTE_NORETURN;
    17 static void watchdog_shutdown(int ATTRIBUTE_UNUSED sig)
     20static void watchdog_shutdown(int sig UNUSED_PARAM)
    1821{
    19     write(3, "V", 1);   /* Magic, see watchdog-api.txt in kernel */
     22    static const char V = 'V';
     23
     24    write(3, &V, 1);  /* Magic, see watchdog-api.txt in kernel */
    2025    if (ENABLE_FEATURE_CLEAN_UP)
    2126        close(3);
    22     exit(0);
     27    _exit(EXIT_SUCCESS);
    2328}
    2429
    25 int watchdog_main(int argc, char **argv);
     30int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    2631int watchdog_main(int argc, char **argv)
    2732{
     33    static const struct suffix_mult suffixes[] = {
     34        { "ms", 1 },
     35        { "", 1000 },
     36        { "", 0 }
     37    };
     38
    2839    unsigned opts;
    29     unsigned timer_duration = 30; /* Userspace timer duration, in seconds */
    30     char *t_arg;
     40    unsigned stimer_duration; /* how often to restart */
     41    unsigned htimer_duration = 60000; /* reboots after N ms if not restarted */
     42    char *st_arg;
     43    char *ht_arg;
    3144
    32     opt_complementary = "=1"; /* must have 1 argument */
    33     opts = getopt32(argv, "Ft:", &t_arg);
     45    opt_complementary = "=1"; /* must have exactly 1 argument */
     46    opts = getopt32(argv, "Ft:T:", &st_arg, &ht_arg);
    3447
    35     if (opts & OPT_TIMER)
    36         timer_duration = xatou(t_arg);
     48    /* We need to daemonize *before* opening the watchdog as many drivers
     49     * will only allow one process at a time to do so.  Since daemonizing
     50     * is not perfect (child may run before parent finishes exiting), we
     51     * can't rely on parent exiting before us (let alone *cleanly* releasing
     52     * the watchdog fd -- something else that may not even be allowed).
     53     */
     54    if (!(opts & OPT_FOREGROUND))
     55        bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
    3756
    38     if (!(opts & OPT_FOREGROUND)) {
    39         bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
    40     }
     57    if (opts & OPT_HTIMER)
     58        htimer_duration = xatou_sfx(ht_arg, suffixes);
     59    stimer_duration = htimer_duration / 2;
     60    if (opts & OPT_STIMER)
     61        stimer_duration = xatou_sfx(st_arg, suffixes);
    4162
    42     signal(SIGHUP, watchdog_shutdown);
    43     signal(SIGINT, watchdog_shutdown);
     63    bb_signals(BB_FATAL_SIGS, watchdog_shutdown);
    4464
    4565    /* Use known fd # - avoid needing global 'int fd' */
    4666    xmove_fd(xopen(argv[argc - 1], O_WRONLY), 3);
    4767
     68    /* WDIOC_SETTIMEOUT takes seconds, not milliseconds */
     69    htimer_duration = htimer_duration / 1000;
     70#ifndef WDIOC_SETTIMEOUT
     71# error WDIOC_SETTIMEOUT is not defined, cannot compile watchdog applet
     72#else
     73# if defined WDIOC_SETOPTIONS && defined WDIOS_ENABLECARD
     74    {
     75        static const int enable = WDIOS_ENABLECARD;
     76        ioctl_or_warn(3, WDIOC_SETOPTIONS, (void*) &enable);
     77    }
     78# endif
     79    ioctl_or_warn(3, WDIOC_SETTIMEOUT, &htimer_duration);
     80#endif
     81
     82#if 0
     83    ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration);
     84    printf("watchdog: SW timer is %dms, HW timer is %ds\n",
     85        stimer_duration, htimer_duration * 1000);
     86#endif
     87
    4888    while (1) {
    4989        /*
    50          * Make sure we clear the counter before sleeping, as the counter value
    51          * is undefined at this point -- PFM
     90         * Make sure we clear the counter before sleeping,
     91         * as the counter value is undefined at this point -- PFM
    5292         */
    53         write(3, "", 1);
    54         sleep(timer_duration);
     93        write(3, "", 1); /* write zero byte */
     94        usleep(stimer_duration * 1000L);
    5595    }
    56 
    57     watchdog_shutdown(0);
    58     /* return EXIT_SUCCESS; */
     96    return EXIT_SUCCESS; /* - not reached, but gcc 4.2.1 is too dumb! */
    5997}
Note: See TracChangeset for help on using the changeset viewer.