AF:
NF:0
PS:10
SRH:1
SFN:
DSR:
MID:<20070124121548.5503f527@ripper.onstor.net>
CFG:
PT:0
S:andy.sharp@onstor.com
RQ:
SSV:onstor-exch02.onstor.net
NSV:
SSH:
R:<larry.scheer@onstor.com>
MAID:1
X-Sylpheed-Privacy-System:
X-Sylpheed-Sign:0
SCF:#mh/Mailbox/sent
RMID:#imap/andys@onstor.net@onstor-exch02.onstor.net/INBOX	0	BB375AF679D4A34E9CA8DFA650E2B04E02215607@onstor-exch02.onstor.net
X-Sylpheed-End-Special-Headers: 1
Date: Wed, 24 Jan 2007 12:17:01 -0800
From: Andrew Sharp <andy.sharp@onstor.com>
To: "Larry Scheer" <larry.scheer@onstor.com>
Subject: Re: One last problem with verify_install.sh but I have a fix.
Message-ID: <20070124121701.67a97327@ripper.onstor.net>
In-Reply-To: <BB375AF679D4A34E9CA8DFA650E2B04E02215607@onstor-exch02.onstor.net>
References: <BB375AF679D4A34E9CA8DFA650E2B04E02215607@onstor-exch02.onstor.net>
Organization: Onstor
X-Mailer: Sylpheed-Claws 2.6.0 (GTK+ 2.8.20; x86_64-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="MP_p6e8RDu5=WN56tCwhhl+oG/"

--MP_p6e8RDu5=WN56tCwhhl+oG/
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

It seems a call to umount_patch() got dropped sometime during your mods
to cmd_upgrade.c.  I've added it back in the attached version of
cmd_upgrade.c, along with copious whitespace and coding style fixes.

Cheers,

a


On Tue, 23 Jan 2007 19:08:56 -0800 "Larry Scheer"
<larry.scheer@onstor.com> wrote:

> Coming dfrom id_secondary():
> 		mount_ffs: /dev/wd1a on /mnt1: Device busy
> 		id_secondary: problem mounting secondary flash root
> file system on device /dev/wd1a
> 		Unmounting secondary disk...
> 
> This is due to cmd_upgrade previously mounting the secondary flash to
> do the mtree stuff.
> 
> Here is my fix if you agree:
> 
> # get the mount points from the fstab file on the secondary flash.
> # they might be different from primary; and they
> # might be "wrong" in that they may have the wrong
> # devices (say, for instance, if CF cards were swapped)
> id_secondary()
> {
> set -x
>     root=`df / | fgrep /dev | awk '{print $1}'`
>     case $root in
>         /dev/wd0a)
>             s_base=/dev/wd1
>             ;;
>         /dev/wd1a)
>             s_base=/dev/wd0
>             ;;
>     esac
> 
> **** ADD: ***
>     # secondary flash may have been previously mounted by cmd_upgrade
> so # silently unmount it if the mount path is in mtab
>     # this is needed to mount the secondary root in the next step
>     mount | fgrep ${MNT1} >>/dev/null && umount_path
> ${MNT1}${ONSTOR_CONF} \
>     ${MNT1}${ONSTOR_PATH} ${MNT1}/var ${MNT1}/tmp  ${MNT1}/usr ${MNT1}
> 
> *** ***
> The rest of the function is the same.
> 
> I will be testing this shortly.
> 
> Larry

--MP_p6e8RDu5=WN56tCwhhl+oG/
Content-Type: text/x-csrc; name=cmd_upgrade.c
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=cmd_upgrade.c


/* vi:ts=4
 *-----------------------------------------------------------------
 *
 * Name: cmd_upgrade
 *
 * RCS:  $Id$
 *
 * Copyright (C) 2001, Agile Storage, Inc.
 *
 * Description:
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created: 04/29/2002
 *
 *-----------------------------------------------------------------
 */

/* Some parts are: */
/*
 * Copyright (c) 1987, 1993
 *  The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *  This product includes software developed by the University of
 *  California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */



#include <sys/types.h>
#include <pwd.h>
#include <readline/history.h>
#include <grp.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <netinet/in.h>

#include "zebra.h"
#include "command.h"
#include "log.h"
#include "vtysh.h"
#include "memory.h"

#include "nfxsh.h"

#include "vector.h"

#include <dirent.h>

#include "nfx-defs.h"
#include "../sm-chassis/cm-api.h"
#include "../sm-anpssc/anpssc-api.h"
#include "../sm-opt/opt-api.h"
#include "../sm-elog/elog-api.h"
#include "../ssc-nfxnis/nfxnis-api.h"
#include "../ssc-nfxnis/nfxauth-api.h"
#include "../sm-ipm/ipm.h"

#include <fstab.h>

#define ALLOW_PROM_UPGRADE_FAIL 1

extern int mount_secondary(vector v);
extern vector make_secondary_fstabs(void);
extern void u_mount_secondary(vector v);
extern void free_fstab_vector(vector v);
extern void do_copy_files(char *fromdir, char *todir, char *files);
//static int is_fp_addr(char *patch_location);

struct descriptor
{
    char *name;
    char *type;
    char *board;
    char *patch_name;
};


struct descriptor default_descriptor = {
    NULL,
    "app",
    "ssc",
    NULL
};


char *board_types[] = {
    "sp",
    "txrx",
    "fp",
    "ssc",
    "toshiba",
    NULL
};


char *file_types[] = {
    "prom",
    "bigprom",
    "runtime",
    "daemon",
    "app",
    "descr",
    "version",
    "kernel",
    "config",
    "services",
    NULL
};

char *fp_ports[] = {
    "fp1.0",
    "fp1.1",
    "fp1.2",
    "fp1.3",
    NULL
};

#define TIME_BUF 27
static char *mount_dir = "/mnt";
static char *patch_dir_name = NULL;
static char *local_dest = "/mnt2";
static char *descriptor_file = "/usr/local/agile/etc/descr";
static char *mtree_file_name = "/etc/mtree/4.4BSD.dist";
static char ftpprefix[] = "ftp://";
static char *patch_location;
static int upgrade_secondary;
static int compare_secondary;
static int force_upgrade;
static char *sys_upgrade_logfile = "/var/log/sys_upgrade.log";
static FILE *sys_upgrade = NULL;
static char sys_log_str[MAXPATHLEN + 1];
static char sys_log_time[TIME_BUF];

extern char *secondary_mount;
extern char *sys_config_files;

struct version
{
    int major;
    int minor;
    int maintenance;
    int patch;
    char platform;
};


static void print_vector(vector v, void (*print_fn)(void*)) __attribute((unused));
static void print_descriptor_vector(vector v) __attribute__ ((unused));
static void print_string_vector(vector v) __attribute__ ((unused));
int sleep_accurately(int secs);
static void my_print(char *str);
static char *get_time();


typedef char* (*truename_func_t)(char *file);

truename_func_t cur_truename_func;

extern int noisy_make_allfs_writable(void);


/*-----------------------------------------------------------------
 * Name :   find_str()
 *
 * Description: Find a string in array of strings
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static char *
find_str(char **array, char *str)
{
    char **ptr;
    for (ptr = &array[0]; *ptr != NULL && strcmp(*ptr, str); ++ptr) {
        /* */
    }
    return *ptr;
}


/* Utility routine for current time printing. */
static char *
get_time ()
{
  int ret;
  time_t clock;
  struct tm *tm;
  time (&clock);
  tm = (struct tm*)localtime (&clock);

  ret = strftime (sys_log_time, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
  if (ret == 0) {
    sprintf(sys_log_time,"Error getting system time");
  }
   return sys_log_time;
}


/*-----------------------------------------------------------------
 * Name :   my_print()
 *
 * Description: print to stdout and file
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/20/05
 *
 *-----------------------------------------------------------------
 */
static void
my_print(char *str)
{
    printf("%s",str);
    fflush(stdout);
    if (sys_upgrade) {
        fprintf(sys_upgrade,"%s",str);
        fflush(sys_upgrade);
    }
}

/*-----------------------------------------------------------------
 * Name :   vector_free_all()
 *
 * Description: Free the vector and call free() for all the elements
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
vector_free_all(vector v)
{
    int i;

    if (v != NULL) {
        for (i = 0; i < vector_max(v); ++i) {
            zfree(MTYPE_VECTOR, vector_lookup_index(v, i));
        }
        vector_free(v);
    }
}



/*-----------------------------------------------------------------
 * Name :   read_descriptor()
 *
 * Description: Read the descriptor file and return the vector of
 * struct descriptor.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static vector
read_descriptor(const char *filename)
{
    struct descriptor *descr;
    char str[300], type[100], board[100], name[100];
    int rc;
    FILE *f = fopen(filename, "r");
    vector v = NULL;

    if (f != NULL) {
        v = vector_init(200);
        while (!feof(f)) {
            if (fgets(str, 300, f) != NULL) {
                descr = zmalloc(MTYPE_VECTOR, sizeof(struct descriptor));
                rc = sscanf(str, "%s %s %s\n", type, board, name);
                if (rc != 3) {
                    rc = sscanf(str, "%s %s %s\n", type, board, name);
                    E_LOG(class_1, notice_s, eee_getApplicationId("nfxsh"),
                          0, 0, 0, ("sscanf retry during system upgrade\n"));
                   if (sys_upgrade) {
                       fprintf(sys_upgrade,"sscanf retry during system upgrade\n");
                       fflush(sys_upgrade);
                   }
                }
                assert(rc == 3);
                descr->name = zstrdup(MTYPE_VECTOR, name);
                descr->patch_name = NULL;
                descr->type = find_str(file_types, type);
                assert(descr->type != NULL);
                descr->board = find_str(board_types, board);
                assert(descr->board != NULL);
                vector_push(v, descr);
            }
        }
        fclose(f);
    }
    return v;
}


/*-----------------------------------------------------------------
 * Name :   print-vector()
 *
 * Description: print the vector elements using function print_fn
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_vector(vector v, void (*print_fn)(void *))
{
    int i;
    char *filename;
    for (i = 0; i < vector_max(v); ++i) {
//        (*print_fn)(vector_lookup_index(v, i));
        filename = (vector_lookup_index(v, i));
        my_print(filename);
        my_print("\n");
    }
}


/*-----------------------------------------------------------------
 * Name :   print_descriptor()
 *
 * Description: print function for descriptors
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_descriptor(void *vd)
{
    struct descriptor *d = vd;
    sprintf(sys_log_str,"%s %s %s %s\n", d->type, d->board, d->name,
           d->patch_name ? d->patch_name : "(null)");
    my_print(sys_log_str);
}


/*-----------------------------------------------------------------
 * Name :   print_descriptor_vector()
 *
 * Description: print vector of struct descriptor
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_descriptor_vector(vector v)
{
    print_vector(v, print_descriptor);
}


/*-----------------------------------------------------------------
 * Name :   print_string_vector()
 *
 * Description: print vector of strings
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_string_vector(vector v)
{
    print_vector(v, (void (*)(void *))puts);
}


/*-----------------------------------------------------------------
 * Name :   parse_version_str()
 *
 * Description: parse a string into struct version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
parse_version_str(char *str, struct version *version)
{
    int rc = sscanf(str, "%d.%d.%d.%d%c",
                    &version->major,
                    &version->minor,
                    &version->maintenance,
                    &version->patch,
                    &version->platform);
    if ((rc != 4) && (rc != 5)) {
        sprintf(sys_log_str,"invalid version string %s\n", str);
        my_print(sys_log_str);
        rc = CMD_ERR_FAILED;
    }
    else {
        if (rc == 4) {
            version->platform = '?';
        }
        rc = CMD_SUCCESS;
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   compare_versions()
 *
 * Description: compare two versions, return value is < 0 if the first is
 * lower, 0 if equal, > 0 if the first is greater
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
compare_versions(struct version *v1, struct version *v2)
{
    int major_diff, minor_diff, maintenance_diff;

    if ((major_diff = v1->major - v2->major) != 0)
        return major_diff;
    else if ((minor_diff = v1->minor - v2->minor) != 0)
        return minor_diff;
    else if ((maintenance_diff = v1->maintenance - v2->maintenance) != 0)
        return maintenance_diff;
    else return v1->patch - v2->patch;
}


/*-----------------------------------------------------------------
 * Name :   check_versions_compatible()
 *
 * Description: compare two versions to see if they are compatible and we can
 * upgrade from the first to the second.
 *
 *-----------------------------------------------------------------
 */
static int
check_versions_compatible(struct version *currVer, struct version *upgradeVer)
{
    int rc = CMD_SUCCESS;

    /* We cannot upgrade from R2.0.x to R1.3.2 or greater. */
    if ((currVer->major == 2) && (currVer->minor == 0)) {
        if ((upgradeVer->major == 1) && (upgradeVer->minor == 3) &&
            (upgradeVer->maintenance >= 2)) {
            rc = CMD_ERR_FAILED;
        }
    }

    /*
     * We cannot upgrade from R1.3.2 or greater to R2.0.  The plan is to merge
     * the release paths in R2.1, so we need to allow the upgrade path to
     * R2.1 or greater.
     */
    else if ((currVer->major == 1) && (currVer->minor == 3) &&
             (currVer->maintenance >= 2)) {
        if ((upgradeVer->major == 2) && (upgradeVer->minor == 0)) {
            rc = CMD_ERR_FAILED;
        }
    }

    return rc;
}

/* In case we need to do an emergency reactivation for cheetah
*  prom upgrade this define can be turned on. But this code should go away
*  when cmd_promupgrade.c supports cheetah updates.
*/
#ifdef REACTIVATE_SYSTEM_CMDS
/*-----------------------------------------------------------------
 * Name :   valid_slot_cpu()
 *
 * Description: Return true if slot/cpu combination is valid
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/09/02
 *
 *-----------------------------------------------------------------
 */
static int
valid_slot_cpu(int slot, int cpu)
{
    switch (slot) {
    case 0 :
        return 0 <= cpu && cpu < 2;
    case 1:
        return 0 <= cpu && cpu < 4;
    case 2:
        return 0 <= cpu && cpu < 4;
    default:
        return 0;
    }

}
#endif /* REACTIVATE_SYSTEM_CMDS */


/*-----------------------------------------------------------------
 * Name :   read_version()
 *
 * Description: Read the version from the file named filename
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
read_version(const char *filename, struct version *version)
{
    FILE *f = fopen(filename, "r");
    char *s;
    int ok = CMD_ERR_FAILED;

    if (f != NULL) {
        size_t size;
        s = fgetln(f, &size);
        if (s != NULL && s[size - 1] == '\n') {
            s[size - 1] = 0;
            ok = parse_version_str(s, version);
        }
        fclose(f);
    }

    return ok;
}


/* In case we need to do an emergency reactivation for cheetah
*  prom upgrade this define can be turned on. But this code should go away
*  when cmd_promupgrade.c supports cheetah updates.
*/
#ifdef REACTIVATE_SYSTEM_CMDS
/*-----------------------------------------------------------------
 * Name :   is_prom()
 *
 * Description: Return true if the descriptor type is prom
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_prom(struct descriptor *descr)
{
    return !strcmp(descr->type, "prom");
}


/*-----------------------------------------------------------------
 * Name :   is_bigprom()
 *
 * Description: Return true if the descriptor type is bigprom
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_bigprom(struct descriptor *descr)
{
    return !strcmp(descr->type, "bigprom");
}
#endif /* REACTIVATE_SYSTEM_CMDS */


/*-----------------------------------------------------------------
 * Name :   print_version()
 *
 * Description:
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_version(struct version *version)
{
    sprintf(sys_log_str,"%d.%d.%d.%d\n", version->major, version->minor,
           version->maintenance, version->patch);
    my_print(sys_log_str);
}


/*-----------------------------------------------------------------
 * Name :   convert_rc()
 *
 * Description: Convert unix return code to nfxsh values
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static inline int
convert_rc(int rc)
{
    return rc == 0 ? CMD_SUCCESS : CMD_ERR_FAILED;
}


/*-----------------------------------------------------------------
 * Name :   is_ftp_upgrade()
 *
 * Description: return true if upgrading using ftp
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static int
is_ftp_upgrade(char *from)
{
    return !strncmp(from, ftpprefix, strlen(ftpprefix));
}


/*-----------------------------------------------------------------
 * Name :   umount_patch()
 *
 * Description: unmount patch directory if it is mounted
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
umount_patch()
{
    do_system("/sbin/umount %s 2>/dev/null", mount_dir);

}

/*-----------------------------------------------------------------
 * Name         : upgrade_resolveName
 *
 * Description  : Resolves a name to an IP address.
 *
 * Arguments    : hostName  - Host Name.
 *                vsId      - Appropriate virtual server context.
 *                ipAddress - Returned value.
 *
 * Return Value : NFX_OK  - Able to resolve the name to an IP address.
 *                NFX_ERR - Unable to resolve the server name .
 *
 * Created by   : Kiran Srinivasan
 *
 * Date Created : 04/23/04
 *
 *-----------------------------------------------------------------
 */
static int32
upgrade_resolveName(char *hostName, vs_id_t vsId, struct in_addr *hostIP)
{
    /*
	 * Check if name is already in IP address format
     */
    if(inet_aton(hostName, hostIP) != 0) {
        return NFX_OK;
	}

    /*
	 * Call the NFXNIS routine to resolve using the virtual
     * server provided (via FP).
     */
    hostIP = (struct in_addr *)nfxauth_resolveName(vsId, hostName);

    if(hostIP->s_addr == 0) {
        sprintf(sys_log_str,"Error : unable to resolve server : (%s).\n",
			hostName);
        my_print(sys_log_str);
        return NFX_ERR;
    }

    return NFX_OK;
}

/*-----------------------------------------------------------------
 * Name         : ftp_getServerIP
 *
 * Description  : Gets the FTP server address from the URL.
 *
 * Arguments    : ftpURL            - FTP URL
 *                vsId              - Virtual server Id.
 *                serverIP          - Pointer to in_addr structure for
 *                                    returning the IP address.
 *
 * Return Value : NFX_OK  - Able to parse the server address out of the FTP
 *                          URL.
 *                NFX_ERR - Unable to get the server address.
 *
 * Created by   : Kiran Srinivasan
 *
 * Date Created : 04/23/04
 *
 *-----------------------------------------------------------------
 */
static int32
ftp_getServerIP(const char *ftpURL,
                vs_id_t vsId,
                struct in_addr *serverIP)
{
    char *start;
    char *end;
    int32 rc;
    uint32 serverLen;
    char *serverName;

    /*
	 * Get the start of the FTP server name
     */
    if((start= strchr(ftpURL, '@')) == NULL) {
        my_print("Error: unable to find @ in FTP URL\n");
        return NFX_ERR;
    }

    /*
	 * Get the end of the server name
     */
    if((end = strchr(start, '/')) == NULL) {
        my_print("Error: unable to find the terminating / in the FTP URL.\n");
        return NFX_ERR;
    }

    start++;
    serverLen = (uint32) (end - start);

    if((serverName = (char *) malloc(serverLen + sizeof(char))) == NULL) {
        my_print("Error: unable to allocate serverName\n");
        return NFX_ERR;
    }
    strncpy(serverName, start, serverLen);
    serverName[serverLen] = '\0';

    /*
	 * Get the IP address
     */
    rc = upgrade_resolveName(serverName, vsId, serverIP);

    free(serverName);
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   mount_patch()
 *
 * Description: mount the patch directory 'from' on mount_dir
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
mount_patch(char *from)
{
	int rc;

    do_system("/sbin/umount -f %s 2>/dev/null", mount_dir);

    if (is_ftp_upgrade(from)) {
        my_print("Downloading external system software distribution.\n");
        rc = do_system("/sbin/mount_mfs -m 0 -s 120000 swap %s", mount_dir);
        rc = convert_rc(rc);

        if (rc == CMD_SUCCESS) {
            if(nfxsh_vs_id != VS_ID_INVALID) {
                /*
				 * Upgrade is being done within the context of a
                 * virtual server, pick the appropriate source IP
                 */
                struct in_addr serverIP;
                struct in_addr srcIP;
                NTSTATUS status;

                /*
				 * Parse the address out of the patch location
                 */
                if(ftp_getServerIP(from, nfxsh_vs_id, &serverIP) != NFX_OK) {
                    my_print("Error: unable to parse the destination IP address"
                           " string from the ftp URL.\n");
                    umount_patch();
                    return CMD_ERR_FAILED;
                }

                /*
				 * Get the source IP address (private)
                 */
                if((status = nfxnis_getSourceIP(nfxsh_vs_id,
                                                serverIP.s_addr,
                                                NULL,
                                                &srcIP.s_addr))
                    != STATUS_SUCCESS) {
                    if (status == STATUS_SERVER_DISABLED) {
                        sprintf(sys_log_str,
                                "Error: virtual server (ID - %d) is disabled. "
                                "FTP server %s unreachable.\n",
                                nfxsh_vs_id,
                                inet_ntoa(serverIP));
                    } else if (status == STATUS_NETWORK_UNREACHABLE) {
                        sprintf(sys_log_str,
                                "Error: virtual server (ID - %d) does not have "
                                "a route to FTP server %s.\n",
                                nfxsh_vs_id,
                                inet_ntoa(serverIP));
                    } else {
                        sprintf(sys_log_str,
                                "Error: Cannot reach FTP server %s from this "
                                "virtual server (ID - %d) context. status=0x%X\n",
                                inet_ntoa(serverIP),
                                nfxsh_vs_id,
                                status);
                    }
                    my_print(sys_log_str);
                    umount_patch();
                    return CMD_ERR_FAILED;
                }

                /* Add the -s option to the ftp client to bind to the
                 * correct IP address before making the connection
                 */
				rc = do_system("/usr/bin/ftp -o - -s %s -m %s | "
				    "tar xzpf - -C %s .%s .%s ./version",
                    inet_ntoa(srcIP), from, mount_dir, descriptor_file,
					mtree_file_name);
            } else {
				    rc = do_system("/usr/bin/ftp -o - -m %s | "
				    "tar xzpf - -C %s .%s .%s ./version",
                    from, mount_dir, descriptor_file, mtree_file_name);
			}
            rc = convert_rc(rc);

            patch_dir_name = mount_dir;
            if (rc == CMD_SUCCESS) {
                my_print("Done.\n");
            } else {
				umount_patch();
                my_print("Download failed.\n");
            }
        }
        return rc;
    } else {
        do_system("/sbin/umount %s 2>/dev/null", mount_dir);

        rc = do_system("/sbin/mount -t nfs %s %s", from, mount_dir);
        patch_dir_name = mount_dir;

        return convert_rc(rc);
    }
}


/*-----------------------------------------------------------------
 * Name :   get_upgrade_version()
 *
 * Description: determine the version of system upgrade
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
get_upgrade_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    strcpy(version_file, patch_dir_name);
    strcat(version_file, "/version");
    return read_version(version_file, version);
}

/*-----------------------------------------------------------------
 * Name :   zero_version()
 *
 * Description: Fill version with zeroes
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    07/03/02
 *
 *-----------------------------------------------------------------
 */
static void
zero_version(struct version *version)
{
    version->major = version->minor = version->maintenance = version->patch = 0;
}


/*-----------------------------------------------------------------
 * Name :   get_org_upgrade_version()
 *
 * Description: read original version of upgrade
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    07/03/02
 *
 *-----------------------------------------------------------------
 */
static void
get_org_upgrade_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    strcpy(version_file, patch_dir_name);
    strcat(version_file, "/version.org");
    if (read_version(version_file, version) != 0) {
        zero_version(version);
    }
}


/*-----------------------------------------------------------------
 * Name :   is_dotdir()
 *
 * Description: return true if the name is "." or "..".
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_dotdir(char *name)
{
    return (name[0] == '.' && name[1] == '\0')
        || (name[0] == '.' && name[1] == '.' && name[2] == '\0');
}


/*-----------------------------------------------------------------
 * Name :   find_files()
 *
 * Description: Find the list of the files in the directory
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
find_files(const char *dir_name, vector files)
{
    int rc = CMD_ERR_FAILED;
    DIR *dir = opendir(dir_name);
    if (dir != NULL) {
        struct dirent *dp;
        int error = 0;
        while (!error && (dp = readdir(dir)) != NULL) {
            if (!is_dotdir(dp->d_name) && strcmp(dp->d_name, ".snapshot")) {
                struct stat stbuf;
                char *fname = zmalloc(MTYPE_VECTOR,
                                      strlen(dir_name) + 2 + dp->d_reclen);
                sprintf(fname, "%s/%s", dir_name, dp->d_name);
                if (stat(fname, &stbuf) < 0) {
                    fprintf(stderr, "Error: can't stat %s: %s\n", fname,
                            strerror(errno));
					if (sys_upgrade) {
						fprintf(sys_upgrade, "Error: can't stat %s: %s\n",
							fname, strerror(errno));
						fflush(sys_upgrade);
					}
                    error = 1;
                } else {
                    if (S_ISREG(stbuf.st_mode)) {
                        vector_push(files, zstrdup(MTYPE_VECTOR, fname));
                    } else if (S_ISDIR(stbuf.st_mode)) {
                        if (find_files(fname, files) != CMD_SUCCESS) {
                            error = 1;
                        }
                    }
                    zfree(MTYPE_VECTOR, fname);
                }
            }
        }
        closedir(dir);
        rc = error ? CMD_ERR_FAILED : CMD_SUCCESS;
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   get_local_version()
 *
 * Description: determine the current system version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
get_local_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    strcpy(version_file, patch_dir_name);
    strcat(version_file, "/version");
    if (read_version(cur_truename_func(version_file),
                     version) != CMD_SUCCESS) {
        zero_version(version);
    }
    return CMD_SUCCESS;
}

/*-----------------------------------------------------------------
 * Name :   get_secondary_version()
 *
 * Description: determine the system version of the secondary flash
 *
 * Created by:  Danqing Jin
 *
 * Date Created:    07/05/06
 *
 *-----------------------------------------------------------------
 */
static int
get_secondary_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    int rc;

    snprintf(version_file, MAXPATHLEN+1, "%s/version", secondary_mount);
    if ((rc = read_version(version_file, version)) != CMD_SUCCESS) {
        zero_version(version);
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   get_root_version()
 *
 * Description: get system version from root directory
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    01/10/03
 *
 *-----------------------------------------------------------------
 */
static int
get_root_version(struct version *version)
{
    if (read_version("/version", version) != CMD_SUCCESS) {
        zero_version(version);
    }
    return CMD_SUCCESS;
}


#ifdef REACTIVATE_SYSTEM_CMDS
/*-----------------------------------------------------------------
 * Name :   compare_descr_file()
 *
 * Description: compare the descriptors using the file names
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
compare_descr_file(void *descr, void *fname)
{
    return !strcmp(((struct descriptor *)descr)->name, fname);
}

/*-----------------------------------------------------------------
 * Name :   get_file_descriptor()
 *
 * Description: find the descriptor for the file in the descriptor
 * vector dv.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static struct descriptor *
get_file_descriptor(vector dv, char *fname)
{
    struct descriptor *descr = vector_find(dv, compare_descr_file, fname);
    if (descr == NULL)
        descr = &default_descriptor;
    return descr;
}
#endif /* REACTIVATE_SYSTEM_CMDS */


/*-----------------------------------------------------------------
 * Name :   file_exists()
 *
 * Description: return true if the file exists
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
file_exists(char *file)
{
    struct stat statbuf;
    return stat(file, &statbuf) == 0;
}


/*-----------------------------------------------------------------
 * Name :   upgrade_truename()
 *
 * Description: return the installation name of a file in upgrade
 * directory.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static char*
upgrade_truename(char *file)
{
    return strchr(file + 1, '/');
}


static char *
secondary_upgrade_truename(char *file)
{
    static char buf[MAXPATHLEN];
    strcpy(buf, secondary_mount);
    strcat(buf, strchr(file + 1, '/'));
    return buf;
}


/*-----------------------------------------------------------------
 * Name :   shutdown_system()
 *
 * Description: tell the user the system is being shut down
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
shutdown_system()
{
    my_print("Shutting down the system software...");
    my_print("done\n");
}


/*-----------------------------------------------------------------
 * Name :   kill_daemon()
 *
 * Description: kill the daemon, pid is in pid_file and the daemon
 * is supposed to remove the file when exiting on SIGTERM
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
void
kill_daemon(char *pid_file)
{
    FILE *f;
    int pid;
    int time_to_sleep = 10;

    f = fopen(pid_file, "r");
    if (f) {
        fscanf(f, "%d\n", &pid);
        fclose(f);
        kill(pid, SIGTERM);
        while (time_to_sleep && file_exists(pid_file)) {
            sleep(1);
            --time_to_sleep;
        }
        if (time_to_sleep == 0) {
            kill(pid, SIGKILL);
            unlink(pid_file);
        }
    }
}


/*-----------------------------------------------------------------
 * Name :   shutdown_inetd()
 *
 * Description: shutdown the inetd
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
shutdown_inetd(void)
{
    my_print("Shutting down the inetd...");
    kill_daemon("/var/run/inetd.pid");
    my_print("done\n");
}


/*-----------------------------------------------------------------
 * Name :   shutdown_pm()
 *
 * Description: shutdown the pm
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
shutdown_pm(void)
{
	/*
     * Shutdown EMRS before stopping PM because EMRS can start an executable
     * that is dependent on PM running.
	 */
	system("/usr/local/agile/bin/emrscron -r");
    my_print("Shutting down PM...");
    kill_daemon("/var/run/pm.pid");
    my_print("done\n");
}


#ifdef REACTIVATE_SYSTEM_CMDS
/*-----------------------------------------------------------------
 * Name :   upgrade_prom_slotcpu()
 *
 * Description: upgrade prom for the specified slot/cpu
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_prom_slotcpu(int slot, int cpu, char *file)
{
    assert(valid_slot_cpu(slot, cpu));
    return convert_rc(do_system("/usr/local/agile/bin/prom-upgrade %d %d %s",
				slot, cpu, file ? file : ""));
}

/*-----------------------------------------------------------------
 * Name :   upgrade_prom()
 *
 * Description: Upgrade the prom on the given board. Returns 0 if prom
 * upgrade successfully for all cpus.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_prom(char *board, char *file)
{
    int slot, cpu_min, cpu_max, cpu, error = 0;
    if (!strcmp(board, "toshiba")) {
        slot = 0;
        cpu_min = 1;
        cpu_max = 1;
    } else if (!strcmp(board, "ssc")) {
        slot = 0;
        cpu_min = 0;
        cpu_max = 0;
    } else if (!strcmp(board, "txrx")) {
        slot = 1;
        cpu_min = 0;
        cpu_max = 0;
    } else if (!strcmp(board, "fp")) {
        slot = 1;
        cpu_min = 3;
        cpu_max = 3;
    } else if (!strcmp(board, "sp")) {
        slot = 2;
        cpu_min = 0;
#ifdef BOBCAT
        cpu_max = 0;
#else
        cpu_max = 3;
#endif
    } else {
        return 1;
    }
    for (cpu = cpu_min; cpu <= cpu_max; ++cpu) {
        if (upgrade_prom_slotcpu(slot, cpu, file) != 0) {
#if ALLOW_PROM_UPGRADE_FAIL
            error = 0;
#else
            sprintf(sys_log_str,
				"Failed to upgrade the prom for slot %d cpu %d\n", slot, cpu);
            my_print(sys_log_str);
            my_print("After the system comes up after reboot, "
				"verify that the slot/cpu\n");
            my_print("is in UP state and execute the following command:\n");
            sprintf(sys_log_str,"system promupgrade %d %d\n", slot, cpu);
            my_print(sys_log_str);
            error = 1;
#endif
        }
    }
    return error;
}

/*-----------------------------------------------------------------
 * Name :   upgrade_proms_if_needed()
 *
 * Description: Upgrade the proms for the boards which had their
 * PROMs modified.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_proms_if_needed(vector dv, vector files_list,
	char *(*truename_func)(char *))
{
    int rc = 0;
    int i;

    for (i = 0; i < vector_max(files_list); ++i) {
        char *dst_file = (*truename_func)(vector_lookup_index(files_list, i));
        char *root_dst_file = upgrade_truename(
            vector_lookup_index(files_list, i));
        struct descriptor *descr = get_file_descriptor(dv, root_dst_file);
        if (is_prom(descr) || is_bigprom(descr)) {
            int j;
            for (j = 0; j < vector_max(dv); ++j) {
                struct descriptor *descr = vector_lookup_index(dv, j);
                if (!strcmp(descr->name, root_dst_file) && is_bigprom(descr)) {
#ifdef BOBCAT
                    /* Don't upgrade big flash through SSC
                     * It will be done through FC
                     */
                    if (strcmp(descr->board, "ssc"))
#endif
                    rc |= upgrade_prom(descr->board, dst_file);
                }
            }
            for (j = 0; j < vector_max(dv); ++j) {
                struct descriptor *descr = vector_lookup_index(dv, j);
                if (!strcmp(descr->name, root_dst_file) && is_prom(descr)) {
#ifdef BOBCAT
                    /* Don't upgrade small prom through SP
                     * because it would be redundant (same as SSC prom)
                     */
                    if (strcmp(descr->board, "sp"))
#endif
                    rc |= upgrade_prom(descr->board, dst_file);
                }
            }
        }
    }
    return rc;
}
#endif /* REACTIVATE_SYSTEM_CMDS */


/*-----------------------------------------------------------------
 * Name :   reboot_boards()
 *
 * Description: reboot slots 1 and 2
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
reboot_boards(char *(*truname_func)(char *))
{
    chassisdMsgRebootReq_t msg;
    my_print("Rebooting boards...");
    msg.hdr.mid = CHASSISD_REBOOT_REQ;
    msg.reboot_type = CM_REBOOT_TYPE_SLOT;
    msg.slot = 1;
    msg.slice = 0;
    nfxsh_send(&msg, sizeof(msg), "cm", 1, 0, 1, NULL, NULL, 0,
        NFXSH_SEND_AGILE);
    msg.slot = 2;
    nfxsh_send(&msg, sizeof(msg), "cm", 1, 0, 1, NULL, NULL, 0,
        NFXSH_SEND_AGILE);
    my_print("done\n");
    return 0;
}


/*-----------------------------------------------------------------
 * Name :   reboot_cold()
 *
 * Description: Do a cold reboot of the system
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
reboot_cold()
{
    my_print("Rebooting the system...\n");
    /* if upgrading to secondary, tell reboot to switch the disks */
    do_system("/sbin/reboot -c %s\n", upgrade_secondary ? "-s" : "");
}


/*-----------------------------------------------------------------
 * Name :   upgrade_directories()
 *
 * Description: Update directories according to new dist file.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_directories(char *mtree_file)
{
    int rc;

    my_print("Updating directories...");

    rc = do_system("/usr/sbin/mtree -qdUef %s -p %s", mtree_file,
            upgrade_secondary ? secondary_mount : "/");

    my_print("done\n");
    return convert_rc(rc);
}


/*-----------------------------------------------------------------
 * Name :   shutdown_all()
 *
 * Description: Shutdown the system software and kill the daemons so
 * we can proceed with upgrade in peace.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
void
shutdown_all(void)
{
    char buf[20];

    /* Stop the hostidd
     */
    strcpy(buf, "suspend");
    nfxsh_send(buf, strlen(buf), "hostid",
               NFX_SSC_UNIX, SSC_SLOT, MGMTPLANE, _4sec, 0, 0,
               NFXSH_SEND_AGILE);
    shutdown_system();
    shutdown_pm();
    shutdown_inetd();
}


/*-----------------------------------------------------------------
 * Name :   reboot_all()
 *
 * Description: reset FP and SP and reboot SSC.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
void
reboot_all(void)
{
    reboot_boards(NULL);
    reboot_cold();
}


/*-----------------------------------------------------------------
 * Name :   noisy_make_allfs_writable
 *
 * Description: Remount local filesystems writable making some noise
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    08/15/02
 *
 *-----------------------------------------------------------------
 */
int
noisy_make_allfs_writable(void)
{
    int rv;
    my_print("Remounting the local filesystem read-write...");
    rv = make_allfs_writable();
    if (rv == 0)
        my_print("done\n");
    else
        my_print("failed\n");
    return rv;
}


/*-----------------------------------------------------------------
 * Name :   complete_upgrade()
 *
 * Description: The worst-case upgrade - shutdown and restart everything
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
complete_upgrade(vector dv, char *(*truename_func)(char *), char *mtree_file)
{
    int rc = 0;
    cmMsgHeartbeatControlReq_t req;
#ifdef BOBCAT
    int i;
    ipm_link_change_status_t   ipm_req, ipm_rsp;
#else
    char buf[20];
#endif

    if (!upgrade_secondary) {
        bzero(&req, sizeof(req));
        req.hdr.srcSlot = 0;
        req.hdr.srcCpu = 0;
        req.hdr.srcApp =
        req.hdr.srcPlane = MGMTPLANE;
        req.hdr.mid = CM_SET_HEARTBEAT_OFF;
        req.feature_en = 0;
        nfxsh_send(&req, sizeof(req), "cm", 0, 1, MGMTPLANE,
                   0, NULL, 0, NFXSH_SEND_AGILE);
        E_LOG(class_1, notice_s, eee_getApplicationId("nfxsh"), 0, 0, 0,
             ("System will reboot due to system upgrade.\n"));
        if (sys_upgrade) {
            fprintf(sys_upgrade,"System will reboot due to system upgrade.\n");
            fflush(sys_upgrade);
        }
#ifndef BOBCAT
        sleep_accurately(3);
        /* Reboot FP and SP for cluster failover and wait for them
         * to come back to resume upgrade.
         */
        reboot_boards(NULL);
#else
        bzero(&ipm_req, sizeof(ipm_link_change_status_t));
        bzero(&ipm_rsp, sizeof(ipm_link_change_status_t));
        ipm_req.hdr.ipmh_mtype = IPM_MSG_LINK_DIS;
        ipm_req.hdr.ipmh_size = sizeof(ipm_link_change_status_t);
        for (i = 0; i < 4; i++) {
            strcpy(ipm_req.link_name, fp_ports[i]);
            if (nfxsh_send(&ipm_req, sizeof(ipm_link_change_status_t), "ipm",
                           NFX_NFP_TXRX1, NFX_SLOTTYPE_NFP, MGMTPLANE, 3,
                           &ipm_rsp, sizeof(ipm_link_change_status_t),
                           NFXSH_SEND_AGILE)
                           < sizeof(ipm_link_change_status_t)) {
                sprintf(sys_log_str,"Timeout disabling FP port %s\n",
					ipm_req.link_name);
                my_print(sys_log_str);
            }
        }
/*
        execute_command("/usr/local/agile/bin/storage", 4, "control", "port",
                        "disable", "once", NULL);
*/
#endif
        execute_command("/usr/local/agile/bin/chassis", 2,
                        "wd", "disable", NULL);
/*
        sleep_accurately(3);
*/
        shutdown_pm();
#ifndef BOBCAT
        sleep_accurately(90);
#endif
        shutdown_system();
        shutdown_inetd();
    }
    if ((upgrade_secondary || (rc = noisy_make_allfs_writable()) == 0)
        && (rc = upgrade_directories(mtree_file)) == 0) {
        my_print("Starting install of filesystem...");
        rc = do_system("/usr/local/agile/bin/verify_install.sh -f %s %s -r",
		          patch_location, upgrade_secondary ? "-s" : "-p") ;

        if (rc) {
			 my_print("Installation failed, exiting...\n") ;
			 return CMD_ERR_FAILED;
		}
        if (upgrade_secondary) {
            sync();

/*
 * Should shutown system or lock configuration files first before copy of
 * from a live system. Files could be open for edit or being modified.
 * We don't want the copied files to be in an indeterminate state.
 */
            if (sys_upgrade) {
                fprintf(sys_upgrade,"Updating configuration files, Start time: %s\n",get_time());
                fflush(sys_upgrade);
            }
            my_print("Updating configuration files\n");

            do_copy_files("/", secondary_mount, sys_config_files);

            do_system("/usr/sbin/pwd_mkdb -d %s/etc %s/etc/master.passwd",
                    secondary_mount, secondary_mount);

            if (sys_upgrade) {
                fprintf(sys_upgrade,
					"Updating configuration files, End time: %s\n", get_time());
                fflush(sys_upgrade);
            }
        } else {
#ifndef BOBCAT
            /* Stop the hostidd before rebooting boards so they can't try
             * to download while SSC is going down.
             */
            strcpy(buf, "suspend");
            nfxsh_send(buf, strlen(buf), "hostid",
                       NFX_SSC_UNIX, SSC_SLOT, MGMTPLANE, _4sec, 0, 0,
                       NFXSH_SEND_AGILE);
            reboot_boards(truename_func);
#endif
			if (sys_upgrade) {
				fprintf(sys_upgrade, "System Upgrade completed at: %s\n",
					get_time());
				fflush(sys_upgrade);
			}
            reboot_cold();
        }

		my_print("Upgrade of the standby flash completed\n");
		if (sys_upgrade) {
			fprintf(sys_upgrade, "System Upgrade completed at: %s\n",
				get_time());
			fflush(sys_upgrade);
		}

    }

    return rc;
}


/*-----------------------------------------------------------------
 * Name :   read_upgrade_descriptor()
 *
 * Description: Read the descriptor in the upgrade directory
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static vector
read_upgrade_descriptor()
{
    return read_descriptor(descriptor_file);
}


/*-----------------------------------------------------------------
 * Name :   has_valid_ip_addr()
 *
 * Description: Return true if the patch location contains a valid
 *              ip address
 * interface.
 *
 * Created by:  Laurent Brard
 *
 * Date Created:07/09/03
 *
 *-----------------------------------------------------------------
 */
static int
has_valid_ip_addr(char *patch_location)
{
    char *column = strchr(patch_location, ':');
    struct in_addr host_addr;
    int rc;

    if (column == NULL) {
        return FALSE;
	}
    *column = 0;
    rc = inet_aton(patch_location, &host_addr);
    *column = ':';

    return rc;
}

/*-----------------------------------------------------------------
 * Name :   is_fp_addr()
 *
 * Description: Return true if the patch is accessed through fp
 * interface.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static int
is_fp_addr(char *patch_location)
{
    char *column = strchr(patch_location, ':');
    struct in_addr host_addr;
    in_addr_t our_addr;
    int rc;
    char iface[256];
    *column = 0;

    inet_aton(patch_location, &host_addr);
    rc = get_our_addr(host_addr.s_addr, iface, &our_addr);
    return !(rc == 0 && (!strcmp(iface, "sc1") || !strcmp(iface, "sc2")));
}

/*-----------------------------------------------------------------
 * Name :   need_local_copy()
 *
 * Description: Return true if need to copy files to local disk before
 * upgrading - if using fp interface to upgrade and not upgrading the standby
 * flash.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    09/13/02
 *
 *-----------------------------------------------------------------
 */
static int
need_local_copy()
{
    return (!upgrade_secondary &&
            !is_ftp_upgrade(patch_location) &&
            is_fp_addr(patch_location));
}

/*-----------------------------------------------------------------
 * Name :   perform_upgrade()
 *
 * Description: upgrade a system from a complete distribution
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
perform_upgrade(void)
{
    vector dv;
    int rc = CMD_ERR_FAILED;
    char mtree_file[256];
	int make_local_copy;

    my_print("Reading the system descriptor...");
    dv = read_upgrade_descriptor();
    if (dv != NULL) {
        my_print("done\n");
        make_local_copy = need_local_copy();
        sprintf(mtree_file, "%s%s", make_local_copy ? local_dest : mount_dir,
                mtree_file_name);
        rc = complete_upgrade(dv, cur_truename_func, mtree_file);
        vector_free_all(dv);
    } else {
        my_print("failed\n");
    }
    return rc;
}

extern int __getopt_initialized;

/*-----------------------------------------------------------------
 * Name :   parse_args()
 *
 * Description: parse command line arguments
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static int
parse_args(int argc, char **argv)
{
    int i;

    upgrade_secondary = 0;
    force_upgrade = 0;

    if ((argc > 1) && (argc <= 3)) {
        for (i = 0; i < argc-1; i++) {
            if (!strcmp(argv[i], "-s")) {
                upgrade_secondary = 1;
			} else if (!strcmp(argv[i], "-f")) {
                force_upgrade = 1;
			} else {
                printf("? Invalid option\n");
                return CMD_ERR_FAILED;
            }
        }
    } else {
        if (argc != 1) {
            printf("? Invalid option\n");
            return CMD_ERR_FAILED;
        }
    }

    patch_location = argv[argc-1];
    if (!is_ftp_upgrade(patch_location)) {
    // if (!is_ftp_upgrade(patch_location) &&
    //     !has_valid_ip_addr(patch_location)) {
        my_print("Invalid upgrade location\n");
        return CMD_ERR_FAILED;
    } else {
        if (sys_upgrade) {
            fprintf(sys_upgrade,
				"Performing system upgrade from location %s\n", patch_location);
            fflush(sys_upgrade);
        }
    }
    return CMD_SUCCESS;
}

/*-----------------------------------------------------------------
 * Name : form_full_path()
 *
 * Description : Get the password and forms a full path for ftp
 *
 * Created by:
 *
 * Date Created: 03/16/06
 *
 * -----------------------------------------------------------------
 */
int
form_full_path(int argc, char **argv, char **full_path)
{
    char passwd[SEC_PWD_MAX], *start, *start_colon, *end_colon;
    char *patch_location = argv[argc-1];
    char strTar[8];
    /*
     * Check for the command incomplete.
     * if ftp is not specified then error msg will be displayed.
     */
    if (!is_ftp_upgrade(patch_location)) {
        my_print("ftp URL is not specified\n");
        return CMD_ERR_INCOMPLETE;
    }

    /* Check if tar file is specified */
    bzero(strTar,8);
    strncpy(strTar,patch_location + strlen(patch_location)-6,6);
    if (strcmp(strTar, "tar.gz")) {
        my_print("tar file is not specified\n");
        return CMD_ERR_FAILED;
    }

     /*
     * Check for the '@' in ftp.
     * If it is not specified then error msg will be displayed.
     */
    if ((start = strchr(patch_location, '@')) == NULL) {
        my_print("Unable to find hostname/ip address in ftp URL\n");
        return CMD_ERR_FAILED;
    }

    /*
     * Check to see whether the password is specified with the username.
     */
    start_colon = strchr(patch_location, ':');
    end_colon = strrchr(patch_location, ':');
    if (start_colon != end_colon) {
        *full_path = NULL;
        return CMD_SUCCESS;
    }

    /*
     * If the password is not specified with the user name, this function
     * gets the password from the user.
     */
    if (getPasswdFromUser(passwd, NULL, 0, sizeof(passwd), TRUE) != 0) {
        return CMD_ERR_FAILED;
    }

    *full_path = (char *)malloc(strlen(argv[argc-1]) + strlen(passwd) + 2);
    if(*full_path == NULL) {
        my_print("Couldn't allocate memory\n");
        return CMD_ERR_FAILED;
    }
    /*
     * Splits the 'ftp://user@ipaddr/path' into two parts.
     * Extracts the 'ftp://user' string.
     */
    memset(*full_path, 0, (strlen(argv[argc-1]) + strlen(passwd) + 2));
    strncat(*full_path, patch_location, start-patch_location);
    /*
     * Concatenates ':' and passwd with 'ftp://user'
     * After that the string will be 'ftp://user:passwd'
     */
    strcat(*full_path, ":");
    strcat(*full_path, passwd);
    /*
     * Appends the remaining string in ftp.
     * The remaining string will be '@ipaddr/path'.
     */
    strcat(*full_path, start);

    /*
     * Assigns the new string to argv[argc-1]
     */
    argv[argc-1] = *full_path;
    return CMD_SUCCESS;
}

/*-----------------------------------------------------------------
 * Name :        sendUpgradeEvent()
 *
 * Description:  Send a "NFX_EVENT_UPGRADE" event to support.sh.
 *
 * Created by:   Ed Kwan
 *
 * Date Created: 09/06/06
 *
 *-----------------------------------------------------------------
 */
static void
sendUpgradeEvent(void)
{

	do_system("/usr/local/agile/bin/support.sh -c0 -g NFX_EVENT_UPGRADE "
			 "-Called_from_nfxsh %s > /dev/null 2>&1", sys_upgrade_logfile);
}

/*-----------------------------------------------------------------
 * Name :   do_upgrade()
 *
 * Description: make system upgrade
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
int
do_upgrade(int argc, char **argv)
{
    struct version current_version, upgrade_version;
    struct version org_upgrade_version;
    int rc = CMD_SUCCESS;
    int i;
    vector secondary_fstabs = NULL;

    become_root();
    if ((sys_upgrade = fopen(sys_upgrade_logfile,"w")) == NULL )
        printf("Error opening file %s.\n",sys_upgrade_logfile);

    if (sys_upgrade) {
        fprintf(sys_upgrade,"System Upgrade Command started at: %s\n",
		    get_time());
        fflush(sys_upgrade);
    }

	/*
	 * system upgrade uses /tmp space. verify that /tmp is not full.
	 * if /tmp is full, then fail upgrade, and log error.
	 */
	if (system("if [ `df -h /tmp | tail -1 | awk '{print $5}' | sed 's/%//'` -lt 99 ]; then exit 0; else exit 1; fi")) {
		fprintf(sys_upgrade, "/tmp is full, system upgrade failed\n");
		printf("/tmp is FULL, system upgrade failed!\n");
		unbecome_root();
		rc = CMD_ERR_FAILED;
		goto done;
	}

    rc = parse_args(argc, argv);
    if (rc != CMD_SUCCESS) {
		goto done;
	}

    if (upgrade_secondary) {
        get_device_names();
		secondary_fstabs = make_secondary_fstabs();
        my_print("Checking file system...\n");
        if (sys_upgrade) {
            fprintf(sys_upgrade,"filesystem check started at: %s\n",get_time());
            fflush(sys_upgrade);
        }
        for (i = 0; i < vector_max(secondary_fstabs); ++i) {
            struct fstab *fs = vector_lookup_index(secondary_fstabs, i);
            execute_command("/sbin/fsck", 2, "-y", fs->fs_spec, NULL);
        }
        my_print("Unmounting secondary disk...");
        u_mount_secondary(secondary_fstabs);
        my_print("Mounting secondary disk...");
        rc = convert_rc(mount_secondary(secondary_fstabs));
        sprintf(sys_log_str, "%s\n", rc == CMD_SUCCESS ? "done." : "failed.");
        my_print(sys_log_str);
        if (sys_upgrade) {
            fprintf(sys_upgrade, "Mounted secondary disk at: %s\n", get_time());
            fflush(sys_upgrade);
        }
        cur_truename_func = secondary_upgrade_truename;
    } else {
        cur_truename_func = upgrade_truename;
    }

    if (rc == CMD_SUCCESS) {
        rc = mount_patch(patch_location);
        if (rc == CMD_SUCCESS) {
            my_print("Mounted the upgrade directory\n");
            if (sys_upgrade) {
                fprintf(sys_upgrade, "Mounted upgrade directory at: %s\n",
					get_time());
                fflush(sys_upgrade);
            }
            if ((rc = get_upgrade_version(&upgrade_version)) == CMD_SUCCESS) {
                get_org_upgrade_version(&org_upgrade_version);
                if ((rc = get_local_version(&current_version)) == CMD_SUCCESS) {
                    if (current_version.platform != upgrade_version.platform) {
                        my_print("The upgrade distribution is not compatible "
							"with this system!\n");
                    } else {
                        sprintf(sys_log_str,
							"Current system version: %d.%d.%d.%d "
                            "upgrade version: %d.%d.%d.%d\n",
                            current_version.major, current_version.minor,
                            current_version.maintenance, current_version.patch,
                            upgrade_version.major, upgrade_version.minor,
                            upgrade_version.maintenance, upgrade_version.patch);
                        my_print(sys_log_str);
                        if (!force_upgrade &&
                            (compare_versions(&current_version,
                                             &upgrade_version) >= 0)) {
                            my_print("The system is up-to-date\n");
                        } else {
                            /* Check for illegal upgrades. */
                            rc = check_versions_compatible(
                                     &current_version,
                                     &upgrade_version);
                            if (rc != CMD_SUCCESS) {
                                sprintf(sys_log_str,"Cannot upgrade from "
                                        "version %d.%d.%d.%d to version "
                                        "%d.%d.%d.%d\n",
                                        current_version.major,
                                        current_version.minor,
                                        current_version.maintenance,
                                        current_version.patch,
                                        upgrade_version.major,
                                        upgrade_version.minor,
                                        upgrade_version.maintenance,
                                        upgrade_version.patch);
                                my_print(sys_log_str);
                            } else if (force_upgrade ||
                                (compare_versions(&current_version,
                                                  &org_upgrade_version) >= 0)) {
                                rc = perform_upgrade();
                            } else {
								sprintf(sys_log_str,
									"Start version %d.%d.%d.%d is newer "
									"than current, can not upgrade\n",
									org_upgrade_version.major,
									org_upgrade_version.minor,
									org_upgrade_version.maintenance,
									org_upgrade_version.patch);
                                my_print(sys_log_str);
                                rc = CMD_ERR_FAILED;
                            }
                        }
                    }
                }
            } else {
                my_print("failed to determine the upgrade version\n");
            }
            umount_patch();
        }
    }

    if (upgrade_secondary) {
        u_mount_secondary(secondary_fstabs);
        free_fstab_vector(secondary_fstabs);
    }

    if (fclose(sys_upgrade) != 0) {
        printf("Error closing file %s.\n", sys_upgrade_logfile);
	}
done:
    unbecome_root();
    sendUpgradeEvent();
    return rc;
}

/*-----------------------------------------------------------------
 * Name :   show_local_version()
 *
 * Description: Show the system version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
show_local_version(void)
{
    struct version current_version;
    int rc = get_root_version(&current_version);
    if (rc != CMD_SUCCESS) {
        fprintf(stderr, "Can't determine current version\n");
        if (sys_upgrade) {
            fprintf(sys_upgrade, "Can't determine current version\n");
            fflush(sys_upgrade);
        }
    } else {
        print_version(&current_version);
    }
    return rc;
}

/*-----------------------------------------------------------------
 * Name :   show_secondary_version()
 *
 * Description: Show the version of the secondary flash
 *
 * Created by:  Danqing Jin
 *
 * Date Created:    07/05/06
 *
 *-----------------------------------------------------------------
 */
static int
show_secondary_version(void)
{
    struct version sec_version;
    int rc;
    vector secondary_fstabs = NULL;

    become_root();
    get_device_names();
    secondary_fstabs = make_secondary_fstabs();

    if ((rc = convert_rc(mount_secondary(secondary_fstabs))) == CMD_SUCCESS) {
        if (get_secondary_version(&sec_version) == CMD_SUCCESS) {
            print_version(&sec_version);
        } else {
            fprintf(stderr, "Failed to get a valid version\n");
        }
    } else {
        fprintf(stderr, "Mount of the secondary flash failed\n");
    }
    u_mount_secondary(secondary_fstabs);
    free_fstab_vector(secondary_fstabs);
    unbecome_root();

    return rc;
}

/*-----------------------------------------------------------------
 * Name :   show_remote_version()
 *
 * Description: Show the version of the patch
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
show_remote_version(char *patch_path)
{
    struct version version;
    int rc;
	char version_file[MAXPATHLEN + 1];

    become_root();
    rc = mount_patch(patch_path);
    if (rc == CMD_SUCCESS) {
	    snprintf(version_file, MAXPATHLEN + 1, "%s/version", mount_dir);
        if ((rc = read_version(version_file, &version)) == CMD_SUCCESS) {
            print_version(&version);
        }
        umount_patch();
    } else {
        fprintf(stderr, "Can not mount the patch directory\n");
        if (sys_upgrade) {
             fprintf(sys_upgrade, "Can not mount the patch directory\n");
             fflush(sys_upgrade);
        }
    }
    unbecome_root();

    return rc;
}


/*-----------------------------------------------------------------
 * Name :   do_show_version()
 *
 * Description: show the local version or a patch version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
int
do_show_version(int argc, char **argv)
{
    int c;
    optind = 0;  // This seems to be the trick for getopt() to work

    if (argc == 0) {
        return show_local_version();
    } else if (argc == 1) {
        while ((c = getopt(argc, argv, "s")) != -1) {
            switch (c) {
            case 's':
                return show_secondary_version();
            default:
                fprintf(stderr, "Invalid option\n");
                return (CMD_ERR_FAILED);
    }
        }
        return show_remote_version(argv[0]);
    } else {
        return (CMD_ERR_FAILED);
    }
}

#ifdef REACTIVATE_SYSTEM_CMDS
/*-----------------------------------------------------------------
 * Name :   do_prom_upgrade()
 *
 * Description: prom upgrade command
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
int
do_prom_upgrade(int argc, char **argv)
{
    int rc = CMD_ERR_FAILED;
    if (argc == 2) {
        int slot = atoi(argv[0]);
        int cpu = atoi(argv[1]);
        if (valid_slot_cpu(slot, cpu)) {
            rc = upgrade_prom_slotcpu(slot, cpu, NULL);
        }
    }
    return rc;
}
#endif /* REACTIVATE_SYSTEM_CMDS */

/*++

Routine Description:
    This routine sleeps for an absolute time more accurately than sleep().

Arguments:
    secs - time to sleep

Return value:
    NFX_OK or NFX_ERR

--*/
int
sleep_accurately(int secs)
{
    uint32 end_secs;
    struct timeval tv;

    if (gettimeofday(&tv, NULL) == 0) {
        end_secs = tv.tv_sec + secs;
    } else {
        return NFX_ERR;
    }
    while (tv.tv_sec < end_secs) {
        sleep(1);
        if (gettimeofday(&tv, NULL) != 0) {
            return NFX_ERR;
        }
    }
    return NFX_OK;
}

extern int __getopt_initialized;

/*-----------------------------------------------------------------
 * Name :   parse_compare_args()
 *
 * Description: parse command line arguments for System compare
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/13/05
 *
 *-----------------------------------------------------------------
 */
static int
parse_compare_args(int argc, char **argv)
{
    int c;

    compare_secondary = 0;

    __getopt_initialized = 0;
    optind = 0;

    while ((c = getopt(argc, argv, "s")) != -1) {
        switch (c) {
        case 's':
            compare_secondary = 1;
            break;
        default:
            printf("Invalid option\n");
            return CMD_ERR_FAILED;
        }
    }

    if (optind != argc - 1) {
        printf("Upgrade location not specified\n");
        return CMD_ERR_FAILED;
    }

    patch_location = argv[optind];
    if (!is_ftp_upgrade(patch_location) &&
        !has_valid_ip_addr(patch_location)) {
        printf("Invalid upgrade location\n");
        return CMD_ERR_FAILED;
    }

    return CMD_SUCCESS;
}


/*-----------------------------------------------------------------
 * Name :   perform_compare()
 *
 * Description: compares a complete system software distribution
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/13/05
 *
 *-----------------------------------------------------------------
 */
static int
perform_compare(void)
{
    vector dv;
	int rc = CMD_ERR_FAILED;

    printf("Reading the system descriptor...");
    fflush(stdout);
    dv = read_upgrade_descriptor();
    if (dv != NULL) {
        printf("done\n");
        rc = do_system("/usr/local/agile/bin/verify_install.sh -f %s %s",
		          patch_location, upgrade_secondary ? "-s" : "-p") ;
        vector_free_all(dv);
        if (rc) {
			 my_print("Verification failed, exiting...\n") ;
			 return CMD_ERR_FAILED;
		}
    } else {
        printf("failed\n");
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   do_compare()
 *
 * Description: compare system software
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/13/05
 *
 *-----------------------------------------------------------------
 */
int
do_compare(int argc, char **argv)
{
    struct version current_version, upgrade_version;
    struct version org_upgrade_version;
    int rc = CMD_SUCCESS;
    int i;
    vector secondary_fstabs = NULL;

    rc = parse_compare_args(argc, argv);
    if (rc != CMD_SUCCESS)
        return rc;

    become_root();
    if (compare_secondary) {
		get_device_names();
        secondary_fstabs = make_secondary_fstabs();
        printf("Checking file system...\n");
        for (i = 0; i < vector_max(secondary_fstabs); ++i) {
            struct fstab *fs = vector_lookup_index(secondary_fstabs, i);
            execute_command("/sbin/fsck", 2, "-y", fs->fs_spec, NULL);
        }
        printf("Mounting secondary disk...");
        fflush(stdout);
        u_mount_secondary(secondary_fstabs);
        rc = convert_rc(mount_secondary(secondary_fstabs));
        printf("%s\n", rc == CMD_SUCCESS ? "done." : "failed.");
        cur_truename_func = secondary_upgrade_truename;
    } else {
        cur_truename_func = upgrade_truename;
    }

    if (rc == CMD_SUCCESS) {
        rc = mount_patch(patch_location);
        if (rc == CMD_SUCCESS) {
            printf("Mounted the external system software directory\n");
            if ((rc = get_upgrade_version(&upgrade_version)) == CMD_SUCCESS) {
                get_org_upgrade_version(&org_upgrade_version);
                if ((rc = get_local_version(&current_version)) == CMD_SUCCESS) {
                    if (current_version.platform != upgrade_version.platform) {
                        printf("The external system software distribution is "
							"not compatible with this system!\n");
                    } else {
                        printf("Current system version: %d.%d.%d.%d "
                            "compare version: %d.%d.%d.%d\n",
                            current_version.major, current_version.minor,
                            current_version.maintenance, current_version.patch,
                            upgrade_version.major, upgrade_version.minor,
                            upgrade_version.maintenance, upgrade_version.patch);
                        rc = perform_compare();
                    }
                }
            } else {
                printf("failed to determine the compare version and perform "
					"comparison\n");
            }
			umount_patch();
        }
    }

    if (compare_secondary) {
        u_mount_secondary(secondary_fstabs);
        free_fstab_vector(secondary_fstabs);
    }

    unbecome_root();
    return rc;
}


--MP_p6e8RDu5=WN56tCwhhl+oG/--
